瀏覽代碼

Merge branch 'topic/asoc' into for-linus

Takashi Iwai 14 年之前
父節點
當前提交
7ec298dfef
共有 100 個文件被更改,包括 13915 次插入1875 次删除
  1. 3 3
      MAINTAINERS
  2. 3 0
      arch/arm/mach-tegra/Kconfig
  3. 4 3
      arch/arm/mach-tegra/board-harmony.c
  4. 3 2
      arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h
  5. 0 1
      drivers/staging/intel_sst/intel_sst_drv_interface.c
  6. 4 0
      drivers/staging/intel_sst/intelmid.c
  7. 49 0
      include/linux/mfd/wm8994/pdata.h
  8. 26 0
      include/sound/ak4641.h
  9. 54 0
      include/sound/max98095.h
  10. 44 36
      include/sound/soc-dapm.h
  11. 27 5
      include/sound/soc.h
  12. 1 1
      include/sound/tlv320dac33-plat.h
  13. 1 1
      include/sound/tpa6130a2-plat.h
  14. 55 0
      include/sound/wm8915.h
  15. 22 0
      include/sound/wm8962.h
  16. 1 1
      sound/soc/atmel/sam9g20_wm8731.c
  17. 1 1
      sound/soc/au1x/db1200.c
  18. 10 3
      sound/soc/blackfin/bf5xx-ac97-pcm.c
  19. 53 113
      sound/soc/blackfin/bf5xx-ac97.c
  20. 21 21
      sound/soc/blackfin/bf5xx-ad1836.c
  21. 35 21
      sound/soc/blackfin/bf5xx-ad193x.c
  22. 20 25
      sound/soc/blackfin/bf5xx-ad1980.c
  23. 21 21
      sound/soc/blackfin/bf5xx-ad73311.c
  24. 13 10
      sound/soc/blackfin/bf5xx-i2s-pcm.c
  25. 73 99
      sound/soc/blackfin/bf5xx-i2s.c
  26. 119 40
      sound/soc/blackfin/bf5xx-sport.c
  27. 11 5
      sound/soc/blackfin/bf5xx-sport.h
  28. 21 21
      sound/soc/blackfin/bf5xx-ssm2602.c
  29. 13 10
      sound/soc/blackfin/bf5xx-tdm-pcm.c
  30. 38 72
      sound/soc/blackfin/bf5xx-tdm.c
  31. 1 1
      sound/soc/codecs/88pm860x-codec.c
  32. 18 2
      sound/soc/codecs/Kconfig
  33. 9 1
      sound/soc/codecs/Makefile
  34. 9 14
      sound/soc/codecs/ad193x.c
  35. 1 1
      sound/soc/codecs/ad1980.c
  36. 1 1
      sound/soc/codecs/ad73311.c
  37. 5 14
      sound/soc/codecs/ak4535.c
  38. 664 0
      sound/soc/codecs/ak4641.c
  39. 47 0
      sound/soc/codecs/ak4641.h
  40. 5 13
      sound/soc/codecs/ak4671.c
  41. 4 14
      sound/soc/codecs/cx20442.c
  42. 25 1
      sound/soc/codecs/dmic.c
  43. 7 11
      sound/soc/codecs/jz4740.c
  44. 52 35
      sound/soc/codecs/max98088.c
  45. 13 0
      sound/soc/codecs/max98088.h
  46. 2396 0
      sound/soc/codecs/max98095.c
  47. 299 0
      sound/soc/codecs/max98095.h
  48. 5 12
      sound/soc/codecs/sn95031.c
  49. 6 2
      sound/soc/codecs/spdif_transciever.c
  50. 260 212
      sound/soc/codecs/ssm2602.c
  51. 0 6
      sound/soc/codecs/ssm2602.h
  52. 5 14
      sound/soc/codecs/tlv320aic23.c
  53. 2 1
      sound/soc/codecs/tlv320aic3x.c
  54. 10 7
      sound/soc/codecs/tlv320dac33.c
  55. 1 1
      sound/soc/codecs/tlv320dac33.h
  56. 2 2
      sound/soc/codecs/tpa6130a2.c
  57. 1 1
      sound/soc/codecs/tpa6130a2.h
  58. 3 3
      sound/soc/codecs/twl6040.c
  59. 0 2
      sound/soc/codecs/uda134x.c
  60. 108 0
      sound/soc/codecs/wm1250-ev1.c
  61. 5 13
      sound/soc/codecs/wm8711.c
  62. 5 13
      sound/soc/codecs/wm8728.c
  63. 7 15
      sound/soc/codecs/wm8731.c
  64. 29 17
      sound/soc/codecs/wm8903.c
  65. 2931 0
      sound/soc/codecs/wm8915.c
  66. 3717 0
      sound/soc/codecs/wm8915.h
  67. 1051 0
      sound/soc/codecs/wm8958-dsp2.c
  68. 58 5
      sound/soc/codecs/wm8962.c
  69. 2 1
      sound/soc/codecs/wm8993.c
  70. 81 314
      sound/soc/codecs/wm8994.c
  71. 97 0
      sound/soc/codecs/wm8994.h
  72. 2 2
      sound/soc/codecs/wm8995.c
  73. 5 13
      sound/soc/codecs/wm9705.c
  74. 5 13
      sound/soc/codecs/wm9712.c
  75. 5 14
      sound/soc/codecs/wm9713.c
  76. 14 10
      sound/soc/codecs/wm_hubs.c
  77. 2 0
      sound/soc/davinci/davinci-mcasp.c
  78. 0 6
      sound/soc/imx/imx-ssi.c
  79. 1 1
      sound/soc/jz4740/jz4740-i2s.c
  80. 16 30
      sound/soc/jz4740/qi_lb60.c
  81. 10 0
      sound/soc/mid-x86/sst_platform.c
  82. 3 3
      sound/soc/omap/omap-mcbsp.c
  83. 1 1
      sound/soc/omap/omap-mcbsp.h
  84. 4 3
      sound/soc/omap/omap-pcm.c
  85. 1 1
      sound/soc/omap/omap-pcm.h
  86. 1 1
      sound/soc/omap/rx51.c
  87. 9 0
      sound/soc/pxa/Kconfig
  88. 2 0
      sound/soc/pxa/Makefile
  89. 1 1
      sound/soc/pxa/corgi.c
  90. 255 0
      sound/soc/pxa/hx4700.c
  91. 1 1
      sound/soc/pxa/poodle.c
  92. 29 12
      sound/soc/pxa/spitz.c
  93. 15 0
      sound/soc/samsung/Kconfig
  94. 4 0
      sound/soc/samsung/Makefile
  95. 0 1
      sound/soc/samsung/goni_wm8994.c
  96. 0 1
      sound/soc/samsung/neo1973_wm8753.c
  97. 206 0
      sound/soc/samsung/smdk_wm8580pcm.c
  98. 332 0
      sound/soc/samsung/speyside.c
  99. 155 33
      sound/soc/sh/fsi.c
  100. 148 464
      sound/soc/soc-cache.c

+ 3 - 3
MAINTAINERS

@@ -5854,7 +5854,7 @@ F:	include/sound/
 F:	sound/
 F:	sound/
 
 
 SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
 SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
-M:	Liam Girdwood <lrg@slimlogic.co.uk>
+M:	Liam Girdwood <lrg@ti.com>
 M:	Mark Brown <broonie@opensource.wolfsonmicro.com>
 M:	Mark Brown <broonie@opensource.wolfsonmicro.com>
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -6105,7 +6105,7 @@ F:	drivers/mmc/host/tifm_sd.c
 F:	include/linux/tifm.h
 F:	include/linux/tifm.h
 
 
 TI TWL4030 SERIES SOC CODEC DRIVER
 TI TWL4030 SERIES SOC CODEC DRIVER
-M:	Peter Ujfalusi <peter.ujfalusi@nokia.com>
+M:	Peter Ujfalusi <peter.ujfalusi@ti.com>
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
 L:	alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:	Maintained
 S:	Maintained
 F:	sound/soc/codecs/twl4030*
 F:	sound/soc/codecs/twl4030*
@@ -6749,7 +6749,7 @@ F:	drivers/scsi/vmw_pvscsi.c
 F:	drivers/scsi/vmw_pvscsi.h
 F:	drivers/scsi/vmw_pvscsi.h
 
 
 VOLTAGE AND CURRENT REGULATOR FRAMEWORK
 VOLTAGE AND CURRENT REGULATOR FRAMEWORK
-M:	Liam Girdwood <lrg@slimlogic.co.uk>
+M:	Liam Girdwood <lrg@ti.com>
 M:	Mark Brown <broonie@opensource.wolfsonmicro.com>
 M:	Mark Brown <broonie@opensource.wolfsonmicro.com>
 W:	http://opensource.wolfsonmicro.com/node/15
 W:	http://opensource.wolfsonmicro.com/node/15
 W:	http://www.slimlogic.co.uk/?p=48
 W:	http://www.slimlogic.co.uk/?p=48

+ 3 - 0
arch/arm/mach-tegra/Kconfig

@@ -27,12 +27,14 @@ comment "Tegra board type"
 
 
 config MACH_HARMONY
 config MACH_HARMONY
        bool "Harmony board"
        bool "Harmony board"
+       select MACH_HAS_SND_SOC_TEGRA_WM8903
        help
        help
          Support for nVidia Harmony development platform
          Support for nVidia Harmony development platform
 
 
 config MACH_KAEN
 config MACH_KAEN
        bool "Kaen board"
        bool "Kaen board"
        select MACH_SEABOARD
        select MACH_SEABOARD
+       select MACH_HAS_SND_SOC_TEGRA_WM8903
        help
        help
          Support for the Kaen version of Seaboard
          Support for the Kaen version of Seaboard
 
 
@@ -43,6 +45,7 @@ config MACH_PAZ00
 
 
 config MACH_SEABOARD
 config MACH_SEABOARD
        bool "Seaboard board"
        bool "Seaboard board"
+       select MACH_HAS_SND_SOC_TEGRA_WM8903
        help
        help
          Support for nVidia Seaboard development platform. It will
          Support for nVidia Seaboard development platform. It will
 	 also be included for some of the derivative boards that
 	 also be included for some of the derivative boards that

+ 4 - 3
arch/arm/mach-tegra/board-harmony.c

@@ -34,7 +34,7 @@
 #include <asm/mach/time.h>
 #include <asm/mach/time.h>
 #include <asm/setup.h>
 #include <asm/setup.h>
 
 
-#include <mach/harmony_audio.h>
+#include <mach/tegra_wm8903_pdata.h>
 #include <mach/iomap.h>
 #include <mach/iomap.h>
 #include <mach/irqs.h>
 #include <mach/irqs.h>
 #include <mach/sdhci.h>
 #include <mach/sdhci.h>
@@ -67,15 +67,16 @@ static struct platform_device debug_uart = {
 	},
 	},
 };
 };
 
 
-static struct harmony_audio_platform_data harmony_audio_pdata = {
+static struct tegra_wm8903_platform_data harmony_audio_pdata = {
 	.gpio_spkr_en		= TEGRA_GPIO_SPKR_EN,
 	.gpio_spkr_en		= TEGRA_GPIO_SPKR_EN,
 	.gpio_hp_det		= TEGRA_GPIO_HP_DET,
 	.gpio_hp_det		= TEGRA_GPIO_HP_DET,
+	.gpio_hp_mute		= -1,
 	.gpio_int_mic_en	= TEGRA_GPIO_INT_MIC_EN,
 	.gpio_int_mic_en	= TEGRA_GPIO_INT_MIC_EN,
 	.gpio_ext_mic_en	= TEGRA_GPIO_EXT_MIC_EN,
 	.gpio_ext_mic_en	= TEGRA_GPIO_EXT_MIC_EN,
 };
 };
 
 
 static struct platform_device harmony_audio_device = {
 static struct platform_device harmony_audio_device = {
-	.name	= "tegra-snd-harmony",
+	.name	= "tegra-snd-wm8903",
 	.id	= 0,
 	.id	= 0,
 	.dev	= {
 	.dev	= {
 		.platform_data  = &harmony_audio_pdata,
 		.platform_data  = &harmony_audio_pdata,

+ 3 - 2
arch/arm/mach-tegra/include/mach/harmony_audio.h → arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h

@@ -1,5 +1,5 @@
 /*
 /*
- * arch/arm/mach-tegra/include/mach/harmony_audio.h
+ * arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h
  *
  *
  * Copyright 2011 NVIDIA, Inc.
  * Copyright 2011 NVIDIA, Inc.
  *
  *
@@ -14,9 +14,10 @@
  *
  *
  */
  */
 
 
-struct harmony_audio_platform_data {
+struct tegra_wm8903_platform_data {
 	int gpio_spkr_en;
 	int gpio_spkr_en;
 	int gpio_hp_det;
 	int gpio_hp_det;
+	int gpio_hp_mute;
 	int gpio_int_mic_en;
 	int gpio_int_mic_en;
 	int gpio_ext_mic_en;
 	int gpio_ext_mic_en;
 };
 };

+ 0 - 1
drivers/staging/intel_sst/intel_sst_drv_interface.c

@@ -508,7 +508,6 @@ int register_sst_card(struct intel_sst_card_ops *card)
 			sst_drv_ctx->pmic_state = SND_MAD_INIT_DONE;
 			sst_drv_ctx->pmic_state = SND_MAD_INIT_DONE;
 			sst_drv_ctx->rx_time_slot_status = 0; /*default AMIC*/
 			sst_drv_ctx->rx_time_slot_status = 0; /*default AMIC*/
 			card->pcm_control = sst_pmic_ops.pcm_control;
 			card->pcm_control = sst_pmic_ops.pcm_control;
-			sst_drv_ctx->scard_ops->card_status = SND_CARD_UN_INIT;
 			return 0;
 			return 0;
 		} else {
 		} else {
 			pr_err("strcmp fail %s\n", card->module_name);
 			pr_err("strcmp fail %s\n", card->module_name);

+ 4 - 0
drivers/staging/intel_sst/intelmid.c

@@ -32,6 +32,7 @@
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/sched.h>
+#include <linux/firmware.h>
 #include <sound/control.h>
 #include <sound/control.h>
 #include <asm/mrst.h>
 #include <asm/mrst.h>
 #include <sound/pcm.h>
 #include <sound/pcm.h>
@@ -40,6 +41,8 @@
 #include <sound/initval.h>
 #include <sound/initval.h>
 #include "intel_sst.h"
 #include "intel_sst.h"
 #include "intel_sst_ioctl.h"
 #include "intel_sst_ioctl.h"
+#include "intel_sst_fw_ipc.h"
+#include "intel_sst_common.h"
 #include "intelmid_snd_control.h"
 #include "intelmid_snd_control.h"
 #include "intelmid.h"
 #include "intelmid.h"
 
 
@@ -802,6 +805,7 @@ static int __devinit snd_intelmad_sst_register(
 		pr_err("sst card registration failed\n");
 		pr_err("sst card registration failed\n");
 		return ret_val;
 		return ret_val;
 	}
 	}
+	sst_drv_ctx->scard_ops->card_status = SND_CARD_UN_INIT;
 
 
 	sst_card_vendor_id = intelmaddata->sstdrv_ops->vendor_id;
 	sst_card_vendor_id = intelmaddata->sstdrv_ops->vendor_id;
 	intelmaddata->pmic_status = PMIC_UNINIT;
 	intelmaddata->pmic_status = PMIC_UNINIT;

+ 49 - 0
include/linux/mfd/wm8994/pdata.h

@@ -32,6 +32,10 @@ struct wm8994_ldo_pdata {
 #define WM8994_EQ_REGS  20
 #define WM8994_EQ_REGS  20
 #define WM8958_MBC_CUTOFF_REGS 20
 #define WM8958_MBC_CUTOFF_REGS 20
 #define WM8958_MBC_COEFF_REGS  48
 #define WM8958_MBC_COEFF_REGS  48
+#define WM8958_MBC_COMBINED_REGS 56
+#define WM8958_VSS_HPF_REGS 2
+#define WM8958_VSS_REGS 148
+#define WM8958_ENH_EQ_REGS 32
 
 
 /**
 /**
  * DRC configurations are specified with a label and a set of register
  * DRC configurations are specified with a label and a set of register
@@ -71,6 +75,42 @@ struct wm8958_mbc_cfg {
 	const char *name;
 	const char *name;
 	u16 cutoff_regs[WM8958_MBC_CUTOFF_REGS];
 	u16 cutoff_regs[WM8958_MBC_CUTOFF_REGS];
 	u16 coeff_regs[WM8958_MBC_COEFF_REGS];
 	u16 coeff_regs[WM8958_MBC_COEFF_REGS];
+
+	/* Coefficient layout when using MBC+VSS firmware */
+	u16 combined_regs[WM8958_MBC_COMBINED_REGS];
+};
+
+/**
+ * VSS HPF configurations are specified with a label and two values to
+ * write.  Configurations are expected to be generated using the
+ * multiband compressor configuration panel in WISCE - see
+ * http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8958_vss_hpf_cfg {
+	const char *name;
+	u16 regs[WM8958_VSS_HPF_REGS];
+};
+
+/**
+ * VSS configurations are specified with a label and array of values
+ * to write.  Configurations are expected to be generated using the
+ * multiband compressor configuration panel in WISCE - see
+ * http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8958_vss_cfg {
+	const char *name;
+	u16 regs[WM8958_VSS_REGS];
+};
+
+/**
+ * Enhanced EQ configurations are specified with a label and array of
+ * values to write.  Configurations are expected to be generated using
+ * the multiband compressor configuration panel in WISCE - see
+ * http://www.wolfsonmicro.com/wisce/
+ */
+struct wm8958_enh_eq_cfg {
+	const char *name;
+	u16 regs[WM8958_ENH_EQ_REGS];
 };
 };
 
 
 struct wm8994_pdata {
 struct wm8994_pdata {
@@ -95,6 +135,15 @@ struct wm8994_pdata {
 	int num_mbc_cfgs;
 	int num_mbc_cfgs;
 	struct wm8958_mbc_cfg *mbc_cfgs;
 	struct wm8958_mbc_cfg *mbc_cfgs;
 
 
+	int num_vss_cfgs;
+	struct wm8958_vss_cfg *vss_cfgs;
+
+	int num_vss_hpf_cfgs;
+	struct wm8958_vss_hpf_cfg *vss_hpf_cfgs;
+
+	int num_enh_eq_cfgs;
+	struct wm8958_enh_eq_cfg *enh_eq_cfgs;
+
         /* LINEOUT can be differential or single ended */
         /* LINEOUT can be differential or single ended */
         unsigned int lineout1_diff:1;
         unsigned int lineout1_diff:1;
         unsigned int lineout2_diff:1;
         unsigned int lineout2_diff:1;

+ 26 - 0
include/sound/ak4641.h

@@ -0,0 +1,26 @@
+/*
+ * AK4641 ALSA SoC Codec driver
+ *
+ * Copyright 2009 Philipp Zabel
+ *
+ * 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 __AK4641_H
+#define __AK4641_H
+
+/**
+ * struct ak4641_platform_data - platform specific AK4641 configuration
+ * @gpio_power:	GPIO to control external power to AK4641
+ * @gpio_npdn:	GPIO connected to AK4641 nPDN pin
+ *
+ * Both GPIO parameters are optional.
+ */
+struct ak4641_platform_data {
+	int gpio_power;
+	int gpio_npdn;
+};
+
+#endif /* __AK4641_H */

+ 54 - 0
include/sound/max98095.h

@@ -0,0 +1,54 @@
+/*
+ * Platform data for MAX98095
+ *
+ * Copyright 2011 Maxim Integrated Products
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __SOUND_MAX98095_PDATA_H__
+#define __SOUND_MAX98095_PDATA_H__
+
+/* Equalizer filter response configuration */
+struct max98095_eq_cfg {
+	const char *name;
+	unsigned int rate;
+	u16 band1[5];
+	u16 band2[5];
+	u16 band3[5];
+	u16 band4[5];
+	u16 band5[5];
+};
+
+/* Biquad filter response configuration */
+struct max98095_biquad_cfg {
+	const char *name;
+	unsigned int rate;
+	u16 band1[5];
+	u16 band2[5];
+};
+
+/* codec platform data */
+struct max98095_pdata {
+
+	/* Equalizers for DAI1 and DAI2 */
+	struct max98095_eq_cfg *eq_cfg;
+	unsigned int eq_cfgcnt;
+
+	/* Biquad filter for DAI1 and DAI2 */
+	struct max98095_biquad_cfg *bq_cfg;
+	unsigned int bq_cfgcnt;
+
+	/* Analog/digital microphone configuration:
+	 * 0 = analog microphone input (normal setting)
+	 * 1 = digital microphone input
+	 */
+	unsigned int digmic_left_mode:1;
+	unsigned int digmic_right_mode:1;
+};
+
+#endif

+ 44 - 36
include/sound/soc-dapm.h

@@ -24,7 +24,7 @@
  * SoC dynamic audio power management
  * SoC dynamic audio power management
  *
  *
  * We can have up to 4 power domains
  * We can have up to 4 power domains
- * 	1. Codec domain - VREF, VMID
+ *  1. Codec domain - VREF, VMID
  *     Usually controlled at codec probe/remove, although can be set
  *     Usually controlled at codec probe/remove, although can be set
  *     at stream time if power is not needed for sidetone, etc.
  *     at stream time if power is not needed for sidetone, etc.
  *  2. Platform/Machine domain - physically connected inputs and outputs
  *  2. Platform/Machine domain - physically connected inputs and outputs
@@ -39,30 +39,30 @@
 
 
 /* codec domain */
 /* codec domain */
 #define SND_SOC_DAPM_VMID(wname) \
 #define SND_SOC_DAPM_VMID(wname) \
-{	.id = snd_soc_dapm_vmid, .name = wname, .kcontrols = NULL, \
+{	.id = snd_soc_dapm_vmid, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0}
 	.num_kcontrols = 0}
 
 
 /* platform domain */
 /* platform domain */
 #define SND_SOC_DAPM_INPUT(wname) \
 #define SND_SOC_DAPM_INPUT(wname) \
-{	.id = snd_soc_dapm_input, .name = wname, .kcontrols = NULL, \
+{	.id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM }
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM }
 #define SND_SOC_DAPM_OUTPUT(wname) \
 #define SND_SOC_DAPM_OUTPUT(wname) \
-{	.id = snd_soc_dapm_output, .name = wname, .kcontrols = NULL, \
+{	.id = snd_soc_dapm_output, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM }
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM }
 #define SND_SOC_DAPM_MIC(wname, wevent) \
 #define SND_SOC_DAPM_MIC(wname, wevent) \
-{	.id = snd_soc_dapm_mic, .name = wname, .kcontrols = NULL, \
+{	.id = snd_soc_dapm_mic, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
 	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
 #define SND_SOC_DAPM_HP(wname, wevent) \
 #define SND_SOC_DAPM_HP(wname, wevent) \
-{	.id = snd_soc_dapm_hp, .name = wname, .kcontrols = NULL, \
+{	.id = snd_soc_dapm_hp, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 #define SND_SOC_DAPM_SPK(wname, wevent) \
 #define SND_SOC_DAPM_SPK(wname, wevent) \
-{	.id = snd_soc_dapm_spk, .name = wname, .kcontrols = NULL, \
+{	.id = snd_soc_dapm_spk, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 #define SND_SOC_DAPM_LINE(wname, wevent) \
 #define SND_SOC_DAPM_LINE(wname, wevent) \
-{	.id = snd_soc_dapm_line, .name = wname, .kcontrols = NULL, \
+{	.id = snd_soc_dapm_line, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 
 
@@ -70,91 +70,91 @@
 #define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\
 #define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\
 	 wcontrols, wncontrols) \
 	 wcontrols, wncontrols) \
 {	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\
 #define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\
 	 wcontrols, wncontrols) \
 	 wcontrols, wncontrols) \
 {	.id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
 #define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
 	 wcontrols, wncontrols)\
 	 wcontrols, wncontrols)\
 {	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \
 #define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \
 	 wcontrols, wncontrols)\
 	 wcontrols, wncontrols)\
 {       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
 {       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
-	.shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
+	.shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
 	.num_kcontrols = wncontrols}
 	.num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \
 #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \
 {	.id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = NULL, .num_kcontrols = 0}
+	.invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0}
 #define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \
 #define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \
 {	.id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
 #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
 {	.id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \
 #define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \
 {	.id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \
 #define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \
 {	.id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \
 {	.id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \
-	.shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
+	.shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
 	.num_kcontrols = 1}
 	.num_kcontrols = 1}
 
 
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
 #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
 	 wcontrols) \
 	 wcontrols) \
 {	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
 #define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \
 #define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \
 	 wcontrols)\
 	 wcontrols)\
 {	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
 #define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \
 #define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \
 	 wcontrols)\
 	 wcontrols)\
 {       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
 {       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
-	.shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
+	.shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
 	.num_kcontrols = ARRAY_SIZE(wcontrols)}
 	.num_kcontrols = ARRAY_SIZE(wcontrols)}
 
 
 /* path domain with event - event handler must return 0 for success */
 /* path domain with event - event handler must return 0 for success */
 #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
 #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
 	wncontrols, wevent, wflags) \
 	wncontrols, wevent, wflags) \
 {	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
 	.event = wevent, .event_flags = wflags}
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \
 #define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \
 	wncontrols, wevent, wflags) \
 	wncontrols, wevent, wflags) \
 {	.id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
 	.event = wevent, .event_flags = wflags}
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \
 #define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \
 	wncontrols, wevent, wflags) \
 	wncontrols, wevent, wflags) \
 {	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
 	.event = wevent, .event_flags = wflags}
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \
 #define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \
 	wcontrols, wncontrols, wevent, wflags) \
 	wcontrols, wncontrols, wevent, wflags) \
 {       .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
 {       .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, \
+	.invert = winvert, .kcontrol_news = wcontrols, \
 	.num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags}
 	.num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MICBIAS_E(wname, wreg, wshift, winvert, wevent, wflags) \
 #define SND_SOC_DAPM_MICBIAS_E(wname, wreg, wshift, winvert, wevent, wflags) \
 {	.id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = NULL, .num_kcontrols = 0, \
+	.invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0, \
 	.event = wevent, .event_flags = wflags}
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
 #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
 	wevent, wflags) \
 	wevent, wflags) \
 {	.id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
 	.event = wevent, .event_flags = wflags}
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
 #define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
 	wevent, wflags) \
 	wevent, wflags) \
 {	.id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
 	.event = wevent, .event_flags = wflags}
 	.event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
 #define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
 	wevent, wflags) \
 	wevent, wflags) \
 {	.id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
 	.event = wevent, .event_flags = wflags}
 	.event = wevent, .event_flags = wflags}
 
 
 /* additional sequencing control within an event type */
 /* additional sequencing control within an event type */
@@ -173,26 +173,26 @@
 #define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
 #define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
 	wevent, wflags) \
 	wevent, wflags) \
 {	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
 	.event = wevent, .event_flags = wflags}
 	.event = wevent, .event_flags = wflags}
 #define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
 #define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
 	wevent, wflags) \
 	wevent, wflags) \
 {	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
 {	.id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
+	.invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
 	.event = wevent, .event_flags = wflags}
 	.event = wevent, .event_flags = wflags}
 #define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \
 #define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \
 	wcontrols, wevent, wflags) \
 	wcontrols, wevent, wflags) \
 {       .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
 {       .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-	.invert = winvert, .kcontrols = wcontrols, \
+	.invert = winvert, .kcontrol_news = wcontrols, \
 	.num_kcontrols = ARRAY_SIZE(wcontrols), .event = wevent, .event_flags = wflags}
 	.num_kcontrols = ARRAY_SIZE(wcontrols), .event = wevent, .event_flags = wflags}
 
 
 /* events that are pre and post DAPM */
 /* events that are pre and post DAPM */
 #define SND_SOC_DAPM_PRE(wname, wevent) \
 #define SND_SOC_DAPM_PRE(wname, wevent) \
-{	.id = snd_soc_dapm_pre, .name = wname, .kcontrols = NULL, \
+{	.id = snd_soc_dapm_pre, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD}
 	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD}
 #define SND_SOC_DAPM_POST(wname, wevent) \
 #define SND_SOC_DAPM_POST(wname, wevent) \
-{	.id = snd_soc_dapm_post, .name = wname, .kcontrols = NULL, \
+{	.id = snd_soc_dapm_post, .name = wname, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD}
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD}
 
 
@@ -232,7 +232,7 @@
 
 
 /* generic widgets */
 /* generic widgets */
 #define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \
 #define SND_SOC_DAPM_REG(wid, wname, wreg, wshift, wmask, won_val, woff_val) \
-{	.id = wid, .name = wname, .kcontrols = NULL, .num_kcontrols = 0, \
+{	.id = wid, .name = wname, .kcontrol_news = NULL, .num_kcontrols = 0, \
 	.reg = -((wreg) + 1), .shift = wshift, .mask = wmask, \
 	.reg = -((wreg) + 1), .shift = wshift, .mask = wmask, \
 	.on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \
 	.on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \
 	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
 	.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
@@ -356,7 +356,8 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card);
 
 
 /* dapm sys fs - used by the core */
 /* dapm sys fs - used by the core */
 int snd_soc_dapm_sys_add(struct device *dev);
 int snd_soc_dapm_sys_add(struct device *dev);
-void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm);
+void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
+				struct dentry *parent);
 
 
 /* dapm audio pin control and status */
 /* dapm audio pin control and status */
 int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm,
 int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm,
@@ -472,7 +473,8 @@ struct snd_soc_dapm_widget {
 
 
 	/* kcontrols that relate to this widget */
 	/* kcontrols that relate to this widget */
 	int num_kcontrols;
 	int num_kcontrols;
-	const struct snd_kcontrol_new *kcontrols;
+	const struct snd_kcontrol_new *kcontrol_news;
+	struct snd_kcontrol **kcontrols;
 
 
 	/* widget input and outputs */
 	/* widget input and outputs */
 	struct list_head sources;
 	struct list_head sources;
@@ -516,4 +518,10 @@ struct snd_soc_dapm_context {
 #endif
 #endif
 };
 };
 
 
+/* A list of widgets associated with an object, typically a snd_kcontrol */
+struct snd_soc_dapm_widget_list {
+	int num_widgets;
+	struct snd_soc_dapm_widget *widgets[0];
+};
+
 #endif
 #endif

+ 27 - 5
include/sound/soc.h

@@ -248,7 +248,7 @@ typedef int (*hw_write_t)(void *,const char* ,int);
 extern struct snd_ac97_bus_ops soc_ac97_ops;
 extern struct snd_ac97_bus_ops soc_ac97_ops;
 
 
 enum snd_soc_control_type {
 enum snd_soc_control_type {
-	SND_SOC_CUSTOM,
+	SND_SOC_CUSTOM = 1,
 	SND_SOC_I2C,
 	SND_SOC_I2C,
 	SND_SOC_SPI,
 	SND_SOC_SPI,
 };
 };
@@ -278,6 +278,10 @@ int snd_soc_register_codec(struct device *dev,
 void snd_soc_unregister_codec(struct device *dev);
 void snd_soc_unregister_codec(struct device *dev);
 int snd_soc_codec_volatile_register(struct snd_soc_codec *codec,
 int snd_soc_codec_volatile_register(struct snd_soc_codec *codec,
 				    unsigned int reg);
 				    unsigned int reg);
+int snd_soc_codec_readable_register(struct snd_soc_codec *codec,
+				    unsigned int reg);
+int snd_soc_codec_writable_register(struct snd_soc_codec *codec,
+				    unsigned int reg);
 int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
 int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
 			       int addr_bits, int data_bits,
 			       int addr_bits, int data_bits,
 			       enum snd_soc_control_type control);
 			       enum snd_soc_control_type control);
@@ -292,6 +296,8 @@ int snd_soc_default_volatile_register(struct snd_soc_codec *codec,
 				      unsigned int reg);
 				      unsigned int reg);
 int snd_soc_default_readable_register(struct snd_soc_codec *codec,
 int snd_soc_default_readable_register(struct snd_soc_codec *codec,
 				      unsigned int reg);
 				      unsigned int reg);
+int snd_soc_default_writable_register(struct snd_soc_codec *codec,
+				      unsigned int reg);
 
 
 /* Utility functions to get clock rates from various things */
 /* Utility functions to get clock rates from various things */
 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
@@ -523,6 +529,7 @@ struct snd_soc_codec {
 	size_t reg_size;	/* reg_cache_size * reg_word_size */
 	size_t reg_size;	/* reg_cache_size * reg_word_size */
 	int (*volatile_register)(struct snd_soc_codec *, unsigned int);
 	int (*volatile_register)(struct snd_soc_codec *, unsigned int);
 	int (*readable_register)(struct snd_soc_codec *, unsigned int);
 	int (*readable_register)(struct snd_soc_codec *, unsigned int);
+	int (*writable_register)(struct snd_soc_codec *, unsigned int);
 
 
 	/* runtime */
 	/* runtime */
 	struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
 	struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
@@ -539,10 +546,12 @@ struct snd_soc_codec {
 
 
 	/* codec IO */
 	/* codec IO */
 	void *control_data; /* codec control (i2c/3wire) data */
 	void *control_data; /* codec control (i2c/3wire) data */
+	enum snd_soc_control_type control_type;
 	hw_write_t hw_write;
 	hw_write_t hw_write;
 	unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
 	unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
 	unsigned int (*read)(struct snd_soc_codec *, unsigned int);
 	unsigned int (*read)(struct snd_soc_codec *, unsigned int);
 	int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
 	int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
+	int (*bulk_write_raw)(struct snd_soc_codec *, unsigned int, const void *, size_t);
 	void *reg_cache;
 	void *reg_cache;
 	const void *reg_def_copy;
 	const void *reg_def_copy;
 	const struct snd_soc_cache_ops *cache_ops;
 	const struct snd_soc_cache_ops *cache_ops;
@@ -568,7 +577,9 @@ struct snd_soc_codec_driver {
 			pm_message_t state);
 			pm_message_t state);
 	int (*resume)(struct snd_soc_codec *);
 	int (*resume)(struct snd_soc_codec *);
 
 
-	/* Default DAPM setup, added after probe() is run */
+	/* Default control and setup, added after probe() is run */
+	const struct snd_kcontrol_new *controls;
+	int num_controls;
 	const struct snd_soc_dapm_widget *dapm_widgets;
 	const struct snd_soc_dapm_widget *dapm_widgets;
 	int num_dapm_widgets;
 	int num_dapm_widgets;
 	const struct snd_soc_dapm_route *dapm_routes;
 	const struct snd_soc_dapm_route *dapm_routes;
@@ -587,6 +598,7 @@ struct snd_soc_codec_driver {
 				size_t, unsigned int);
 				size_t, unsigned int);
 	int (*volatile_register)(struct snd_soc_codec *, unsigned int);
 	int (*volatile_register)(struct snd_soc_codec *, unsigned int);
 	int (*readable_register)(struct snd_soc_codec *, unsigned int);
 	int (*readable_register)(struct snd_soc_codec *, unsigned int);
+	int (*writable_register)(struct snd_soc_codec *, unsigned int);
 	short reg_cache_size;
 	short reg_cache_size;
 	short reg_cache_step;
 	short reg_cache_step;
 	short reg_word_size;
 	short reg_word_size;
@@ -690,6 +702,8 @@ struct snd_soc_aux_dev {
 /* SoC card */
 /* SoC card */
 struct snd_soc_card {
 struct snd_soc_card {
 	const char *name;
 	const char *name;
+	const char *long_name;
+	const char *driver_name;
 	struct device *dev;
 	struct device *dev;
 	struct snd_card *snd_card;
 	struct snd_card *snd_card;
 	struct module *owner;
 	struct module *owner;
@@ -737,12 +751,15 @@ struct snd_soc_card {
 	struct snd_soc_pcm_runtime *rtd_aux;
 	struct snd_soc_pcm_runtime *rtd_aux;
 	int num_aux_rtd;
 	int num_aux_rtd;
 
 
+	const struct snd_kcontrol_new *controls;
+	int num_controls;
+
 	/*
 	/*
 	 * Card-specific routes and widgets.
 	 * Card-specific routes and widgets.
 	 */
 	 */
-	struct snd_soc_dapm_widget *dapm_widgets;
+	const struct snd_soc_dapm_widget *dapm_widgets;
 	int num_dapm_widgets;
 	int num_dapm_widgets;
-	struct snd_soc_dapm_route *dapm_routes;
+	const struct snd_soc_dapm_route *dapm_routes;
 	int num_dapm_routes;
 	int num_dapm_routes;
 
 
 	struct work_struct deferred_resume_work;
 	struct work_struct deferred_resume_work;
@@ -805,7 +822,7 @@ struct soc_enum {
 	unsigned char shift_r;
 	unsigned char shift_r;
 	unsigned int max;
 	unsigned int max;
 	unsigned int mask;
 	unsigned int mask;
-	const char **texts;
+	const char * const *texts;
 	const unsigned int *values;
 	const unsigned int *values;
 	void *dapm;
 	void *dapm;
 };
 };
@@ -814,6 +831,8 @@ struct soc_enum {
 unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
 unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
 unsigned int snd_soc_write(struct snd_soc_codec *codec,
 unsigned int snd_soc_write(struct snd_soc_codec *codec,
 			   unsigned int reg, unsigned int val);
 			   unsigned int reg, unsigned int val);
+unsigned int snd_soc_bulk_write_raw(struct snd_soc_codec *codec,
+				    unsigned int reg, const void *data, size_t len);
 
 
 /* device driver data */
 /* device driver data */
 
 
@@ -871,6 +890,9 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card)
 	INIT_LIST_HEAD(&card->dapm_list);
 	INIT_LIST_HEAD(&card->dapm_list);
 }
 }
 
 
+int snd_soc_util_init(void);
+void snd_soc_util_exit(void);
+
 #include <sound/soc-dai.h>
 #include <sound/soc-dai.h>
 
 
 #ifdef CONFIG_DEBUG_FS
 #ifdef CONFIG_DEBUG_FS

+ 1 - 1
include/sound/tlv320dac33-plat.h

@@ -1,7 +1,7 @@
 /*
 /*
  * Platform header for Texas Instruments TLV320DAC33 codec driver
  * Platform header for Texas Instruments TLV320DAC33 codec driver
  *
  *
- * Author:	Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  *
  * Copyright:   (C) 2009 Nokia Corporation
  * Copyright:   (C) 2009 Nokia Corporation
  *
  *

+ 1 - 1
include/sound/tpa6130a2-plat.h

@@ -3,7 +3,7 @@
  *
  *
  * Copyright (C) Nokia Corporation
  * Copyright (C) Nokia Corporation
  *
  *
- * Written by Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  *
  * This program is free software; you can redistribute it and/or
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * modify it under the terms of the GNU General Public License

+ 55 - 0
include/sound/wm8915.h

@@ -0,0 +1,55 @@
+/*
+ * linux/sound/wm8915.h -- Platform data for WM8915
+ *
+ * Copyright 2011 Wolfson Microelectronics. PLC.
+ *
+ * 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 __LINUX_SND_WM8903_H
+#define __LINUX_SND_WM8903_H
+
+enum wm8915_inmode {
+	WM8915_DIFFERRENTIAL_1 = 0,   /* IN1xP - IN1xN */
+	WM8915_INVERTING = 1,         /* IN1xN */
+	WM8915_NON_INVERTING = 2,     /* IN1xP */
+	WM8915_DIFFERENTIAL_2 = 3,    /* IN2xP - IN2xP */
+};
+
+/**
+ * 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 wm8915_retune_mobile_config {
+	const char *name;
+	int rate;
+	u16 regs[20];
+};
+
+#define WM8915_SET_DEFAULT 0x10000
+
+struct wm8915_pdata {
+	int irq_flags;  /** Set IRQ trigger flags; default active low */
+
+	int ldo_ena;  /** GPIO for LDO1; -1 for none */
+
+	int micdet_def;  /** Default MICDET_SRC/HP1FB_SRC/MICD_BIAS */
+
+	enum wm8915_inmode inl_mode;
+	enum wm8915_inmode inr_mode;
+
+	u32 spkmute_seq;  /** Value for register 0x802 */
+
+	int gpio_base;
+	u32 gpio_default[5];
+
+	int num_retune_mobile_cfgs;
+	struct wm8915_retune_mobile_config *retune_mobile_cfgs;
+};
+
+#endif

+ 22 - 0
include/sound/wm8962.h

@@ -14,6 +14,28 @@
 /* Use to set GPIO default values to zero */
 /* Use to set GPIO default values to zero */
 #define WM8962_GPIO_SET 0x10000
 #define WM8962_GPIO_SET 0x10000
 
 
+#define WM8962_GPIO_FN_CLKOUT           0
+#define WM8962_GPIO_FN_LOGIC            1
+#define WM8962_GPIO_FN_SDOUT            2
+#define WM8962_GPIO_FN_IRQ              3
+#define WM8962_GPIO_FN_THERMAL          4
+#define WM8962_GPIO_FN_PLL2_LOCK        6
+#define WM8962_GPIO_FN_PLL3_LOCK        7
+#define WM8962_GPIO_FN_FLL_LOCK         9
+#define WM8962_GPIO_FN_DRC_ACT         10
+#define WM8962_GPIO_FN_WSEQ_DONE       11
+#define WM8962_GPIO_FN_ALC_NG_ACT      12
+#define WM8962_GPIO_FN_ALC_PEAK_LIMIT  13
+#define WM8962_GPIO_FN_ALC_SATURATION  14
+#define WM8962_GPIO_FN_ALC_LEVEL_THR   15
+#define WM8962_GPIO_FN_ALC_LEVEL_LOCK  16
+#define WM8962_GPIO_FN_FIFO_ERR        17
+#define WM8962_GPIO_FN_OPCLK           18
+#define WM8962_GPIO_FN_DMICCLK         19
+#define WM8962_GPIO_FN_DMICDAT         20
+#define WM8962_GPIO_FN_MICD            21
+#define WM8962_GPIO_FN_MICSCD          22
+
 struct wm8962_pdata {
 struct wm8962_pdata {
 	int gpio_base;
 	int gpio_base;
 	u32 gpio_init[WM8962_MAX_GPIO];
 	u32 gpio_init[WM8962_MAX_GPIO];

+ 1 - 1
sound/soc/atmel/sam9g20_wm8731.c

@@ -184,7 +184,7 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = {
 	.codec_dai_name = "wm8731-hifi",
 	.codec_dai_name = "wm8731-hifi",
 	.init = at91sam9g20ek_wm8731_init,
 	.init = at91sam9g20ek_wm8731_init,
 	.platform_name = "atmel-pcm-audio",
 	.platform_name = "atmel-pcm-audio",
-	.codec_name = "wm8731-codec.0-001b",
+	.codec_name = "wm8731.0-001b",
 	.ops = &at91sam9g20ek_ops,
 	.ops = &at91sam9g20ek_ops,
 };
 };
 
 

+ 1 - 1
sound/soc/au1x/db1200.c

@@ -77,7 +77,7 @@ static struct snd_soc_dai_link db1200_i2s_dai = {
 	.codec_dai_name	= "wm8731-hifi",
 	.codec_dai_name	= "wm8731-hifi",
 	.cpu_dai_name	= "au1xpsc_i2s.1",
 	.cpu_dai_name	= "au1xpsc_i2s.1",
 	.platform_name	= "au1xpsc-pcm.1",
 	.platform_name	= "au1xpsc-pcm.1",
-	.codec_name	= "wm8731-codec.0-001b",
+	.codec_name	= "wm8731.0-001b",
 	.ops		= &db1200_i2s_wm8731_ops,
 	.ops		= &db1200_i2s_wm8731_ops,
 };
 };
 
 

+ 10 - 3
sound/soc/blackfin/bf5xx-ac97-pcm.c

@@ -243,6 +243,9 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
 
 
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 {
 {
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	int ret;
 	int ret;
 
 
@@ -314,6 +317,9 @@ static struct snd_pcm_ops bf5xx_pcm_ac97_ops = {
 
 
 static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 {
 {
+	struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
 	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
 	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
 	struct snd_dma_buffer *buf = &substream->dma_buffer;
 	struct snd_dma_buffer *buf = &substream->dma_buffer;
 	size_t size = bf5xx_pcm_hardware.buffer_bytes_max
 	size_t size = bf5xx_pcm_hardware.buffer_bytes_max
@@ -377,6 +383,9 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 	struct snd_dma_buffer *buf;
 	struct snd_dma_buffer *buf;
 	int stream;
 	int stream;
 #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
 #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT)
+	struct snd_soc_pcm_runtime *rtd = pcm->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
 	size_t size = bf5xx_pcm_hardware.buffer_bytes_max *
 	size_t size = bf5xx_pcm_hardware.buffer_bytes_max *
 		sizeof(struct ac97_frame) / 4;
 		sizeof(struct ac97_frame) / 4;
 #endif
 #endif
@@ -405,8 +414,6 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 	}
 	}
 #endif
 #endif
 	}
 	}
-	if (sport_handle)
-		sport_done(sport_handle);
 }
 }
 
 
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
@@ -458,7 +465,7 @@ static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
 
 
 static struct platform_driver bf5xx_pcm_driver = {
 static struct platform_driver bf5xx_pcm_driver = {
 	.driver = {
 	.driver = {
-			.name = "bf5xx-pcm-audio",
+			.name = "bfin-ac97-pcm-audio",
 			.owner = THIS_MODULE,
 			.owner = THIS_MODULE,
 	},
 	},
 
 

+ 53 - 113
sound/soc/blackfin/bf5xx-ac97.c

@@ -41,48 +41,7 @@
  *		anomaly does not affect blackfin sound drivers.
  *		anomaly does not affect blackfin sound drivers.
 */
 */
 
 
-static int *cmd_count;
-static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
-
-#define SPORT_REQ(x) \
-	[x] = {P_SPORT##x##_TFS, P_SPORT##x##_DTPRI, P_SPORT##x##_TSCLK, \
-	       P_SPORT##x##_RFS, P_SPORT##x##_DRPRI, P_SPORT##x##_RSCLK, 0}
-static u16 sport_req[][7] = {
-#ifdef SPORT0_TCR1
-	SPORT_REQ(0),
-#endif
-#ifdef SPORT1_TCR1
-	SPORT_REQ(1),
-#endif
-#ifdef SPORT2_TCR1
-	SPORT_REQ(2),
-#endif
-#ifdef SPORT3_TCR1
-	SPORT_REQ(3),
-#endif
-};
-
-#define SPORT_PARAMS(x) \
-	[x] = { \
-		.dma_rx_chan = CH_SPORT##x##_RX, \
-		.dma_tx_chan = CH_SPORT##x##_TX, \
-		.err_irq     = IRQ_SPORT##x##_ERROR, \
-		.regs        = (struct sport_register *)SPORT##x##_TCR1, \
-	}
-static struct sport_param sport_params[4] = {
-#ifdef SPORT0_TCR1
-	SPORT_PARAMS(0),
-#endif
-#ifdef SPORT1_TCR1
-	SPORT_PARAMS(1),
-#endif
-#ifdef SPORT2_TCR1
-	SPORT_PARAMS(2),
-#endif
-#ifdef SPORT3_TCR1
-	SPORT_PARAMS(3),
-#endif
-};
+static struct sport_device *ac97_sport_handle;
 
 
 void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src,
 void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src,
 		size_t count, unsigned int chan_mask)
 		size_t count, unsigned int chan_mask)
@@ -140,7 +99,8 @@ static unsigned int sport_tx_curr_frag(struct sport_device *sport)
 
 
 static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
 static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
 {
 {
-	struct sport_device *sport = sport_handle;
+	struct sport_device *sport = ac97_sport_handle;
+	int *cmd_count = sport->private_data;
 	int nextfrag = sport_tx_curr_frag(sport);
 	int nextfrag = sport_tx_curr_frag(sport);
 	struct ac97_frame *nextwrite;
 	struct ac97_frame *nextwrite;
 
 
@@ -161,6 +121,7 @@ static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
 static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97,
 static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97,
 	unsigned short reg)
 	unsigned short reg)
 {
 {
+	struct sport_device *sport_handle = ac97_sport_handle;
 	struct ac97_frame out_frame[2], in_frame[2];
 	struct ac97_frame out_frame[2], in_frame[2];
 
 
 	pr_debug("%s enter 0x%x\n", __func__, reg);
 	pr_debug("%s enter 0x%x\n", __func__, reg);
@@ -185,6 +146,8 @@ static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97,
 void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 	unsigned short val)
 	unsigned short val)
 {
 {
+	struct sport_device *sport_handle = ac97_sport_handle;
+
 	pr_debug("%s enter 0x%x:0x%04x\n", __func__, reg, val);
 	pr_debug("%s enter 0x%x:0x%04x\n", __func__, reg, val);
 
 
 	if (sport_handle->tx_run) {
 	if (sport_handle->tx_run) {
@@ -203,28 +166,19 @@ void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 
 
 static void bf5xx_ac97_warm_reset(struct snd_ac97 *ac97)
 static void bf5xx_ac97_warm_reset(struct snd_ac97 *ac97)
 {
 {
-#if defined(CONFIG_BF54x) || defined(CONFIG_BF561) || \
- (defined(BF537_FAMILY) && (CONFIG_SND_BF5XX_SPORT_NUM == 1))
-
-#define CONCAT(a, b, c) a ## b ## c
-#define BFIN_SPORT_RFS(x) CONCAT(P_SPORT, x, _RFS)
-
-	u16 per = BFIN_SPORT_RFS(CONFIG_SND_BF5XX_SPORT_NUM);
-	u16 gpio = P_IDENT(BFIN_SPORT_RFS(CONFIG_SND_BF5XX_SPORT_NUM));
+	struct sport_device *sport_handle = ac97_sport_handle;
+	u16 gpio = P_IDENT(sport_handle->pin_req[3]);
 
 
 	pr_debug("%s enter\n", __func__);
 	pr_debug("%s enter\n", __func__);
 
 
-	peripheral_free(per);
+	peripheral_free_list(sport_handle->pin_req);
 	gpio_request(gpio, "bf5xx-ac97");
 	gpio_request(gpio, "bf5xx-ac97");
 	gpio_direction_output(gpio, 1);
 	gpio_direction_output(gpio, 1);
 	udelay(2);
 	udelay(2);
 	gpio_set_value(gpio, 0);
 	gpio_set_value(gpio, 0);
 	udelay(1);
 	udelay(1);
 	gpio_free(gpio);
 	gpio_free(gpio);
-	peripheral_request(per, "soc-audio");
-#else
-	pr_info("%s: Not implemented\n", __func__);
-#endif
+	peripheral_request_list(sport_handle->pin_req, "soc-audio");
 }
 }
 
 
 static void bf5xx_ac97_cold_reset(struct snd_ac97 *ac97)
 static void bf5xx_ac97_cold_reset(struct snd_ac97 *ac97)
@@ -306,18 +260,32 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
 #define bf5xx_ac97_resume	NULL
 #define bf5xx_ac97_resume	NULL
 #endif
 #endif
 
 
-static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
+static struct snd_soc_dai_driver bfin_ac97_dai = {
+	.ac97_control = 1,
+	.suspend = bf5xx_ac97_suspend,
+	.resume = bf5xx_ac97_resume,
+	.playback = {
+		.stream_name = "AC97 Playback",
+		.channels_min = 2,
+#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
+		.channels_max = 6,
+#else
+		.channels_max = 2,
+#endif
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
+	.capture = {
+		.stream_name = "AC97 Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
+};
+
+static int __devinit asoc_bfin_ac97_probe(struct platform_device *pdev)
 {
 {
-	int ret = 0;
-	cmd_count = (int *)get_zeroed_page(GFP_KERNEL);
-	if (cmd_count == NULL)
-		return -ENOMEM;
-
-	if (peripheral_request_list(sport_req[sport_num], "soc-audio")) {
-		pr_err("Requesting Peripherals failed\n");
-		ret =  -EFAULT;
-		goto peripheral_err;
-	}
+	struct sport_device *sport_handle;
+	int ret;
 
 
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
 	/* Request PB3 as reset pin */
 	/* Request PB3 as reset pin */
@@ -329,12 +297,14 @@ static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
 	}
 	}
 	gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1);
 	gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1);
 #endif
 #endif
-	sport_handle = sport_init(&sport_params[sport_num], 2, \
-			sizeof(struct ac97_frame), NULL);
+
+	sport_handle = sport_init(pdev, 2, sizeof(struct ac97_frame),
+		PAGE_SIZE);
 	if (!sport_handle) {
 	if (!sport_handle) {
 		ret = -ENODEV;
 		ret = -ENODEV;
 		goto sport_err;
 		goto sport_err;
 	}
 	}
+
 	/*SPORT works in TDM mode to simulate AC97 transfers*/
 	/*SPORT works in TDM mode to simulate AC97 transfers*/
 #if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
 #if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
 	ret = sport_set_multichannel(sport_handle, 16, 0x3FF, 1);
 	ret = sport_set_multichannel(sport_handle, 16, 0x3FF, 1);
@@ -361,67 +331,37 @@ static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
 		goto sport_config_err;
 		goto sport_config_err;
 	}
 	}
 
 
+	ret = snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai);
+	if (ret) {
+		pr_err("Failed to register DAI: %d\n", ret);
+		goto sport_config_err;
+	}
+
+	ac97_sport_handle = sport_handle;
+
 	return 0;
 	return 0;
 
 
 sport_config_err:
 sport_config_err:
-	kfree(sport_handle);
+	sport_done(sport_handle);
 sport_err:
 sport_err:
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
 	gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
 	gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
 gpio_err:
 gpio_err:
 #endif
 #endif
-	peripheral_free_list(sport_req[sport_num]);
-peripheral_err:
-	free_page((unsigned long)cmd_count);
-	cmd_count = NULL;
 
 
 	return ret;
 	return ret;
 }
 }
 
 
-static int bf5xx_ac97_remove(struct snd_soc_dai *dai)
+static int __devexit asoc_bfin_ac97_remove(struct platform_device *pdev)
 {
 {
-	free_page((unsigned long)cmd_count);
-	cmd_count = NULL;
-	peripheral_free_list(sport_req[sport_num]);
+	struct sport_device *sport_handle = platform_get_drvdata(pdev);
+
+	snd_soc_unregister_dai(&pdev->dev);
+	sport_done(sport_handle);
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
 	gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
 	gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
 #endif
 #endif
-	return 0;
-}
-
-struct snd_soc_dai_driver bfin_ac97_dai = {
-	.ac97_control = 1,
-	.probe = bf5xx_ac97_probe,
-	.remove = bf5xx_ac97_remove,
-	.suspend = bf5xx_ac97_suspend,
-	.resume = bf5xx_ac97_resume,
-	.playback = {
-		.stream_name = "AC97 Playback",
-		.channels_min = 2,
-#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
-		.channels_max = 6,
-#else
-		.channels_max = 2,
-#endif
-		.rates = SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
-	.capture = {
-		.stream_name = "AC97 Capture",
-		.channels_min = 2,
-		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_48000,
-		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
-};
-EXPORT_SYMBOL_GPL(bfin_ac97_dai);
-
-static __devinit int asoc_bfin_ac97_probe(struct platform_device *pdev)
-{
-	return snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai);
-}
 
 
-static int __devexit asoc_bfin_ac97_remove(struct platform_device *pdev)
-{
-	snd_soc_unregister_dai(&pdev->dev);
 	return 0;
 	return 0;
 }
 }
 
 

+ 21 - 21
sound/soc/blackfin/bf5xx-ad1836.c

@@ -29,22 +29,12 @@
 #include <asm/portmux.h>
 #include <asm/portmux.h>
 
 
 #include "../codecs/ad1836.h"
 #include "../codecs/ad1836.h"
-#include "bf5xx-sport.h"
 
 
 #include "bf5xx-tdm-pcm.h"
 #include "bf5xx-tdm-pcm.h"
 #include "bf5xx-tdm.h"
 #include "bf5xx-tdm.h"
 
 
 static struct snd_soc_card bf5xx_ad1836;
 static struct snd_soc_card bf5xx_ad1836;
 
 
-static int bf5xx_ad1836_startup(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-	snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-	return 0;
-}
-
 static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
 static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
 	struct snd_pcm_hw_params *params)
 {
 {
@@ -75,23 +65,33 @@ static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
 }
 }
 
 
 static struct snd_soc_ops bf5xx_ad1836_ops = {
 static struct snd_soc_ops bf5xx_ad1836_ops = {
-	.startup = bf5xx_ad1836_startup,
 	.hw_params = bf5xx_ad1836_hw_params,
 	.hw_params = bf5xx_ad1836_hw_params,
 };
 };
 
 
-static struct snd_soc_dai_link bf5xx_ad1836_dai = {
-	.name = "ad1836",
-	.stream_name = "AD1836",
-	.cpu_dai_name = "bf5xx-tdm",
-	.codec_dai_name = "ad1836-hifi",
-	.platform_name = "bf5xx-tdm-pcm-audio",
-	.codec_name = "ad1836-codec.0",
-	.ops = &bf5xx_ad1836_ops,
+static struct snd_soc_dai_link bf5xx_ad1836_dai[] = {
+	{
+		.name = "ad1836",
+		.stream_name = "AD1836",
+		.cpu_dai_name = "bfin-tdm.0",
+		.codec_dai_name = "ad1836-hifi",
+		.platform_name = "bfin-tdm-pcm-audio",
+		.codec_name = "ad1836.0",
+		.ops = &bf5xx_ad1836_ops,
+	},
+	{
+		.name = "ad1836",
+		.stream_name = "AD1836",
+		.cpu_dai_name = "bfin-tdm.1",
+		.codec_dai_name = "ad1836-hifi",
+		.platform_name = "bfin-tdm-pcm-audio",
+		.codec_name = "ad1836.0",
+		.ops = &bf5xx_ad1836_ops,
+	},
 };
 };
 
 
 static struct snd_soc_card bf5xx_ad1836 = {
 static struct snd_soc_card bf5xx_ad1836 = {
-	.name = "bf5xx_ad1836",
-	.dai_link = &bf5xx_ad1836_dai,
+	.name = "bfin-ad1836",
+	.dai_link = &bf5xx_ad1836_dai[CONFIG_SND_BF5XX_SPORT_NUM],
 	.num_links = 1,
 	.num_links = 1,
 };
 };
 
 

+ 35 - 21
sound/soc/blackfin/bf5xx-ad193x.c

@@ -38,30 +38,28 @@
 #include <asm/portmux.h>
 #include <asm/portmux.h>
 
 
 #include "../codecs/ad193x.h"
 #include "../codecs/ad193x.h"
-#include "bf5xx-sport.h"
 
 
 #include "bf5xx-tdm-pcm.h"
 #include "bf5xx-tdm-pcm.h"
 #include "bf5xx-tdm.h"
 #include "bf5xx-tdm.h"
 
 
 static struct snd_soc_card bf5xx_ad193x;
 static struct snd_soc_card bf5xx_ad193x;
 
 
-static int bf5xx_ad193x_startup(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-	snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-	return 0;
-}
-
 static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
 static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
 	struct snd_pcm_hw_params *params)
 {
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	unsigned int clk = 0;
 	unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7};
 	unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7};
 	int ret = 0;
 	int ret = 0;
+
+	switch (params_rate(params)) {
+	case 48000:
+		clk = 12288000;
+		break;
+	}
+
 	/* set cpu DAI configuration */
 	/* set cpu DAI configuration */
 	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
 	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
 		SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
 		SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
@@ -74,6 +72,12 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
+	/* set the codec system clock for DAC and ADC */
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
 	/* set codec DAI slots, 8 channels, all channels are enabled */
 	/* set codec DAI slots, 8 channels, all channels are enabled */
 	ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 0xFF, 8, 32);
 	ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 0xFF, 8, 32);
 	if (ret < 0)
 	if (ret < 0)
@@ -89,23 +93,33 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
 }
 }
 
 
 static struct snd_soc_ops bf5xx_ad193x_ops = {
 static struct snd_soc_ops bf5xx_ad193x_ops = {
-	.startup = bf5xx_ad193x_startup,
 	.hw_params = bf5xx_ad193x_hw_params,
 	.hw_params = bf5xx_ad193x_hw_params,
 };
 };
 
 
-static struct snd_soc_dai_link bf5xx_ad193x_dai = {
-	.name = "ad193x",
-	.stream_name = "AD193X",
-	.cpu_dai_name = "bf5xx-tdm",
-	.codec_dai_name ="ad193x-hifi",
-	.platform_name = "bf5xx-tdm-pcm-audio",
-	.codec_name = "ad193x-codec.5",
-	.ops = &bf5xx_ad193x_ops,
+static struct snd_soc_dai_link bf5xx_ad193x_dai[] = {
+	{
+		.name = "ad193x",
+		.stream_name = "AD193X",
+		.cpu_dai_name = "bfin-tdm.0",
+		.codec_dai_name ="ad193x-hifi",
+		.platform_name = "bfin-tdm-pcm-audio",
+		.codec_name = "ad193x.5",
+		.ops = &bf5xx_ad193x_ops,
+	},
+	{
+		.name = "ad193x",
+		.stream_name = "AD193X",
+		.cpu_dai_name = "bfin-tdm.1",
+		.codec_dai_name ="ad193x-hifi",
+		.platform_name = "bfin-tdm-pcm-audio",
+		.codec_name = "ad193x.5",
+		.ops = &bf5xx_ad193x_ops,
+	},
 };
 };
 
 
 static struct snd_soc_card bf5xx_ad193x = {
 static struct snd_soc_card bf5xx_ad193x = {
-	.name = "bf5xx_ad193x",
-	.dai_link = &bf5xx_ad193x_dai,
+	.name = "bfin-ad193x",
+	.dai_link = &bf5xx_ad193x_dai[CONFIG_SND_BF5XX_SPORT_NUM],
 	.num_links = 1,
 	.num_links = 1,
 };
 };
 
 

+ 20 - 25
sound/soc/blackfin/bf5xx-ad1980.c

@@ -47,39 +47,34 @@
 #include <asm/portmux.h>
 #include <asm/portmux.h>
 
 
 #include "../codecs/ad1980.h"
 #include "../codecs/ad1980.h"
-#include "bf5xx-sport.h"
+
 #include "bf5xx-ac97-pcm.h"
 #include "bf5xx-ac97-pcm.h"
 #include "bf5xx-ac97.h"
 #include "bf5xx-ac97.h"
 
 
 static struct snd_soc_card bf5xx_board;
 static struct snd_soc_card bf5xx_board;
 
 
-static int bf5xx_board_startup(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-	pr_debug("%s enter\n", __func__);
-	snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-	return 0;
-}
-
-static struct snd_soc_ops bf5xx_board_ops = {
-	.startup = bf5xx_board_startup,
-};
-
-static struct snd_soc_dai_link bf5xx_board_dai = {
-	.name = "AC97",
-	.stream_name = "AC97 HiFi",
-	.cpu_dai_name = "bfin-ac97",
-	.codec_dai_name = "ad1980-hifi",
-	.platform_name = "bfin-pcm-audio",
-	.codec_name = "ad1980-codec",
-	.ops = &bf5xx_board_ops,
+static struct snd_soc_dai_link bf5xx_board_dai[] = {
+	{
+		.name = "AC97",
+		.stream_name = "AC97 HiFi",
+		.cpu_dai_name = "bfin-ac97.0",
+		.codec_dai_name = "ad1980-hifi",
+		.platform_name = "bfin-ac97-pcm-audio",
+		.codec_name = "ad1980",
+	},
+	{
+		.name = "AC97",
+		.stream_name = "AC97 HiFi",
+		.cpu_dai_name = "bfin-ac97.1",
+		.codec_dai_name = "ad1980-hifi",
+		.platform_name = "bfin-ac97-pcm-audio",
+		.codec_name = "ad1980",
+	},
 };
 };
 
 
 static struct snd_soc_card bf5xx_board = {
 static struct snd_soc_card bf5xx_board = {
-	.name = "bf5xx-board",
-	.dai_link = &bf5xx_board_dai,
+	.name = "bfin-ad1980",
+	.dai_link = &bf5xx_board_dai[CONFIG_SND_BF5XX_SPORT_NUM],
 	.num_links = 1,
 	.num_links = 1,
 };
 };
 
 

+ 21 - 21
sound/soc/blackfin/bf5xx-ad73311.c

@@ -145,16 +145,6 @@ static int bf5xx_probe(struct platform_device *pdev)
 	return 0;
 	return 0;
 }
 }
 
 
-static int bf5xx_ad73311_startup(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-	pr_debug("%s enter\n", __func__);
-	snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-	return 0;
-}
-
 static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
 static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
 	struct snd_pcm_hw_params *params)
 {
 {
@@ -176,24 +166,34 @@ static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
 
 
 
 
 static struct snd_soc_ops bf5xx_ad73311_ops = {
 static struct snd_soc_ops bf5xx_ad73311_ops = {
-	.startup = bf5xx_ad73311_startup,
 	.hw_params = bf5xx_ad73311_hw_params,
 	.hw_params = bf5xx_ad73311_hw_params,
 };
 };
 
 
-static struct snd_soc_dai_link bf5xx_ad73311_dai = {
-	.name = "ad73311",
-	.stream_name = "AD73311",
-	.cpu_dai_name = "bf5xx-i2s",
-	.codec_dai_name = "ad73311-hifi",
-	.platform_name = "bfin-pcm-audio",
-	.codec_name = "ad73311-codec",
-	.ops = &bf5xx_ad73311_ops,
+static struct snd_soc_dai_link bf5xx_ad73311_dai[] = {
+	{
+		.name = "ad73311",
+		.stream_name = "AD73311",
+		.cpu_dai_name = "bfin-i2s.0",
+		.codec_dai_name = "ad73311-hifi",
+		.platform_name = "bfin-i2s-pcm-audio",
+		.codec_name = "ad73311",
+		.ops = &bf5xx_ad73311_ops,
+	},
+	{
+		.name = "ad73311",
+		.stream_name = "AD73311",
+		.cpu_dai_name = "bfin-i2s.1",
+		.codec_dai_name = "ad73311-hifi",
+		.platform_name = "bfin-i2s-pcm-audio",
+		.codec_name = "ad73311",
+		.ops = &bf5xx_ad73311_ops,
+	},
 };
 };
 
 
 static struct snd_soc_card bf5xx_ad73311 = {
 static struct snd_soc_card bf5xx_ad73311 = {
-	.name = "bf5xx_ad73311",
+	.name = "bfin-ad73311",
 	.probe = bf5xx_probe,
 	.probe = bf5xx_probe,
-	.dai_link = &bf5xx_ad73311_dai,
+	.dai_link = &bf5xx_ad73311_dai[CONFIG_SND_BF5XX_SPORT_NUM],
 	.num_links = 1,
 	.num_links = 1,
 };
 };
 
 

+ 13 - 10
sound/soc/blackfin/bf5xx-i2s-pcm.c

@@ -148,10 +148,15 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
 
 
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 {
 {
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
 	int ret;
 	int ret;
 
 
 	pr_debug("%s enter\n", __func__);
 	pr_debug("%s enter\n", __func__);
+
 	snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
 	snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
 
 
 	ret = snd_pcm_hw_constraint_integer(runtime, \
 	ret = snd_pcm_hw_constraint_integer(runtime, \
@@ -159,9 +164,14 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 	if (ret < 0)
 	if (ret < 0)
 		goto out;
 		goto out;
 
 
-	if (sport_handle != NULL)
+	if (sport_handle != NULL) {
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			sport_handle->tx_buf = buf->area;
+		else
+			sport_handle->rx_buf = buf->area;
+
 		runtime->private_data = sport_handle;
 		runtime->private_data = sport_handle;
-	else {
+	} else {
 		pr_err("sport_handle is NULL\n");
 		pr_err("sport_handle is NULL\n");
 		return -1;
 		return -1;
 	}
 	}
@@ -214,11 +224,6 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 	pr_debug("%s, area:%p, size:0x%08lx\n", __func__,
 	pr_debug("%s, area:%p, size:0x%08lx\n", __func__,
 		buf->area, buf->bytes);
 		buf->area, buf->bytes);
 
 
-	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-		sport_handle->tx_buf = buf->area;
-	else
-		sport_handle->rx_buf = buf->area;
-
 	return 0;
 	return 0;
 }
 }
 
 
@@ -239,8 +244,6 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 		dma_free_coherent(NULL, buf->bytes, buf->area, 0);
 		dma_free_coherent(NULL, buf->bytes, buf->area, 0);
 		buf->area = NULL;
 		buf->area = NULL;
 	}
 	}
-	if (sport_handle)
-		sport_done(sport_handle);
 }
 }
 
 
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
@@ -292,7 +295,7 @@ static int __devexit bfin_i2s_soc_platform_remove(struct platform_device *pdev)
 
 
 static struct platform_driver bfin_i2s_pcm_driver = {
 static struct platform_driver bfin_i2s_pcm_driver = {
 	.driver = {
 	.driver = {
-			.name = "bfin-pcm-audio",
+			.name = "bfin-i2s-pcm-audio",
 			.owner = THIS_MODULE,
 			.owner = THIS_MODULE,
 	},
 	},
 
 

+ 73 - 99
sound/soc/blackfin/bf5xx-i2s.c

@@ -51,59 +51,24 @@ struct bf5xx_i2s_port {
 	int configured;
 	int configured;
 };
 };
 
 
-static struct bf5xx_i2s_port bf5xx_i2s;
-static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
-
-static struct sport_param sport_params[2] = {
-	{
-		.dma_rx_chan	= CH_SPORT0_RX,
-		.dma_tx_chan	= CH_SPORT0_TX,
-		.err_irq	= IRQ_SPORT0_ERROR,
-		.regs		= (struct sport_register *)SPORT0_TCR1,
-	},
-	{
-		.dma_rx_chan	= CH_SPORT1_RX,
-		.dma_tx_chan	= CH_SPORT1_TX,
-		.err_irq	= IRQ_SPORT1_ERROR,
-		.regs		= (struct sport_register *)SPORT1_TCR1,
-	}
-};
-
-/*
- * Setting the TFS pin selector for SPORT 0 based on whether the selected
- * port id F or G. If the port is F then no conflict should exist for the
- * TFS. When Port G is selected and EMAC then there is a conflict between
- * the PHY interrupt line and TFS.  Current settings prevent the conflict
- * by ignoring the TFS pin when Port G is selected. This allows both
- * codecs and EMAC using Port G concurrently.
- */
-#ifdef CONFIG_BF527_SPORT0_PORTG
-#define LOCAL_SPORT0_TFS (0)
-#else
-#define LOCAL_SPORT0_TFS (P_SPORT0_TFS)
-#endif
-
-static u16 sport_req[][7] = { {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
-		P_SPORT0_DRPRI, P_SPORT0_RSCLK, LOCAL_SPORT0_TFS, 0},
-		{P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, P_SPORT1_DRPRI,
-		P_SPORT1_RSCLK, P_SPORT1_TFS, 0} };
-
 static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 		unsigned int fmt)
 		unsigned int fmt)
 {
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
+	struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
 	int ret = 0;
 	int ret = 0;
 
 
 	/* interface format:support I2S,slave mode */
 	/* interface format:support I2S,slave mode */
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
 	case SND_SOC_DAIFMT_I2S:
-		bf5xx_i2s.tcr1 |= TFSR | TCKFE;
-		bf5xx_i2s.rcr1 |= RFSR | RCKFE;
-		bf5xx_i2s.tcr2 |= TSFSE;
-		bf5xx_i2s.rcr2 |= RSFSE;
+		bf5xx_i2s->tcr1 |= TFSR | TCKFE;
+		bf5xx_i2s->rcr1 |= RFSR | RCKFE;
+		bf5xx_i2s->tcr2 |= TSFSE;
+		bf5xx_i2s->rcr2 |= RSFSE;
 		break;
 		break;
 	case SND_SOC_DAIFMT_DSP_A:
 	case SND_SOC_DAIFMT_DSP_A:
-		bf5xx_i2s.tcr1 |= TFSR;
-		bf5xx_i2s.rcr1 |= RFSR;
+		bf5xx_i2s->tcr1 |= TFSR;
+		bf5xx_i2s->rcr1 |= RFSR;
 		break;
 		break;
 	case SND_SOC_DAIFMT_LEFT_J:
 	case SND_SOC_DAIFMT_LEFT_J:
 		ret = -EINVAL;
 		ret = -EINVAL;
@@ -135,29 +100,35 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params,
 				struct snd_pcm_hw_params *params,
 				struct snd_soc_dai *dai)
 				struct snd_soc_dai *dai)
 {
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+	struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
 	int ret = 0;
 	int ret = 0;
 
 
-	bf5xx_i2s.tcr2 &= ~0x1f;
-	bf5xx_i2s.rcr2 &= ~0x1f;
+	bf5xx_i2s->tcr2 &= ~0x1f;
+	bf5xx_i2s->rcr2 &= ~0x1f;
 	switch (params_format(params)) {
 	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		bf5xx_i2s->tcr2 |= 7;
+		bf5xx_i2s->rcr2 |= 7;
+		sport_handle->wdsize = 1;
 	case SNDRV_PCM_FORMAT_S16_LE:
 	case SNDRV_PCM_FORMAT_S16_LE:
-		bf5xx_i2s.tcr2 |= 15;
-		bf5xx_i2s.rcr2 |= 15;
+		bf5xx_i2s->tcr2 |= 15;
+		bf5xx_i2s->rcr2 |= 15;
 		sport_handle->wdsize = 2;
 		sport_handle->wdsize = 2;
 		break;
 		break;
 	case SNDRV_PCM_FORMAT_S24_LE:
 	case SNDRV_PCM_FORMAT_S24_LE:
-		bf5xx_i2s.tcr2 |= 23;
-		bf5xx_i2s.rcr2 |= 23;
+		bf5xx_i2s->tcr2 |= 23;
+		bf5xx_i2s->rcr2 |= 23;
 		sport_handle->wdsize = 3;
 		sport_handle->wdsize = 3;
 		break;
 		break;
 	case SNDRV_PCM_FORMAT_S32_LE:
 	case SNDRV_PCM_FORMAT_S32_LE:
-		bf5xx_i2s.tcr2 |= 31;
-		bf5xx_i2s.rcr2 |= 31;
+		bf5xx_i2s->tcr2 |= 31;
+		bf5xx_i2s->rcr2 |= 31;
 		sport_handle->wdsize = 4;
 		sport_handle->wdsize = 4;
 		break;
 		break;
 	}
 	}
 
 
-	if (!bf5xx_i2s.configured) {
+	if (!bf5xx_i2s->configured) {
 		/*
 		/*
 		 * TX and RX are not independent,they are enabled at the
 		 * TX and RX are not independent,they are enabled at the
 		 * same time, even if only one side is running. So, we
 		 * same time, even if only one side is running. So, we
@@ -166,16 +137,16 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
 		 *
 		 *
 		 * CPU DAI:slave mode.
 		 * CPU DAI:slave mode.
 		 */
 		 */
-		bf5xx_i2s.configured = 1;
-		ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1,
-				      bf5xx_i2s.rcr2, 0, 0);
+		bf5xx_i2s->configured = 1;
+		ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
+				      bf5xx_i2s->rcr2, 0, 0);
 		if (ret) {
 		if (ret) {
 			pr_err("SPORT is busy!\n");
 			pr_err("SPORT is busy!\n");
 			return -EBUSY;
 			return -EBUSY;
 		}
 		}
 
 
-		ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1,
-				      bf5xx_i2s.tcr2, 0, 0);
+		ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
+				      bf5xx_i2s->tcr2, 0, 0);
 		if (ret) {
 		if (ret) {
 			pr_err("SPORT is busy!\n");
 			pr_err("SPORT is busy!\n");
 			return -EBUSY;
 			return -EBUSY;
@@ -188,41 +159,19 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
 static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
 static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
 			       struct snd_soc_dai *dai)
 			       struct snd_soc_dai *dai)
 {
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+	struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
+
 	pr_debug("%s enter\n", __func__);
 	pr_debug("%s enter\n", __func__);
 	/* No active stream, SPORT is allowed to be configured again. */
 	/* No active stream, SPORT is allowed to be configured again. */
 	if (!dai->active)
 	if (!dai->active)
-		bf5xx_i2s.configured = 0;
-}
-
-static int bf5xx_i2s_probe(struct snd_soc_dai *dai)
-{
-	pr_debug("%s enter\n", __func__);
-	if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
-		pr_err("Requesting Peripherals failed\n");
-		return -EFAULT;
-	}
-
-	/* request DMA for SPORT */
-	sport_handle = sport_init(&sport_params[sport_num], 4, \
-			2 * sizeof(u32), NULL);
-	if (!sport_handle) {
-		peripheral_free_list(&sport_req[sport_num][0]);
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static int bf5xx_i2s_remove(struct snd_soc_dai *dai)
-{
-	pr_debug("%s enter\n", __func__);
-	peripheral_free_list(&sport_req[sport_num][0]);
-	return 0;
+		bf5xx_i2s->configured = 0;
 }
 }
 
 
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
 static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
 {
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
 
 
 	pr_debug("%s : sport %d\n", __func__, dai->id);
 	pr_debug("%s : sport %d\n", __func__, dai->id);
 
 
@@ -235,19 +184,21 @@ static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
 
 
 static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
 static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
 {
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+	struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
 	int ret;
 	int ret;
 
 
 	pr_debug("%s : sport %d\n", __func__, dai->id);
 	pr_debug("%s : sport %d\n", __func__, dai->id);
 
 
-	ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1,
-				      bf5xx_i2s.rcr2, 0, 0);
+	ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
+				      bf5xx_i2s->rcr2, 0, 0);
 	if (ret) {
 	if (ret) {
 		pr_err("SPORT is busy!\n");
 		pr_err("SPORT is busy!\n");
 		return -EBUSY;
 		return -EBUSY;
 	}
 	}
 
 
-	ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1,
-				      bf5xx_i2s.tcr2, 0, 0);
+	ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
+				      bf5xx_i2s->tcr2, 0, 0);
 	if (ret) {
 	if (ret) {
 		pr_err("SPORT is busy!\n");
 		pr_err("SPORT is busy!\n");
 		return -EBUSY;
 		return -EBUSY;
@@ -266,8 +217,11 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
 		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
 		SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
 		SNDRV_PCM_RATE_96000)
 		SNDRV_PCM_RATE_96000)
 
 
-#define BF5XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\
-	SNDRV_PCM_FMTBIT_S32_LE)
+#define BF5XX_I2S_FORMATS \
+	(SNDRV_PCM_FMTBIT_S8 | \
+	 SNDRV_PCM_FMTBIT_S16_LE | \
+	 SNDRV_PCM_FMTBIT_S24_LE | \
+	 SNDRV_PCM_FMTBIT_S32_LE)
 
 
 static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
 static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
 	.shutdown	= bf5xx_i2s_shutdown,
 	.shutdown	= bf5xx_i2s_shutdown,
@@ -276,8 +230,6 @@ static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
 };
 };
 
 
 static struct snd_soc_dai_driver bf5xx_i2s_dai = {
 static struct snd_soc_dai_driver bf5xx_i2s_dai = {
-	.probe = bf5xx_i2s_probe,
-	.remove = bf5xx_i2s_remove,
 	.suspend = bf5xx_i2s_suspend,
 	.suspend = bf5xx_i2s_suspend,
 	.resume = bf5xx_i2s_resume,
 	.resume = bf5xx_i2s_resume,
 	.playback = {
 	.playback = {
@@ -293,23 +245,45 @@ static struct snd_soc_dai_driver bf5xx_i2s_dai = {
 	.ops = &bf5xx_i2s_dai_ops,
 	.ops = &bf5xx_i2s_dai_ops,
 };
 };
 
 
-static int bfin_i2s_drv_probe(struct platform_device *pdev)
+static int __devinit bf5xx_i2s_probe(struct platform_device *pdev)
 {
 {
-	return snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai);
+	struct sport_device *sport_handle;
+	int ret;
+
+	/* configure SPORT for I2S */
+	sport_handle = sport_init(pdev, 4, 2 * sizeof(u32),
+		sizeof(struct bf5xx_i2s_port));
+	if (!sport_handle)
+		return -ENODEV;
+
+	/* register with the ASoC layers */
+	ret = snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai);
+	if (ret) {
+		pr_err("Failed to register DAI: %d\n", ret);
+		sport_done(sport_handle);
+		return ret;
+	}
+
+	return 0;
 }
 }
 
 
-static int __devexit bfin_i2s_drv_remove(struct platform_device *pdev)
+static int __devexit bf5xx_i2s_remove(struct platform_device *pdev)
 {
 {
+	struct sport_device *sport_handle = platform_get_drvdata(pdev);
+
+	pr_debug("%s enter\n", __func__);
+
 	snd_soc_unregister_dai(&pdev->dev);
 	snd_soc_unregister_dai(&pdev->dev);
+	sport_done(sport_handle);
+
 	return 0;
 	return 0;
 }
 }
 
 
 static struct platform_driver bfin_i2s_driver = {
 static struct platform_driver bfin_i2s_driver = {
-	.probe = bfin_i2s_drv_probe,
-	.remove = __devexit_p(bfin_i2s_drv_remove),
-
+	.probe  = bf5xx_i2s_probe,
+	.remove = __devexit_p(bf5xx_i2s_remove),
 	.driver = {
 	.driver = {
-		.name = "bf5xx-i2s",
+		.name = "bfin-i2s",
 		.owner = THIS_MODULE,
 		.owner = THIS_MODULE,
 	},
 	},
 };
 };

+ 119 - 40
sound/soc/blackfin/bf5xx-sport.c

@@ -42,8 +42,6 @@
 /* delay between frame sync pulse and first data bit in multichannel mode */
 /* delay between frame sync pulse and first data bit in multichannel mode */
 #define FRAME_DELAY (1<<12)
 #define FRAME_DELAY (1<<12)
 
 
-struct sport_device *sport_handle;
-EXPORT_SYMBOL(sport_handle);
 /* note: multichannel is in units of 8 channels,
 /* note: multichannel is in units of 8 channels,
  * tdm_count is # channels NOT / 8 ! */
  * tdm_count is # channels NOT / 8 ! */
 int sport_set_multichannel(struct sport_device *sport,
 int sport_set_multichannel(struct sport_device *sport,
@@ -798,86 +796,164 @@ int sport_set_err_callback(struct sport_device *sport,
 }
 }
 EXPORT_SYMBOL(sport_set_err_callback);
 EXPORT_SYMBOL(sport_set_err_callback);
 
 
-struct sport_device *sport_init(struct sport_param *param, unsigned wdsize,
-		unsigned dummy_count, void *private_data)
+static int sport_config_pdev(struct platform_device *pdev, struct sport_param *param)
 {
 {
-	int ret;
+	/* Extract settings from platform data */
+	struct device *dev = &pdev->dev;
+	struct bfin_snd_platform_data *pdata = dev->platform_data;
+	struct resource *res;
+
+	param->num = pdev->id;
+
+	if (!pdata) {
+		dev_err(dev, "no platform_data\n");
+		return -ENODEV;
+	}
+	param->pin_req = pdata->pin_req;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "no MEM resource\n");
+		return -ENODEV;
+	}
+	param->regs = (struct sport_register *)res->start;
+
+	/* first RX, then TX */
+	res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+	if (!res) {
+		dev_err(dev, "no rx DMA resource\n");
+		return -ENODEV;
+	}
+	param->dma_rx_chan = res->start;
+
+	res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+	if (!res) {
+		dev_err(dev, "no tx DMA resource\n");
+		return -ENODEV;
+	}
+	param->dma_tx_chan = res->start;
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		dev_err(dev, "no irq resource\n");
+		return -ENODEV;
+	}
+	param->err_irq = res->start;
+
+	return 0;
+}
+
+struct sport_device *sport_init(struct platform_device *pdev,
+	unsigned int wdsize, unsigned int dummy_count, size_t priv_size)
+{
+	struct device *dev = &pdev->dev;
+	struct sport_param param;
 	struct sport_device *sport;
 	struct sport_device *sport;
-	pr_debug("%s enter\n", __func__);
-	BUG_ON(param == NULL);
-	BUG_ON(wdsize == 0 || dummy_count == 0);
-	sport = kmalloc(sizeof(struct sport_device), GFP_KERNEL);
-	if (!sport) {
-		pr_err("Failed to allocate for sport device\n");
+	int ret;
+
+	dev_dbg(dev, "%s enter\n", __func__);
+
+	param.wdsize = wdsize;
+	param.dummy_count = dummy_count;
+	BUG_ON(param.wdsize == 0 || param.dummy_count == 0);
+
+	ret = sport_config_pdev(pdev, &param);
+	if (ret)
+		return NULL;
+
+	if (peripheral_request_list(param.pin_req, "soc-audio")) {
+		dev_err(dev, "requesting Peripherals failed\n");
 		return NULL;
 		return NULL;
 	}
 	}
 
 
-	memset(sport, 0, sizeof(struct sport_device));
-	sport->dma_rx_chan = param->dma_rx_chan;
-	sport->dma_tx_chan = param->dma_tx_chan;
-	sport->err_irq = param->err_irq;
-	sport->regs = param->regs;
-	sport->private_data = private_data;
+	sport = kzalloc(sizeof(*sport), GFP_KERNEL);
+	if (!sport) {
+		dev_err(dev, "failed to allocate for sport device\n");
+		goto __init_err0;
+	}
+
+	sport->num = param.num;
+	sport->dma_rx_chan = param.dma_rx_chan;
+	sport->dma_tx_chan = param.dma_tx_chan;
+	sport->err_irq = param.err_irq;
+	sport->regs = param.regs;
+	sport->pin_req = param.pin_req;
 
 
 	if (request_dma(sport->dma_rx_chan, "SPORT RX Data") == -EBUSY) {
 	if (request_dma(sport->dma_rx_chan, "SPORT RX Data") == -EBUSY) {
-		pr_err("Failed to request RX dma %d\n", \
-				sport->dma_rx_chan);
+		dev_err(dev, "failed to request RX dma %d\n", sport->dma_rx_chan);
 		goto __init_err1;
 		goto __init_err1;
 	}
 	}
 	if (set_dma_callback(sport->dma_rx_chan, rx_handler, sport) != 0) {
 	if (set_dma_callback(sport->dma_rx_chan, rx_handler, sport) != 0) {
-		pr_err("Failed to request RX irq %d\n", \
-				sport->dma_rx_chan);
+		dev_err(dev, "failed to request RX irq %d\n", sport->dma_rx_chan);
 		goto __init_err2;
 		goto __init_err2;
 	}
 	}
 
 
 	if (request_dma(sport->dma_tx_chan, "SPORT TX Data") == -EBUSY) {
 	if (request_dma(sport->dma_tx_chan, "SPORT TX Data") == -EBUSY) {
-		pr_err("Failed to request TX dma %d\n", \
-				sport->dma_tx_chan);
+		dev_err(dev, "failed to request TX dma %d\n", sport->dma_tx_chan);
 		goto __init_err2;
 		goto __init_err2;
 	}
 	}
 
 
 	if (set_dma_callback(sport->dma_tx_chan, tx_handler, sport) != 0) {
 	if (set_dma_callback(sport->dma_tx_chan, tx_handler, sport) != 0) {
-		pr_err("Failed to request TX irq %d\n", \
-				sport->dma_tx_chan);
+		dev_err(dev, "failed to request TX irq %d\n", sport->dma_tx_chan);
 		goto __init_err3;
 		goto __init_err3;
 	}
 	}
 
 
 	if (request_irq(sport->err_irq, err_handler, IRQF_SHARED, "SPORT err",
 	if (request_irq(sport->err_irq, err_handler, IRQF_SHARED, "SPORT err",
 			sport) < 0) {
 			sport) < 0) {
-		pr_err("Failed to request err irq:%d\n", \
-				sport->err_irq);
+		dev_err(dev, "failed to request err irq %d\n", sport->err_irq);
 		goto __init_err3;
 		goto __init_err3;
 	}
 	}
 
 
-	pr_err("dma rx:%d tx:%d, err irq:%d, regs:%p\n",
+	dev_info(dev, "dma rx:%d tx:%d, err irq:%d, regs:%p\n",
 			sport->dma_rx_chan, sport->dma_tx_chan,
 			sport->dma_rx_chan, sport->dma_tx_chan,
 			sport->err_irq, sport->regs);
 			sport->err_irq, sport->regs);
 
 
-	sport->wdsize = wdsize;
-	sport->dummy_count = dummy_count;
+	sport->wdsize = param.wdsize;
+	sport->dummy_count = param.dummy_count;
+
+	sport->private_data = kzalloc(priv_size, GFP_KERNEL);
+	if (!sport->private_data) {
+		dev_err(dev, "could not alloc priv data %zu bytes\n", priv_size);
+		goto __init_err4;
+	}
 
 
 	if (L1_DATA_A_LENGTH)
 	if (L1_DATA_A_LENGTH)
-		sport->dummy_buf = l1_data_sram_zalloc(dummy_count * 2);
+		sport->dummy_buf = l1_data_sram_zalloc(param.dummy_count * 2);
 	else
 	else
-		sport->dummy_buf = kzalloc(dummy_count * 2, GFP_KERNEL);
+		sport->dummy_buf = kzalloc(param.dummy_count * 2, GFP_KERNEL);
 	if (sport->dummy_buf == NULL) {
 	if (sport->dummy_buf == NULL) {
-		pr_err("Failed to allocate dummy buffer\n");
-		goto __error;
+		dev_err(dev, "failed to allocate dummy buffer\n");
+		goto __error1;
 	}
 	}
 
 
 	ret = sport_config_rx_dummy(sport);
 	ret = sport_config_rx_dummy(sport);
 	if (ret) {
 	if (ret) {
-		pr_err("Failed to config rx dummy ring\n");
-		goto __error;
+		dev_err(dev, "failed to config rx dummy ring\n");
+		goto __error2;
 	}
 	}
 	ret = sport_config_tx_dummy(sport);
 	ret = sport_config_tx_dummy(sport);
 	if (ret) {
 	if (ret) {
-		pr_err("Failed to config tx dummy ring\n");
-		goto __error;
+		dev_err(dev, "failed to config tx dummy ring\n");
+		goto __error3;
 	}
 	}
 
 
+	platform_set_drvdata(pdev, sport);
+
 	return sport;
 	return sport;
-__error:
+__error3:
+	if (L1_DATA_A_LENGTH)
+		l1_data_sram_free(sport->dummy_rx_desc);
+	else
+		dma_free_coherent(NULL, 2*sizeof(struct dmasg),
+				sport->dummy_rx_desc, 0);
+__error2:
+	if (L1_DATA_A_LENGTH)
+		l1_data_sram_free(sport->dummy_buf);
+	else
+		kfree(sport->dummy_buf);
+__error1:
+	kfree(sport->private_data);
+__init_err4:
 	free_irq(sport->err_irq, sport);
 	free_irq(sport->err_irq, sport);
 __init_err3:
 __init_err3:
 	free_dma(sport->dma_tx_chan);
 	free_dma(sport->dma_tx_chan);
@@ -885,6 +961,8 @@ __init_err2:
 	free_dma(sport->dma_rx_chan);
 	free_dma(sport->dma_rx_chan);
 __init_err1:
 __init_err1:
 	kfree(sport);
 	kfree(sport);
+__init_err0:
+	peripheral_free_list(param.pin_req);
 	return NULL;
 	return NULL;
 }
 }
 EXPORT_SYMBOL(sport_init);
 EXPORT_SYMBOL(sport_init);
@@ -917,8 +995,9 @@ void sport_done(struct sport_device *sport)
 	free_dma(sport->dma_tx_chan);
 	free_dma(sport->dma_tx_chan);
 	free_irq(sport->err_irq, sport);
 	free_irq(sport->err_irq, sport);
 
 
+	kfree(sport->private_data);
+	peripheral_free_list(sport->pin_req);
 	kfree(sport);
 	kfree(sport);
-		sport = NULL;
 }
 }
 EXPORT_SYMBOL(sport_done);
 EXPORT_SYMBOL(sport_done);
 
 

+ 11 - 5
sound/soc/blackfin/bf5xx-sport.h

@@ -1,5 +1,5 @@
 /*
 /*
- * File:         bf5xx_ac97_sport.h
+ * File:         bf5xx_sport.h
  * Based on:
  * Based on:
  * Author:       Roy Huang <roy.huang@analog.com>
  * Author:       Roy Huang <roy.huang@analog.com>
  *
  *
@@ -33,15 +33,18 @@
 #include <linux/types.h>
 #include <linux/types.h>
 #include <linux/wait.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 #include <linux/workqueue.h>
+#include <linux/platform_device.h>
 #include <asm/dma.h>
 #include <asm/dma.h>
 #include <asm/bfin_sport.h>
 #include <asm/bfin_sport.h>
 
 
 #define DESC_ELEMENT_COUNT 9
 #define DESC_ELEMENT_COUNT 9
 
 
 struct sport_device {
 struct sport_device {
+	int num;
 	int dma_rx_chan;
 	int dma_rx_chan;
 	int dma_tx_chan;
 	int dma_tx_chan;
 	int err_irq;
 	int err_irq;
+	const unsigned short *pin_req;
 	struct sport_register *regs;
 	struct sport_register *regs;
 
 
 	unsigned char *rx_buf;
 	unsigned char *rx_buf;
@@ -103,17 +106,20 @@ struct sport_device {
 	void *private_data;
 	void *private_data;
 };
 };
 
 
-extern struct sport_device *sport_handle;
-
 struct sport_param {
 struct sport_param {
+	int num;
 	int dma_rx_chan;
 	int dma_rx_chan;
 	int dma_tx_chan;
 	int dma_tx_chan;
 	int err_irq;
 	int err_irq;
+	const unsigned short *pin_req;
 	struct sport_register *regs;
 	struct sport_register *regs;
+	unsigned int wdsize;
+	unsigned int dummy_count;
+	void *private_data;
 };
 };
 
 
-struct sport_device *sport_init(struct sport_param *param, unsigned wdsize,
-		unsigned dummy_count, void *private_data);
+struct sport_device *sport_init(struct platform_device *pdev,
+	unsigned int wdsize, unsigned int dummy_count, size_t priv_size);
 
 
 void sport_done(struct sport_device *sport);
 void sport_done(struct sport_device *sport);
 
 

+ 21 - 21
sound/soc/blackfin/bf5xx-ssm2602.c

@@ -44,16 +44,6 @@
 
 
 static struct snd_soc_card bf5xx_ssm2602;
 static struct snd_soc_card bf5xx_ssm2602;
 
 
-static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-
-	pr_debug("%s enter\n", __func__);
-	snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
-	return 0;
-}
-
 static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
 static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
 	struct snd_pcm_hw_params *params)
 {
 {
@@ -109,23 +99,33 @@ static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
 }
 }
 
 
 static struct snd_soc_ops bf5xx_ssm2602_ops = {
 static struct snd_soc_ops bf5xx_ssm2602_ops = {
-	.startup = bf5xx_ssm2602_startup,
 	.hw_params = bf5xx_ssm2602_hw_params,
 	.hw_params = bf5xx_ssm2602_hw_params,
 };
 };
 
 
-static struct snd_soc_dai_link bf5xx_ssm2602_dai = {
-	.name = "ssm2602",
-	.stream_name = "SSM2602",
-	.cpu_dai_name = "bf5xx-i2s",
-	.codec_dai_name = "ssm2602-hifi",
-	.platform_name = "bf5xx-pcm-audio",
-	.codec_name = "ssm2602-codec.0-001b",
-	.ops = &bf5xx_ssm2602_ops,
+static struct snd_soc_dai_link bf5xx_ssm2602_dai[] = {
+	{
+		.name = "ssm2602",
+		.stream_name = "SSM2602",
+		.cpu_dai_name = "bfin-i2s.0",
+		.codec_dai_name = "ssm2602-hifi",
+		.platform_name = "bfin-i2s-pcm-audio",
+		.codec_name = "ssm2602.0-001b",
+		.ops = &bf5xx_ssm2602_ops,
+	},
+	{
+		.name = "ssm2602",
+		.stream_name = "SSM2602",
+		.cpu_dai_name = "bfin-i2s.1",
+		.codec_dai_name = "ssm2602-hifi",
+		.platform_name = "bfin-i2s-pcm-audio",
+		.codec_name = "ssm2602.0-001b",
+		.ops = &bf5xx_ssm2602_ops,
+	},
 };
 };
 
 
 static struct snd_soc_card bf5xx_ssm2602 = {
 static struct snd_soc_card bf5xx_ssm2602 = {
-	.name = "bf5xx_ssm2602",
-	.dai_link = &bf5xx_ssm2602_dai,
+	.name = "bfin-ssm2602",
+	.dai_link = &bf5xx_ssm2602_dai[CONFIG_SND_BF5XX_SPORT_NUM],
 	.num_links = 1,
 	.num_links = 1,
 };
 };
 
 

+ 13 - 10
sound/soc/blackfin/bf5xx-tdm-pcm.c

@@ -154,7 +154,12 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
 
 
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 {
 {
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+
 	int ret = 0;
 	int ret = 0;
 
 
 	snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
 	snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
@@ -164,9 +169,14 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
 	if (ret < 0)
 	if (ret < 0)
 		goto out;
 		goto out;
 
 
-	if (sport_handle != NULL)
+	if (sport_handle != NULL) {
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			sport_handle->tx_buf = buf->area;
+		else
+			sport_handle->rx_buf = buf->area;
+
 		runtime->private_data = sport_handle;
 		runtime->private_data = sport_handle;
-	else {
+	} else {
 		pr_err("sport_handle is NULL\n");
 		pr_err("sport_handle is NULL\n");
 		ret = -ENODEV;
 		ret = -ENODEV;
 	}
 	}
@@ -249,11 +259,6 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 	}
 	}
 	buf->bytes = size;
 	buf->bytes = size;
 
 
-	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-		sport_handle->tx_buf = buf->area;
-	else
-		sport_handle->rx_buf = buf->area;
-
 	return 0;
 	return 0;
 }
 }
 
 
@@ -274,8 +279,6 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 		dma_free_coherent(NULL, buf->bytes, buf->area, 0);
 		dma_free_coherent(NULL, buf->bytes, buf->area, 0);
 		buf->area = NULL;
 		buf->area = NULL;
 	}
 	}
-	if (sport_handle)
-		sport_done(sport_handle);
 }
 }
 
 
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
 static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
@@ -326,7 +329,7 @@ static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
 
 
 static struct platform_driver bfin_tdm_driver = {
 static struct platform_driver bfin_tdm_driver = {
 	.driver = {
 	.driver = {
-			.name = "bf5xx-tdm-pcm-audio",
+			.name = "bfin-tdm-pcm-audio",
 			.owner = THIS_MODULE,
 			.owner = THIS_MODULE,
 	},
 	},
 
 

+ 38 - 72
sound/soc/blackfin/bf5xx-tdm.c

@@ -46,43 +46,6 @@
 #include "bf5xx-sport.h"
 #include "bf5xx-sport.h"
 #include "bf5xx-tdm.h"
 #include "bf5xx-tdm.h"
 
 
-static struct bf5xx_tdm_port bf5xx_tdm;
-static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
-
-static struct sport_param sport_params[2] = {
-	{
-		.dma_rx_chan    = CH_SPORT0_RX,
-		.dma_tx_chan    = CH_SPORT0_TX,
-		.err_irq        = IRQ_SPORT0_ERROR,
-		.regs           = (struct sport_register *)SPORT0_TCR1,
-	},
-	{
-		.dma_rx_chan    = CH_SPORT1_RX,
-		.dma_tx_chan    = CH_SPORT1_TX,
-		.err_irq        = IRQ_SPORT1_ERROR,
-		.regs           = (struct sport_register *)SPORT1_TCR1,
-	}
-};
-
-/*
- * Setting the TFS pin selector for SPORT 0 based on whether the selected
- * port id F or G. If the port is F then no conflict should exist for the
- * TFS. When Port G is selected and EMAC then there is a conflict between
- * the PHY interrupt line and TFS.  Current settings prevent the conflict
- * by ignoring the TFS pin when Port G is selected. This allows both
- * codecs and EMAC using Port G concurrently.
- */
-#ifdef CONFIG_BF527_SPORT0_PORTG
-#define LOCAL_SPORT0_TFS (0)
-#else
-#define LOCAL_SPORT0_TFS (P_SPORT0_TFS)
-#endif
-
-static u16 sport_req[][7] = { {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
-	P_SPORT0_DRPRI, P_SPORT0_RSCLK, LOCAL_SPORT0_TFS, 0},
-	   {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, P_SPORT1_DRPRI,
-		   P_SPORT1_RSCLK, P_SPORT1_TFS, 0} };
-
 static int bf5xx_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 static int bf5xx_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 	unsigned int fmt)
 	unsigned int fmt)
 {
 {
@@ -119,14 +82,16 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params,
 	struct snd_pcm_hw_params *params,
 	struct snd_soc_dai *dai)
 	struct snd_soc_dai *dai)
 {
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+	struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
 	int ret = 0;
 	int ret = 0;
 
 
-	bf5xx_tdm.tcr2 &= ~0x1f;
-	bf5xx_tdm.rcr2 &= ~0x1f;
+	bf5xx_tdm->tcr2 &= ~0x1f;
+	bf5xx_tdm->rcr2 &= ~0x1f;
 	switch (params_format(params)) {
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S32_LE:
 	case SNDRV_PCM_FORMAT_S32_LE:
-		bf5xx_tdm.tcr2 |= 31;
-		bf5xx_tdm.rcr2 |= 31;
+		bf5xx_tdm->tcr2 |= 31;
+		bf5xx_tdm->rcr2 |= 31;
 		sport_handle->wdsize = 4;
 		sport_handle->wdsize = 4;
 		break;
 		break;
 		/* at present, we only support 32bit transfer */
 		/* at present, we only support 32bit transfer */
@@ -136,7 +101,7 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
 		break;
 		break;
 	}
 	}
 
 
-	if (!bf5xx_tdm.configured) {
+	if (!bf5xx_tdm->configured) {
 		/*
 		/*
 		 * TX and RX are not independent,they are enabled at the
 		 * TX and RX are not independent,they are enabled at the
 		 * same time, even if only one side is running. So, we
 		 * same time, even if only one side is running. So, we
@@ -145,21 +110,21 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
 		 *
 		 *
 		 * CPU DAI:slave mode.
 		 * CPU DAI:slave mode.
 		 */
 		 */
-		ret = sport_config_rx(sport_handle, bf5xx_tdm.rcr1,
-			bf5xx_tdm.rcr2, 0, 0);
+		ret = sport_config_rx(sport_handle, bf5xx_tdm->rcr1,
+			bf5xx_tdm->rcr2, 0, 0);
 		if (ret) {
 		if (ret) {
 			pr_err("SPORT is busy!\n");
 			pr_err("SPORT is busy!\n");
 			return -EBUSY;
 			return -EBUSY;
 		}
 		}
 
 
-		ret = sport_config_tx(sport_handle, bf5xx_tdm.tcr1,
-			bf5xx_tdm.tcr2, 0, 0);
+		ret = sport_config_tx(sport_handle, bf5xx_tdm->tcr1,
+			bf5xx_tdm->tcr2, 0, 0);
 		if (ret) {
 		if (ret) {
 			pr_err("SPORT is busy!\n");
 			pr_err("SPORT is busy!\n");
 			return -EBUSY;
 			return -EBUSY;
 		}
 		}
 
 
-		bf5xx_tdm.configured = 1;
+		bf5xx_tdm->configured = 1;
 	}
 	}
 
 
 	return 0;
 	return 0;
@@ -168,15 +133,20 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
 static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream,
 static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream,
 	struct snd_soc_dai *dai)
 	struct snd_soc_dai *dai)
 {
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+	struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
+
 	/* No active stream, SPORT is allowed to be configured again. */
 	/* No active stream, SPORT is allowed to be configured again. */
 	if (!dai->active)
 	if (!dai->active)
-		bf5xx_tdm.configured = 0;
+		bf5xx_tdm->configured = 0;
 }
 }
 
 
 static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
 static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
 		unsigned int tx_num, unsigned int *tx_slot,
 		unsigned int tx_num, unsigned int *tx_slot,
 		unsigned int rx_num, unsigned int *rx_slot)
 		unsigned int rx_num, unsigned int *rx_slot)
 {
 {
+	struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
+	struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
 	int i;
 	int i;
 	unsigned int slot;
 	unsigned int slot;
 	unsigned int tx_mapped = 0, rx_mapped = 0;
 	unsigned int tx_mapped = 0, rx_mapped = 0;
@@ -189,7 +159,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
 		slot = tx_slot[i];
 		slot = tx_slot[i];
 		if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
 		if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
 				(!(tx_mapped & (1 << slot)))) {
 				(!(tx_mapped & (1 << slot)))) {
-			bf5xx_tdm.tx_map[i] = slot;
+			bf5xx_tdm->tx_map[i] = slot;
 			tx_mapped |= 1 << slot;
 			tx_mapped |= 1 << slot;
 		} else
 		} else
 			return -EINVAL;
 			return -EINVAL;
@@ -198,7 +168,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
 		slot = rx_slot[i];
 		slot = rx_slot[i];
 		if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
 		if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
 				(!(rx_mapped & (1 << slot)))) {
 				(!(rx_mapped & (1 << slot)))) {
-			bf5xx_tdm.rx_map[i] = slot;
+			bf5xx_tdm->rx_map[i] = slot;
 			rx_mapped |= 1 << slot;
 			rx_mapped |= 1 << slot;
 		} else
 		} else
 			return -EINVAL;
 			return -EINVAL;
@@ -212,12 +182,14 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
 {
 {
 	struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 	struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
 
-	if (!dai->active)
-		return 0;
-	if (dai->capture_active)
-		sport_rx_stop(sport);
 	if (dai->playback_active)
 	if (dai->playback_active)
 		sport_tx_stop(sport);
 		sport_tx_stop(sport);
+	if (dai->capture_active)
+		sport_rx_stop(sport);
+
+	/* isolate sync/clock pins from codec while sports resume */
+	peripheral_free_list(sport->pin_req);
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -226,9 +198,6 @@ static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
 	int ret;
 	int ret;
 	struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 	struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
 
-	if (!dai->active)
-		return 0;
-
 	ret = sport_set_multichannel(sport, 8, 0xFF, 1);
 	ret = sport_set_multichannel(sport, 8, 0xFF, 1);
 	if (ret) {
 	if (ret) {
 		pr_err("SPORT is busy!\n");
 		pr_err("SPORT is busy!\n");
@@ -247,6 +216,8 @@ static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
 		ret = -EBUSY;
 		ret = -EBUSY;
 	}
 	}
 
 
+	peripheral_request_list(sport->pin_req, "soc-audio");
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -280,20 +251,14 @@ static struct snd_soc_dai_driver bf5xx_tdm_dai = {
 
 
 static int __devinit bfin_tdm_probe(struct platform_device *pdev)
 static int __devinit bfin_tdm_probe(struct platform_device *pdev)
 {
 {
-	int ret = 0;
-
-	if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
-		pr_err("Requesting Peripherals failed\n");
-		return -EFAULT;
-	}
+	struct sport_device *sport_handle;
+	int ret;
 
 
-	/* request DMA for SPORT */
-	sport_handle = sport_init(&sport_params[sport_num], 4, \
-		8 * sizeof(u32), NULL);
-	if (!sport_handle) {
-		peripheral_free_list(&sport_req[sport_num][0]);
+	/* configure SPORT for TDM */
+	sport_handle = sport_init(pdev, 4, 8 * sizeof(u32),
+		sizeof(struct bf5xx_tdm_port));
+	if (!sport_handle)
 		return -ENODEV;
 		return -ENODEV;
-	}
 
 
 	/* SPORT works in TDM mode */
 	/* SPORT works in TDM mode */
 	ret = sport_set_multichannel(sport_handle, 8, 0xFF, 1);
 	ret = sport_set_multichannel(sport_handle, 8, 0xFF, 1);
@@ -323,18 +288,19 @@ static int __devinit bfin_tdm_probe(struct platform_device *pdev)
 		goto sport_config_err;
 		goto sport_config_err;
 	}
 	}
 
 
-	sport_handle->private_data = &bf5xx_tdm;
 	return 0;
 	return 0;
 
 
 sport_config_err:
 sport_config_err:
-	peripheral_free_list(&sport_req[sport_num][0]);
+	sport_done(sport_handle);
 	return ret;
 	return ret;
 }
 }
 
 
 static int __devexit bfin_tdm_remove(struct platform_device *pdev)
 static int __devexit bfin_tdm_remove(struct platform_device *pdev)
 {
 {
-	peripheral_free_list(&sport_req[sport_num][0]);
+	struct sport_device *sport_handle = platform_get_drvdata(pdev);
+
 	snd_soc_unregister_dai(&pdev->dev);
 	snd_soc_unregister_dai(&pdev->dev);
+	sport_done(sport_handle);
 
 
 	return 0;
 	return 0;
 }
 }

+ 1 - 1
sound/soc/codecs/88pm860x-codec.c

@@ -120,7 +120,7 @@
  */
  */
 #define PM860X_DAPM_OUTPUT(wname, wevent)	\
 #define PM860X_DAPM_OUTPUT(wname, wevent)	\
 {	.id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \
 {	.id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \
-	.shift = 0, .invert = 0, .kcontrols = NULL, \
+	.shift = 0, .invert = 0, .kcontrol_news = NULL, \
 	.num_kcontrols = 0, .event = wevent, \
 	.num_kcontrols = 0, .event = wevent, \
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD, }
 	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD, }
 
 

+ 18 - 2
sound/soc/codecs/Kconfig

@@ -16,10 +16,11 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_AD1836 if SPI_MASTER
 	select SND_SOC_AD1836 if SPI_MASTER
 	select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI
 	select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI
 	select SND_SOC_AD1980 if SND_SOC_AC97_BUS
 	select SND_SOC_AD1980 if SND_SOC_AC97_BUS
+	select SND_SOC_AD73311
 	select SND_SOC_ADS117X
 	select SND_SOC_ADS117X
-	select SND_SOC_AD73311 if I2C
 	select SND_SOC_AK4104 if SPI_MASTER
 	select SND_SOC_AK4104 if SPI_MASTER
 	select SND_SOC_AK4535 if I2C
 	select SND_SOC_AK4535 if I2C
+	select SND_SOC_AK4641 if I2C
 	select SND_SOC_AK4642 if I2C
 	select SND_SOC_AK4642 if I2C
 	select SND_SOC_AK4671 if I2C
 	select SND_SOC_AK4671 if I2C
 	select SND_SOC_ALC5623 if I2C
 	select SND_SOC_ALC5623 if I2C
@@ -33,13 +34,14 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_JZ4740_CODEC if SOC_JZ4740
 	select SND_SOC_JZ4740_CODEC if SOC_JZ4740
 	select SND_SOC_LM4857 if I2C
 	select SND_SOC_LM4857 if I2C
 	select SND_SOC_MAX98088 if I2C
 	select SND_SOC_MAX98088 if I2C
+	select SND_SOC_MAX98095 if I2C
 	select SND_SOC_MAX9850 if I2C
 	select SND_SOC_MAX9850 if I2C
 	select SND_SOC_MAX9877 if I2C
 	select SND_SOC_MAX9877 if I2C
 	select SND_SOC_PCM3008
 	select SND_SOC_PCM3008
 	select SND_SOC_SGTL5000 if I2C
 	select SND_SOC_SGTL5000 if I2C
 	select SND_SOC_SN95031 if INTEL_SCU_IPC
 	select SND_SOC_SN95031 if INTEL_SCU_IPC
 	select SND_SOC_SPDIF
 	select SND_SOC_SPDIF
-	select SND_SOC_SSM2602 if I2C
+	select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
 	select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
 	select SND_SOC_TLV320AIC23 if I2C
 	select SND_SOC_TLV320AIC23 if I2C
 	select SND_SOC_TLV320AIC26 if SPI_MASTER
 	select SND_SOC_TLV320AIC26 if SPI_MASTER
@@ -52,6 +54,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_UDA134X
 	select SND_SOC_UDA134X
 	select SND_SOC_UDA1380 if I2C
 	select SND_SOC_UDA1380 if I2C
 	select SND_SOC_WL1273 if MFD_WL1273_CORE
 	select SND_SOC_WL1273 if MFD_WL1273_CORE
+	select SND_SOC_WM1250_EV1 if I2C
 	select SND_SOC_WM2000 if I2C
 	select SND_SOC_WM2000 if I2C
 	select SND_SOC_WM8350 if MFD_WM8350
 	select SND_SOC_WM8350 if MFD_WM8350
 	select SND_SOC_WM8400 if MFD_WM8400
 	select SND_SOC_WM8400 if MFD_WM8400
@@ -72,6 +75,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_WM8900 if I2C
 	select SND_SOC_WM8900 if I2C
 	select SND_SOC_WM8903 if I2C
 	select SND_SOC_WM8903 if I2C
 	select SND_SOC_WM8904 if I2C
 	select SND_SOC_WM8904 if I2C
+	select SND_SOC_WM8915 if I2C
 	select SND_SOC_WM8940 if I2C
 	select SND_SOC_WM8940 if I2C
 	select SND_SOC_WM8955 if I2C
 	select SND_SOC_WM8955 if I2C
 	select SND_SOC_WM8960 if I2C
 	select SND_SOC_WM8960 if I2C
@@ -136,6 +140,9 @@ config SND_SOC_AK4104
 config SND_SOC_AK4535
 config SND_SOC_AK4535
 	tristate
 	tristate
 
 
+config SND_SOC_AK4641
+	tristate
+
 config SND_SOC_AK4642
 config SND_SOC_AK4642
 	tristate
 	tristate
 
 
@@ -187,6 +194,9 @@ config SND_SOC_DMIC
 config SND_SOC_MAX98088
 config SND_SOC_MAX98088
        tristate
        tristate
 
 
+config SND_SOC_MAX98095
+       tristate
+
 config SND_SOC_MAX9850
 config SND_SOC_MAX9850
 	tristate
 	tristate
 
 
@@ -241,6 +251,9 @@ config SND_SOC_UDA1380
 config SND_SOC_WL1273
 config SND_SOC_WL1273
 	tristate
 	tristate
 
 
+config SND_SOC_WM1250_EV1
+	tristate
+
 config SND_SOC_WM8350
 config SND_SOC_WM8350
 	tristate
 	tristate
 
 
@@ -298,6 +311,9 @@ config SND_SOC_WM8903
 config SND_SOC_WM8904
 config SND_SOC_WM8904
 	tristate
 	tristate
 
 
+config SND_SOC_WM8915
+	tristate
+
 config SND_SOC_WM8940
 config SND_SOC_WM8940
         tristate
         tristate
 
 

+ 9 - 1
sound/soc/codecs/Makefile

@@ -7,6 +7,7 @@ snd-soc-ad73311-objs := ad73311.o
 snd-soc-ads117x-objs := ads117x.o
 snd-soc-ads117x-objs := ads117x.o
 snd-soc-ak4104-objs := ak4104.o
 snd-soc-ak4104-objs := ak4104.o
 snd-soc-ak4535-objs := ak4535.o
 snd-soc-ak4535-objs := ak4535.o
+snd-soc-ak4641-objs := ak4641.o
 snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
 snd-soc-ak4671-objs := ak4671.o
 snd-soc-cq93vc-objs := cq93vc.o
 snd-soc-cq93vc-objs := cq93vc.o
@@ -19,6 +20,7 @@ snd-soc-dfbmcs320-objs := dfbmcs320.o
 snd-soc-dmic-objs := dmic.o
 snd-soc-dmic-objs := dmic.o
 snd-soc-l3-objs := l3.o
 snd-soc-l3-objs := l3.o
 snd-soc-max98088-objs := max98088.o
 snd-soc-max98088-objs := max98088.o
+snd-soc-max98095-objs := max98095.o
 snd-soc-max9850-objs := max9850.o
 snd-soc-max9850-objs := max9850.o
 snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-sgtl5000-objs := sgtl5000.o
 snd-soc-sgtl5000-objs := sgtl5000.o
@@ -37,6 +39,7 @@ snd-soc-twl6040-objs := twl6040.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-uda1380-objs := uda1380.o
 snd-soc-wl1273-objs := wl1273.o
 snd-soc-wl1273-objs := wl1273.o
+snd-soc-wm1250-ev1-objs := wm1250-ev1.o
 snd-soc-wm8350-objs := wm8350.o
 snd-soc-wm8350-objs := wm8350.o
 snd-soc-wm8400-objs := wm8400.o
 snd-soc-wm8400-objs := wm8400.o
 snd-soc-wm8510-objs := wm8510.o
 snd-soc-wm8510-objs := wm8510.o
@@ -56,6 +59,7 @@ snd-soc-wm8804-objs := wm8804.o
 snd-soc-wm8900-objs := wm8900.o
 snd-soc-wm8900-objs := wm8900.o
 snd-soc-wm8903-objs := wm8903.o
 snd-soc-wm8903-objs := wm8903.o
 snd-soc-wm8904-objs := wm8904.o
 snd-soc-wm8904-objs := wm8904.o
+snd-soc-wm8915-objs := wm8915.o
 snd-soc-wm8940-objs := wm8940.o
 snd-soc-wm8940-objs := wm8940.o
 snd-soc-wm8955-objs := wm8955.o
 snd-soc-wm8955-objs := wm8955.o
 snd-soc-wm8960-objs := wm8960.o
 snd-soc-wm8960-objs := wm8960.o
@@ -69,7 +73,7 @@ snd-soc-wm8988-objs := wm8988.o
 snd-soc-wm8990-objs := wm8990.o
 snd-soc-wm8990-objs := wm8990.o
 snd-soc-wm8991-objs := wm8991.o
 snd-soc-wm8991-objs := wm8991.o
 snd-soc-wm8993-objs := wm8993.o
 snd-soc-wm8993-objs := wm8993.o
-snd-soc-wm8994-objs := wm8994.o wm8994-tables.o
+snd-soc-wm8994-objs := wm8994.o wm8994-tables.o wm8958-dsp2.o
 snd-soc-wm8995-objs := wm8995.o
 snd-soc-wm8995-objs := wm8995.o
 snd-soc-wm9081-objs := wm9081.o
 snd-soc-wm9081-objs := wm9081.o
 snd-soc-wm9705-objs := wm9705.o
 snd-soc-wm9705-objs := wm9705.o
@@ -94,6 +98,7 @@ obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
 obj-$(CONFIG_SND_SOC_ADS117X)	+= snd-soc-ads117x.o
 obj-$(CONFIG_SND_SOC_ADS117X)	+= snd-soc-ads117x.o
 obj-$(CONFIG_SND_SOC_AK4104)	+= snd-soc-ak4104.o
 obj-$(CONFIG_SND_SOC_AK4104)	+= snd-soc-ak4104.o
 obj-$(CONFIG_SND_SOC_AK4535)	+= snd-soc-ak4535.o
 obj-$(CONFIG_SND_SOC_AK4535)	+= snd-soc-ak4535.o
+obj-$(CONFIG_SND_SOC_AK4641)	+= snd-soc-ak4641.o
 obj-$(CONFIG_SND_SOC_AK4642)	+= snd-soc-ak4642.o
 obj-$(CONFIG_SND_SOC_AK4642)	+= snd-soc-ak4642.o
 obj-$(CONFIG_SND_SOC_AK4671)	+= snd-soc-ak4671.o
 obj-$(CONFIG_SND_SOC_AK4671)	+= snd-soc-ak4671.o
 obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
 obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
@@ -108,6 +113,7 @@ obj-$(CONFIG_SND_SOC_DMIC)	+= snd-soc-dmic.o
 obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
 obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)	+= snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)	+= snd-soc-jz4740-codec.o
 obj-$(CONFIG_SND_SOC_MAX98088)	+= snd-soc-max98088.o
 obj-$(CONFIG_SND_SOC_MAX98088)	+= snd-soc-max98088.o
+obj-$(CONFIG_SND_SOC_MAX98095)	+= snd-soc-max98095.o
 obj-$(CONFIG_SND_SOC_MAX9850)	+= snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_MAX9850)	+= snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
 obj-$(CONFIG_SND_SOC_SGTL5000)  += snd-soc-sgtl5000.o
@@ -125,6 +131,7 @@ obj-$(CONFIG_SND_SOC_TWL6040)	+= snd-soc-twl6040.o
 obj-$(CONFIG_SND_SOC_UDA134X)	+= snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA134X)	+= snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)	+= snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_UDA1380)	+= snd-soc-uda1380.o
 obj-$(CONFIG_SND_SOC_WL1273)	+= snd-soc-wl1273.o
 obj-$(CONFIG_SND_SOC_WL1273)	+= snd-soc-wl1273.o
+obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
 obj-$(CONFIG_SND_SOC_WM8350)	+= snd-soc-wm8350.o
 obj-$(CONFIG_SND_SOC_WM8350)	+= snd-soc-wm8350.o
 obj-$(CONFIG_SND_SOC_WM8400)	+= snd-soc-wm8400.o
 obj-$(CONFIG_SND_SOC_WM8400)	+= snd-soc-wm8400.o
 obj-$(CONFIG_SND_SOC_WM8510)	+= snd-soc-wm8510.o
 obj-$(CONFIG_SND_SOC_WM8510)	+= snd-soc-wm8510.o
@@ -144,6 +151,7 @@ obj-$(CONFIG_SND_SOC_WM8804)	+= snd-soc-wm8804.o
 obj-$(CONFIG_SND_SOC_WM8900)	+= snd-soc-wm8900.o
 obj-$(CONFIG_SND_SOC_WM8900)	+= snd-soc-wm8900.o
 obj-$(CONFIG_SND_SOC_WM8903)	+= snd-soc-wm8903.o
 obj-$(CONFIG_SND_SOC_WM8903)	+= snd-soc-wm8903.o
 obj-$(CONFIG_SND_SOC_WM8904)	+= snd-soc-wm8904.o
 obj-$(CONFIG_SND_SOC_WM8904)	+= snd-soc-wm8904.o
+obj-$(CONFIG_SND_SOC_WM8915)	+= snd-soc-wm8915.o
 obj-$(CONFIG_SND_SOC_WM8940)	+= snd-soc-wm8940.o
 obj-$(CONFIG_SND_SOC_WM8940)	+= snd-soc-wm8940.o
 obj-$(CONFIG_SND_SOC_WM8955)	+= snd-soc-wm8955.o
 obj-$(CONFIG_SND_SOC_WM8955)	+= snd-soc-wm8955.o
 obj-$(CONFIG_SND_SOC_WM8960)	+= snd-soc-wm8960.o
 obj-$(CONFIG_SND_SOC_WM8960)	+= snd-soc-wm8960.o

+ 9 - 14
sound/soc/codecs/ad193x.c

@@ -23,8 +23,7 @@
 
 
 /* codec private data */
 /* codec private data */
 struct ad193x_priv {
 struct ad193x_priv {
-	enum snd_soc_control_type bus_type;
-	void *control_data;
+	enum snd_soc_control_type control_type;
 	int sysclk;
 	int sysclk;
 };
 };
 
 
@@ -354,14 +353,12 @@ static int ad193x_probe(struct snd_soc_codec *codec)
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	struct snd_soc_dapm_context *dapm = &codec->dapm;
 	int ret;
 	int ret;
 
 
-	codec->control_data = ad193x->control_data;
-	if (ad193x->bus_type == SND_SOC_I2C)
-		ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->bus_type);
+	if (ad193x->control_type == SND_SOC_I2C)
+		ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->control_type);
 	else
 	else
-		ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->bus_type);
+		ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->control_type);
 	if (ret < 0) {
 	if (ret < 0) {
-		dev_err(codec->dev, "failed to set cache I/O: %d\n",
-				ret);
+		dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
 		return ret;
 		return ret;
 	}
 	}
 
 
@@ -408,8 +405,7 @@ static int __devinit ad193x_spi_probe(struct spi_device *spi)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	spi_set_drvdata(spi, ad193x);
 	spi_set_drvdata(spi, ad193x);
-	ad193x->control_data = spi;
-	ad193x->bus_type = SND_SOC_SPI;
+	ad193x->control_type = SND_SOC_SPI;
 
 
 	ret = snd_soc_register_codec(&spi->dev,
 	ret = snd_soc_register_codec(&spi->dev,
 			&soc_codec_dev_ad193x, &ad193x_dai, 1);
 			&soc_codec_dev_ad193x, &ad193x_dai, 1);
@@ -427,7 +423,7 @@ static int __devexit ad193x_spi_remove(struct spi_device *spi)
 
 
 static struct spi_driver ad193x_spi_driver = {
 static struct spi_driver ad193x_spi_driver = {
 	.driver = {
 	.driver = {
-		.name	= "ad193x-codec",
+		.name	= "ad193x",
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,
 	},
 	},
 	.probe		= ad193x_spi_probe,
 	.probe		= ad193x_spi_probe,
@@ -454,8 +450,7 @@ static int __devinit ad193x_i2c_probe(struct i2c_client *client,
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	i2c_set_clientdata(client, ad193x);
 	i2c_set_clientdata(client, ad193x);
-	ad193x->control_data = client;
-	ad193x->bus_type = SND_SOC_I2C;
+	ad193x->control_type = SND_SOC_I2C;
 
 
 	ret =  snd_soc_register_codec(&client->dev,
 	ret =  snd_soc_register_codec(&client->dev,
 			&soc_codec_dev_ad193x, &ad193x_dai, 1);
 			&soc_codec_dev_ad193x, &ad193x_dai, 1);
@@ -473,7 +468,7 @@ static int __devexit ad193x_i2c_remove(struct i2c_client *client)
 
 
 static struct i2c_driver ad193x_i2c_driver = {
 static struct i2c_driver ad193x_i2c_driver = {
 	.driver = {
 	.driver = {
-		.name = "ad193x-codec",
+		.name = "ad193x",
 	},
 	},
 	.probe    = ad193x_i2c_probe,
 	.probe    = ad193x_i2c_probe,
 	.remove   = __devexit_p(ad193x_i2c_remove),
 	.remove   = __devexit_p(ad193x_i2c_remove),

+ 1 - 1
sound/soc/codecs/ad1980.c

@@ -266,7 +266,7 @@ static int __devexit ad1980_remove(struct platform_device *pdev)
 
 
 static struct platform_driver ad1980_codec_driver = {
 static struct platform_driver ad1980_codec_driver = {
 	.driver = {
 	.driver = {
-			.name = "ad1980-codec",
+			.name = "ad1980",
 			.owner = THIS_MODULE,
 			.owner = THIS_MODULE,
 	},
 	},
 
 

+ 1 - 1
sound/soc/codecs/ad73311.c

@@ -55,7 +55,7 @@ static int __devexit ad73311_remove(struct platform_device *pdev)
 
 
 static struct platform_driver ad73311_codec_driver = {
 static struct platform_driver ad73311_codec_driver = {
 	.driver = {
 	.driver = {
-			.name = "ad73311-codec",
+			.name = "ad73311",
 			.owner = THIS_MODULE,
 			.owner = THIS_MODULE,
 	},
 	},
 
 

+ 5 - 14
sound/soc/codecs/ak4535.c

@@ -230,7 +230,7 @@ static const struct snd_soc_dapm_widget ak4535_dapm_widgets[] = {
 	SND_SOC_DAPM_INPUT("AIN"),
 	SND_SOC_DAPM_INPUT("AIN"),
 };
 };
 
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route ak4535_audio_map[] = {
 	/*stereo mixer */
 	/*stereo mixer */
 	{"Stereo Mixer", "Playback Switch", "DAC"},
 	{"Stereo Mixer", "Playback Switch", "DAC"},
 	{"Stereo Mixer", "Mic Sidetone Switch", "Mic"},
 	{"Stereo Mixer", "Mic Sidetone Switch", "Mic"},
@@ -287,17 +287,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	{"Input Mixer", "Aux Capture Switch", "Aux In"},
 	{"Input Mixer", "Aux Capture Switch", "Aux In"},
 };
 };
 
 
-static int ak4535_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, ak4535_dapm_widgets,
-				  ARRAY_SIZE(ak4535_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-	return 0;
-}
-
 static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 static int ak4535_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 	int clk_id, unsigned int freq, int dir)
 	int clk_id, unsigned int freq, int dir)
 {
 {
@@ -457,8 +446,6 @@ static int ak4535_probe(struct snd_soc_codec *codec)
 
 
 	snd_soc_add_controls(codec, ak4535_snd_controls,
 	snd_soc_add_controls(codec, ak4535_snd_controls,
 				ARRAY_SIZE(ak4535_snd_controls));
 				ARRAY_SIZE(ak4535_snd_controls));
-	ak4535_add_widgets(codec);
-
 	return 0;
 	return 0;
 }
 }
 
 
@@ -480,6 +467,10 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
 	.reg_cache_size = ARRAY_SIZE(ak4535_reg),
 	.reg_cache_size = ARRAY_SIZE(ak4535_reg),
 	.reg_word_size = sizeof(u8),
 	.reg_word_size = sizeof(u8),
 	.reg_cache_default = ak4535_reg,
 	.reg_cache_default = ak4535_reg,
+	.dapm_widgets = ak4535_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets),
+	.dapm_routes = ak4535_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(ak4535_audio_map),
 };
 };
 
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)

+ 664 - 0
sound/soc/codecs/ak4641.c

@@ -0,0 +1,664 @@
+/*
+ * ak4641.c  --  AK4641 ALSA Soc Audio driver
+ *
+ * Copyright (C) 2008 Harald Welte <laforge@gnufiish.org>
+ * Copyright (C) 2011 Dmitry Artamonow <mad_soft@inbox.ru>
+ *
+ * Based on ak4535.c by Richard Purdie
+ *
+ * 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/init.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/ak4641.h>
+
+#include "ak4641.h"
+
+/* codec private data */
+struct ak4641_priv {
+	struct snd_soc_codec *codec;
+	unsigned int sysclk;
+	int deemph;
+	int playback_fs;
+};
+
+/*
+ * ak4641 register cache
+ */
+static const u8 ak4641_reg[AK4641_CACHEREGNUM] = {
+	0x00, 0x80, 0x00, 0x80,
+	0x02, 0x00, 0x11, 0x05,
+	0x00, 0x00, 0x36, 0x10,
+	0x00, 0x00, 0x57, 0x00,
+	0x88, 0x88, 0x08, 0x08
+};
+
+static const int deemph_settings[] = {44100, 0, 48000, 32000};
+
+static int ak4641_set_deemph(struct snd_soc_codec *codec)
+{
+	struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
+	int i, best = 0;
+
+	for (i = 0 ; i < ARRAY_SIZE(deemph_settings); i++) {
+		/* if deemphasis is on, select the nearest available rate */
+		if (ak4641->deemph && deemph_settings[i] != 0 &&
+		    abs(deemph_settings[i] - ak4641->playback_fs) <
+		    abs(deemph_settings[best] - ak4641->playback_fs))
+			best = i;
+
+		if (!ak4641->deemph && deemph_settings[i] == 0)
+			best = i;
+	}
+
+	dev_dbg(codec->dev, "Set deemphasis %d\n", best);
+
+	return snd_soc_update_bits(codec, AK4641_DAC, 0x3, best);
+}
+
+static int ak4641_put_deemph(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
+	int deemph = ucontrol->value.enumerated.item[0];
+
+	if (deemph > 1)
+		return -EINVAL;
+
+	ak4641->deemph = deemph;
+
+	return ak4641_set_deemph(codec);
+}
+
+static int ak4641_get_deemph(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.enumerated.item[0] = ak4641->deemph;
+	return 0;
+};
+
+static const char *ak4641_mono_out[] = {"(L + R)/2", "Hi-Z"};
+static const char *ak4641_hp_out[] = {"Stereo", "Mono"};
+static const char *ak4641_mic_select[] = {"Internal", "External"};
+static const char *ak4641_mic_or_dac[] = {"Microphone", "Voice DAC"};
+
+
+static const DECLARE_TLV_DB_SCALE(mono_gain_tlv, -1700, 2300, 0);
+static const DECLARE_TLV_DB_SCALE(mic_boost_tlv, 0, 2000, 0);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1050, 150, 0);
+static const DECLARE_TLV_DB_SCALE(master_tlv, -12750, 50, 0);
+static const DECLARE_TLV_DB_SCALE(mic_stereo_sidetone_tlv, -2700, 300, 0);
+static const DECLARE_TLV_DB_SCALE(mic_mono_sidetone_tlv, -400, 400, 0);
+static const DECLARE_TLV_DB_SCALE(capture_tlv, -800, 50, 0);
+static const DECLARE_TLV_DB_SCALE(alc_tlv, -800, 50, 0);
+static const DECLARE_TLV_DB_SCALE(aux_in_tlv, -2100, 300, 0);
+
+
+static const struct soc_enum ak4641_mono_out_enum =
+	SOC_ENUM_SINGLE(AK4641_SIG1, 6, 2, ak4641_mono_out);
+static const struct soc_enum ak4641_hp_out_enum =
+	SOC_ENUM_SINGLE(AK4641_MODE2, 2, 2, ak4641_hp_out);
+static const struct soc_enum ak4641_mic_select_enum =
+	SOC_ENUM_SINGLE(AK4641_MIC, 1, 2, ak4641_mic_select);
+static const struct soc_enum ak4641_mic_or_dac_enum =
+	SOC_ENUM_SINGLE(AK4641_BTIF, 4, 2, ak4641_mic_or_dac);
+
+static const struct snd_kcontrol_new ak4641_snd_controls[] = {
+	SOC_ENUM("Mono 1 Output", ak4641_mono_out_enum),
+	SOC_SINGLE_TLV("Mono 1 Gain Volume", AK4641_SIG1, 7, 1, 1,
+							mono_gain_tlv),
+	SOC_ENUM("Headphone Output", ak4641_hp_out_enum),
+	SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0,
+					ak4641_get_deemph, ak4641_put_deemph),
+
+	SOC_SINGLE_TLV("Mic Boost Volume", AK4641_MIC, 0, 1, 0, mic_boost_tlv),
+
+	SOC_SINGLE("ALC Operation Time", AK4641_TIMER, 0, 3, 0),
+	SOC_SINGLE("ALC Recovery Time", AK4641_TIMER, 2, 3, 0),
+	SOC_SINGLE("ALC ZC Time", AK4641_TIMER, 4, 3, 0),
+
+	SOC_SINGLE("ALC 1 Switch", AK4641_ALC1, 5, 1, 0),
+
+	SOC_SINGLE_TLV("ALC Volume", AK4641_ALC2, 0, 71, 0, alc_tlv),
+	SOC_SINGLE("Left Out Enable Switch", AK4641_SIG2, 1, 1, 0),
+	SOC_SINGLE("Right Out Enable Switch", AK4641_SIG2, 0, 1, 0),
+
+	SOC_SINGLE_TLV("Capture Volume", AK4641_PGA, 0, 71, 0, capture_tlv),
+
+	SOC_DOUBLE_R_TLV("Master Playback Volume", AK4641_LATT,
+				AK4641_RATT, 0, 255, 1, master_tlv),
+
+	SOC_SINGLE_TLV("AUX In Volume", AK4641_VOL, 0, 15, 0, aux_in_tlv),
+
+	SOC_SINGLE("Equalizer Switch", AK4641_DAC, 2, 1, 0),
+	SOC_SINGLE_TLV("EQ1 100 Hz Volume", AK4641_EQLO, 0, 15, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ2 250 Hz Volume", AK4641_EQLO, 4, 15, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ3 1 kHz Volume", AK4641_EQMID, 0, 15, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ4 3.5 kHz Volume", AK4641_EQMID, 4, 15, 1, eq_tlv),
+	SOC_SINGLE_TLV("EQ5 10 kHz Volume", AK4641_EQHI, 0, 15, 1, eq_tlv),
+};
+
+/* Mono 1 Mixer */
+static const struct snd_kcontrol_new ak4641_mono1_mixer_controls[] = {
+	SOC_DAPM_SINGLE_TLV("Mic Mono Sidetone Volume", AK4641_VOL, 7, 1, 0,
+						mic_mono_sidetone_tlv),
+	SOC_DAPM_SINGLE("Mic Mono Sidetone Switch", AK4641_SIG1, 4, 1, 0),
+	SOC_DAPM_SINGLE("Mono Playback Switch", AK4641_SIG1, 5, 1, 0),
+};
+
+/* Stereo Mixer */
+static const struct snd_kcontrol_new ak4641_stereo_mixer_controls[] = {
+	SOC_DAPM_SINGLE_TLV("Mic Sidetone Volume", AK4641_VOL, 4, 7, 0,
+						mic_stereo_sidetone_tlv),
+	SOC_DAPM_SINGLE("Mic Sidetone Switch", AK4641_SIG2, 4, 1, 0),
+	SOC_DAPM_SINGLE("Playback Switch", AK4641_SIG2, 7, 1, 0),
+	SOC_DAPM_SINGLE("Aux Bypass Switch", AK4641_SIG2, 5, 1, 0),
+};
+
+/* Input Mixer */
+static const struct snd_kcontrol_new ak4641_input_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Mic Capture Switch", AK4641_MIC, 2, 1, 0),
+	SOC_DAPM_SINGLE("Aux Capture Switch", AK4641_MIC, 5, 1, 0),
+};
+
+/* Mic mux */
+static const struct snd_kcontrol_new ak4641_mic_mux_control =
+	SOC_DAPM_ENUM("Mic Select", ak4641_mic_select_enum);
+
+/* Input mux */
+static const struct snd_kcontrol_new ak4641_input_mux_control =
+	SOC_DAPM_ENUM("Input Select", ak4641_mic_or_dac_enum);
+
+/* mono 2 switch */
+static const struct snd_kcontrol_new ak4641_mono2_control =
+	SOC_DAPM_SINGLE("Switch", AK4641_SIG1, 0, 1, 0);
+
+/* ak4641 dapm widgets */
+static const struct snd_soc_dapm_widget ak4641_dapm_widgets[] = {
+	SND_SOC_DAPM_MIXER("Stereo Mixer", SND_SOC_NOPM, 0, 0,
+		&ak4641_stereo_mixer_controls[0],
+		ARRAY_SIZE(ak4641_stereo_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Mono1 Mixer", SND_SOC_NOPM, 0, 0,
+		&ak4641_mono1_mixer_controls[0],
+		ARRAY_SIZE(ak4641_mono1_mixer_controls)),
+	SND_SOC_DAPM_MIXER("Input Mixer", SND_SOC_NOPM, 0, 0,
+		&ak4641_input_mixer_controls[0],
+		ARRAY_SIZE(ak4641_input_mixer_controls)),
+	SND_SOC_DAPM_MUX("Mic Mux", SND_SOC_NOPM, 0, 0,
+		&ak4641_mic_mux_control),
+	SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
+		&ak4641_input_mux_control),
+	SND_SOC_DAPM_SWITCH("Mono 2 Enable", SND_SOC_NOPM, 0, 0,
+		&ak4641_mono2_control),
+
+	SND_SOC_DAPM_OUTPUT("LOUT"),
+	SND_SOC_DAPM_OUTPUT("ROUT"),
+	SND_SOC_DAPM_OUTPUT("MOUT1"),
+	SND_SOC_DAPM_OUTPUT("MOUT2"),
+	SND_SOC_DAPM_OUTPUT("MICOUT"),
+
+	SND_SOC_DAPM_ADC("ADC", "HiFi Capture", AK4641_PM1, 0, 0),
+	SND_SOC_DAPM_PGA("Mic", AK4641_PM1, 1, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("AUX In", AK4641_PM1, 2, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mono Out", AK4641_PM1, 3, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Line Out", AK4641_PM1, 4, 0, NULL, 0),
+
+	SND_SOC_DAPM_DAC("DAC", "HiFi Playback", AK4641_PM2, 0, 0),
+	SND_SOC_DAPM_PGA("Mono Out 2", AK4641_PM2, 3, 0, NULL, 0),
+
+	SND_SOC_DAPM_ADC("Voice ADC", "Voice Capture", AK4641_BTIF, 0, 0),
+	SND_SOC_DAPM_ADC("Voice DAC", "Voice Playback", AK4641_BTIF, 1, 0),
+
+	SND_SOC_DAPM_MICBIAS("Mic Int Bias", AK4641_MIC, 3, 0),
+	SND_SOC_DAPM_MICBIAS("Mic Ext Bias", AK4641_MIC, 4, 0),
+
+	SND_SOC_DAPM_INPUT("MICIN"),
+	SND_SOC_DAPM_INPUT("MICEXT"),
+	SND_SOC_DAPM_INPUT("AUX"),
+	SND_SOC_DAPM_INPUT("AIN"),
+};
+
+static const struct snd_soc_dapm_route ak4641_audio_map[] = {
+	/* Stereo Mixer */
+	{"Stereo Mixer", "Playback Switch", "DAC"},
+	{"Stereo Mixer", "Mic Sidetone Switch", "Input Mux"},
+	{"Stereo Mixer", "Aux Bypass Switch", "AUX In"},
+
+	/* Mono 1 Mixer */
+	{"Mono1 Mixer", "Mic Mono Sidetone Switch", "Input Mux"},
+	{"Mono1 Mixer", "Mono Playback Switch", "DAC"},
+
+	/* Mic */
+	{"Mic", NULL, "AIN"},
+	{"Mic Mux", "Internal", "Mic Int Bias"},
+	{"Mic Mux", "External", "Mic Ext Bias"},
+	{"Mic Int Bias", NULL, "MICIN"},
+	{"Mic Ext Bias", NULL, "MICEXT"},
+	{"MICOUT", NULL, "Mic Mux"},
+
+	/* Input Mux */
+	{"Input Mux", "Microphone", "Mic"},
+	{"Input Mux", "Voice DAC", "Voice DAC"},
+
+	/* Line Out */
+	{"LOUT", NULL, "Line Out"},
+	{"ROUT", NULL, "Line Out"},
+	{"Line Out", NULL, "Stereo Mixer"},
+
+	/* Mono 1 Out */
+	{"MOUT1", NULL, "Mono Out"},
+	{"Mono Out", NULL, "Mono1 Mixer"},
+
+	/* Mono 2 Out */
+	{"MOUT2", NULL, "Mono 2 Enable"},
+	{"Mono 2 Enable", "Switch", "Mono Out 2"},
+	{"Mono Out 2", NULL, "Stereo Mixer"},
+
+	{"Voice ADC", NULL, "Mono 2 Enable"},
+
+	/* Aux In */
+	{"AUX In", NULL, "AUX"},
+
+	/* ADC */
+	{"ADC", NULL, "Input Mixer"},
+	{"Input Mixer", "Mic Capture Switch", "Mic"},
+	{"Input Mixer", "Aux Capture Switch", "AUX In"},
+};
+
+static int ak4641_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+	int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
+
+	ak4641->sysclk = freq;
+	return 0;
+}
+
+static int ak4641_i2s_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->codec;
+	struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
+	int rate = params_rate(params), fs = 256;
+	u8 mode2;
+
+	if (rate)
+		fs = ak4641->sysclk / rate;
+	else
+		return -EINVAL;
+
+	/* set fs */
+	switch (fs) {
+	case 1024:
+		mode2 = (0x2 << 5);
+		break;
+	case 512:
+		mode2 = (0x1 << 5);
+		break;
+	case 256:
+		mode2 = (0x0 << 5);
+		break;
+	default:
+		dev_err(codec->dev, "Error: unsupported fs=%d\n", fs);
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, AK4641_MODE2, (0x3 << 5), mode2);
+
+	/* Update de-emphasis filter for the new rate */
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		ak4641->playback_fs = rate;
+		ak4641_set_deemph(codec);
+	};
+
+	return 0;
+}
+
+static int ak4641_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
+				  unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u8 btif;
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		btif = (0x3 << 5);
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		btif = (0x2 << 5);
+		break;
+	case SND_SOC_DAIFMT_DSP_A:	/* MSB after FRM */
+		btif = (0x0 << 5);
+		break;
+	case SND_SOC_DAIFMT_DSP_B:	/* MSB during FRM */
+		btif = (0x1 << 5);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return snd_soc_update_bits(codec, AK4641_BTIF, (0x3 << 5), btif);
+}
+
+static int ak4641_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
+		unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u8 mode1 = 0;
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		mode1 = 0x02;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		mode1 = 0x01;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return snd_soc_write(codec, AK4641_MODE1, mode1);
+}
+
+static int ak4641_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+
+	return snd_soc_update_bits(codec, AK4641_DAC, 0x20, mute ? 0x20 : 0);
+}
+
+static int ak4641_set_bias_level(struct snd_soc_codec *codec,
+	enum snd_soc_bias_level level)
+{
+	struct ak4641_platform_data *pdata = codec->dev->platform_data;
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* unmute */
+		snd_soc_update_bits(codec, AK4641_DAC, 0x20, 0);
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		/* mute */
+		snd_soc_update_bits(codec, AK4641_DAC, 0x20, 0x20);
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			if (pdata && gpio_is_valid(pdata->gpio_power))
+				gpio_set_value(pdata->gpio_power, 1);
+			mdelay(1);
+			if (pdata && gpio_is_valid(pdata->gpio_npdn))
+				gpio_set_value(pdata->gpio_npdn, 1);
+			mdelay(1);
+
+			ret = snd_soc_cache_sync(codec);
+			if (ret) {
+				dev_err(codec->dev,
+					"Failed to sync cache: %d\n", ret);
+				return ret;
+			}
+		}
+		snd_soc_update_bits(codec, AK4641_PM1, 0x80, 0x80);
+		snd_soc_update_bits(codec, AK4641_PM2, 0x80, 0);
+		break;
+	case SND_SOC_BIAS_OFF:
+		snd_soc_update_bits(codec, AK4641_PM1, 0x80, 0);
+		if (pdata && gpio_is_valid(pdata->gpio_npdn))
+			gpio_set_value(pdata->gpio_npdn, 0);
+		if (pdata && gpio_is_valid(pdata->gpio_power))
+			gpio_set_value(pdata->gpio_power, 0);
+		codec->cache_sync = 1;
+		break;
+	}
+	codec->dapm.bias_level = level;
+	return 0;
+}
+
+#define AK4641_RATES	(SNDRV_PCM_RATE_8000_48000)
+#define AK4641_RATES_BT (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+			 SNDRV_PCM_RATE_16000)
+#define AK4641_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE)
+
+static struct snd_soc_dai_ops ak4641_i2s_dai_ops = {
+	.hw_params    = ak4641_i2s_hw_params,
+	.set_fmt      = ak4641_i2s_set_dai_fmt,
+	.digital_mute = ak4641_mute,
+	.set_sysclk   = ak4641_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_ops ak4641_pcm_dai_ops = {
+	.hw_params    = NULL, /* rates are controlled by BT chip */
+	.set_fmt      = ak4641_pcm_set_dai_fmt,
+	.digital_mute = ak4641_mute,
+	.set_sysclk   = ak4641_set_dai_sysclk,
+};
+
+struct snd_soc_dai_driver ak4641_dai[] = {
+{
+	.name = "ak4641-hifi",
+	.id = 1,
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = AK4641_RATES,
+		.formats = AK4641_FORMATS,
+	},
+	.capture = {
+		.stream_name = "HiFi Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = AK4641_RATES,
+		.formats = AK4641_FORMATS,
+	},
+	.ops = &ak4641_i2s_dai_ops,
+	.symmetric_rates = 1,
+},
+{
+	.name = "ak4641-voice",
+	.id = 1,
+	.playback = {
+		.stream_name = "Voice Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = AK4641_RATES_BT,
+		.formats = AK4641_FORMATS,
+	},
+	.capture = {
+		.stream_name = "Voice Capture",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = AK4641_RATES_BT,
+		.formats = AK4641_FORMATS,
+	},
+	.ops = &ak4641_pcm_dai_ops,
+	.symmetric_rates = 1,
+},
+};
+
+static int ak4641_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+	ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int ak4641_resume(struct snd_soc_codec *codec)
+{
+	ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	return 0;
+}
+
+static int ak4641_probe(struct snd_soc_codec *codec)
+{
+	struct ak4641_platform_data *pdata = codec->dev->platform_data;
+	int ret;
+
+
+	if (pdata) {
+		if (gpio_is_valid(pdata->gpio_power)) {
+			ret = gpio_request_one(pdata->gpio_power,
+					GPIOF_OUT_INIT_LOW, "ak4641 power");
+			if (ret)
+				goto err_out;
+		}
+		if (gpio_is_valid(pdata->gpio_npdn)) {
+			ret = gpio_request_one(pdata->gpio_npdn,
+					GPIOF_OUT_INIT_LOW, "ak4641 npdn");
+			if (ret)
+				goto err_gpio;
+
+			udelay(1); /* > 150 ns */
+			gpio_set_value(pdata->gpio_npdn, 1);
+		}
+	}
+
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		goto err_register;
+	}
+
+	/* power on device */
+	ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	return 0;
+
+err_register:
+	if (pdata) {
+		if (gpio_is_valid(pdata->gpio_power))
+			gpio_set_value(pdata->gpio_power, 0);
+		if (gpio_is_valid(pdata->gpio_npdn))
+			gpio_free(pdata->gpio_npdn);
+	}
+err_gpio:
+	if (pdata && gpio_is_valid(pdata->gpio_power))
+		gpio_free(pdata->gpio_power);
+err_out:
+	return ret;
+}
+
+static int ak4641_remove(struct snd_soc_codec *codec)
+{
+	struct ak4641_platform_data *pdata = codec->dev->platform_data;
+
+	ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	if (pdata) {
+		if (gpio_is_valid(pdata->gpio_power)) {
+			gpio_set_value(pdata->gpio_power, 0);
+			gpio_free(pdata->gpio_power);
+		}
+		if (gpio_is_valid(pdata->gpio_npdn))
+			gpio_free(pdata->gpio_npdn);
+	}
+	return 0;
+}
+
+
+static struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
+	.probe			= ak4641_probe,
+	.remove			= ak4641_remove,
+	.suspend		= ak4641_suspend,
+	.resume			= ak4641_resume,
+	.controls		= ak4641_snd_controls,
+	.num_controls		= ARRAY_SIZE(ak4641_snd_controls),
+	.dapm_widgets		= ak4641_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(ak4641_dapm_widgets),
+	.dapm_routes		= ak4641_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(ak4641_audio_map),
+	.set_bias_level		= ak4641_set_bias_level,
+	.reg_cache_size		= ARRAY_SIZE(ak4641_reg),
+	.reg_word_size		= sizeof(u8),
+	.reg_cache_default	= ak4641_reg,
+	.reg_cache_step		= 1,
+};
+
+
+static int __devinit ak4641_i2c_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
+{
+	struct ak4641_priv *ak4641;
+	int ret;
+
+	ak4641 = kzalloc(sizeof(struct ak4641_priv), GFP_KERNEL);
+	if (!ak4641)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, ak4641);
+
+	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_ak4641,
+				ak4641_dai, ARRAY_SIZE(ak4641_dai));
+	if (ret < 0)
+		kfree(ak4641);
+
+	return ret;
+}
+
+static int __devexit ak4641_i2c_remove(struct i2c_client *i2c)
+{
+	snd_soc_unregister_codec(&i2c->dev);
+	kfree(i2c_get_clientdata(i2c));
+	return 0;
+}
+
+static const struct i2c_device_id ak4641_i2c_id[] = {
+	{ "ak4641", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ak4641_i2c_id);
+
+static struct i2c_driver ak4641_i2c_driver = {
+	.driver = {
+		.name = "ak4641",
+		.owner = THIS_MODULE,
+	},
+	.probe =    ak4641_i2c_probe,
+	.remove =   __devexit_p(ak4641_i2c_remove),
+	.id_table = ak4641_i2c_id,
+};
+
+static int __init ak4641_modinit(void)
+{
+	int ret;
+
+	ret = i2c_add_driver(&ak4641_i2c_driver);
+	if (ret != 0)
+		pr_err("Failed to register AK4641 I2C driver: %d\n", ret);
+
+	return ret;
+}
+module_init(ak4641_modinit);
+
+static void __exit ak4641_exit(void)
+{
+	i2c_del_driver(&ak4641_i2c_driver);
+}
+module_exit(ak4641_exit);
+
+MODULE_DESCRIPTION("SoC AK4641 driver");
+MODULE_AUTHOR("Harald Welte <laforge@gnufiish.org>");
+MODULE_LICENSE("GPL");

+ 47 - 0
sound/soc/codecs/ak4641.h

@@ -0,0 +1,47 @@
+/*
+ * ak4641.h  --  AK4641 SoC Audio driver
+ *
+ * Copyright 2008 Harald Welte <laforge@gnufiish.org>
+ *
+ * Based on ak4535.h
+ *
+ * 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 _AK4641_H
+#define _AK4641_H
+
+/* AK4641 register space */
+
+#define AK4641_PM1		0x00
+#define AK4641_PM2		0x01
+#define AK4641_SIG1		0x02
+#define AK4641_SIG2		0x03
+#define AK4641_MODE1		0x04
+#define AK4641_MODE2		0x05
+#define AK4641_DAC		0x06
+#define AK4641_MIC		0x07
+#define AK4641_TIMER		0x08
+#define AK4641_ALC1		0x09
+#define AK4641_ALC2		0x0a
+#define AK4641_PGA		0x0b
+#define AK4641_LATT		0x0c
+#define AK4641_RATT		0x0d
+#define AK4641_VOL		0x0e
+#define AK4641_STATUS		0x0f
+#define AK4641_EQLO		0x10
+#define AK4641_EQMID		0x11
+#define AK4641_EQHI		0x12
+#define AK4641_BTIF		0x13
+
+#define AK4641_CACHEREGNUM	0x14
+
+
+
+#define AK4641_DAI_HIFI		0
+#define AK4641_DAI_VOICE	1
+
+
+#endif

+ 5 - 13
sound/soc/codecs/ak4671.c

@@ -352,7 +352,7 @@ static const struct snd_soc_dapm_widget ak4671_dapm_widgets[] = {
 	SND_SOC_DAPM_SUPPLY("PMPLL", AK4671_PLL_MODE_SELECT1, 0, 0, NULL, 0),
 	SND_SOC_DAPM_SUPPLY("PMPLL", AK4671_PLL_MODE_SELECT1, 0, 0, NULL, 0),
 };
 };
 
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route ak4671_intercon[] = {
 	{"DAC Left", "NULL", "PMPLL"},
 	{"DAC Left", "NULL", "PMPLL"},
 	{"DAC Right", "NULL", "PMPLL"},
 	{"DAC Right", "NULL", "PMPLL"},
 	{"ADC Left", "NULL", "PMPLL"},
 	{"ADC Left", "NULL", "PMPLL"},
@@ -433,17 +433,6 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"ROUT3 Mixer", "RINS4", "RIN4 Mixing Circuit"},
 	{"ROUT3 Mixer", "RINS4", "RIN4 Mixing Circuit"},
 };
 };
 
 
-static int ak4671_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, ak4671_dapm_widgets,
-				  ARRAY_SIZE(ak4671_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-	return 0;
-}
-
 static int ak4671_hw_params(struct snd_pcm_substream *substream,
 static int ak4671_hw_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params,
 		struct snd_pcm_hw_params *params,
 		struct snd_soc_dai *dai)
 		struct snd_soc_dai *dai)
@@ -650,7 +639,6 @@ static int ak4671_probe(struct snd_soc_codec *codec)
 
 
 	snd_soc_add_controls(codec, ak4671_snd_controls,
 	snd_soc_add_controls(codec, ak4671_snd_controls,
 			     ARRAY_SIZE(ak4671_snd_controls));
 			     ARRAY_SIZE(ak4671_snd_controls));
-	ak4671_add_widgets(codec);
 
 
 	ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
 
@@ -670,6 +658,10 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
 	.reg_cache_size = AK4671_CACHEREGNUM,
 	.reg_cache_size = AK4671_CACHEREGNUM,
 	.reg_word_size = sizeof(u8),
 	.reg_word_size = sizeof(u8),
 	.reg_cache_default = ak4671_reg,
 	.reg_cache_default = ak4671_reg,
+	.dapm_widgets = ak4671_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(ak4671_dapm_widgets),
+	.dapm_routes = ak4671_intercon,
+	.num_dapm_routes = ARRAY_SIZE(ak4671_intercon),
 };
 };
 
 
 static int __devinit ak4671_i2c_probe(struct i2c_client *client,
 static int __devinit ak4671_i2c_probe(struct i2c_client *client,

+ 4 - 14
sound/soc/codecs/cx20442.c

@@ -86,18 +86,6 @@ static const struct snd_soc_dapm_route cx20442_audio_map[] = {
 	{"ADC", NULL, "Input Mixer"},
 	{"ADC", NULL, "Input Mixer"},
 };
 };
 
 
-static int cx20442_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, cx20442_dapm_widgets,
-				  ARRAY_SIZE(cx20442_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, cx20442_audio_map,
-				ARRAY_SIZE(cx20442_audio_map));
-
-	return 0;
-}
-
 static unsigned int cx20442_read_reg_cache(struct snd_soc_codec *codec,
 static unsigned int cx20442_read_reg_cache(struct snd_soc_codec *codec,
 							unsigned int reg)
 							unsigned int reg)
 {
 {
@@ -344,8 +332,6 @@ static int cx20442_codec_probe(struct snd_soc_codec *codec)
 		return -ENOMEM;
 		return -ENOMEM;
 	snd_soc_codec_set_drvdata(codec, cx20442);
 	snd_soc_codec_set_drvdata(codec, cx20442);
 
 
-	cx20442_add_widgets(codec);
-
 	cx20442->control_data = NULL;
 	cx20442->control_data = NULL;
 	codec->hw_write = NULL;
 	codec->hw_write = NULL;
 	codec->card->pop_time = 0;
 	codec->card->pop_time = 0;
@@ -377,6 +363,10 @@ static struct snd_soc_codec_driver cx20442_codec_dev = {
 	.reg_word_size = sizeof(u8),
 	.reg_word_size = sizeof(u8),
 	.read = cx20442_read_reg_cache,
 	.read = cx20442_read_reg_cache,
 	.write = cx20442_write,
 	.write = cx20442_write,
+	.dapm_widgets = cx20442_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(cx20442_dapm_widgets),
+	.dapm_routes = cx20442_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(cx20442_audio_map),
 };
 };
 
 
 static int cx20442_platform_probe(struct platform_device *pdev)
 static int cx20442_platform_probe(struct platform_device *pdev)

+ 25 - 1
sound/soc/codecs/dmic.c

@@ -39,7 +39,31 @@ static struct snd_soc_dai_driver dmic_dai = {
 	},
 	},
 };
 };
 
 
-static struct snd_soc_codec_driver soc_dmic = {};
+static const struct snd_soc_dapm_widget dmic_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_OUT("DMIC AIF", "Capture", 0,
+			     SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_INPUT("DMic"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+	{"DMIC AIF", NULL, "DMic"},
+};
+
+static int dmic_probe(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+
+	snd_soc_dapm_new_controls(dapm, dmic_dapm_widgets,
+				  ARRAY_SIZE(dmic_dapm_widgets));
+        snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
+	snd_soc_dapm_new_widgets(dapm);
+
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_dmic = {
+	.probe	= dmic_probe,
+};
 
 
 static int __devinit dmic_dev_probe(struct platform_device *pdev)
 static int __devinit dmic_dev_probe(struct platform_device *pdev)
 {
 {

+ 7 - 11
sound/soc/codecs/jz4740.c

@@ -294,20 +294,9 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
 
 
 static int jz4740_codec_dev_probe(struct snd_soc_codec *codec)
 static int jz4740_codec_dev_probe(struct snd_soc_codec *codec)
 {
 {
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
 	snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
 	snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
 			JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
 			JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
 
 
-	snd_soc_add_controls(codec, jz4740_codec_controls,
-		ARRAY_SIZE(jz4740_codec_controls));
-
-	snd_soc_dapm_new_controls(dapm, jz4740_codec_dapm_widgets,
-		ARRAY_SIZE(jz4740_codec_dapm_widgets));
-
-	snd_soc_dapm_add_routes(dapm, jz4740_codec_dapm_routes,
-		ARRAY_SIZE(jz4740_codec_dapm_routes));
-
 	jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
 
 	return 0;
 	return 0;
@@ -348,6 +337,13 @@ static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = {
 	.reg_cache_default	= jz4740_codec_regs,
 	.reg_cache_default	= jz4740_codec_regs,
 	.reg_word_size = sizeof(u32),
 	.reg_word_size = sizeof(u32),
 	.reg_cache_size	= 2,
 	.reg_cache_size	= 2,
+
+	.controls = jz4740_codec_controls,
+	.num_controls = ARRAY_SIZE(jz4740_codec_controls),
+	.dapm_widgets = jz4740_codec_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(jz4740_codec_dapm_widgets),
+	.dapm_routes = jz4740_codec_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(jz4740_codec_dapm_routes),
 };
 };
 
 
 static int __devinit jz4740_codec_probe(struct platform_device *pdev)
 static int __devinit jz4740_codec_probe(struct platform_device *pdev)

+ 52 - 35
sound/soc/codecs/max98088.c

@@ -656,8 +656,6 @@ static const struct soc_enum max98088_exmode_enum =
                              ARRAY_SIZE(max98088_exmode_texts),
                              ARRAY_SIZE(max98088_exmode_texts),
                              max98088_exmode_texts,
                              max98088_exmode_texts,
                              max98088_exmode_values);
                              max98088_exmode_values);
-static const struct snd_kcontrol_new max98088_exmode_controls =
-       SOC_DAPM_VALUE_ENUM("Route", max98088_exmode_enum);
 
 
 static const char *max98088_ex_thresh[] = { /* volts PP */
 static const char *max98088_ex_thresh[] = { /* volts PP */
        "0.6", "1.2", "1.8", "2.4", "3.0", "3.6", "4.2", "4.8"};
        "0.6", "1.2", "1.8", "2.4", "3.0", "3.6", "4.2", "4.8"};
@@ -783,6 +781,7 @@ static const struct snd_kcontrol_new max98088_snd_controls[] = {
        SOC_SINGLE("EQ1 Switch", M98088_REG_49_CFG_LEVEL, 0, 1, 0),
        SOC_SINGLE("EQ1 Switch", M98088_REG_49_CFG_LEVEL, 0, 1, 0),
        SOC_SINGLE("EQ2 Switch", M98088_REG_49_CFG_LEVEL, 1, 1, 0),
        SOC_SINGLE("EQ2 Switch", M98088_REG_49_CFG_LEVEL, 1, 1, 0),
 
 
+       SOC_ENUM("EX Limiter Mode", max98088_exmode_enum),
        SOC_ENUM("EX Limiter Threshold", max98088_ex_thresh_enum),
        SOC_ENUM("EX Limiter Threshold", max98088_ex_thresh_enum),
 
 
        SOC_ENUM("DAI1 Filter Mode", max98088_filter_mode_enum),
        SOC_ENUM("DAI1 Filter Mode", max98088_filter_mode_enum),
@@ -808,10 +807,10 @@ static const struct snd_kcontrol_new max98088_snd_controls[] = {
 
 
 /* Left speaker mixer switch */
 /* Left speaker mixer switch */
 static const struct snd_kcontrol_new max98088_left_speaker_mixer_controls[] = {
 static const struct snd_kcontrol_new max98088_left_speaker_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
-       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
-       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
-       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 7, 1, 0),
        SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 5, 1, 0),
        SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 5, 1, 0),
        SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 6, 1, 0),
        SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_2B_MIX_SPK_LEFT, 6, 1, 0),
        SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 1, 1, 0),
        SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_2B_MIX_SPK_LEFT, 1, 1, 0),
@@ -836,10 +835,10 @@ static const struct snd_kcontrol_new max98088_right_speaker_mixer_controls[] = {
 
 
 /* Left headphone mixer switch */
 /* Left headphone mixer switch */
 static const struct snd_kcontrol_new max98088_left_hp_mixer_controls[] = {
 static const struct snd_kcontrol_new max98088_left_hp_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
-       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
-       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
-       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_25_MIX_HP_LEFT, 7, 1, 0),
        SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_25_MIX_HP_LEFT, 5, 1, 0),
        SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_25_MIX_HP_LEFT, 5, 1, 0),
        SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_25_MIX_HP_LEFT, 6, 1, 0),
        SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_25_MIX_HP_LEFT, 6, 1, 0),
        SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_25_MIX_HP_LEFT, 1, 1, 0),
        SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_25_MIX_HP_LEFT, 1, 1, 0),
@@ -864,10 +863,10 @@ static const struct snd_kcontrol_new max98088_right_hp_mixer_controls[] = {
 
 
 /* Left earpiece/receiver mixer switch */
 /* Left earpiece/receiver mixer switch */
 static const struct snd_kcontrol_new max98088_left_rec_mixer_controls[] = {
 static const struct snd_kcontrol_new max98088_left_rec_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
-       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
-       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
-       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC1 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
+       SOC_DAPM_SINGLE("Left DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 0, 1, 0),
+       SOC_DAPM_SINGLE("Right DAC2 Switch", M98088_REG_28_MIX_REC_LEFT, 7, 1, 0),
        SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_28_MIX_REC_LEFT, 5, 1, 0),
        SOC_DAPM_SINGLE("MIC1 Switch", M98088_REG_28_MIX_REC_LEFT, 5, 1, 0),
        SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_28_MIX_REC_LEFT, 6, 1, 0),
        SOC_DAPM_SINGLE("MIC2 Switch", M98088_REG_28_MIX_REC_LEFT, 6, 1, 0),
        SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_28_MIX_REC_LEFT, 1, 1, 0),
        SOC_DAPM_SINGLE("INA1 Switch", M98088_REG_28_MIX_REC_LEFT, 1, 1, 0),
@@ -1094,9 +1093,6 @@ static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = {
 
 
        SND_SOC_DAPM_MICBIAS("MICBIAS", M98088_REG_4C_PWR_EN_IN, 3, 0),
        SND_SOC_DAPM_MICBIAS("MICBIAS", M98088_REG_4C_PWR_EN_IN, 3, 0),
 
 
-       SND_SOC_DAPM_MUX("EX Limiter Mode", SND_SOC_NOPM, 0, 0,
-               &max98088_exmode_controls),
-
        SND_SOC_DAPM_OUTPUT("HPL"),
        SND_SOC_DAPM_OUTPUT("HPL"),
        SND_SOC_DAPM_OUTPUT("HPR"),
        SND_SOC_DAPM_OUTPUT("HPR"),
        SND_SOC_DAPM_OUTPUT("SPKL"),
        SND_SOC_DAPM_OUTPUT("SPKL"),
@@ -1112,7 +1108,7 @@ static const struct snd_soc_dapm_widget max98088_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("INB2"),
        SND_SOC_DAPM_INPUT("INB2"),
 };
 };
 
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route max98088_audio_map[] = {
        /* Left headphone output mixer */
        /* Left headphone output mixer */
        {"Left HP Mixer", "Left DAC1 Switch", "DACL1"},
        {"Left HP Mixer", "Left DAC1 Switch", "DACL1"},
        {"Left HP Mixer", "Left DAC2 Switch", "DACL2"},
        {"Left HP Mixer", "Left DAC2 Switch", "DACL2"},
@@ -1226,22 +1222,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"MIC2 Input", NULL, "MIC2"},
        {"MIC2 Input", NULL, "MIC2"},
 };
 };
 
 
-static int max98088_add_widgets(struct snd_soc_codec *codec)
-{
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_new_controls(dapm, max98088_dapm_widgets,
-                                 ARRAY_SIZE(max98088_dapm_widgets));
-
-       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-       snd_soc_add_controls(codec, max98088_snd_controls,
-                            ARRAY_SIZE(max98088_snd_controls));
-
-       snd_soc_dapm_new_widgets(dapm);
-       return 0;
-}
-
 /* codec mclk clock divider coefficients */
 /* codec mclk clock divider coefficients */
 static const struct {
 static const struct {
        u32 rate;
        u32 rate;
@@ -1586,6 +1566,36 @@ static int max98088_dai2_set_fmt(struct snd_soc_dai *codec_dai,
        return 0;
        return 0;
 }
 }
 
 
+static int max98088_dai1_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int reg;
+
+       if (mute)
+               reg = M98088_DAI_MUTE;
+       else
+               reg = 0;
+
+       snd_soc_update_bits(codec, M98088_REG_2F_LVL_DAI1_PLAY,
+                           M98088_DAI_MUTE_MASK, reg);
+       return 0;
+}
+
+static int max98088_dai2_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int reg;
+
+       if (mute)
+               reg = M98088_DAI_MUTE;
+       else
+               reg = 0;
+
+       snd_soc_update_bits(codec, M98088_REG_31_LVL_DAI2_PLAY,
+                           M98088_DAI_MUTE_MASK, reg);
+       return 0;
+}
+
 static void max98088_sync_cache(struct snd_soc_codec *codec)
 static void max98088_sync_cache(struct snd_soc_codec *codec)
 {
 {
        u16 *reg_cache = codec->reg_cache;
        u16 *reg_cache = codec->reg_cache;
@@ -1647,12 +1657,14 @@ static struct snd_soc_dai_ops max98088_dai1_ops = {
        .set_sysclk = max98088_dai_set_sysclk,
        .set_sysclk = max98088_dai_set_sysclk,
        .set_fmt = max98088_dai1_set_fmt,
        .set_fmt = max98088_dai1_set_fmt,
        .hw_params = max98088_dai1_hw_params,
        .hw_params = max98088_dai1_hw_params,
+       .digital_mute = max98088_dai1_digital_mute,
 };
 };
 
 
 static struct snd_soc_dai_ops max98088_dai2_ops = {
 static struct snd_soc_dai_ops max98088_dai2_ops = {
        .set_sysclk = max98088_dai_set_sysclk,
        .set_sysclk = max98088_dai_set_sysclk,
        .set_fmt = max98088_dai2_set_fmt,
        .set_fmt = max98088_dai2_set_fmt,
        .hw_params = max98088_dai2_hw_params,
        .hw_params = max98088_dai2_hw_params,
+       .digital_mute = max98088_dai2_digital_mute,
 };
 };
 
 
 static struct snd_soc_dai_driver max98088_dai[] = {
 static struct snd_soc_dai_driver max98088_dai[] = {
@@ -2010,7 +2022,8 @@ static int max98088_probe(struct snd_soc_codec *codec)
 
 
        max98088_handle_pdata(codec);
        max98088_handle_pdata(codec);
 
 
-       max98088_add_widgets(codec);
+       snd_soc_add_controls(codec, max98088_snd_controls,
+                            ARRAY_SIZE(max98088_snd_controls));
 
 
 err_access:
 err_access:
        return ret;
        return ret;
@@ -2036,6 +2049,10 @@ static struct snd_soc_codec_driver soc_codec_dev_max98088 = {
        .reg_word_size = sizeof(u8),
        .reg_word_size = sizeof(u8),
        .reg_cache_default = max98088_reg,
        .reg_cache_default = max98088_reg,
        .volatile_register = max98088_volatile_register,
        .volatile_register = max98088_volatile_register,
+	.dapm_widgets = max98088_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(max98088_dapm_widgets),
+	.dapm_routes = max98088_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(max98088_audio_map),
 };
 };
 
 
 static int max98088_i2c_probe(struct i2c_client *i2c,
 static int max98088_i2c_probe(struct i2c_client *i2c,

+ 13 - 0
sound/soc/codecs/max98088.h

@@ -133,6 +133,19 @@
        #define M98088_REC_LINEMODE             (1<<7)
        #define M98088_REC_LINEMODE             (1<<7)
        #define M98088_REC_LINEMODE_MASK        (1<<7)
        #define M98088_REC_LINEMODE_MASK        (1<<7)
 
 
+/* M98088_REG_2D_MIX_SPK_CNTL */
+       #define M98088_MIX_SPKR_GAIN_MASK       (3<<2)
+       #define M98088_MIX_SPKR_GAIN_SHIFT      2
+       #define M98088_MIX_SPKL_GAIN_MASK       (3<<0)
+       #define M98088_MIX_SPKL_GAIN_SHIFT      0
+
+/* M98088_REG_2F_LVL_DAI1_PLAY, M98088_REG_31_LVL_DAI2_PLAY */
+       #define M98088_DAI_MUTE                 (1<<7)
+       #define M98088_DAI_MUTE_MASK            (1<<7)
+       #define M98088_DAI_VOICE_GAIN_MASK      (3<<4)
+       #define M98088_DAI_ATTENUATION_MASK     (0xF<<0)
+       #define M98088_DAI_ATTENUATION_SHIFT    0
+
 /* M98088_REG_35_LVL_MIC1, M98088_REG_36_LVL_MIC2 */
 /* M98088_REG_35_LVL_MIC1, M98088_REG_36_LVL_MIC2 */
        #define M98088_MICPRE_MASK              (3<<5)
        #define M98088_MICPRE_MASK              (3<<5)
        #define M98088_MICPRE_SHIFT             5
        #define M98088_MICPRE_SHIFT             5

+ 2396 - 0
sound/soc/codecs/max98095.c

@@ -0,0 +1,2396 @@
+/*
+ * max98095.c -- MAX98095 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <linux/slab.h>
+#include <asm/div64.h>
+#include <sound/max98095.h>
+#include "max98095.h"
+
+enum max98095_type {
+	MAX98095,
+};
+
+struct max98095_cdata {
+	unsigned int rate;
+	unsigned int fmt;
+	int eq_sel;
+	int bq_sel;
+};
+
+struct max98095_priv {
+	enum max98095_type devtype;
+	void *control_data;
+	struct max98095_pdata *pdata;
+	unsigned int sysclk;
+	struct max98095_cdata dai[3];
+	const char **eq_texts;
+	const char **bq_texts;
+	struct soc_enum eq_enum;
+	struct soc_enum bq_enum;
+	int eq_textcnt;
+	int bq_textcnt;
+	u8 lin_state;
+	unsigned int mic1pre;
+	unsigned int mic2pre;
+};
+
+static const u8 max98095_reg_def[M98095_REG_CNT] = {
+	0x00, /* 00 */
+	0x00, /* 01 */
+	0x00, /* 02 */
+	0x00, /* 03 */
+	0x00, /* 04 */
+	0x00, /* 05 */
+	0x00, /* 06 */
+	0x00, /* 07 */
+	0x00, /* 08 */
+	0x00, /* 09 */
+	0x00, /* 0A */
+	0x00, /* 0B */
+	0x00, /* 0C */
+	0x00, /* 0D */
+	0x00, /* 0E */
+	0x00, /* 0F */
+	0x00, /* 10 */
+	0x00, /* 11 */
+	0x00, /* 12 */
+	0x00, /* 13 */
+	0x00, /* 14 */
+	0x00, /* 15 */
+	0x00, /* 16 */
+	0x00, /* 17 */
+	0x00, /* 18 */
+	0x00, /* 19 */
+	0x00, /* 1A */
+	0x00, /* 1B */
+	0x00, /* 1C */
+	0x00, /* 1D */
+	0x00, /* 1E */
+	0x00, /* 1F */
+	0x00, /* 20 */
+	0x00, /* 21 */
+	0x00, /* 22 */
+	0x00, /* 23 */
+	0x00, /* 24 */
+	0x00, /* 25 */
+	0x00, /* 26 */
+	0x00, /* 27 */
+	0x00, /* 28 */
+	0x00, /* 29 */
+	0x00, /* 2A */
+	0x00, /* 2B */
+	0x00, /* 2C */
+	0x00, /* 2D */
+	0x00, /* 2E */
+	0x00, /* 2F */
+	0x00, /* 30 */
+	0x00, /* 31 */
+	0x00, /* 32 */
+	0x00, /* 33 */
+	0x00, /* 34 */
+	0x00, /* 35 */
+	0x00, /* 36 */
+	0x00, /* 37 */
+	0x00, /* 38 */
+	0x00, /* 39 */
+	0x00, /* 3A */
+	0x00, /* 3B */
+	0x00, /* 3C */
+	0x00, /* 3D */
+	0x00, /* 3E */
+	0x00, /* 3F */
+	0x00, /* 40 */
+	0x00, /* 41 */
+	0x00, /* 42 */
+	0x00, /* 43 */
+	0x00, /* 44 */
+	0x00, /* 45 */
+	0x00, /* 46 */
+	0x00, /* 47 */
+	0x00, /* 48 */
+	0x00, /* 49 */
+	0x00, /* 4A */
+	0x00, /* 4B */
+	0x00, /* 4C */
+	0x00, /* 4D */
+	0x00, /* 4E */
+	0x00, /* 4F */
+	0x00, /* 50 */
+	0x00, /* 51 */
+	0x00, /* 52 */
+	0x00, /* 53 */
+	0x00, /* 54 */
+	0x00, /* 55 */
+	0x00, /* 56 */
+	0x00, /* 57 */
+	0x00, /* 58 */
+	0x00, /* 59 */
+	0x00, /* 5A */
+	0x00, /* 5B */
+	0x00, /* 5C */
+	0x00, /* 5D */
+	0x00, /* 5E */
+	0x00, /* 5F */
+	0x00, /* 60 */
+	0x00, /* 61 */
+	0x00, /* 62 */
+	0x00, /* 63 */
+	0x00, /* 64 */
+	0x00, /* 65 */
+	0x00, /* 66 */
+	0x00, /* 67 */
+	0x00, /* 68 */
+	0x00, /* 69 */
+	0x00, /* 6A */
+	0x00, /* 6B */
+	0x00, /* 6C */
+	0x00, /* 6D */
+	0x00, /* 6E */
+	0x00, /* 6F */
+	0x00, /* 70 */
+	0x00, /* 71 */
+	0x00, /* 72 */
+	0x00, /* 73 */
+	0x00, /* 74 */
+	0x00, /* 75 */
+	0x00, /* 76 */
+	0x00, /* 77 */
+	0x00, /* 78 */
+	0x00, /* 79 */
+	0x00, /* 7A */
+	0x00, /* 7B */
+	0x00, /* 7C */
+	0x00, /* 7D */
+	0x00, /* 7E */
+	0x00, /* 7F */
+	0x00, /* 80 */
+	0x00, /* 81 */
+	0x00, /* 82 */
+	0x00, /* 83 */
+	0x00, /* 84 */
+	0x00, /* 85 */
+	0x00, /* 86 */
+	0x00, /* 87 */
+	0x00, /* 88 */
+	0x00, /* 89 */
+	0x00, /* 8A */
+	0x00, /* 8B */
+	0x00, /* 8C */
+	0x00, /* 8D */
+	0x00, /* 8E */
+	0x00, /* 8F */
+	0x00, /* 90 */
+	0x00, /* 91 */
+	0x30, /* 92 */
+	0xF0, /* 93 */
+	0x00, /* 94 */
+	0x00, /* 95 */
+	0x3F, /* 96 */
+	0x00, /* 97 */
+	0x00, /* 98 */
+	0x00, /* 99 */
+	0x00, /* 9A */
+	0x00, /* 9B */
+	0x00, /* 9C */
+	0x00, /* 9D */
+	0x00, /* 9E */
+	0x00, /* 9F */
+	0x00, /* A0 */
+	0x00, /* A1 */
+	0x00, /* A2 */
+	0x00, /* A3 */
+	0x00, /* A4 */
+	0x00, /* A5 */
+	0x00, /* A6 */
+	0x00, /* A7 */
+	0x00, /* A8 */
+	0x00, /* A9 */
+	0x00, /* AA */
+	0x00, /* AB */
+	0x00, /* AC */
+	0x00, /* AD */
+	0x00, /* AE */
+	0x00, /* AF */
+	0x00, /* B0 */
+	0x00, /* B1 */
+	0x00, /* B2 */
+	0x00, /* B3 */
+	0x00, /* B4 */
+	0x00, /* B5 */
+	0x00, /* B6 */
+	0x00, /* B7 */
+	0x00, /* B8 */
+	0x00, /* B9 */
+	0x00, /* BA */
+	0x00, /* BB */
+	0x00, /* BC */
+	0x00, /* BD */
+	0x00, /* BE */
+	0x00, /* BF */
+	0x00, /* C0 */
+	0x00, /* C1 */
+	0x00, /* C2 */
+	0x00, /* C3 */
+	0x00, /* C4 */
+	0x00, /* C5 */
+	0x00, /* C6 */
+	0x00, /* C7 */
+	0x00, /* C8 */
+	0x00, /* C9 */
+	0x00, /* CA */
+	0x00, /* CB */
+	0x00, /* CC */
+	0x00, /* CD */
+	0x00, /* CE */
+	0x00, /* CF */
+	0x00, /* D0 */
+	0x00, /* D1 */
+	0x00, /* D2 */
+	0x00, /* D3 */
+	0x00, /* D4 */
+	0x00, /* D5 */
+	0x00, /* D6 */
+	0x00, /* D7 */
+	0x00, /* D8 */
+	0x00, /* D9 */
+	0x00, /* DA */
+	0x00, /* DB */
+	0x00, /* DC */
+	0x00, /* DD */
+	0x00, /* DE */
+	0x00, /* DF */
+	0x00, /* E0 */
+	0x00, /* E1 */
+	0x00, /* E2 */
+	0x00, /* E3 */
+	0x00, /* E4 */
+	0x00, /* E5 */
+	0x00, /* E6 */
+	0x00, /* E7 */
+	0x00, /* E8 */
+	0x00, /* E9 */
+	0x00, /* EA */
+	0x00, /* EB */
+	0x00, /* EC */
+	0x00, /* ED */
+	0x00, /* EE */
+	0x00, /* EF */
+	0x00, /* F0 */
+	0x00, /* F1 */
+	0x00, /* F2 */
+	0x00, /* F3 */
+	0x00, /* F4 */
+	0x00, /* F5 */
+	0x00, /* F6 */
+	0x00, /* F7 */
+	0x00, /* F8 */
+	0x00, /* F9 */
+	0x00, /* FA */
+	0x00, /* FB */
+	0x00, /* FC */
+	0x00, /* FD */
+	0x00, /* FE */
+	0x00, /* FF */
+};
+
+static struct {
+	int readable;
+	int writable;
+} max98095_access[M98095_REG_CNT] = {
+	{ 0x00, 0x00 }, /* 00 */
+	{ 0xFF, 0x00 }, /* 01 */
+	{ 0xFF, 0x00 }, /* 02 */
+	{ 0xFF, 0x00 }, /* 03 */
+	{ 0xFF, 0x00 }, /* 04 */
+	{ 0xFF, 0x00 }, /* 05 */
+	{ 0xFF, 0x00 }, /* 06 */
+	{ 0xFF, 0x00 }, /* 07 */
+	{ 0xFF, 0x00 }, /* 08 */
+	{ 0xFF, 0x00 }, /* 09 */
+	{ 0xFF, 0x00 }, /* 0A */
+	{ 0xFF, 0x00 }, /* 0B */
+	{ 0xFF, 0x00 }, /* 0C */
+	{ 0xFF, 0x00 }, /* 0D */
+	{ 0xFF, 0x00 }, /* 0E */
+	{ 0xFF, 0x9F }, /* 0F */
+	{ 0xFF, 0xFF }, /* 10 */
+	{ 0xFF, 0xFF }, /* 11 */
+	{ 0xFF, 0xFF }, /* 12 */
+	{ 0xFF, 0xFF }, /* 13 */
+	{ 0xFF, 0xFF }, /* 14 */
+	{ 0xFF, 0xFF }, /* 15 */
+	{ 0xFF, 0xFF }, /* 16 */
+	{ 0xFF, 0xFF }, /* 17 */
+	{ 0xFF, 0xFF }, /* 18 */
+	{ 0xFF, 0xFF }, /* 19 */
+	{ 0xFF, 0xFF }, /* 1A */
+	{ 0xFF, 0xFF }, /* 1B */
+	{ 0xFF, 0xFF }, /* 1C */
+	{ 0xFF, 0xFF }, /* 1D */
+	{ 0xFF, 0x77 }, /* 1E */
+	{ 0xFF, 0x77 }, /* 1F */
+	{ 0xFF, 0x77 }, /* 20 */
+	{ 0xFF, 0x77 }, /* 21 */
+	{ 0xFF, 0x77 }, /* 22 */
+	{ 0xFF, 0x77 }, /* 23 */
+	{ 0xFF, 0xFF }, /* 24 */
+	{ 0xFF, 0x7F }, /* 25 */
+	{ 0xFF, 0x31 }, /* 26 */
+	{ 0xFF, 0xFF }, /* 27 */
+	{ 0xFF, 0xFF }, /* 28 */
+	{ 0xFF, 0xFF }, /* 29 */
+	{ 0xFF, 0xF7 }, /* 2A */
+	{ 0xFF, 0x2F }, /* 2B */
+	{ 0xFF, 0xEF }, /* 2C */
+	{ 0xFF, 0xFF }, /* 2D */
+	{ 0xFF, 0xFF }, /* 2E */
+	{ 0xFF, 0xFF }, /* 2F */
+	{ 0xFF, 0xFF }, /* 30 */
+	{ 0xFF, 0xFF }, /* 31 */
+	{ 0xFF, 0xFF }, /* 32 */
+	{ 0xFF, 0xFF }, /* 33 */
+	{ 0xFF, 0xF7 }, /* 34 */
+	{ 0xFF, 0x2F }, /* 35 */
+	{ 0xFF, 0xCF }, /* 36 */
+	{ 0xFF, 0xFF }, /* 37 */
+	{ 0xFF, 0xFF }, /* 38 */
+	{ 0xFF, 0xFF }, /* 39 */
+	{ 0xFF, 0xFF }, /* 3A */
+	{ 0xFF, 0xFF }, /* 3B */
+	{ 0xFF, 0xFF }, /* 3C */
+	{ 0xFF, 0xFF }, /* 3D */
+	{ 0xFF, 0xF7 }, /* 3E */
+	{ 0xFF, 0x2F }, /* 3F */
+	{ 0xFF, 0xCF }, /* 40 */
+	{ 0xFF, 0xFF }, /* 41 */
+	{ 0xFF, 0x77 }, /* 42 */
+	{ 0xFF, 0xFF }, /* 43 */
+	{ 0xFF, 0xFF }, /* 44 */
+	{ 0xFF, 0xFF }, /* 45 */
+	{ 0xFF, 0xFF }, /* 46 */
+	{ 0xFF, 0xFF }, /* 47 */
+	{ 0xFF, 0xFF }, /* 48 */
+	{ 0xFF, 0x0F }, /* 49 */
+	{ 0xFF, 0xFF }, /* 4A */
+	{ 0xFF, 0xFF }, /* 4B */
+	{ 0xFF, 0x3F }, /* 4C */
+	{ 0xFF, 0x3F }, /* 4D */
+	{ 0xFF, 0x3F }, /* 4E */
+	{ 0xFF, 0xFF }, /* 4F */
+	{ 0xFF, 0x7F }, /* 50 */
+	{ 0xFF, 0x7F }, /* 51 */
+	{ 0xFF, 0x0F }, /* 52 */
+	{ 0xFF, 0x3F }, /* 53 */
+	{ 0xFF, 0x3F }, /* 54 */
+	{ 0xFF, 0x3F }, /* 55 */
+	{ 0xFF, 0xFF }, /* 56 */
+	{ 0xFF, 0xFF }, /* 57 */
+	{ 0xFF, 0xBF }, /* 58 */
+	{ 0xFF, 0x1F }, /* 59 */
+	{ 0xFF, 0xBF }, /* 5A */
+	{ 0xFF, 0x1F }, /* 5B */
+	{ 0xFF, 0xBF }, /* 5C */
+	{ 0xFF, 0x3F }, /* 5D */
+	{ 0xFF, 0x3F }, /* 5E */
+	{ 0xFF, 0x7F }, /* 5F */
+	{ 0xFF, 0x7F }, /* 60 */
+	{ 0xFF, 0x47 }, /* 61 */
+	{ 0xFF, 0x9F }, /* 62 */
+	{ 0xFF, 0x9F }, /* 63 */
+	{ 0xFF, 0x9F }, /* 64 */
+	{ 0xFF, 0x9F }, /* 65 */
+	{ 0xFF, 0x9F }, /* 66 */
+	{ 0xFF, 0xBF }, /* 67 */
+	{ 0xFF, 0xBF }, /* 68 */
+	{ 0xFF, 0xFF }, /* 69 */
+	{ 0xFF, 0xFF }, /* 6A */
+	{ 0xFF, 0x7F }, /* 6B */
+	{ 0xFF, 0xF7 }, /* 6C */
+	{ 0xFF, 0xFF }, /* 6D */
+	{ 0xFF, 0xFF }, /* 6E */
+	{ 0xFF, 0x1F }, /* 6F */
+	{ 0xFF, 0xF7 }, /* 70 */
+	{ 0xFF, 0xFF }, /* 71 */
+	{ 0xFF, 0xFF }, /* 72 */
+	{ 0xFF, 0x1F }, /* 73 */
+	{ 0xFF, 0xF7 }, /* 74 */
+	{ 0xFF, 0xFF }, /* 75 */
+	{ 0xFF, 0xFF }, /* 76 */
+	{ 0xFF, 0x1F }, /* 77 */
+	{ 0xFF, 0xF7 }, /* 78 */
+	{ 0xFF, 0xFF }, /* 79 */
+	{ 0xFF, 0xFF }, /* 7A */
+	{ 0xFF, 0x1F }, /* 7B */
+	{ 0xFF, 0xF7 }, /* 7C */
+	{ 0xFF, 0xFF }, /* 7D */
+	{ 0xFF, 0xFF }, /* 7E */
+	{ 0xFF, 0x1F }, /* 7F */
+	{ 0xFF, 0xF7 }, /* 80 */
+	{ 0xFF, 0xFF }, /* 81 */
+	{ 0xFF, 0xFF }, /* 82 */
+	{ 0xFF, 0x1F }, /* 83 */
+	{ 0xFF, 0x7F }, /* 84 */
+	{ 0xFF, 0x0F }, /* 85 */
+	{ 0xFF, 0xD8 }, /* 86 */
+	{ 0xFF, 0xFF }, /* 87 */
+	{ 0xFF, 0xEF }, /* 88 */
+	{ 0xFF, 0xFE }, /* 89 */
+	{ 0xFF, 0xFE }, /* 8A */
+	{ 0xFF, 0xFF }, /* 8B */
+	{ 0xFF, 0xFF }, /* 8C */
+	{ 0xFF, 0x3F }, /* 8D */
+	{ 0xFF, 0xFF }, /* 8E */
+	{ 0xFF, 0x3F }, /* 8F */
+	{ 0xFF, 0x8F }, /* 90 */
+	{ 0xFF, 0xFF }, /* 91 */
+	{ 0xFF, 0x3F }, /* 92 */
+	{ 0xFF, 0xFF }, /* 93 */
+	{ 0xFF, 0xFF }, /* 94 */
+	{ 0xFF, 0x0F }, /* 95 */
+	{ 0xFF, 0x3F }, /* 96 */
+	{ 0xFF, 0x8C }, /* 97 */
+	{ 0x00, 0x00 }, /* 98 */
+	{ 0x00, 0x00 }, /* 99 */
+	{ 0x00, 0x00 }, /* 9A */
+	{ 0x00, 0x00 }, /* 9B */
+	{ 0x00, 0x00 }, /* 9C */
+	{ 0x00, 0x00 }, /* 9D */
+	{ 0x00, 0x00 }, /* 9E */
+	{ 0x00, 0x00 }, /* 9F */
+	{ 0x00, 0x00 }, /* A0 */
+	{ 0x00, 0x00 }, /* A1 */
+	{ 0x00, 0x00 }, /* A2 */
+	{ 0x00, 0x00 }, /* A3 */
+	{ 0x00, 0x00 }, /* A4 */
+	{ 0x00, 0x00 }, /* A5 */
+	{ 0x00, 0x00 }, /* A6 */
+	{ 0x00, 0x00 }, /* A7 */
+	{ 0x00, 0x00 }, /* A8 */
+	{ 0x00, 0x00 }, /* A9 */
+	{ 0x00, 0x00 }, /* AA */
+	{ 0x00, 0x00 }, /* AB */
+	{ 0x00, 0x00 }, /* AC */
+	{ 0x00, 0x00 }, /* AD */
+	{ 0x00, 0x00 }, /* AE */
+	{ 0x00, 0x00 }, /* AF */
+	{ 0x00, 0x00 }, /* B0 */
+	{ 0x00, 0x00 }, /* B1 */
+	{ 0x00, 0x00 }, /* B2 */
+	{ 0x00, 0x00 }, /* B3 */
+	{ 0x00, 0x00 }, /* B4 */
+	{ 0x00, 0x00 }, /* B5 */
+	{ 0x00, 0x00 }, /* B6 */
+	{ 0x00, 0x00 }, /* B7 */
+	{ 0x00, 0x00 }, /* B8 */
+	{ 0x00, 0x00 }, /* B9 */
+	{ 0x00, 0x00 }, /* BA */
+	{ 0x00, 0x00 }, /* BB */
+	{ 0x00, 0x00 }, /* BC */
+	{ 0x00, 0x00 }, /* BD */
+	{ 0x00, 0x00 }, /* BE */
+	{ 0x00, 0x00 }, /* BF */
+	{ 0x00, 0x00 }, /* C0 */
+	{ 0x00, 0x00 }, /* C1 */
+	{ 0x00, 0x00 }, /* C2 */
+	{ 0x00, 0x00 }, /* C3 */
+	{ 0x00, 0x00 }, /* C4 */
+	{ 0x00, 0x00 }, /* C5 */
+	{ 0x00, 0x00 }, /* C6 */
+	{ 0x00, 0x00 }, /* C7 */
+	{ 0x00, 0x00 }, /* C8 */
+	{ 0x00, 0x00 }, /* C9 */
+	{ 0x00, 0x00 }, /* CA */
+	{ 0x00, 0x00 }, /* CB */
+	{ 0x00, 0x00 }, /* CC */
+	{ 0x00, 0x00 }, /* CD */
+	{ 0x00, 0x00 }, /* CE */
+	{ 0x00, 0x00 }, /* CF */
+	{ 0x00, 0x00 }, /* D0 */
+	{ 0x00, 0x00 }, /* D1 */
+	{ 0x00, 0x00 }, /* D2 */
+	{ 0x00, 0x00 }, /* D3 */
+	{ 0x00, 0x00 }, /* D4 */
+	{ 0x00, 0x00 }, /* D5 */
+	{ 0x00, 0x00 }, /* D6 */
+	{ 0x00, 0x00 }, /* D7 */
+	{ 0x00, 0x00 }, /* D8 */
+	{ 0x00, 0x00 }, /* D9 */
+	{ 0x00, 0x00 }, /* DA */
+	{ 0x00, 0x00 }, /* DB */
+	{ 0x00, 0x00 }, /* DC */
+	{ 0x00, 0x00 }, /* DD */
+	{ 0x00, 0x00 }, /* DE */
+	{ 0x00, 0x00 }, /* DF */
+	{ 0x00, 0x00 }, /* E0 */
+	{ 0x00, 0x00 }, /* E1 */
+	{ 0x00, 0x00 }, /* E2 */
+	{ 0x00, 0x00 }, /* E3 */
+	{ 0x00, 0x00 }, /* E4 */
+	{ 0x00, 0x00 }, /* E5 */
+	{ 0x00, 0x00 }, /* E6 */
+	{ 0x00, 0x00 }, /* E7 */
+	{ 0x00, 0x00 }, /* E8 */
+	{ 0x00, 0x00 }, /* E9 */
+	{ 0x00, 0x00 }, /* EA */
+	{ 0x00, 0x00 }, /* EB */
+	{ 0x00, 0x00 }, /* EC */
+	{ 0x00, 0x00 }, /* ED */
+	{ 0x00, 0x00 }, /* EE */
+	{ 0x00, 0x00 }, /* EF */
+	{ 0x00, 0x00 }, /* F0 */
+	{ 0x00, 0x00 }, /* F1 */
+	{ 0x00, 0x00 }, /* F2 */
+	{ 0x00, 0x00 }, /* F3 */
+	{ 0x00, 0x00 }, /* F4 */
+	{ 0x00, 0x00 }, /* F5 */
+	{ 0x00, 0x00 }, /* F6 */
+	{ 0x00, 0x00 }, /* F7 */
+	{ 0x00, 0x00 }, /* F8 */
+	{ 0x00, 0x00 }, /* F9 */
+	{ 0x00, 0x00 }, /* FA */
+	{ 0x00, 0x00 }, /* FB */
+	{ 0x00, 0x00 }, /* FC */
+	{ 0x00, 0x00 }, /* FD */
+	{ 0x00, 0x00 }, /* FE */
+	{ 0xFF, 0x00 }, /* FF */
+};
+
+static int max98095_readable(struct snd_soc_codec *codec, unsigned int reg)
+{
+	if (reg >= M98095_REG_CNT)
+		return 0;
+	return max98095_access[reg].readable != 0;
+}
+
+static int max98095_volatile(struct snd_soc_codec *codec, unsigned int reg)
+{
+	if (reg > M98095_REG_MAX_CACHED)
+		return 1;
+
+	switch (reg) {
+	case M98095_000_HOST_DATA:
+	case M98095_001_HOST_INT_STS:
+	case M98095_002_HOST_RSP_STS:
+	case M98095_003_HOST_CMD_STS:
+	case M98095_004_CODEC_STS:
+	case M98095_005_DAI1_ALC_STS:
+	case M98095_006_DAI2_ALC_STS:
+	case M98095_007_JACK_AUTO_STS:
+	case M98095_008_JACK_MANUAL_STS:
+	case M98095_009_JACK_VBAT_STS:
+	case M98095_00A_ACC_ADC_STS:
+	case M98095_00B_MIC_NG_AGC_STS:
+	case M98095_00C_SPK_L_VOLT_STS:
+	case M98095_00D_SPK_R_VOLT_STS:
+	case M98095_00E_TEMP_SENSOR_STS:
+		return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Filter coefficients are in a separate register segment
+ * and they share the address space of the normal registers.
+ * The coefficient registers do not need or share the cache.
+ */
+static int max98095_hw_write(struct snd_soc_codec *codec, unsigned int reg,
+			     unsigned int value)
+{
+	u8 data[2];
+
+	data[0] = reg;
+	data[1] = value;
+	if (codec->hw_write(codec->control_data, data, 2) == 2)
+		return 0;
+	else
+		return -EIO;
+}
+
+/*
+ * Load equalizer DSP coefficient configurations registers
+ */
+static void m98095_eq_band(struct snd_soc_codec *codec, unsigned int dai,
+		    unsigned int band, u16 *coefs)
+{
+	unsigned int eq_reg;
+	unsigned int i;
+
+	BUG_ON(band > 4);
+	BUG_ON(dai > 1);
+
+	/* Load the base register address */
+	eq_reg = dai ? M98095_142_DAI2_EQ_BASE : M98095_110_DAI1_EQ_BASE;
+
+	/* Add the band address offset, note adjustment for word address */
+	eq_reg += band * (M98095_COEFS_PER_BAND << 1);
+
+	/* Step through the registers and coefs */
+	for (i = 0; i < M98095_COEFS_PER_BAND; i++) {
+		max98095_hw_write(codec, eq_reg++, M98095_BYTE1(coefs[i]));
+		max98095_hw_write(codec, eq_reg++, M98095_BYTE0(coefs[i]));
+	}
+}
+
+/*
+ * Load biquad filter coefficient configurations registers
+ */
+static void m98095_biquad_band(struct snd_soc_codec *codec, unsigned int dai,
+		    unsigned int band, u16 *coefs)
+{
+	unsigned int bq_reg;
+	unsigned int i;
+
+	BUG_ON(band > 1);
+	BUG_ON(dai > 1);
+
+	/* Load the base register address */
+	bq_reg = dai ? M98095_17E_DAI2_BQ_BASE : M98095_174_DAI1_BQ_BASE;
+
+	/* Add the band address offset, note adjustment for word address */
+	bq_reg += band * (M98095_COEFS_PER_BAND << 1);
+
+	/* Step through the registers and coefs */
+	for (i = 0; i < M98095_COEFS_PER_BAND; i++) {
+		max98095_hw_write(codec, bq_reg++, M98095_BYTE1(coefs[i]));
+		max98095_hw_write(codec, bq_reg++, M98095_BYTE0(coefs[i]));
+	}
+}
+
+static const char * const max98095_fltr_mode[] = { "Voice", "Music" };
+static const struct soc_enum max98095_dai1_filter_mode_enum[] = {
+	SOC_ENUM_SINGLE(M98095_02E_DAI1_FILTERS, 7, 2, max98095_fltr_mode),
+};
+static const struct soc_enum max98095_dai2_filter_mode_enum[] = {
+	SOC_ENUM_SINGLE(M98095_038_DAI2_FILTERS, 7, 2, max98095_fltr_mode),
+};
+
+static const char * const max98095_extmic_text[] = { "None", "MIC1", "MIC2" };
+
+static const struct soc_enum max98095_extmic_enum =
+	SOC_ENUM_SINGLE(M98095_087_CFG_MIC, 0, 3, max98095_extmic_text);
+
+static const struct snd_kcontrol_new max98095_extmic_mux =
+	SOC_DAPM_ENUM("External MIC Mux", max98095_extmic_enum);
+
+static const char * const max98095_linein_text[] = { "INA", "INB" };
+
+static const struct soc_enum max98095_linein_enum =
+	SOC_ENUM_SINGLE(M98095_086_CFG_LINE, 6, 2, max98095_linein_text);
+
+static const struct snd_kcontrol_new max98095_linein_mux =
+	SOC_DAPM_ENUM("Linein Input Mux", max98095_linein_enum);
+
+static const char * const max98095_line_mode_text[] = {
+	"Stereo", "Differential"};
+
+static const struct soc_enum max98095_linein_mode_enum =
+	SOC_ENUM_SINGLE(M98095_086_CFG_LINE, 7, 2, max98095_line_mode_text);
+
+static const struct soc_enum max98095_lineout_mode_enum =
+	SOC_ENUM_SINGLE(M98095_086_CFG_LINE, 4, 2, max98095_line_mode_text);
+
+static const char * const max98095_dai_fltr[] = {
+	"Off", "Elliptical-HPF-16k", "Butterworth-HPF-16k",
+	"Elliptical-HPF-8k", "Butterworth-HPF-8k", "Butterworth-HPF-Fs/240"};
+static const struct soc_enum max98095_dai1_dac_filter_enum[] = {
+	SOC_ENUM_SINGLE(M98095_02E_DAI1_FILTERS, 0, 6, max98095_dai_fltr),
+};
+static const struct soc_enum max98095_dai2_dac_filter_enum[] = {
+	SOC_ENUM_SINGLE(M98095_038_DAI2_FILTERS, 0, 6, max98095_dai_fltr),
+};
+static const struct soc_enum max98095_dai3_dac_filter_enum[] = {
+	SOC_ENUM_SINGLE(M98095_042_DAI3_FILTERS, 0, 6, max98095_dai_fltr),
+};
+
+static int max98095_mic1pre_set(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	unsigned int sel = ucontrol->value.integer.value[0];
+
+	max98095->mic1pre = sel;
+	snd_soc_update_bits(codec, M98095_05F_LVL_MIC1, M98095_MICPRE_MASK,
+		(1+sel)<<M98095_MICPRE_SHIFT);
+
+	return 0;
+}
+
+static int max98095_mic1pre_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = max98095->mic1pre;
+	return 0;
+}
+
+static int max98095_mic2pre_set(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	unsigned int sel = ucontrol->value.integer.value[0];
+
+	max98095->mic2pre = sel;
+	snd_soc_update_bits(codec, M98095_060_LVL_MIC2, M98095_MICPRE_MASK,
+		(1+sel)<<M98095_MICPRE_SHIFT);
+
+	return 0;
+}
+
+static int max98095_mic2pre_get(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = max98095->mic2pre;
+	return 0;
+}
+
+static const unsigned int max98095_micboost_tlv[] = {
+	TLV_DB_RANGE_HEAD(2),
+	0, 1, TLV_DB_SCALE_ITEM(0, 2000, 0),
+	2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
+};
+
+static const DECLARE_TLV_DB_SCALE(max98095_mic_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(max98095_adc_tlv, -1200, 100, 0);
+static const DECLARE_TLV_DB_SCALE(max98095_adcboost_tlv, 0, 600, 0);
+
+static const unsigned int max98095_hp_tlv[] = {
+	TLV_DB_RANGE_HEAD(5),
+	0, 6, TLV_DB_SCALE_ITEM(-6700, 400, 0),
+	7, 14, TLV_DB_SCALE_ITEM(-4000, 300, 0),
+	15, 21, TLV_DB_SCALE_ITEM(-1700, 200, 0),
+	22, 27, TLV_DB_SCALE_ITEM(-400, 100, 0),
+	28, 31, TLV_DB_SCALE_ITEM(150, 50, 0),
+};
+
+static const unsigned int max98095_spk_tlv[] = {
+	TLV_DB_RANGE_HEAD(4),
+	0, 10, TLV_DB_SCALE_ITEM(-5900, 400, 0),
+	11, 18, TLV_DB_SCALE_ITEM(-1700, 200, 0),
+	19, 27, TLV_DB_SCALE_ITEM(-200, 100, 0),
+	28, 39, TLV_DB_SCALE_ITEM(650, 50, 0),
+};
+
+static const unsigned int max98095_rcv_lout_tlv[] = {
+	TLV_DB_RANGE_HEAD(5),
+	0, 6, TLV_DB_SCALE_ITEM(-6200, 400, 0),
+	7, 14, TLV_DB_SCALE_ITEM(-3500, 300, 0),
+	15, 21, TLV_DB_SCALE_ITEM(-1200, 200, 0),
+	22, 27, TLV_DB_SCALE_ITEM(100, 100, 0),
+	28, 31, TLV_DB_SCALE_ITEM(650, 50, 0),
+};
+
+static const unsigned int max98095_lin_tlv[] = {
+	TLV_DB_RANGE_HEAD(3),
+	0, 2, TLV_DB_SCALE_ITEM(-600, 300, 0),
+	3, 3, TLV_DB_SCALE_ITEM(300, 1100, 0),
+	4, 5, TLV_DB_SCALE_ITEM(1400, 600, 0),
+};
+
+static const struct snd_kcontrol_new max98095_snd_controls[] = {
+
+	SOC_DOUBLE_R_TLV("Headphone Volume", M98095_064_LVL_HP_L,
+		M98095_065_LVL_HP_R, 0, 31, 0, max98095_hp_tlv),
+
+	SOC_DOUBLE_R_TLV("Speaker Volume", M98095_067_LVL_SPK_L,
+		M98095_068_LVL_SPK_R, 0, 39, 0, max98095_spk_tlv),
+
+	SOC_SINGLE_TLV("Receiver Volume", M98095_066_LVL_RCV,
+		0, 31, 0, max98095_rcv_lout_tlv),
+
+	SOC_DOUBLE_R_TLV("Lineout Volume", M98095_062_LVL_LINEOUT1,
+		M98095_063_LVL_LINEOUT2, 0, 31, 0, max98095_rcv_lout_tlv),
+
+	SOC_DOUBLE_R("Headphone Switch", M98095_064_LVL_HP_L,
+		M98095_065_LVL_HP_R, 7, 1, 1),
+
+	SOC_DOUBLE_R("Speaker Switch", M98095_067_LVL_SPK_L,
+		M98095_068_LVL_SPK_R, 7, 1, 1),
+
+	SOC_SINGLE("Receiver Switch", M98095_066_LVL_RCV, 7, 1, 1),
+
+	SOC_DOUBLE_R("Lineout Switch", M98095_062_LVL_LINEOUT1,
+		M98095_063_LVL_LINEOUT2, 7, 1, 1),
+
+	SOC_SINGLE_TLV("MIC1 Volume", M98095_05F_LVL_MIC1, 0, 20, 1,
+		max98095_mic_tlv),
+
+	SOC_SINGLE_TLV("MIC2 Volume", M98095_060_LVL_MIC2, 0, 20, 1,
+		max98095_mic_tlv),
+
+	SOC_SINGLE_EXT_TLV("MIC1 Boost Volume",
+			M98095_05F_LVL_MIC1, 5, 2, 0,
+			max98095_mic1pre_get, max98095_mic1pre_set,
+			max98095_micboost_tlv),
+	SOC_SINGLE_EXT_TLV("MIC2 Boost Volume",
+			M98095_060_LVL_MIC2, 5, 2, 0,
+			max98095_mic2pre_get, max98095_mic2pre_set,
+			max98095_micboost_tlv),
+
+	SOC_SINGLE_TLV("Linein Volume", M98095_061_LVL_LINEIN, 0, 5, 1,
+		max98095_lin_tlv),
+
+	SOC_SINGLE_TLV("ADCL Volume", M98095_05D_LVL_ADC_L, 0, 15, 1,
+		max98095_adc_tlv),
+	SOC_SINGLE_TLV("ADCR Volume", M98095_05E_LVL_ADC_R, 0, 15, 1,
+		max98095_adc_tlv),
+
+	SOC_SINGLE_TLV("ADCL Boost Volume", M98095_05D_LVL_ADC_L, 4, 3, 0,
+		max98095_adcboost_tlv),
+	SOC_SINGLE_TLV("ADCR Boost Volume", M98095_05E_LVL_ADC_R, 4, 3, 0,
+		max98095_adcboost_tlv),
+
+	SOC_SINGLE("EQ1 Switch", M98095_088_CFG_LEVEL, 0, 1, 0),
+	SOC_SINGLE("EQ2 Switch", M98095_088_CFG_LEVEL, 1, 1, 0),
+
+	SOC_SINGLE("Biquad1 Switch", M98095_088_CFG_LEVEL, 2, 1, 0),
+	SOC_SINGLE("Biquad2 Switch", M98095_088_CFG_LEVEL, 3, 1, 0),
+
+	SOC_ENUM("DAI1 Filter Mode", max98095_dai1_filter_mode_enum),
+	SOC_ENUM("DAI2 Filter Mode", max98095_dai2_filter_mode_enum),
+	SOC_ENUM("DAI1 DAC Filter", max98095_dai1_dac_filter_enum),
+	SOC_ENUM("DAI2 DAC Filter", max98095_dai2_dac_filter_enum),
+	SOC_ENUM("DAI3 DAC Filter", max98095_dai3_dac_filter_enum),
+
+	SOC_ENUM("Linein Mode", max98095_linein_mode_enum),
+	SOC_ENUM("Lineout Mode", max98095_lineout_mode_enum),
+};
+
+/* Left speaker mixer switch */
+static const struct snd_kcontrol_new max98095_left_speaker_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_050_MIX_SPK_LEFT, 0, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_050_MIX_SPK_LEFT, 6, 1, 0),
+	SOC_DAPM_SINGLE("Mono DAC2 Switch", M98095_050_MIX_SPK_LEFT, 3, 1, 0),
+	SOC_DAPM_SINGLE("Mono DAC3 Switch", M98095_050_MIX_SPK_LEFT, 3, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_050_MIX_SPK_LEFT, 4, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_050_MIX_SPK_LEFT, 5, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_050_MIX_SPK_LEFT, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_050_MIX_SPK_LEFT, 2, 1, 0),
+};
+
+/* Right speaker mixer switch */
+static const struct snd_kcontrol_new max98095_right_speaker_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_051_MIX_SPK_RIGHT, 6, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_051_MIX_SPK_RIGHT, 0, 1, 0),
+	SOC_DAPM_SINGLE("Mono DAC2 Switch", M98095_051_MIX_SPK_RIGHT, 3, 1, 0),
+	SOC_DAPM_SINGLE("Mono DAC3 Switch", M98095_051_MIX_SPK_RIGHT, 3, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_051_MIX_SPK_RIGHT, 5, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_051_MIX_SPK_RIGHT, 4, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_051_MIX_SPK_RIGHT, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_051_MIX_SPK_RIGHT, 2, 1, 0),
+};
+
+/* Left headphone mixer switch */
+static const struct snd_kcontrol_new max98095_left_hp_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_04C_MIX_HP_LEFT, 0, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_04C_MIX_HP_LEFT, 5, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_04C_MIX_HP_LEFT, 3, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_04C_MIX_HP_LEFT, 4, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_04C_MIX_HP_LEFT, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_04C_MIX_HP_LEFT, 2, 1, 0),
+};
+
+/* Right headphone mixer switch */
+static const struct snd_kcontrol_new max98095_right_hp_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_04D_MIX_HP_RIGHT, 5, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_04D_MIX_HP_RIGHT, 0, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_04D_MIX_HP_RIGHT, 3, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_04D_MIX_HP_RIGHT, 4, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_04D_MIX_HP_RIGHT, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_04D_MIX_HP_RIGHT, 2, 1, 0),
+};
+
+/* Receiver earpiece mixer switch */
+static const struct snd_kcontrol_new max98095_mono_rcv_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_04F_MIX_RCV, 0, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_04F_MIX_RCV, 5, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_04F_MIX_RCV, 3, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_04F_MIX_RCV, 4, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_04F_MIX_RCV, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_04F_MIX_RCV, 2, 1, 0),
+};
+
+/* Left lineout mixer switch */
+static const struct snd_kcontrol_new max98095_left_lineout_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_053_MIX_LINEOUT1, 5, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_053_MIX_LINEOUT1, 0, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_053_MIX_LINEOUT1, 3, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_053_MIX_LINEOUT1, 4, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_053_MIX_LINEOUT1, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_053_MIX_LINEOUT1, 2, 1, 0),
+};
+
+/* Right lineout mixer switch */
+static const struct snd_kcontrol_new max98095_right_lineout_mixer_controls[] = {
+	SOC_DAPM_SINGLE("Left DAC1 Switch", M98095_054_MIX_LINEOUT2, 0, 1, 0),
+	SOC_DAPM_SINGLE("Right DAC1 Switch", M98095_054_MIX_LINEOUT2, 5, 1, 0),
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_054_MIX_LINEOUT2, 3, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_054_MIX_LINEOUT2, 4, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_054_MIX_LINEOUT2, 1, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_054_MIX_LINEOUT2, 2, 1, 0),
+};
+
+/* Left ADC mixer switch */
+static const struct snd_kcontrol_new max98095_left_ADC_mixer_controls[] = {
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_04A_MIX_ADC_LEFT, 7, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_04A_MIX_ADC_LEFT, 6, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_04A_MIX_ADC_LEFT, 3, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_04A_MIX_ADC_LEFT, 2, 1, 0),
+};
+
+/* Right ADC mixer switch */
+static const struct snd_kcontrol_new max98095_right_ADC_mixer_controls[] = {
+	SOC_DAPM_SINGLE("MIC1 Switch", M98095_04B_MIX_ADC_RIGHT, 7, 1, 0),
+	SOC_DAPM_SINGLE("MIC2 Switch", M98095_04B_MIX_ADC_RIGHT, 6, 1, 0),
+	SOC_DAPM_SINGLE("IN1 Switch", M98095_04B_MIX_ADC_RIGHT, 3, 1, 0),
+	SOC_DAPM_SINGLE("IN2 Switch", M98095_04B_MIX_ADC_RIGHT, 2, 1, 0),
+};
+
+static int max98095_mic_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		if (w->reg == M98095_05F_LVL_MIC1) {
+			snd_soc_update_bits(codec, w->reg, M98095_MICPRE_MASK,
+				(1+max98095->mic1pre)<<M98095_MICPRE_SHIFT);
+		} else {
+			snd_soc_update_bits(codec, w->reg, M98095_MICPRE_MASK,
+				(1+max98095->mic2pre)<<M98095_MICPRE_SHIFT);
+		}
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, w->reg, M98095_MICPRE_MASK, 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * The line inputs are stereo inputs with the left and right
+ * channels sharing a common PGA power control signal.
+ */
+static int max98095_line_pga(struct snd_soc_dapm_widget *w,
+			     int event, u8 channel)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	u8 *state;
+
+	BUG_ON(!((channel == 1) || (channel == 2)));
+
+	state = &max98095->lin_state;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		*state |= channel;
+		snd_soc_update_bits(codec, w->reg,
+			(1 << w->shift), (1 << w->shift));
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		*state &= ~channel;
+		if (*state == 0) {
+			snd_soc_update_bits(codec, w->reg,
+				(1 << w->shift), 0);
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int max98095_pga_in1_event(struct snd_soc_dapm_widget *w,
+				   struct snd_kcontrol *k, int event)
+{
+	return max98095_line_pga(w, event, 1);
+}
+
+static int max98095_pga_in2_event(struct snd_soc_dapm_widget *w,
+				   struct snd_kcontrol *k, int event)
+{
+	return max98095_line_pga(w, event, 2);
+}
+
+/*
+ * The stereo line out mixer outputs to two stereo line outs.
+ * The 2nd pair has a separate set of enables.
+ */
+static int max98095_lineout_event(struct snd_soc_dapm_widget *w,
+			     struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		snd_soc_update_bits(codec, w->reg,
+			(1 << (w->shift+2)), (1 << (w->shift+2)));
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		snd_soc_update_bits(codec, w->reg,
+			(1 << (w->shift+2)), 0);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget max98095_dapm_widgets[] = {
+
+	SND_SOC_DAPM_ADC("ADCL", "HiFi Capture", M98095_090_PWR_EN_IN, 0, 0),
+	SND_SOC_DAPM_ADC("ADCR", "HiFi Capture", M98095_090_PWR_EN_IN, 1, 0),
+
+	SND_SOC_DAPM_DAC("DACL1", "HiFi Playback",
+		M98095_091_PWR_EN_OUT, 0, 0),
+	SND_SOC_DAPM_DAC("DACR1", "HiFi Playback",
+		M98095_091_PWR_EN_OUT, 1, 0),
+	SND_SOC_DAPM_DAC("DACM2", "Aux Playback",
+		M98095_091_PWR_EN_OUT, 2, 0),
+	SND_SOC_DAPM_DAC("DACM3", "Voice Playback",
+		M98095_091_PWR_EN_OUT, 2, 0),
+
+	SND_SOC_DAPM_PGA("HP Left Out", M98095_091_PWR_EN_OUT,
+		6, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("HP Right Out", M98095_091_PWR_EN_OUT,
+		7, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("SPK Left Out", M98095_091_PWR_EN_OUT,
+		4, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("SPK Right Out", M98095_091_PWR_EN_OUT,
+		5, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA("RCV Mono Out", M98095_091_PWR_EN_OUT,
+		3, 0, NULL, 0),
+
+	SND_SOC_DAPM_PGA_E("LINE Left Out", M98095_092_PWR_EN_OUT,
+		0, 0, NULL, 0, max98095_lineout_event, SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_PGA_E("LINE Right Out", M98095_092_PWR_EN_OUT,
+		1, 0, NULL, 0, max98095_lineout_event, SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_MUX("External MIC", SND_SOC_NOPM, 0, 0,
+		&max98095_extmic_mux),
+
+	SND_SOC_DAPM_MUX("Linein Mux", SND_SOC_NOPM, 0, 0,
+		&max98095_linein_mux),
+
+	SND_SOC_DAPM_MIXER("Left Headphone Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_left_hp_mixer_controls[0],
+		ARRAY_SIZE(max98095_left_hp_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Right Headphone Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_right_hp_mixer_controls[0],
+		ARRAY_SIZE(max98095_right_hp_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Left Speaker Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_left_speaker_mixer_controls[0],
+		ARRAY_SIZE(max98095_left_speaker_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Right Speaker Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_right_speaker_mixer_controls[0],
+		ARRAY_SIZE(max98095_right_speaker_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Receiver Mixer", SND_SOC_NOPM, 0, 0,
+	  &max98095_mono_rcv_mixer_controls[0],
+		ARRAY_SIZE(max98095_mono_rcv_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Left Lineout Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_left_lineout_mixer_controls[0],
+		ARRAY_SIZE(max98095_left_lineout_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Right Lineout Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_right_lineout_mixer_controls[0],
+		ARRAY_SIZE(max98095_right_lineout_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Left ADC Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_left_ADC_mixer_controls[0],
+		ARRAY_SIZE(max98095_left_ADC_mixer_controls)),
+
+	SND_SOC_DAPM_MIXER("Right ADC Mixer", SND_SOC_NOPM, 0, 0,
+		&max98095_right_ADC_mixer_controls[0],
+		ARRAY_SIZE(max98095_right_ADC_mixer_controls)),
+
+	SND_SOC_DAPM_PGA_E("MIC1 Input", M98095_05F_LVL_MIC1,
+		5, 0, NULL, 0, max98095_mic_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_PGA_E("MIC2 Input", M98095_060_LVL_MIC2,
+		5, 0, NULL, 0, max98095_mic_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_PGA_E("IN1 Input", M98095_090_PWR_EN_IN,
+		7, 0, NULL, 0, max98095_pga_in1_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_PGA_E("IN2 Input", M98095_090_PWR_EN_IN,
+		7, 0, NULL, 0, max98095_pga_in2_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_MICBIAS("MICBIAS1", M98095_090_PWR_EN_IN, 2, 0),
+	SND_SOC_DAPM_MICBIAS("MICBIAS2", M98095_090_PWR_EN_IN, 3, 0),
+
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+	SND_SOC_DAPM_OUTPUT("SPKL"),
+	SND_SOC_DAPM_OUTPUT("SPKR"),
+	SND_SOC_DAPM_OUTPUT("RCV"),
+	SND_SOC_DAPM_OUTPUT("OUT1"),
+	SND_SOC_DAPM_OUTPUT("OUT2"),
+	SND_SOC_DAPM_OUTPUT("OUT3"),
+	SND_SOC_DAPM_OUTPUT("OUT4"),
+
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_INPUT("INA1"),
+	SND_SOC_DAPM_INPUT("INA2"),
+	SND_SOC_DAPM_INPUT("INB1"),
+	SND_SOC_DAPM_INPUT("INB2"),
+};
+
+static const struct snd_soc_dapm_route max98095_audio_map[] = {
+	/* Left headphone output mixer */
+	{"Left Headphone Mixer", "Left DAC1 Switch", "DACL1"},
+	{"Left Headphone Mixer", "Right DAC1 Switch", "DACR1"},
+	{"Left Headphone Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Left Headphone Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Left Headphone Mixer", "IN1 Switch", "IN1 Input"},
+	{"Left Headphone Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Right headphone output mixer */
+	{"Right Headphone Mixer", "Left DAC1 Switch", "DACL1"},
+	{"Right Headphone Mixer", "Right DAC1 Switch", "DACR1"},
+	{"Right Headphone Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Right Headphone Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Right Headphone Mixer", "IN1 Switch", "IN1 Input"},
+	{"Right Headphone Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Left speaker output mixer */
+	{"Left Speaker Mixer", "Left DAC1 Switch", "DACL1"},
+	{"Left Speaker Mixer", "Right DAC1 Switch", "DACR1"},
+	{"Left Speaker Mixer", "Mono DAC2 Switch", "DACM2"},
+	{"Left Speaker Mixer", "Mono DAC3 Switch", "DACM3"},
+	{"Left Speaker Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Left Speaker Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Left Speaker Mixer", "IN1 Switch", "IN1 Input"},
+	{"Left Speaker Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Right speaker output mixer */
+	{"Right Speaker Mixer", "Left DAC1 Switch", "DACL1"},
+	{"Right Speaker Mixer", "Right DAC1 Switch", "DACR1"},
+	{"Right Speaker Mixer", "Mono DAC2 Switch", "DACM2"},
+	{"Right Speaker Mixer", "Mono DAC3 Switch", "DACM3"},
+	{"Right Speaker Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Right Speaker Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Right Speaker Mixer", "IN1 Switch", "IN1 Input"},
+	{"Right Speaker Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Earpiece/Receiver output mixer */
+	{"Receiver Mixer", "Left DAC1 Switch", "DACL1"},
+	{"Receiver Mixer", "Right DAC1 Switch", "DACR1"},
+	{"Receiver Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Receiver Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Receiver Mixer", "IN1 Switch", "IN1 Input"},
+	{"Receiver Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Left Lineout output mixer */
+	{"Left Lineout Mixer", "Left DAC1 Switch", "DACL1"},
+	{"Left Lineout Mixer", "Right DAC1 Switch", "DACR1"},
+	{"Left Lineout Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Left Lineout Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Left Lineout Mixer", "IN1 Switch", "IN1 Input"},
+	{"Left Lineout Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Right lineout output mixer */
+	{"Right Lineout Mixer", "Left DAC1 Switch", "DACL1"},
+	{"Right Lineout Mixer", "Right DAC1 Switch", "DACR1"},
+	{"Right Lineout Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Right Lineout Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Right Lineout Mixer", "IN1 Switch", "IN1 Input"},
+	{"Right Lineout Mixer", "IN2 Switch", "IN2 Input"},
+
+	{"HP Left Out", NULL, "Left Headphone Mixer"},
+	{"HP Right Out", NULL, "Right Headphone Mixer"},
+	{"SPK Left Out", NULL, "Left Speaker Mixer"},
+	{"SPK Right Out", NULL, "Right Speaker Mixer"},
+	{"RCV Mono Out", NULL, "Receiver Mixer"},
+	{"LINE Left Out", NULL, "Left Lineout Mixer"},
+	{"LINE Right Out", NULL, "Right Lineout Mixer"},
+
+	{"HPL", NULL, "HP Left Out"},
+	{"HPR", NULL, "HP Right Out"},
+	{"SPKL", NULL, "SPK Left Out"},
+	{"SPKR", NULL, "SPK Right Out"},
+	{"RCV", NULL, "RCV Mono Out"},
+	{"OUT1", NULL, "LINE Left Out"},
+	{"OUT2", NULL, "LINE Right Out"},
+	{"OUT3", NULL, "LINE Left Out"},
+	{"OUT4", NULL, "LINE Right Out"},
+
+	/* Left ADC input mixer */
+	{"Left ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Left ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Left ADC Mixer", "IN1 Switch", "IN1 Input"},
+	{"Left ADC Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Right ADC input mixer */
+	{"Right ADC Mixer", "MIC1 Switch", "MIC1 Input"},
+	{"Right ADC Mixer", "MIC2 Switch", "MIC2 Input"},
+	{"Right ADC Mixer", "IN1 Switch", "IN1 Input"},
+	{"Right ADC Mixer", "IN2 Switch", "IN2 Input"},
+
+	/* Inputs */
+	{"ADCL", NULL, "Left ADC Mixer"},
+	{"ADCR", NULL, "Right ADC Mixer"},
+
+	{"IN1 Input", NULL, "INA1"},
+	{"IN2 Input", NULL, "INA2"},
+
+	{"MIC1 Input", NULL, "MIC1"},
+	{"MIC2 Input", NULL, "MIC2"},
+};
+
+static int max98095_add_widgets(struct snd_soc_codec *codec)
+{
+	snd_soc_add_controls(codec, max98095_snd_controls,
+			     ARRAY_SIZE(max98095_snd_controls));
+
+	return 0;
+}
+
+/* codec mclk clock divider coefficients */
+static const struct {
+	u32 rate;
+	u8  sr;
+} rate_table[] = {
+	{8000,  0x01},
+	{11025, 0x02},
+	{16000, 0x03},
+	{22050, 0x04},
+	{24000, 0x05},
+	{32000, 0x06},
+	{44100, 0x07},
+	{48000, 0x08},
+	{88200, 0x09},
+	{96000, 0x0A},
+};
+
+static int rate_value(int rate, u8 *value)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(rate_table); i++) {
+		if (rate_table[i].rate >= rate) {
+			*value = rate_table[i].sr;
+			return 0;
+		}
+	}
+	*value = rate_table[0].sr;
+	return -EINVAL;
+}
+
+static int max98095_dai1_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 max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_cdata *cdata;
+	unsigned long long ni;
+	unsigned int rate;
+	u8 regval;
+
+	cdata = &max98095->dai[0];
+
+	rate = params_rate(params);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		snd_soc_update_bits(codec, M98095_02A_DAI1_FORMAT,
+			M98095_DAI_WS, 0);
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		snd_soc_update_bits(codec, M98095_02A_DAI1_FORMAT,
+			M98095_DAI_WS, M98095_DAI_WS);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (rate_value(rate, &regval))
+		return -EINVAL;
+
+	snd_soc_update_bits(codec, M98095_027_DAI1_CLKMODE,
+		M98095_CLKMODE_MASK, regval);
+	cdata->rate = rate;
+
+	/* Configure NI when operating as master */
+	if (snd_soc_read(codec, M98095_02A_DAI1_FORMAT) & M98095_DAI_MAS) {
+		if (max98095->sysclk == 0) {
+			dev_err(codec->dev, "Invalid system clock frequency\n");
+			return -EINVAL;
+		}
+		ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+				* (unsigned long long int)rate;
+		do_div(ni, (unsigned long long int)max98095->sysclk);
+		snd_soc_write(codec, M98095_028_DAI1_CLKCFG_HI,
+			(ni >> 8) & 0x7F);
+		snd_soc_write(codec, M98095_029_DAI1_CLKCFG_LO,
+			ni & 0xFF);
+	}
+
+	/* Update sample rate mode */
+	if (rate < 50000)
+		snd_soc_update_bits(codec, M98095_02E_DAI1_FILTERS,
+			M98095_DAI_DHF, 0);
+	else
+		snd_soc_update_bits(codec, M98095_02E_DAI1_FILTERS,
+			M98095_DAI_DHF, M98095_DAI_DHF);
+
+	return 0;
+}
+
+static int max98095_dai2_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 max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_cdata *cdata;
+	unsigned long long ni;
+	unsigned int rate;
+	u8 regval;
+
+	cdata = &max98095->dai[1];
+
+	rate = params_rate(params);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		snd_soc_update_bits(codec, M98095_034_DAI2_FORMAT,
+			M98095_DAI_WS, 0);
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		snd_soc_update_bits(codec, M98095_034_DAI2_FORMAT,
+			M98095_DAI_WS, M98095_DAI_WS);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (rate_value(rate, &regval))
+		return -EINVAL;
+
+	snd_soc_update_bits(codec, M98095_031_DAI2_CLKMODE,
+		M98095_CLKMODE_MASK, regval);
+	cdata->rate = rate;
+
+	/* Configure NI when operating as master */
+	if (snd_soc_read(codec, M98095_034_DAI2_FORMAT) & M98095_DAI_MAS) {
+		if (max98095->sysclk == 0) {
+			dev_err(codec->dev, "Invalid system clock frequency\n");
+			return -EINVAL;
+		}
+		ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+				* (unsigned long long int)rate;
+		do_div(ni, (unsigned long long int)max98095->sysclk);
+		snd_soc_write(codec, M98095_032_DAI2_CLKCFG_HI,
+			(ni >> 8) & 0x7F);
+		snd_soc_write(codec, M98095_033_DAI2_CLKCFG_LO,
+			ni & 0xFF);
+	}
+
+	/* Update sample rate mode */
+	if (rate < 50000)
+		snd_soc_update_bits(codec, M98095_038_DAI2_FILTERS,
+			M98095_DAI_DHF, 0);
+	else
+		snd_soc_update_bits(codec, M98095_038_DAI2_FILTERS,
+			M98095_DAI_DHF, M98095_DAI_DHF);
+
+	return 0;
+}
+
+static int max98095_dai3_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 max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_cdata *cdata;
+	unsigned long long ni;
+	unsigned int rate;
+	u8 regval;
+
+	cdata = &max98095->dai[2];
+
+	rate = params_rate(params);
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		snd_soc_update_bits(codec, M98095_03E_DAI3_FORMAT,
+			M98095_DAI_WS, 0);
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		snd_soc_update_bits(codec, M98095_03E_DAI3_FORMAT,
+			M98095_DAI_WS, M98095_DAI_WS);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (rate_value(rate, &regval))
+		return -EINVAL;
+
+	snd_soc_update_bits(codec, M98095_03B_DAI3_CLKMODE,
+		M98095_CLKMODE_MASK, regval);
+	cdata->rate = rate;
+
+	/* Configure NI when operating as master */
+	if (snd_soc_read(codec, M98095_03E_DAI3_FORMAT) & M98095_DAI_MAS) {
+		if (max98095->sysclk == 0) {
+			dev_err(codec->dev, "Invalid system clock frequency\n");
+			return -EINVAL;
+		}
+		ni = 65536ULL * (rate < 50000 ? 96ULL : 48ULL)
+				* (unsigned long long int)rate;
+		do_div(ni, (unsigned long long int)max98095->sysclk);
+		snd_soc_write(codec, M98095_03C_DAI3_CLKCFG_HI,
+			(ni >> 8) & 0x7F);
+		snd_soc_write(codec, M98095_03D_DAI3_CLKCFG_LO,
+			ni & 0xFF);
+	}
+
+	/* Update sample rate mode */
+	if (rate < 50000)
+		snd_soc_update_bits(codec, M98095_042_DAI3_FILTERS,
+			M98095_DAI_DHF, 0);
+	else
+		snd_soc_update_bits(codec, M98095_042_DAI3_FILTERS,
+			M98095_DAI_DHF, M98095_DAI_DHF);
+
+	return 0;
+}
+
+static int max98095_dai_set_sysclk(struct snd_soc_dai *dai,
+				   int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+
+	/* Requested clock frequency is already setup */
+	if (freq == max98095->sysclk)
+		return 0;
+
+	max98095->sysclk = freq; /* remember current sysclk */
+
+	/* Setup clocks for slave mode, and using the PLL
+	 * PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
+	 *         0x02 (when master clk is 20MHz to 40MHz)..
+	 *         0x03 (when master clk is 40MHz to 60MHz)..
+	 */
+	if ((freq >= 10000000) && (freq < 20000000)) {
+		snd_soc_write(codec, M98095_026_SYS_CLK, 0x10);
+	} else if ((freq >= 20000000) && (freq < 40000000)) {
+		snd_soc_write(codec, M98095_026_SYS_CLK, 0x20);
+	} else if ((freq >= 40000000) && (freq < 60000000)) {
+		snd_soc_write(codec, M98095_026_SYS_CLK, 0x30);
+	} else {
+		dev_err(codec->dev, "Invalid master clock frequency\n");
+		return -EINVAL;
+	}
+
+	dev_dbg(dai->dev, "Clock source is %d at %uHz\n", clk_id, freq);
+
+	max98095->sysclk = freq;
+	return 0;
+}
+
+static int max98095_dai1_set_fmt(struct snd_soc_dai *codec_dai,
+				 unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_cdata *cdata;
+	u8 regval = 0;
+
+	cdata = &max98095->dai[0];
+
+	if (fmt != cdata->fmt) {
+		cdata->fmt = fmt;
+
+		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+		case SND_SOC_DAIFMT_CBS_CFS:
+			/* Slave mode PLL */
+			snd_soc_write(codec, M98095_028_DAI1_CLKCFG_HI,
+				0x80);
+			snd_soc_write(codec, M98095_029_DAI1_CLKCFG_LO,
+				0x00);
+			break;
+		case SND_SOC_DAIFMT_CBM_CFM:
+			/* Set to master mode */
+			regval |= M98095_DAI_MAS;
+			break;
+		case SND_SOC_DAIFMT_CBS_CFM:
+		case SND_SOC_DAIFMT_CBM_CFS:
+		default:
+			dev_err(codec->dev, "Clock mode unsupported");
+			return -EINVAL;
+		}
+
+		switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+		case SND_SOC_DAIFMT_I2S:
+			regval |= M98095_DAI_DLY;
+			break;
+		case SND_SOC_DAIFMT_LEFT_J:
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			regval |= M98095_DAI_WCI;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			regval |= M98095_DAI_BCI;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			regval |= M98095_DAI_BCI|M98095_DAI_WCI;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		snd_soc_update_bits(codec, M98095_02A_DAI1_FORMAT,
+			M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI |
+			M98095_DAI_WCI, regval);
+
+		snd_soc_write(codec, M98095_02B_DAI1_CLOCK, M98095_DAI_BSEL64);
+	}
+
+	return 0;
+}
+
+static int max98095_dai2_set_fmt(struct snd_soc_dai *codec_dai,
+				 unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_cdata *cdata;
+	u8 regval = 0;
+
+	cdata = &max98095->dai[1];
+
+	if (fmt != cdata->fmt) {
+		cdata->fmt = fmt;
+
+		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+		case SND_SOC_DAIFMT_CBS_CFS:
+			/* Slave mode PLL */
+			snd_soc_write(codec, M98095_032_DAI2_CLKCFG_HI,
+				0x80);
+			snd_soc_write(codec, M98095_033_DAI2_CLKCFG_LO,
+				0x00);
+			break;
+		case SND_SOC_DAIFMT_CBM_CFM:
+			/* Set to master mode */
+			regval |= M98095_DAI_MAS;
+			break;
+		case SND_SOC_DAIFMT_CBS_CFM:
+		case SND_SOC_DAIFMT_CBM_CFS:
+		default:
+			dev_err(codec->dev, "Clock mode unsupported");
+			return -EINVAL;
+		}
+
+		switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+		case SND_SOC_DAIFMT_I2S:
+			regval |= M98095_DAI_DLY;
+			break;
+		case SND_SOC_DAIFMT_LEFT_J:
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			regval |= M98095_DAI_WCI;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			regval |= M98095_DAI_BCI;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			regval |= M98095_DAI_BCI|M98095_DAI_WCI;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		snd_soc_update_bits(codec, M98095_034_DAI2_FORMAT,
+			M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI |
+			M98095_DAI_WCI, regval);
+
+		snd_soc_write(codec, M98095_035_DAI2_CLOCK,
+			M98095_DAI_BSEL64);
+	}
+
+	return 0;
+}
+
+static int max98095_dai3_set_fmt(struct snd_soc_dai *codec_dai,
+				 unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_cdata *cdata;
+	u8 regval = 0;
+
+	cdata = &max98095->dai[2];
+
+	if (fmt != cdata->fmt) {
+		cdata->fmt = fmt;
+
+		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+		case SND_SOC_DAIFMT_CBS_CFS:
+			/* Slave mode PLL */
+			snd_soc_write(codec, M98095_03C_DAI3_CLKCFG_HI,
+				0x80);
+			snd_soc_write(codec, M98095_03D_DAI3_CLKCFG_LO,
+				0x00);
+			break;
+		case SND_SOC_DAIFMT_CBM_CFM:
+			/* Set to master mode */
+			regval |= M98095_DAI_MAS;
+			break;
+		case SND_SOC_DAIFMT_CBS_CFM:
+		case SND_SOC_DAIFMT_CBM_CFS:
+		default:
+			dev_err(codec->dev, "Clock mode unsupported");
+			return -EINVAL;
+		}
+
+		switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+		case SND_SOC_DAIFMT_I2S:
+			regval |= M98095_DAI_DLY;
+			break;
+		case SND_SOC_DAIFMT_LEFT_J:
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			break;
+		case SND_SOC_DAIFMT_NB_IF:
+			regval |= M98095_DAI_WCI;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			regval |= M98095_DAI_BCI;
+			break;
+		case SND_SOC_DAIFMT_IB_IF:
+			regval |= M98095_DAI_BCI|M98095_DAI_WCI;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		snd_soc_update_bits(codec, M98095_03E_DAI3_FORMAT,
+			M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI |
+			M98095_DAI_WCI, regval);
+
+		snd_soc_write(codec, M98095_03F_DAI3_CLOCK,
+			M98095_DAI_BSEL64);
+	}
+
+	return 0;
+}
+
+static int max98095_set_bias_level(struct snd_soc_codec *codec,
+				   enum snd_soc_bias_level level)
+{
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			ret = snd_soc_cache_sync(codec);
+
+			if (ret != 0) {
+				dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
+				return ret;
+			}
+		}
+
+		snd_soc_update_bits(codec, M98095_090_PWR_EN_IN,
+				M98095_MBEN, M98095_MBEN);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		snd_soc_update_bits(codec, M98095_090_PWR_EN_IN,
+				M98095_MBEN, 0);
+		codec->cache_sync = 1;
+		break;
+	}
+	codec->dapm.bias_level = level;
+	return 0;
+}
+
+#define MAX98095_RATES SNDRV_PCM_RATE_8000_96000
+#define MAX98095_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops max98095_dai1_ops = {
+	.set_sysclk = max98095_dai_set_sysclk,
+	.set_fmt = max98095_dai1_set_fmt,
+	.hw_params = max98095_dai1_hw_params,
+};
+
+static struct snd_soc_dai_ops max98095_dai2_ops = {
+	.set_sysclk = max98095_dai_set_sysclk,
+	.set_fmt = max98095_dai2_set_fmt,
+	.hw_params = max98095_dai2_hw_params,
+};
+
+static struct snd_soc_dai_ops max98095_dai3_ops = {
+	.set_sysclk = max98095_dai_set_sysclk,
+	.set_fmt = max98095_dai3_set_fmt,
+	.hw_params = max98095_dai3_hw_params,
+};
+
+static struct snd_soc_dai_driver max98095_dai[] = {
+{
+	.name = "HiFi",
+	.playback = {
+		.stream_name = "HiFi Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = MAX98095_RATES,
+		.formats = MAX98095_FORMATS,
+	},
+	.capture = {
+		.stream_name = "HiFi Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = MAX98095_RATES,
+		.formats = MAX98095_FORMATS,
+	},
+	 .ops = &max98095_dai1_ops,
+},
+{
+	.name = "Aux",
+	.playback = {
+		.stream_name = "Aux Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = MAX98095_RATES,
+		.formats = MAX98095_FORMATS,
+	},
+	.ops = &max98095_dai2_ops,
+},
+{
+	.name = "Voice",
+	.playback = {
+		.stream_name = "Voice Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = MAX98095_RATES,
+		.formats = MAX98095_FORMATS,
+	},
+	.ops = &max98095_dai3_ops,
+}
+
+};
+
+static int max98095_get_eq_channel(const char *name)
+{
+	if (strcmp(name, "EQ1 Mode") == 0)
+		return 0;
+	if (strcmp(name, "EQ2 Mode") == 0)
+		return 1;
+	return -EINVAL;
+}
+
+static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_pdata *pdata = max98095->pdata;
+	int channel = max98095_get_eq_channel(kcontrol->id.name);
+	struct max98095_cdata *cdata;
+	int sel = ucontrol->value.integer.value[0];
+	struct max98095_eq_cfg *coef_set;
+	int fs, best, best_val, i;
+	int regmask, regsave;
+
+	BUG_ON(channel > 1);
+
+	if (!pdata || !max98095->eq_textcnt)
+		return 0;
+
+	if (sel >= pdata->eq_cfgcnt)
+		return -EINVAL;
+
+	cdata = &max98095->dai[channel];
+	cdata->eq_sel = sel;
+	fs = cdata->rate;
+
+	/* Find the selected configuration with nearest sample rate */
+	best = 0;
+	best_val = INT_MAX;
+	for (i = 0; i < pdata->eq_cfgcnt; i++) {
+		if (strcmp(pdata->eq_cfg[i].name, max98095->eq_texts[sel]) == 0 &&
+			abs(pdata->eq_cfg[i].rate - fs) < best_val) {
+			best = i;
+			best_val = abs(pdata->eq_cfg[i].rate - fs);
+		}
+	}
+
+	dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+		pdata->eq_cfg[best].name,
+		pdata->eq_cfg[best].rate, fs);
+
+	coef_set = &pdata->eq_cfg[best];
+
+	regmask = (channel == 0) ? M98095_EQ1EN : M98095_EQ2EN;
+
+	/* Disable filter while configuring, and save current on/off state */
+	regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL);
+	snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0);
+
+	mutex_lock(&codec->mutex);
+	snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
+	m98095_eq_band(codec, channel, 0, coef_set->band1);
+	m98095_eq_band(codec, channel, 1, coef_set->band2);
+	m98095_eq_band(codec, channel, 2, coef_set->band3);
+	m98095_eq_band(codec, channel, 3, coef_set->band4);
+	m98095_eq_band(codec, channel, 4, coef_set->band5);
+	snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0);
+	mutex_unlock(&codec->mutex);
+
+	/* Restore the original on/off state */
+	snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave);
+	return 0;
+}
+
+static int max98095_get_eq_enum(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	int channel = max98095_get_eq_channel(kcontrol->id.name);
+	struct max98095_cdata *cdata;
+
+	cdata = &max98095->dai[channel];
+	ucontrol->value.enumerated.item[0] = cdata->eq_sel;
+
+	return 0;
+}
+
+static void max98095_handle_eq_pdata(struct snd_soc_codec *codec)
+{
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_pdata *pdata = max98095->pdata;
+	struct max98095_eq_cfg *cfg;
+	unsigned int cfgcnt;
+	int i, j;
+	const char **t;
+	int ret;
+
+	struct snd_kcontrol_new controls[] = {
+		SOC_ENUM_EXT("EQ1 Mode",
+			max98095->eq_enum,
+			max98095_get_eq_enum,
+			max98095_put_eq_enum),
+		SOC_ENUM_EXT("EQ2 Mode",
+			max98095->eq_enum,
+			max98095_get_eq_enum,
+			max98095_put_eq_enum),
+	};
+
+	cfg = pdata->eq_cfg;
+	cfgcnt = pdata->eq_cfgcnt;
+
+	/* Setup an array of texts for the equalizer enum.
+	 * This is based on Mark Brown's equalizer driver code.
+	 */
+	max98095->eq_textcnt = 0;
+	max98095->eq_texts = NULL;
+	for (i = 0; i < cfgcnt; i++) {
+		for (j = 0; j < max98095->eq_textcnt; j++) {
+			if (strcmp(cfg[i].name, max98095->eq_texts[j]) == 0)
+				break;
+		}
+
+		if (j != max98095->eq_textcnt)
+			continue;
+
+		/* Expand the array */
+		t = krealloc(max98095->eq_texts,
+			     sizeof(char *) * (max98095->eq_textcnt + 1),
+			     GFP_KERNEL);
+		if (t == NULL)
+			continue;
+
+		/* Store the new entry */
+		t[max98095->eq_textcnt] = cfg[i].name;
+		max98095->eq_textcnt++;
+		max98095->eq_texts = t;
+	}
+
+	/* Now point the soc_enum to .texts array items */
+	max98095->eq_enum.texts = max98095->eq_texts;
+	max98095->eq_enum.max = max98095->eq_textcnt;
+
+	ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls));
+	if (ret != 0)
+		dev_err(codec->dev, "Failed to add EQ control: %d\n", ret);
+}
+
+static int max98095_get_bq_channel(const char *name)
+{
+	if (strcmp(name, "Biquad1 Mode") == 0)
+		return 0;
+	if (strcmp(name, "Biquad2 Mode") == 0)
+		return 1;
+	return -EINVAL;
+}
+
+static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_pdata *pdata = max98095->pdata;
+	int channel = max98095_get_bq_channel(kcontrol->id.name);
+	struct max98095_cdata *cdata;
+	int sel = ucontrol->value.integer.value[0];
+	struct max98095_biquad_cfg *coef_set;
+	int fs, best, best_val, i;
+	int regmask, regsave;
+
+	BUG_ON(channel > 1);
+
+	if (!pdata || !max98095->bq_textcnt)
+		return 0;
+
+	if (sel >= pdata->bq_cfgcnt)
+		return -EINVAL;
+
+	cdata = &max98095->dai[channel];
+	cdata->bq_sel = sel;
+	fs = cdata->rate;
+
+	/* Find the selected configuration with nearest sample rate */
+	best = 0;
+	best_val = INT_MAX;
+	for (i = 0; i < pdata->bq_cfgcnt; i++) {
+		if (strcmp(pdata->bq_cfg[i].name, max98095->bq_texts[sel]) == 0 &&
+			abs(pdata->bq_cfg[i].rate - fs) < best_val) {
+			best = i;
+			best_val = abs(pdata->bq_cfg[i].rate - fs);
+		}
+	}
+
+	dev_dbg(codec->dev, "Selected %s/%dHz for %dHz sample rate\n",
+		pdata->bq_cfg[best].name,
+		pdata->bq_cfg[best].rate, fs);
+
+	coef_set = &pdata->bq_cfg[best];
+
+	regmask = (channel == 0) ? M98095_BQ1EN : M98095_BQ2EN;
+
+	/* Disable filter while configuring, and save current on/off state */
+	regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL);
+	snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0);
+
+	mutex_lock(&codec->mutex);
+	snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
+	m98095_biquad_band(codec, channel, 0, coef_set->band1);
+	m98095_biquad_band(codec, channel, 1, coef_set->band2);
+	snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0);
+	mutex_unlock(&codec->mutex);
+
+	/* Restore the original on/off state */
+	snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave);
+	return 0;
+}
+
+static int max98095_get_bq_enum(struct snd_kcontrol *kcontrol,
+				 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	int channel = max98095_get_bq_channel(kcontrol->id.name);
+	struct max98095_cdata *cdata;
+
+	cdata = &max98095->dai[channel];
+	ucontrol->value.enumerated.item[0] = cdata->bq_sel;
+
+	return 0;
+}
+
+static void max98095_handle_bq_pdata(struct snd_soc_codec *codec)
+{
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_pdata *pdata = max98095->pdata;
+	struct max98095_biquad_cfg *cfg;
+	unsigned int cfgcnt;
+	int i, j;
+	const char **t;
+	int ret;
+
+	struct snd_kcontrol_new controls[] = {
+		SOC_ENUM_EXT("Biquad1 Mode",
+			max98095->bq_enum,
+			max98095_get_bq_enum,
+			max98095_put_bq_enum),
+		SOC_ENUM_EXT("Biquad2 Mode",
+			max98095->bq_enum,
+			max98095_get_bq_enum,
+			max98095_put_bq_enum),
+	};
+
+	cfg = pdata->bq_cfg;
+	cfgcnt = pdata->bq_cfgcnt;
+
+	/* Setup an array of texts for the biquad enum.
+	 * This is based on Mark Brown's equalizer driver code.
+	 */
+	max98095->bq_textcnt = 0;
+	max98095->bq_texts = NULL;
+	for (i = 0; i < cfgcnt; i++) {
+		for (j = 0; j < max98095->bq_textcnt; j++) {
+			if (strcmp(cfg[i].name, max98095->bq_texts[j]) == 0)
+				break;
+		}
+
+		if (j != max98095->bq_textcnt)
+			continue;
+
+		/* Expand the array */
+		t = krealloc(max98095->bq_texts,
+			     sizeof(char *) * (max98095->bq_textcnt + 1),
+			     GFP_KERNEL);
+		if (t == NULL)
+			continue;
+
+		/* Store the new entry */
+		t[max98095->bq_textcnt] = cfg[i].name;
+		max98095->bq_textcnt++;
+		max98095->bq_texts = t;
+	}
+
+	/* Now point the soc_enum to .texts array items */
+	max98095->bq_enum.texts = max98095->bq_texts;
+	max98095->bq_enum.max = max98095->bq_textcnt;
+
+	ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls));
+	if (ret != 0)
+		dev_err(codec->dev, "Failed to add Biquad control: %d\n", ret);
+}
+
+static void max98095_handle_pdata(struct snd_soc_codec *codec)
+{
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_pdata *pdata = max98095->pdata;
+	u8 regval = 0;
+
+	if (!pdata) {
+		dev_dbg(codec->dev, "No platform data\n");
+		return;
+	}
+
+	/* Configure mic for analog/digital mic mode */
+	if (pdata->digmic_left_mode)
+		regval |= M98095_DIGMIC_L;
+
+	if (pdata->digmic_right_mode)
+		regval |= M98095_DIGMIC_R;
+
+	snd_soc_write(codec, M98095_087_CFG_MIC, regval);
+
+	/* Configure equalizers */
+	if (pdata->eq_cfgcnt)
+		max98095_handle_eq_pdata(codec);
+
+	/* Configure bi-quad filters */
+	if (pdata->bq_cfgcnt)
+		max98095_handle_bq_pdata(codec);
+}
+
+#ifdef CONFIG_PM
+static int max98095_suspend(struct snd_soc_codec *codec, pm_message_t state)
+{
+	max98095_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static int max98095_resume(struct snd_soc_codec *codec)
+{
+	max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	return 0;
+}
+#else
+#define max98095_suspend NULL
+#define max98095_resume NULL
+#endif
+
+static int max98095_reset(struct snd_soc_codec *codec)
+{
+	int i, ret;
+
+	/* Gracefully reset the DSP core and the codec hardware
+	 * in a proper sequence */
+	ret = snd_soc_write(codec, M98095_00F_HOST_CFG, 0);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to reset DSP: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_write(codec, M98095_097_PWR_SYS, 0);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to reset codec: %d\n", ret);
+		return ret;
+	}
+
+	/* Reset to hardware default for registers, as there is not
+	 * a soft reset hardware control register */
+	for (i = M98095_010_HOST_INT_CFG; i < M98095_REG_MAX_CACHED; i++) {
+		ret = snd_soc_write(codec, i, max98095_reg_def[i]);
+		if (ret < 0) {
+			dev_err(codec->dev, "Failed to reset: %d\n", ret);
+			return ret;
+		}
+	}
+
+	return ret;
+}
+
+static int max98095_probe(struct snd_soc_codec *codec)
+{
+	struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+	struct max98095_cdata *cdata;
+	int ret = 0;
+
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
+
+	/* reset the codec, the DSP core, and disable all interrupts */
+	max98095_reset(codec);
+
+	/* initialize private data */
+
+	max98095->sysclk = (unsigned)-1;
+	max98095->eq_textcnt = 0;
+	max98095->bq_textcnt = 0;
+
+	cdata = &max98095->dai[0];
+	cdata->rate = (unsigned)-1;
+	cdata->fmt  = (unsigned)-1;
+	cdata->eq_sel = 0;
+	cdata->bq_sel = 0;
+
+	cdata = &max98095->dai[1];
+	cdata->rate = (unsigned)-1;
+	cdata->fmt  = (unsigned)-1;
+	cdata->eq_sel = 0;
+	cdata->bq_sel = 0;
+
+	cdata = &max98095->dai[2];
+	cdata->rate = (unsigned)-1;
+	cdata->fmt  = (unsigned)-1;
+	cdata->eq_sel = 0;
+	cdata->bq_sel = 0;
+
+	max98095->lin_state = 0;
+	max98095->mic1pre = 0;
+	max98095->mic2pre = 0;
+
+	ret = snd_soc_read(codec, M98095_0FF_REV_ID);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to read device revision: %d\n",
+			ret);
+		goto err_access;
+	}
+	dev_info(codec->dev, "revision %c\n", ret + 'A');
+
+	snd_soc_write(codec, M98095_097_PWR_SYS, M98095_PWRSV);
+
+	/* initialize registers cache to hardware default */
+	max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	snd_soc_write(codec, M98095_048_MIX_DAC_LR,
+		M98095_DAI1L_TO_DACL|M98095_DAI1R_TO_DACR);
+
+	snd_soc_write(codec, M98095_049_MIX_DAC_M,
+		M98095_DAI2M_TO_DACM|M98095_DAI3M_TO_DACM);
+
+	snd_soc_write(codec, M98095_092_PWR_EN_OUT, M98095_SPK_SPREADSPECTRUM);
+	snd_soc_write(codec, M98095_045_CFG_DSP, M98095_DSPNORMAL);
+	snd_soc_write(codec, M98095_04E_CFG_HP, M98095_HPNORMAL);
+
+	snd_soc_write(codec, M98095_02C_DAI1_IOCFG,
+		M98095_S1NORMAL|M98095_SDATA);
+
+	snd_soc_write(codec, M98095_036_DAI2_IOCFG,
+		M98095_S2NORMAL|M98095_SDATA);
+
+	snd_soc_write(codec, M98095_040_DAI3_IOCFG,
+		M98095_S3NORMAL|M98095_SDATA);
+
+	max98095_handle_pdata(codec);
+
+	/* take the codec out of the shut down */
+	snd_soc_update_bits(codec, M98095_097_PWR_SYS, M98095_SHDNRUN,
+		M98095_SHDNRUN);
+
+	max98095_add_widgets(codec);
+
+err_access:
+	return ret;
+}
+
+static int max98095_remove(struct snd_soc_codec *codec)
+{
+	max98095_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_max98095 = {
+	.probe   = max98095_probe,
+	.remove  = max98095_remove,
+	.suspend = max98095_suspend,
+	.resume  = max98095_resume,
+	.set_bias_level = max98095_set_bias_level,
+	.reg_cache_size = ARRAY_SIZE(max98095_reg_def),
+	.reg_word_size = sizeof(u8),
+	.reg_cache_default = max98095_reg_def,
+	.readable_register = max98095_readable,
+	.volatile_register = max98095_volatile,
+	.dapm_widgets	  = max98095_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(max98095_dapm_widgets),
+	.dapm_routes     = max98095_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(max98095_audio_map),
+};
+
+static int max98095_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	struct max98095_priv *max98095;
+	int ret;
+
+	max98095 = kzalloc(sizeof(struct max98095_priv), GFP_KERNEL);
+	if (max98095 == NULL)
+		return -ENOMEM;
+
+	max98095->devtype = id->driver_data;
+	i2c_set_clientdata(i2c, max98095);
+	max98095->control_data = i2c;
+	max98095->pdata = i2c->dev.platform_data;
+
+	ret = snd_soc_register_codec(&i2c->dev,
+			&soc_codec_dev_max98095, &max98095_dai[0], 3);
+	if (ret < 0)
+		kfree(max98095);
+	return ret;
+}
+
+static int __devexit max98095_i2c_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	kfree(i2c_get_clientdata(client));
+
+	return 0;
+}
+
+static const struct i2c_device_id max98095_i2c_id[] = {
+	{ "max98095", MAX98095 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, max98095_i2c_id);
+
+static struct i2c_driver max98095_i2c_driver = {
+	.driver = {
+		.name = "max98095",
+		.owner = THIS_MODULE,
+	},
+	.probe  = max98095_i2c_probe,
+	.remove = __devexit_p(max98095_i2c_remove),
+	.id_table = max98095_i2c_id,
+};
+
+static int __init max98095_init(void)
+{
+	int ret;
+
+	ret = i2c_add_driver(&max98095_i2c_driver);
+	if (ret)
+		pr_err("Failed to register max98095 I2C driver: %d\n", ret);
+
+	return ret;
+}
+module_init(max98095_init);
+
+static void __exit max98095_exit(void)
+{
+	i2c_del_driver(&max98095_i2c_driver);
+}
+module_exit(max98095_exit);
+
+MODULE_DESCRIPTION("ALSA SoC MAX98095 driver");
+MODULE_AUTHOR("Peter Hsiang");
+MODULE_LICENSE("GPL");

+ 299 - 0
sound/soc/codecs/max98095.h

@@ -0,0 +1,299 @@
+/*
+ * max98095.h -- MAX98095 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Maxim Integrated Products
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _MAX98095_H
+#define _MAX98095_H
+
+/*
+ * MAX98095 Registers Definition
+ */
+
+#define M98095_000_HOST_DATA                0x00
+#define M98095_001_HOST_INT_STS             0x01
+#define M98095_002_HOST_RSP_STS             0x02
+#define M98095_003_HOST_CMD_STS             0x03
+#define M98095_004_CODEC_STS                0x04
+#define M98095_005_DAI1_ALC_STS             0x05
+#define M98095_006_DAI2_ALC_STS             0x06
+#define M98095_007_JACK_AUTO_STS            0x07
+#define M98095_008_JACK_MANUAL_STS          0x08
+#define M98095_009_JACK_VBAT_STS            0x09
+#define M98095_00A_ACC_ADC_STS              0x0A
+#define M98095_00B_MIC_NG_AGC_STS           0x0B
+#define M98095_00C_SPK_L_VOLT_STS           0x0C
+#define M98095_00D_SPK_R_VOLT_STS           0x0D
+#define M98095_00E_TEMP_SENSOR_STS          0x0E
+#define M98095_00F_HOST_CFG                 0x0F
+#define M98095_010_HOST_INT_CFG             0x10
+#define M98095_011_HOST_INT_EN              0x11
+#define M98095_012_CODEC_INT_EN             0x12
+#define M98095_013_JACK_INT_EN              0x13
+#define M98095_014_JACK_INT_EN              0x14
+#define M98095_015_DEC                      0x15
+#define M98095_016_RESERVED                 0x16
+#define M98095_017_RESERVED                 0x17
+#define M98095_018_KEYCODE3                 0x18
+#define M98095_019_KEYCODE2                 0x19
+#define M98095_01A_KEYCODE1                 0x1A
+#define M98095_01B_KEYCODE0                 0x1B
+#define M98095_01C_OEMCODE1                 0x1C
+#define M98095_01D_OEMCODE0                 0x1D
+#define M98095_01E_XCFG1                    0x1E
+#define M98095_01F_XCFG2                    0x1F
+#define M98095_020_XCFG3                    0x20
+#define M98095_021_XCFG4                    0x21
+#define M98095_022_XCFG5                    0x22
+#define M98095_023_XCFG6                    0x23
+#define M98095_024_XGPIO                    0x24
+#define M98095_025_XCLKCFG                  0x25
+#define M98095_026_SYS_CLK                  0x26
+#define M98095_027_DAI1_CLKMODE             0x27
+#define M98095_028_DAI1_CLKCFG_HI           0x28
+#define M98095_029_DAI1_CLKCFG_LO           0x29
+#define M98095_02A_DAI1_FORMAT              0x2A
+#define M98095_02B_DAI1_CLOCK               0x2B
+#define M98095_02C_DAI1_IOCFG               0x2C
+#define M98095_02D_DAI1_TDM                 0x2D
+#define M98095_02E_DAI1_FILTERS             0x2E
+#define M98095_02F_DAI1_LVL1                0x2F
+#define M98095_030_DAI1_LVL2                0x30
+#define M98095_031_DAI2_CLKMODE             0x31
+#define M98095_032_DAI2_CLKCFG_HI           0x32
+#define M98095_033_DAI2_CLKCFG_LO           0x33
+#define M98095_034_DAI2_FORMAT              0x34
+#define M98095_035_DAI2_CLOCK               0x35
+#define M98095_036_DAI2_IOCFG               0x36
+#define M98095_037_DAI2_TDM                 0x37
+#define M98095_038_DAI2_FILTERS             0x38
+#define M98095_039_DAI2_LVL1                0x39
+#define M98095_03A_DAI2_LVL2                0x3A
+#define M98095_03B_DAI3_CLKMODE             0x3B
+#define M98095_03C_DAI3_CLKCFG_HI           0x3C
+#define M98095_03D_DAI3_CLKCFG_LO           0x3D
+#define M98095_03E_DAI3_FORMAT              0x3E
+#define M98095_03F_DAI3_CLOCK               0x3F
+#define M98095_040_DAI3_IOCFG               0x40
+#define M98095_041_DAI3_TDM                 0x41
+#define M98095_042_DAI3_FILTERS             0x42
+#define M98095_043_DAI3_LVL1                0x43
+#define M98095_044_DAI3_LVL2                0x44
+#define M98095_045_CFG_DSP                  0x45
+#define M98095_046_DAC_CTRL1                0x46
+#define M98095_047_DAC_CTRL2                0x47
+#define M98095_048_MIX_DAC_LR               0x48
+#define M98095_049_MIX_DAC_M                0x49
+#define M98095_04A_MIX_ADC_LEFT             0x4A
+#define M98095_04B_MIX_ADC_RIGHT            0x4B
+#define M98095_04C_MIX_HP_LEFT              0x4C
+#define M98095_04D_MIX_HP_RIGHT             0x4D
+#define M98095_04E_CFG_HP                   0x4E
+#define M98095_04F_MIX_RCV                  0x4F
+#define M98095_050_MIX_SPK_LEFT             0x50
+#define M98095_051_MIX_SPK_RIGHT            0x51
+#define M98095_052_MIX_SPK_CFG              0x52
+#define M98095_053_MIX_LINEOUT1             0x53
+#define M98095_054_MIX_LINEOUT2             0x54
+#define M98095_055_MIX_LINEOUT_CFG          0x55
+#define M98095_056_LVL_SIDETONE_DAI12       0x56
+#define M98095_057_LVL_SIDETONE_DAI3        0x57
+#define M98095_058_LVL_DAI1_PLAY            0x58
+#define M98095_059_LVL_DAI1_EQ              0x59
+#define M98095_05A_LVL_DAI2_PLAY            0x5A
+#define M98095_05B_LVL_DAI2_EQ              0x5B
+#define M98095_05C_LVL_DAI3_PLAY            0x5C
+#define M98095_05D_LVL_ADC_L                0x5D
+#define M98095_05E_LVL_ADC_R                0x5E
+#define M98095_05F_LVL_MIC1                 0x5F
+#define M98095_060_LVL_MIC2                 0x60
+#define M98095_061_LVL_LINEIN               0x61
+#define M98095_062_LVL_LINEOUT1             0x62
+#define M98095_063_LVL_LINEOUT2             0x63
+#define M98095_064_LVL_HP_L                 0x64
+#define M98095_065_LVL_HP_R                 0x65
+#define M98095_066_LVL_RCV                  0x66
+#define M98095_067_LVL_SPK_L                0x67
+#define M98095_068_LVL_SPK_R                0x68
+#define M98095_069_MICAGC_CFG               0x69
+#define M98095_06A_MICAGC_THRESH            0x6A
+#define M98095_06B_SPK_NOISEGATE            0x6B
+#define M98095_06C_DAI1_ALC1_TIME           0x6C
+#define M98095_06D_DAI1_ALC1_COMP           0x6D
+#define M98095_06E_DAI1_ALC1_EXPN           0x6E
+#define M98095_06F_DAI1_ALC1_GAIN           0x6F
+#define M98095_070_DAI1_ALC2_TIME           0x70
+#define M98095_071_DAI1_ALC2_COMP           0x71
+#define M98095_072_DAI1_ALC2_EXPN           0x72
+#define M98095_073_DAI1_ALC2_GAIN           0x73
+#define M98095_074_DAI1_ALC3_TIME           0x74
+#define M98095_075_DAI1_ALC3_COMP           0x75
+#define M98095_076_DAI1_ALC3_EXPN           0x76
+#define M98095_077_DAI1_ALC3_GAIN           0x77
+#define M98095_078_DAI2_ALC1_TIME           0x78
+#define M98095_079_DAI2_ALC1_COMP           0x79
+#define M98095_07A_DAI2_ALC1_EXPN           0x7A
+#define M98095_07B_DAI2_ALC1_GAIN           0x7B
+#define M98095_07C_DAI2_ALC2_TIME           0x7C
+#define M98095_07D_DAI2_ALC2_COMP           0x7D
+#define M98095_07E_DAI2_ALC2_EXPN           0x7E
+#define M98095_07F_DAI2_ALC2_GAIN           0x7F
+#define M98095_080_DAI2_ALC3_TIME           0x80
+#define M98095_081_DAI2_ALC3_COMP           0x81
+#define M98095_082_DAI2_ALC3_EXPN           0x82
+#define M98095_083_DAI2_ALC3_GAIN           0x83
+#define M98095_084_HP_NOISE_GATE            0x84
+#define M98095_085_AUX_ADC                  0x85
+#define M98095_086_CFG_LINE                 0x86
+#define M98095_087_CFG_MIC                  0x87
+#define M98095_088_CFG_LEVEL                0x88
+#define M98095_089_JACK_DET_AUTO            0x89
+#define M98095_08A_JACK_DET_MANUAL          0x8A
+#define M98095_08B_JACK_KEYSCAN_DBC         0x8B
+#define M98095_08C_JACK_KEYSCAN_DLY         0x8C
+#define M98095_08D_JACK_KEY_THRESH          0x8D
+#define M98095_08E_JACK_DC_SLEW             0x8E
+#define M98095_08F_JACK_TEST_CFG            0x8F
+#define M98095_090_PWR_EN_IN                0x90
+#define M98095_091_PWR_EN_OUT               0x91
+#define M98095_092_PWR_EN_OUT               0x92
+#define M98095_093_BIAS_CTRL                0x93
+#define M98095_094_PWR_DAC_21               0x94
+#define M98095_095_PWR_DAC_03               0x95
+#define M98095_096_PWR_DAC_CK               0x96
+#define M98095_097_PWR_SYS                  0x97
+
+#define M98095_0FF_REV_ID                   0xFF
+
+#define M98095_REG_CNT                      (0xFF+1)
+#define M98095_REG_MAX_CACHED               0X97
+
+/* MAX98095 Registers Bit Fields */
+
+/* M98095_00F_HOST_CFG */
+	#define M98095_SEG                      (1<<0)
+	#define M98095_XTEN                     (1<<1)
+	#define M98095_MDLLEN                   (1<<2)
+
+/* M98095_027_DAI1_CLKMODE, M98095_031_DAI2_CLKMODE, M98095_03B_DAI3_CLKMODE */
+	#define M98095_CLKMODE_MASK             0xFF
+
+/* M98095_02A_DAI1_FORMAT, M98095_034_DAI2_FORMAT, M98095_03E_DAI3_FORMAT */
+	#define M98095_DAI_MAS                  (1<<7)
+	#define M98095_DAI_WCI                  (1<<6)
+	#define M98095_DAI_BCI                  (1<<5)
+	#define M98095_DAI_DLY                  (1<<4)
+	#define M98095_DAI_TDM                  (1<<2)
+	#define M98095_DAI_FSW                  (1<<1)
+	#define M98095_DAI_WS                   (1<<0)
+
+/* M98095_02B_DAI1_CLOCK, M98095_035_DAI2_CLOCK, M98095_03F_DAI3_CLOCK */
+	#define M98095_DAI_BSEL64               (1<<0)
+	#define M98095_DAI_DOSR_DIV2            (0<<5)
+	#define M98095_DAI_DOSR_DIV4            (1<<5)
+
+/* M98095_02C_DAI1_IOCFG, M98095_036_DAI2_IOCFG, M98095_040_DAI3_IOCFG */
+	#define M98095_S1NORMAL                 (1<<6)
+	#define M98095_S2NORMAL                 (2<<6)
+	#define M98095_S3NORMAL                 (3<<6)
+	#define M98095_SDATA                    (3<<0)
+
+/* M98095_02E_DAI1_FILTERS, M98095_038_DAI2_FILTERS, M98095_042_DAI3_FILTERS */
+	#define M98095_DAI_DHF                  (1<<3)
+
+/* M98095_045_DSP_CFG */
+	#define M98095_DSPNORMAL                (5<<4)
+
+/* M98095_048_MIX_DAC_LR */
+	#define M98095_DAI1L_TO_DACR            (1<<7)
+	#define M98095_DAI1R_TO_DACR            (1<<6)
+	#define M98095_DAI2M_TO_DACR            (1<<5)
+	#define M98095_DAI1L_TO_DACL            (1<<3)
+	#define M98095_DAI1R_TO_DACL            (1<<2)
+	#define M98095_DAI2M_TO_DACL            (1<<1)
+	#define M98095_DAI3M_TO_DACL            (1<<0)
+
+/* M98095_049_MIX_DAC_M */
+	#define M98095_DAI1L_TO_DACM            (1<<3)
+	#define M98095_DAI1R_TO_DACM            (1<<2)
+	#define M98095_DAI2M_TO_DACM            (1<<1)
+	#define M98095_DAI3M_TO_DACM            (1<<0)
+
+/* M98095_04E_MIX_HP_CFG */
+	#define M98095_HPNORMAL                 (3<<4)
+
+/* M98095_05F_LVL_MIC1, M98095_060_LVL_MIC2 */
+	#define M98095_MICPRE_MASK              (3<<5)
+	#define M98095_MICPRE_SHIFT             5
+
+/* M98095_064_LVL_HP_L, M98095_065_LVL_HP_R */
+	#define M98095_HP_MUTE                  (1<<7)
+
+/* M98095_066_LVL_RCV */
+	#define M98095_REC_MUTE                 (1<<7)
+
+/* M98095_067_LVL_SPK_L, M98095_068_LVL_SPK_R */
+	#define M98095_SP_MUTE                  (1<<7)
+
+/* M98095_087_CFG_MIC */
+	#define M98095_MICSEL_MASK              (3<<0)
+	#define M98095_DIGMIC_L                 (1<<2)
+	#define M98095_DIGMIC_R                 (1<<3)
+	#define M98095_DIGMIC2L                 (1<<4)
+	#define M98095_DIGMIC2R                 (1<<5)
+
+/* M98095_088_CFG_LEVEL */
+	#define M98095_VSEN                     (1<<6)
+	#define M98095_ZDEN                     (1<<5)
+	#define M98095_BQ2EN                    (1<<3)
+	#define M98095_BQ1EN                    (1<<2)
+	#define M98095_EQ2EN                    (1<<1)
+	#define M98095_EQ1EN                    (1<<0)
+
+/* M98095_090_PWR_EN_IN */
+	#define M98095_INEN                     (1<<7)
+	#define M98095_MB2EN                    (1<<3)
+	#define M98095_MB1EN                    (1<<2)
+	#define M98095_MBEN                     (3<<2)
+	#define M98095_ADREN                    (1<<1)
+	#define M98095_ADLEN                    (1<<0)
+
+/* M98095_091_PWR_EN_OUT */
+	#define M98095_HPLEN                    (1<<7)
+	#define M98095_HPREN                    (1<<6)
+	#define M98095_SPLEN                    (1<<5)
+	#define M98095_SPREN                    (1<<4)
+	#define M98095_RECEN                    (1<<3)
+	#define M98095_DALEN                    (1<<1)
+	#define M98095_DAREN                    (1<<0)
+
+/* M98095_092_PWR_EN_OUT */
+	#define M98095_SPK_FIXEDSPECTRUM        (0<<4)
+	#define M98095_SPK_SPREADSPECTRUM       (1<<4)
+
+/* M98095_097_PWR_SYS */
+	#define M98095_SHDNRUN                  (1<<7)
+	#define M98095_PERFMODE                 (1<<3)
+	#define M98095_HPPLYBACK                (1<<2)
+	#define M98095_PWRSV8K                  (1<<1)
+	#define M98095_PWRSV                    (1<<0)
+
+#define M98095_COEFS_PER_BAND            5
+
+#define M98095_BYTE1(w) ((w >> 8) & 0xff)
+#define M98095_BYTE0(w) (w & 0xff)
+
+/* Equalizer filter coefficients */
+#define M98095_110_DAI1_EQ_BASE             0x10
+#define M98095_142_DAI2_EQ_BASE             0x42
+
+/* Biquad filter coefficients */
+#define M98095_174_DAI1_BQ_BASE             0x74
+#define M98095_17E_DAI2_BQ_BASE             0x7E
+
+#endif

+ 5 - 12
sound/soc/codecs/sn95031.c

@@ -827,8 +827,6 @@ EXPORT_SYMBOL_GPL(sn95031_jack_detection);
 /* codec registration */
 /* codec registration */
 static int sn95031_codec_probe(struct snd_soc_codec *codec)
 static int sn95031_codec_probe(struct snd_soc_codec *codec)
 {
 {
-	int ret;
-
 	pr_debug("codec_probe called\n");
 	pr_debug("codec_probe called\n");
 
 
 	codec->dapm.bias_level = SND_SOC_BIAS_OFF;
 	codec->dapm.bias_level = SND_SOC_BIAS_OFF;
@@ -879,16 +877,7 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec)
 	snd_soc_add_controls(codec, sn95031_snd_controls,
 	snd_soc_add_controls(codec, sn95031_snd_controls,
 			     ARRAY_SIZE(sn95031_snd_controls));
 			     ARRAY_SIZE(sn95031_snd_controls));
 
 
-	ret = snd_soc_dapm_new_controls(&codec->dapm, sn95031_dapm_widgets,
-				ARRAY_SIZE(sn95031_dapm_widgets));
-	if (ret)
-		pr_err("soc_dapm_new_control failed %d", ret);
-	ret = snd_soc_dapm_add_routes(&codec->dapm, sn95031_audio_map,
-				ARRAY_SIZE(sn95031_audio_map));
-	if (ret)
-		pr_err("soc_dapm_add_routes failed %d", ret);
-
-	return ret;
+	return 0;
 }
 }
 
 
 static int sn95031_codec_remove(struct snd_soc_codec *codec)
 static int sn95031_codec_remove(struct snd_soc_codec *codec)
@@ -905,6 +894,10 @@ struct snd_soc_codec_driver sn95031_codec = {
 	.read		= sn95031_read,
 	.read		= sn95031_read,
 	.write		= sn95031_write,
 	.write		= sn95031_write,
 	.set_bias_level	= sn95031_set_vaud_bias,
 	.set_bias_level	= sn95031_set_vaud_bias,
+	.dapm_widgets	= sn95031_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(sn95031_dapm_widgets),
+	.dapm_routes	= sn95031_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(sn95031_audio_map),
 };
 };
 
 
 static int __devinit sn95031_device_probe(struct platform_device *pdev)
 static int __devinit sn95031_device_probe(struct platform_device *pdev)

+ 6 - 2
sound/soc/codecs/spdif_transciever.c

@@ -21,7 +21,7 @@
 #include <sound/pcm.h>
 #include <sound/pcm.h>
 #include <sound/initval.h>
 #include <sound/initval.h>
 
 
-MODULE_LICENSE("GPL");
+#define DRV_NAME "spdif-dit"
 
 
 #define STUB_RATES	SNDRV_PCM_RATE_8000_96000
 #define STUB_RATES	SNDRV_PCM_RATE_8000_96000
 #define STUB_FORMATS	SNDRV_PCM_FMTBIT_S16_LE
 #define STUB_FORMATS	SNDRV_PCM_FMTBIT_S16_LE
@@ -56,7 +56,7 @@ static struct platform_driver spdif_dit_driver = {
 	.probe		= spdif_dit_probe,
 	.probe		= spdif_dit_probe,
 	.remove		= spdif_dit_remove,
 	.remove		= spdif_dit_remove,
 	.driver		= {
 	.driver		= {
-		.name	= "spdif-dit",
+		.name	= DRV_NAME,
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,
 	},
 	},
 };
 };
@@ -74,3 +74,7 @@ static void __exit dit_exit(void)
 module_init(dit_modinit);
 module_init(dit_modinit);
 module_exit(dit_exit);
 module_exit(dit_exit);
 
 
+MODULE_AUTHOR("Steve Chen <schen@mvista.com>");
+MODULE_DESCRIPTION("SPDIF dummy codec driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);

+ 260 - 212
sound/soc/codecs/ssm2602.c

@@ -32,6 +32,7 @@
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
 #include <linux/i2c.h>
+#include <linux/spi/spi.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/core.h>
@@ -39,18 +40,25 @@
 #include <sound/pcm_params.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/soc.h>
 #include <sound/initval.h>
 #include <sound/initval.h>
+#include <sound/tlv.h>
 
 
 #include "ssm2602.h"
 #include "ssm2602.h"
 
 
 #define SSM2602_VERSION "0.1"
 #define SSM2602_VERSION "0.1"
 
 
+enum ssm2602_type {
+	SSM2602,
+	SSM2604,
+};
+
 /* codec private data */
 /* codec private data */
 struct ssm2602_priv {
 struct ssm2602_priv {
 	unsigned int sysclk;
 	unsigned int sysclk;
 	enum snd_soc_control_type control_type;
 	enum snd_soc_control_type control_type;
-	void *control_data;
 	struct snd_pcm_substream *master_substream;
 	struct snd_pcm_substream *master_substream;
 	struct snd_pcm_substream *slave_substream;
 	struct snd_pcm_substream *slave_substream;
+
+	enum ssm2602_type type;
 };
 };
 
 
 /*
 /*
@@ -60,60 +68,12 @@ struct ssm2602_priv {
  * There is no point in caching the reset register
  * There is no point in caching the reset register
  */
  */
 static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = {
 static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = {
-	0x0017, 0x0017, 0x0079, 0x0079,
-	0x0000, 0x0000, 0x0000, 0x000a,
+	0x0097, 0x0097, 0x0079, 0x0079,
+	0x000a, 0x0008, 0x009f, 0x000a,
 	0x0000, 0x0000
 	0x0000, 0x0000
 };
 };
 
 
-/*
- * read ssm2602 register cache
- */
-static inline unsigned int ssm2602_read_reg_cache(struct snd_soc_codec *codec,
-	unsigned int reg)
-{
-	u16 *cache = codec->reg_cache;
-	if (reg == SSM2602_RESET)
-		return 0;
-	if (reg >= SSM2602_CACHEREGNUM)
-		return -1;
-	return cache[reg];
-}
-
-/*
- * write ssm2602 register cache
- */
-static inline void ssm2602_write_reg_cache(struct snd_soc_codec *codec,
-	u16 reg, unsigned int value)
-{
-	u16 *cache = codec->reg_cache;
-	if (reg >= SSM2602_CACHEREGNUM)
-		return;
-	cache[reg] = value;
-}
-
-/*
- * write to the ssm2602 register space
- */
-static int ssm2602_write(struct snd_soc_codec *codec, unsigned int reg,
-	unsigned int value)
-{
-	u8 data[2];
-
-	/* data is
-	 *   D15..D9 ssm2602 register offset
-	 *   D8...D0 register data
-	 */
-	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
-	data[1] = value & 0x00ff;
-
-	ssm2602_write_reg_cache(codec, reg, value);
-	if (codec->hw_write(codec->control_data, data, 2) == 2)
-		return 0;
-	else
-		return -EIO;
-}
-
-#define ssm2602_reset(c)	ssm2602_write(c, SSM2602_RESET, 0)
+#define ssm2602_reset(c)	snd_soc_write(c, SSM2602_RESET, 0)
 
 
 /*Appending several "None"s just for OSS mixer use*/
 /*Appending several "None"s just for OSS mixer use*/
 static const char *ssm2602_input_select[] = {
 static const char *ssm2602_input_select[] = {
@@ -128,174 +88,187 @@ static const struct soc_enum ssm2602_enum[] = {
 	SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, 4, ssm2602_deemph),
 	SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, 4, ssm2602_deemph),
 };
 };
 
 
-static const struct snd_kcontrol_new ssm2602_snd_controls[] = {
+static const unsigned int ssm260x_outmix_tlv[] = {
+	TLV_DB_RANGE_HEAD(2),
+	0, 47, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
+	48, 127, TLV_DB_SCALE_ITEM(-7400, 100, 0),
+};
 
 
-SOC_DOUBLE_R("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V,
-	0, 127, 0),
-SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V,
-	7, 1, 0),
+static const DECLARE_TLV_DB_SCALE(ssm260x_inpga_tlv, -3450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(ssm260x_sidetone_tlv, -1500, 300, 0);
 
 
-SOC_DOUBLE_R("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 31, 0),
+static const struct snd_kcontrol_new ssm260x_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 45, 0,
+	ssm260x_inpga_tlv),
 SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1),
 SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1),
 
 
-SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0),
-SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 7, 1, 0),
-SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1),
-
-SOC_SINGLE("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1),
-
 SOC_SINGLE("ADC High Pass Filter Switch", SSM2602_APDIGI, 0, 1, 1),
 SOC_SINGLE("ADC High Pass Filter Switch", SSM2602_APDIGI, 0, 1, 1),
 SOC_SINGLE("Store DC Offset Switch", SSM2602_APDIGI, 4, 1, 0),
 SOC_SINGLE("Store DC Offset Switch", SSM2602_APDIGI, 4, 1, 0),
 
 
-SOC_ENUM("Capture Source", ssm2602_enum[0]),
-
 SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]),
 SOC_ENUM("Playback De-emphasis", ssm2602_enum[1]),
 };
 };
 
 
+static const struct snd_kcontrol_new ssm2602_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Master Playback Volume", SSM2602_LOUT1V, SSM2602_ROUT1V,
+	0, 127, 0, ssm260x_outmix_tlv),
+SOC_DOUBLE_R("Master Playback ZC Switch", SSM2602_LOUT1V, SSM2602_ROUT1V,
+	7, 1, 0),
+SOC_SINGLE_TLV("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1,
+	ssm260x_sidetone_tlv),
+
+SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0),
+SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 8, 1, 0),
+SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1),
+};
+
 /* Output Mixer */
 /* Output Mixer */
-static const struct snd_kcontrol_new ssm2602_output_mixer_controls[] = {
+static const struct snd_kcontrol_new ssm260x_output_mixer_controls[] = {
 SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0),
 SOC_DAPM_SINGLE("Line Bypass Switch", SSM2602_APANA, 3, 1, 0),
-SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0),
 SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0),
 SOC_DAPM_SINGLE("HiFi Playback Switch", SSM2602_APANA, 4, 1, 0),
+SOC_DAPM_SINGLE("Mic Sidetone Switch", SSM2602_APANA, 5, 1, 0),
 };
 };
 
 
 /* Input mux */
 /* Input mux */
 static const struct snd_kcontrol_new ssm2602_input_mux_controls =
 static const struct snd_kcontrol_new ssm2602_input_mux_controls =
 SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]);
 SOC_DAPM_ENUM("Input Select", ssm2602_enum[0]);
 
 
-static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = {
-SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1,
-	&ssm2602_output_mixer_controls[0],
-	ARRAY_SIZE(ssm2602_output_mixer_controls)),
+static const struct snd_soc_dapm_widget ssm260x_dapm_widgets[] = {
 SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1),
 SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM2602_PWR, 3, 1),
+SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1),
+SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("Digital Core Power", SSM2602_ACTIVE, 0, 0, NULL, 0),
+
 SND_SOC_DAPM_OUTPUT("LOUT"),
 SND_SOC_DAPM_OUTPUT("LOUT"),
-SND_SOC_DAPM_OUTPUT("LHPOUT"),
 SND_SOC_DAPM_OUTPUT("ROUT"),
 SND_SOC_DAPM_OUTPUT("ROUT"),
-SND_SOC_DAPM_OUTPUT("RHPOUT"),
-SND_SOC_DAPM_ADC("ADC", "HiFi Capture", SSM2602_PWR, 2, 1),
+SND_SOC_DAPM_INPUT("RLINEIN"),
+SND_SOC_DAPM_INPUT("LLINEIN"),
+};
+
+static const struct snd_soc_dapm_widget ssm2602_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Output Mixer", SSM2602_PWR, 4, 1,
+	ssm260x_output_mixer_controls,
+	ARRAY_SIZE(ssm260x_output_mixer_controls)),
+
 SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls),
 SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &ssm2602_input_mux_controls),
-SND_SOC_DAPM_PGA("Line Input", SSM2602_PWR, 0, 1, NULL, 0),
 SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1),
 SND_SOC_DAPM_MICBIAS("Mic Bias", SSM2602_PWR, 1, 1),
+
+SND_SOC_DAPM_OUTPUT("LHPOUT"),
+SND_SOC_DAPM_OUTPUT("RHPOUT"),
 SND_SOC_DAPM_INPUT("MICIN"),
 SND_SOC_DAPM_INPUT("MICIN"),
-SND_SOC_DAPM_INPUT("RLINEIN"),
-SND_SOC_DAPM_INPUT("LLINEIN"),
 };
 };
 
 
-static const struct snd_soc_dapm_route audio_conn[] = {
-	/* output mixer */
+static const struct snd_soc_dapm_widget ssm2604_dapm_widgets[] = {
+SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0,
+	ssm260x_output_mixer_controls,
+	ARRAY_SIZE(ssm260x_output_mixer_controls) - 1), /* Last element is the mic */
+};
+
+static const struct snd_soc_dapm_route ssm260x_routes[] = {
+	{"DAC", NULL, "Digital Core Power"},
+	{"ADC", NULL, "Digital Core Power"},
+
 	{"Output Mixer", "Line Bypass Switch", "Line Input"},
 	{"Output Mixer", "Line Bypass Switch", "Line Input"},
 	{"Output Mixer", "HiFi Playback Switch", "DAC"},
 	{"Output Mixer", "HiFi Playback Switch", "DAC"},
+
+	{"ROUT", NULL, "Output Mixer"},
+	{"LOUT", NULL, "Output Mixer"},
+
+	{"Line Input", NULL, "LLINEIN"},
+	{"Line Input", NULL, "RLINEIN"},
+};
+
+static const struct snd_soc_dapm_route ssm2602_routes[] = {
 	{"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
 	{"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
 
 
-	/* outputs */
 	{"RHPOUT", NULL, "Output Mixer"},
 	{"RHPOUT", NULL, "Output Mixer"},
-	{"ROUT", NULL, "Output Mixer"},
 	{"LHPOUT", NULL, "Output Mixer"},
 	{"LHPOUT", NULL, "Output Mixer"},
-	{"LOUT", NULL, "Output Mixer"},
 
 
-	/* input mux */
 	{"Input Mux", "Line", "Line Input"},
 	{"Input Mux", "Line", "Line Input"},
 	{"Input Mux", "Mic", "Mic Bias"},
 	{"Input Mux", "Mic", "Mic Bias"},
 	{"ADC", NULL, "Input Mux"},
 	{"ADC", NULL, "Input Mux"},
 
 
-	/* inputs */
-	{"Line Input", NULL, "LLINEIN"},
-	{"Line Input", NULL, "RLINEIN"},
 	{"Mic Bias", NULL, "MICIN"},
 	{"Mic Bias", NULL, "MICIN"},
 };
 };
 
 
-static int ssm2602_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, ssm2602_dapm_widgets,
-				  ARRAY_SIZE(ssm2602_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, audio_conn, ARRAY_SIZE(audio_conn));
-
-	return 0;
-}
+static const struct snd_soc_dapm_route ssm2604_routes[] = {
+	{"ADC", NULL, "Line Input"},
+};
 
 
-struct _coeff_div {
+struct ssm2602_coeff {
 	u32 mclk;
 	u32 mclk;
 	u32 rate;
 	u32 rate;
-	u16 fs;
-	u8 sr:4;
-	u8 bosr:1;
-	u8 usb:1;
+	u8 srate;
 };
 };
 
 
-/* codec mclk clock divider coefficients */
-static const struct _coeff_div coeff_div[] = {
+#define SSM2602_COEFF_SRATE(sr, bosr, usb) (((sr) << 2) | ((bosr) << 1) | (usb))
+
+/* codec mclk clock coefficients */
+static const struct ssm2602_coeff ssm2602_coeff_table[] = {
 	/* 48k */
 	/* 48k */
-	{12288000, 48000, 256, 0x0, 0x0, 0x0},
-	{18432000, 48000, 384, 0x0, 0x1, 0x0},
-	{12000000, 48000, 250, 0x0, 0x0, 0x1},
+	{12288000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x0)},
+	{18432000, 48000, SSM2602_COEFF_SRATE(0x0, 0x1, 0x0)},
+	{12000000, 48000, SSM2602_COEFF_SRATE(0x0, 0x0, 0x1)},
 
 
 	/* 32k */
 	/* 32k */
-	{12288000, 32000, 384, 0x6, 0x0, 0x0},
-	{18432000, 32000, 576, 0x6, 0x1, 0x0},
-	{12000000, 32000, 375, 0x6, 0x0, 0x1},
+	{12288000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x0)},
+	{18432000, 32000, SSM2602_COEFF_SRATE(0x6, 0x1, 0x0)},
+	{12000000, 32000, SSM2602_COEFF_SRATE(0x6, 0x0, 0x1)},
 
 
 	/* 8k */
 	/* 8k */
-	{12288000, 8000, 1536, 0x3, 0x0, 0x0},
-	{18432000, 8000, 2304, 0x3, 0x1, 0x0},
-	{11289600, 8000, 1408, 0xb, 0x0, 0x0},
-	{16934400, 8000, 2112, 0xb, 0x1, 0x0},
-	{12000000, 8000, 1500, 0x3, 0x0, 0x1},
+	{12288000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x0)},
+	{18432000, 8000, SSM2602_COEFF_SRATE(0x3, 0x1, 0x0)},
+	{11289600, 8000, SSM2602_COEFF_SRATE(0xb, 0x0, 0x0)},
+	{16934400, 8000, SSM2602_COEFF_SRATE(0xb, 0x1, 0x0)},
+	{12000000, 8000, SSM2602_COEFF_SRATE(0x3, 0x0, 0x1)},
 
 
 	/* 96k */
 	/* 96k */
-	{12288000, 96000, 128, 0x7, 0x0, 0x0},
-	{18432000, 96000, 192, 0x7, 0x1, 0x0},
-	{12000000, 96000, 125, 0x7, 0x0, 0x1},
+	{12288000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x0)},
+	{18432000, 96000, SSM2602_COEFF_SRATE(0x7, 0x1, 0x0)},
+	{12000000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x1)},
 
 
 	/* 44.1k */
 	/* 44.1k */
-	{11289600, 44100, 256, 0x8, 0x0, 0x0},
-	{16934400, 44100, 384, 0x8, 0x1, 0x0},
-	{12000000, 44100, 272, 0x8, 0x1, 0x1},
+	{11289600, 44100, SSM2602_COEFF_SRATE(0x8, 0x0, 0x0)},
+	{16934400, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x0)},
+	{12000000, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x1)},
 
 
 	/* 88.2k */
 	/* 88.2k */
-	{11289600, 88200, 128, 0xf, 0x0, 0x0},
-	{16934400, 88200, 192, 0xf, 0x1, 0x0},
-	{12000000, 88200, 136, 0xf, 0x1, 0x1},
+	{11289600, 88200, SSM2602_COEFF_SRATE(0xf, 0x0, 0x0)},
+	{16934400, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x0)},
+	{12000000, 88200, SSM2602_COEFF_SRATE(0xf, 0x1, 0x1)},
 };
 };
 
 
-static inline int get_coeff(int mclk, int rate)
+static inline int ssm2602_get_coeff(int mclk, int rate)
 {
 {
 	int i;
 	int i;
 
 
-	for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
-		if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
-			return i;
+	for (i = 0; i < ARRAY_SIZE(ssm2602_coeff_table); i++) {
+		if (ssm2602_coeff_table[i].rate == rate &&
+			ssm2602_coeff_table[i].mclk == mclk)
+			return ssm2602_coeff_table[i].srate;
 	}
 	}
-	return i;
+	return -EINVAL;
 }
 }
 
 
 static int ssm2602_hw_params(struct snd_pcm_substream *substream,
 static int ssm2602_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params,
 	struct snd_pcm_hw_params *params,
 	struct snd_soc_dai *dai)
 	struct snd_soc_dai *dai)
 {
 {
-	u16 srate;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_codec *codec = rtd->codec;
 	struct snd_soc_codec *codec = rtd->codec;
 	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
-	struct i2c_client *i2c = codec->control_data;
-	u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3;
-	int i = get_coeff(ssm2602->sysclk, params_rate(params));
+	u16 iface = snd_soc_read(codec, SSM2602_IFACE) & 0xfff3;
+	int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params));
 
 
 	if (substream == ssm2602->slave_substream) {
 	if (substream == ssm2602->slave_substream) {
-		dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n");
+		dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n");
 		return 0;
 		return 0;
 	}
 	}
 
 
-	/*no match is found*/
-	if (i == ARRAY_SIZE(coeff_div))
-		return -EINVAL;
-
-	srate = (coeff_div[i].sr << 2) |
-		(coeff_div[i].bosr << 1) | coeff_div[i].usb;
+	if (srate < 0)
+		return srate;
 
 
-	ssm2602_write(codec, SSM2602_ACTIVE, 0);
-	ssm2602_write(codec, SSM2602_SRATE, srate);
+	snd_soc_write(codec, SSM2602_SRATE, srate);
 
 
 	/* bit size */
 	/* bit size */
 	switch (params_format(params)) {
 	switch (params_format(params)) {
@@ -311,8 +284,7 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
 		iface |= 0x000c;
 		iface |= 0x000c;
 		break;
 		break;
 	}
 	}
-	ssm2602_write(codec, SSM2602_IFACE, iface);
-	ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
+	snd_soc_write(codec, SSM2602_IFACE, iface);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -354,17 +326,6 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
 	return 0;
 	return 0;
 }
 }
 
 
-static int ssm2602_pcm_prepare(struct snd_pcm_substream *substream,
-			       struct snd_soc_dai *dai)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_codec *codec = rtd->codec;
-	/* set active */
-	ssm2602_write(codec, SSM2602_ACTIVE, ACTIVE_ACTIVATE_CODEC);
-
-	return 0;
-}
-
 static void ssm2602_shutdown(struct snd_pcm_substream *substream,
 static void ssm2602_shutdown(struct snd_pcm_substream *substream,
 			     struct snd_soc_dai *dai)
 			     struct snd_soc_dai *dai)
 {
 {
@@ -372,25 +333,22 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream,
 	struct snd_soc_codec *codec = rtd->codec;
 	struct snd_soc_codec *codec = rtd->codec;
 	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 
 
-	/* deactivate */
-	if (!codec->active)
-		ssm2602_write(codec, SSM2602_ACTIVE, 0);
-
 	if (ssm2602->master_substream == substream)
 	if (ssm2602->master_substream == substream)
 		ssm2602->master_substream = ssm2602->slave_substream;
 		ssm2602->master_substream = ssm2602->slave_substream;
 
 
 	ssm2602->slave_substream = NULL;
 	ssm2602->slave_substream = NULL;
 }
 }
 
 
+
 static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
 static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
 {
 {
 	struct snd_soc_codec *codec = dai->codec;
 	struct snd_soc_codec *codec = dai->codec;
-	u16 mute_reg = ssm2602_read_reg_cache(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE;
+	u16 mute_reg = snd_soc_read(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE;
 	if (mute)
 	if (mute)
-		ssm2602_write(codec, SSM2602_APDIGI,
+		snd_soc_write(codec, SSM2602_APDIGI,
 				mute_reg | APDIGI_ENABLE_DAC_MUTE);
 				mute_reg | APDIGI_ENABLE_DAC_MUTE);
 	else
 	else
-		ssm2602_write(codec, SSM2602_APDIGI, mute_reg);
+		snd_soc_write(codec, SSM2602_APDIGI, mute_reg);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -466,30 +424,29 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
 	}
 	}
 
 
 	/* set iface */
 	/* set iface */
-	ssm2602_write(codec, SSM2602_IFACE, iface);
+	snd_soc_write(codec, SSM2602_IFACE, iface);
 	return 0;
 	return 0;
 }
 }
 
 
 static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
 static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 				 enum snd_soc_bias_level level)
 {
 {
-	u16 reg = ssm2602_read_reg_cache(codec, SSM2602_PWR) & 0xff7f;
+	u16 reg = snd_soc_read(codec, SSM2602_PWR) & 0xff7f;
 
 
 	switch (level) {
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 	case SND_SOC_BIAS_ON:
 		/* vref/mid, osc on, dac unmute */
 		/* vref/mid, osc on, dac unmute */
-		ssm2602_write(codec, SSM2602_PWR, reg);
+		snd_soc_write(codec, SSM2602_PWR, reg);
 		break;
 		break;
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_PREPARE:
 		break;
 		break;
 	case SND_SOC_BIAS_STANDBY:
 	case SND_SOC_BIAS_STANDBY:
 		/* everything off except vref/vmid, */
 		/* everything off except vref/vmid, */
-		ssm2602_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN);
+		snd_soc_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN);
 		break;
 		break;
 	case SND_SOC_BIAS_OFF:
 	case SND_SOC_BIAS_OFF:
 		/* everything off, dac mute, inactive */
 		/* everything off, dac mute, inactive */
-		ssm2602_write(codec, SSM2602_ACTIVE, 0);
-		ssm2602_write(codec, SSM2602_PWR, 0xffff);
+		snd_soc_write(codec, SSM2602_PWR, 0xffff);
 		break;
 		break;
 
 
 	}
 	}
@@ -506,7 +463,6 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
 
 
 static struct snd_soc_dai_ops ssm2602_dai_ops = {
 static struct snd_soc_dai_ops ssm2602_dai_ops = {
 	.startup	= ssm2602_startup,
 	.startup	= ssm2602_startup,
-	.prepare	= ssm2602_pcm_prepare,
 	.hw_params	= ssm2602_hw_params,
 	.hw_params	= ssm2602_hw_params,
 	.shutdown	= ssm2602_shutdown,
 	.shutdown	= ssm2602_shutdown,
 	.digital_mute	= ssm2602_mute,
 	.digital_mute	= ssm2602_mute,
@@ -539,50 +495,87 @@ static int ssm2602_suspend(struct snd_soc_codec *codec, pm_message_t state)
 
 
 static int ssm2602_resume(struct snd_soc_codec *codec)
 static int ssm2602_resume(struct snd_soc_codec *codec)
 {
 {
-	int i;
-	u8 data[2];
-	u16 *cache = codec->reg_cache;
-
-	/* Sync reg_cache with the hardware */
-	for (i = 0; i < ARRAY_SIZE(ssm2602_reg); i++) {
-		data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
-		data[1] = cache[i] & 0x00ff;
-		codec->hw_write(codec->control_data, data, 2);
-	}
+	snd_soc_cache_sync(codec);
+
 	ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
 	return 0;
 	return 0;
 }
 }
 
 
 static int ssm2602_probe(struct snd_soc_codec *codec)
 static int ssm2602_probe(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	int ret, reg;
+
+	reg = snd_soc_read(codec, SSM2602_LOUT1V);
+	snd_soc_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH);
+	reg = snd_soc_read(codec, SSM2602_ROUT1V);
+	snd_soc_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH);
+
+	ret = snd_soc_add_controls(codec, ssm2602_snd_controls,
+			ARRAY_SIZE(ssm2602_snd_controls));
+	if (ret)
+		return ret;
+
+	ret = snd_soc_dapm_new_controls(dapm, ssm2602_dapm_widgets,
+			ARRAY_SIZE(ssm2602_dapm_widgets));
+	if (ret)
+		return ret;
+
+	return snd_soc_dapm_add_routes(dapm, ssm2602_routes,
+			ARRAY_SIZE(ssm2602_routes));
+}
+
+static int ssm2604_probe(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	int ret;
+
+	ret = snd_soc_dapm_new_controls(dapm, ssm2604_dapm_widgets,
+			ARRAY_SIZE(ssm2604_dapm_widgets));
+	if (ret)
+		return ret;
+
+	return snd_soc_dapm_add_routes(dapm, ssm2604_routes,
+			ARRAY_SIZE(ssm2604_routes));
+}
+
+static int ssm260x_probe(struct snd_soc_codec *codec)
 {
 {
 	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
 	struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
-	int ret = 0, reg;
+	int ret, reg;
 
 
 	pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
 	pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
 
 
-	codec->control_data = ssm2602->control_data;
+	ret = snd_soc_codec_set_cache_io(codec, 7, 9, ssm2602->control_type);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
 
 
-	ssm2602_reset(codec);
+	ret = ssm2602_reset(codec);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
+		return ret;
+	}
 
 
-	/*power on device*/
-	ssm2602_write(codec, SSM2602_ACTIVE, 0);
 	/* set the update bits */
 	/* set the update bits */
-	reg = ssm2602_read_reg_cache(codec, SSM2602_LINVOL);
-	ssm2602_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH);
-	reg = ssm2602_read_reg_cache(codec, SSM2602_RINVOL);
-	ssm2602_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH);
-	reg = ssm2602_read_reg_cache(codec, SSM2602_LOUT1V);
-	ssm2602_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH);
-	reg = ssm2602_read_reg_cache(codec, SSM2602_ROUT1V);
-	ssm2602_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH);
+	reg = snd_soc_read(codec, SSM2602_LINVOL);
+	snd_soc_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH);
+	reg = snd_soc_read(codec, SSM2602_RINVOL);
+	snd_soc_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH);
 	/*select Line in as default input*/
 	/*select Line in as default input*/
-	ssm2602_write(codec, SSM2602_APANA, APANA_SELECT_DAC |
+	snd_soc_write(codec, SSM2602_APANA, APANA_SELECT_DAC |
 			APANA_ENABLE_MIC_BOOST);
 			APANA_ENABLE_MIC_BOOST);
-	ssm2602_write(codec, SSM2602_PWR, 0);
 
 
-	snd_soc_add_controls(codec, ssm2602_snd_controls,
-				ARRAY_SIZE(ssm2602_snd_controls));
-	ssm2602_add_widgets(codec);
+	switch (ssm2602->type) {
+	case SSM2602:
+		ret = ssm2602_probe(codec);
+		break;
+	case SSM2604:
+		ret = ssm2604_probe(codec);
+		break;
+	}
 
 
 	return ret;
 	return ret;
 }
 }
@@ -595,18 +588,61 @@ static int ssm2602_remove(struct snd_soc_codec *codec)
 }
 }
 
 
 static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
 static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
-	.probe =	ssm2602_probe,
+	.probe =	ssm260x_probe,
 	.remove =	ssm2602_remove,
 	.remove =	ssm2602_remove,
 	.suspend =	ssm2602_suspend,
 	.suspend =	ssm2602_suspend,
 	.resume =	ssm2602_resume,
 	.resume =	ssm2602_resume,
-	.read = ssm2602_read_reg_cache,
-	.write = ssm2602_write,
 	.set_bias_level = ssm2602_set_bias_level,
 	.set_bias_level = ssm2602_set_bias_level,
-	.reg_cache_size = sizeof(ssm2602_reg),
+	.reg_cache_size = ARRAY_SIZE(ssm2602_reg),
 	.reg_word_size = sizeof(u16),
 	.reg_word_size = sizeof(u16),
 	.reg_cache_default = ssm2602_reg,
 	.reg_cache_default = ssm2602_reg,
+
+	.controls = ssm260x_snd_controls,
+	.num_controls = ARRAY_SIZE(ssm260x_snd_controls),
+	.dapm_widgets = ssm260x_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(ssm260x_dapm_widgets),
+	.dapm_routes = ssm260x_routes,
+	.num_dapm_routes = ARRAY_SIZE(ssm260x_routes),
 };
 };
 
 
+#if defined(CONFIG_SPI_MASTER)
+static int __devinit ssm2602_spi_probe(struct spi_device *spi)
+{
+	struct ssm2602_priv *ssm2602;
+	int ret;
+
+	ssm2602 = kzalloc(sizeof(struct ssm2602_priv), GFP_KERNEL);
+	if (ssm2602 == NULL)
+		return -ENOMEM;
+
+	spi_set_drvdata(spi, ssm2602);
+	ssm2602->control_type = SND_SOC_SPI;
+	ssm2602->type = SSM2602;
+
+	ret = snd_soc_register_codec(&spi->dev,
+			&soc_codec_dev_ssm2602, &ssm2602_dai, 1);
+	if (ret < 0)
+		kfree(ssm2602);
+	return ret;
+}
+
+static int __devexit ssm2602_spi_remove(struct spi_device *spi)
+{
+	snd_soc_unregister_codec(&spi->dev);
+	kfree(spi_get_drvdata(spi));
+	return 0;
+}
+
+static struct spi_driver ssm2602_spi_driver = {
+	.driver = {
+		.name	= "ssm2602",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ssm2602_spi_probe,
+	.remove		= __devexit_p(ssm2602_spi_remove),
+};
+#endif
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 /*
 /*
  * ssm2602 2 wire address is determined by GPIO5
  * ssm2602 2 wire address is determined by GPIO5
@@ -614,7 +650,7 @@ static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
  *    low  = 0x1a
  *    low  = 0x1a
  *    high = 0x1b
  *    high = 0x1b
  */
  */
-static int ssm2602_i2c_probe(struct i2c_client *i2c,
+static int __devinit ssm2602_i2c_probe(struct i2c_client *i2c,
 			     const struct i2c_device_id *id)
 			     const struct i2c_device_id *id)
 {
 {
 	struct ssm2602_priv *ssm2602;
 	struct ssm2602_priv *ssm2602;
@@ -625,8 +661,8 @@ static int ssm2602_i2c_probe(struct i2c_client *i2c,
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	i2c_set_clientdata(i2c, ssm2602);
 	i2c_set_clientdata(i2c, ssm2602);
-	ssm2602->control_data = i2c;
 	ssm2602->control_type = SND_SOC_I2C;
 	ssm2602->control_type = SND_SOC_I2C;
+	ssm2602->type = id->driver_data;
 
 
 	ret = snd_soc_register_codec(&i2c->dev,
 	ret = snd_soc_register_codec(&i2c->dev,
 			&soc_codec_dev_ssm2602, &ssm2602_dai, 1);
 			&soc_codec_dev_ssm2602, &ssm2602_dai, 1);
@@ -635,7 +671,7 @@ static int ssm2602_i2c_probe(struct i2c_client *i2c,
 	return ret;
 	return ret;
 }
 }
 
 
-static int ssm2602_i2c_remove(struct i2c_client *client)
+static int __devexit ssm2602_i2c_remove(struct i2c_client *client)
 {
 {
 	snd_soc_unregister_codec(&client->dev);
 	snd_soc_unregister_codec(&client->dev);
 	kfree(i2c_get_clientdata(client));
 	kfree(i2c_get_clientdata(client));
@@ -643,7 +679,9 @@ static int ssm2602_i2c_remove(struct i2c_client *client)
 }
 }
 
 
 static const struct i2c_device_id ssm2602_i2c_id[] = {
 static const struct i2c_device_id ssm2602_i2c_id[] = {
-	{ "ssm2602", 0 },
+	{ "ssm2602", SSM2602 },
+	{ "ssm2603", SSM2602 },
+	{ "ssm2604", SSM2604 },
 	{ }
 	{ }
 };
 };
 MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
 MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
@@ -651,11 +689,11 @@ MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id);
 /* corgi i2c codec control layer */
 /* corgi i2c codec control layer */
 static struct i2c_driver ssm2602_i2c_driver = {
 static struct i2c_driver ssm2602_i2c_driver = {
 	.driver = {
 	.driver = {
-		.name = "ssm2602-codec",
+		.name = "ssm2602",
 		.owner = THIS_MODULE,
 		.owner = THIS_MODULE,
 	},
 	},
 	.probe = ssm2602_i2c_probe,
 	.probe = ssm2602_i2c_probe,
-	.remove = ssm2602_i2c_remove,
+	.remove = __devexit_p(ssm2602_i2c_remove),
 	.id_table = ssm2602_i2c_id,
 	.id_table = ssm2602_i2c_id,
 };
 };
 #endif
 #endif
@@ -664,25 +702,35 @@ static struct i2c_driver ssm2602_i2c_driver = {
 static int __init ssm2602_modinit(void)
 static int __init ssm2602_modinit(void)
 {
 {
 	int ret = 0;
 	int ret = 0;
+
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&ssm2602_spi_driver);
+	if (ret)
+		return ret;
+#endif
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	ret = i2c_add_driver(&ssm2602_i2c_driver);
 	ret = i2c_add_driver(&ssm2602_i2c_driver);
-	if (ret != 0) {
-		printk(KERN_ERR "Failed to register SSM2602 I2C driver: %d\n",
-		       ret);
-	}
+	if (ret)
+		return ret;
 #endif
 #endif
+
 	return ret;
 	return ret;
 }
 }
 module_init(ssm2602_modinit);
 module_init(ssm2602_modinit);
 
 
 static void __exit ssm2602_exit(void)
 static void __exit ssm2602_exit(void)
 {
 {
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&ssm2602_spi_driver);
+#endif
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	i2c_del_driver(&ssm2602_i2c_driver);
 	i2c_del_driver(&ssm2602_i2c_driver);
 #endif
 #endif
 }
 }
 module_exit(ssm2602_exit);
 module_exit(ssm2602_exit);
 
 
-MODULE_DESCRIPTION("ASoC ssm2602 driver");
+MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 driver");
 MODULE_AUTHOR("Cliff Cai");
 MODULE_AUTHOR("Cliff Cai");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");

+ 0 - 6
sound/soc/codecs/ssm2602.h

@@ -117,11 +117,5 @@
 #define SSM2602_CACHEREGNUM 	10
 #define SSM2602_CACHEREGNUM 	10
 
 
 #define SSM2602_SYSCLK	0
 #define SSM2602_SYSCLK	0
-#define SSM2602_DAI		0
-
-struct ssm2602_setup_data {
-	int i2c_bus;
-	unsigned short i2c_address;
-};
 
 
 #endif
 #endif

+ 5 - 14
sound/soc/codecs/tlv320aic23.c

@@ -212,7 +212,7 @@ static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
 	SND_SOC_DAPM_INPUT("MICIN"),
 	SND_SOC_DAPM_INPUT("MICIN"),
 };
 };
 
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route tlv320aic23_intercon[] = {
 	/* Output Mixer */
 	/* Output Mixer */
 	{"Output Mixer", "Line Bypass Switch", "Line Input"},
 	{"Output Mixer", "Line Bypass Switch", "Line Input"},
 	{"Output Mixer", "Playback Switch", "DAC"},
 	{"Output Mixer", "Playback Switch", "DAC"},
@@ -388,18 +388,6 @@ static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk,
 	return 0;
 	return 0;
 }
 }
 
 
-static int tlv320aic23_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets,
-				  ARRAY_SIZE(tlv320aic23_dapm_widgets));
-	/* set up audio path interconnects */
-	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-	return 0;
-}
-
 static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
 static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *dai)
 				 struct snd_soc_dai *dai)
@@ -676,7 +664,6 @@ static int tlv320aic23_probe(struct snd_soc_codec *codec)
 
 
 	snd_soc_add_controls(codec, tlv320aic23_snd_controls,
 	snd_soc_add_controls(codec, tlv320aic23_snd_controls,
 				ARRAY_SIZE(tlv320aic23_snd_controls));
 				ARRAY_SIZE(tlv320aic23_snd_controls));
-	tlv320aic23_add_widgets(codec);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -698,6 +685,10 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
 	.read = tlv320aic23_read_reg_cache,
 	.read = tlv320aic23_read_reg_cache,
 	.write = tlv320aic23_write,
 	.write = tlv320aic23_write,
 	.set_bias_level = tlv320aic23_set_bias_level,
 	.set_bias_level = tlv320aic23_set_bias_level,
+	.dapm_widgets = tlv320aic23_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
+	.dapm_routes = tlv320aic23_intercon,
+	.num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon),
 };
 };
 
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)

+ 2 - 1
sound/soc/codecs/tlv320aic3x.c

@@ -157,7 +157,8 @@ static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg,
 static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
 static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
 					struct snd_ctl_elem_value *ucontrol)
 					struct snd_ctl_elem_value *ucontrol)
 {
 {
-	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct soc_mixer_control *mc =
 	struct soc_mixer_control *mc =
 		(struct soc_mixer_control *)kcontrol->private_value;
 		(struct soc_mixer_control *)kcontrol->private_value;
 	unsigned int reg = mc->reg;
 	unsigned int reg = mc->reg;

+ 10 - 7
sound/soc/codecs/tlv320dac33.c

@@ -1,7 +1,7 @@
 /*
 /*
  * ALSA SoC Texas Instruments TLV320DAC33 codec driver
  * ALSA SoC Texas Instruments TLV320DAC33 codec driver
  *
  *
- * Author:	Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  *
  * Copyright:   (C) 2009 Nokia Corporation
  * Copyright:   (C) 2009 Nokia Corporation
  *
  *
@@ -587,6 +587,9 @@ static const struct snd_soc_dapm_widget dac33_dapm_widgets[] = {
 	SND_SOC_DAPM_SUPPLY("Right DAC Power",
 	SND_SOC_DAPM_SUPPLY("Right DAC Power",
 			    DAC33_RDAC_PWR_CTRL, 2, 0, NULL, 0),
 			    DAC33_RDAC_PWR_CTRL, 2, 0, NULL, 0),
 
 
+	SND_SOC_DAPM_SUPPLY("Codec Power",
+			    DAC33_PWR_CTRL, 4, 0, NULL, 0),
+
 	SND_SOC_DAPM_PRE("Pre Playback", dac33_playback_event),
 	SND_SOC_DAPM_PRE("Pre Playback", dac33_playback_event),
 	SND_SOC_DAPM_POST("Post Playback", dac33_playback_event),
 	SND_SOC_DAPM_POST("Post Playback", dac33_playback_event),
 };
 };
@@ -619,6 +622,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	/* output */
 	/* output */
 	{"LEFT_LO", NULL, "Output Left Amplifier"},
 	{"LEFT_LO", NULL, "Output Left Amplifier"},
 	{"RIGHT_LO", NULL, "Output Right Amplifier"},
 	{"RIGHT_LO", NULL, "Output Right Amplifier"},
+
+	{"LEFT_LO", NULL, "Codec Power"},
+	{"RIGHT_LO", NULL, "Codec Power"},
 };
 };
 
 
 static int dac33_add_widgets(struct snd_soc_codec *codec)
 static int dac33_add_widgets(struct snd_soc_codec *codec)
@@ -636,13 +642,10 @@ static int dac33_add_widgets(struct snd_soc_codec *codec)
 static int dac33_set_bias_level(struct snd_soc_codec *codec,
 static int dac33_set_bias_level(struct snd_soc_codec *codec,
 				enum snd_soc_bias_level level)
 				enum snd_soc_bias_level level)
 {
 {
-	struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 	int ret;
 	int ret;
 
 
 	switch (level) {
 	switch (level) {
 	case SND_SOC_BIAS_ON:
 	case SND_SOC_BIAS_ON:
-		if (!dac33->substream)
-			dac33_soft_power(codec, 1);
 		break;
 		break;
 	case SND_SOC_BIAS_PREPARE:
 	case SND_SOC_BIAS_PREPARE:
 		break;
 		break;
@@ -943,8 +946,8 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
 	/* Write registers 0x08 and 0x09 (MSB, LSB) */
 	/* Write registers 0x08 and 0x09 (MSB, LSB) */
 	dac33_write16(codec, DAC33_INT_OSC_FREQ_RAT_A, oscset);
 	dac33_write16(codec, DAC33_INT_OSC_FREQ_RAT_A, oscset);
 
 
-	/* calib time: 128 is a nice number ;) */
-	dac33_write(codec, DAC33_CALIB_TIME, 128);
+	/* OSC calibration time */
+	dac33_write(codec, DAC33_CALIB_TIME, 96);
 
 
 	/* adjustment treshold & step */
 	/* adjustment treshold & step */
 	dac33_write(codec, DAC33_INT_OSC_CTRL_B, DAC33_ADJTHRSHLD(2) |
 	dac33_write(codec, DAC33_INT_OSC_CTRL_B, DAC33_ADJTHRSHLD(2) |
@@ -1655,5 +1658,5 @@ module_exit(dac33_module_exit);
 
 
 
 
 MODULE_DESCRIPTION("ASoC TLV320DAC33 codec driver");
 MODULE_DESCRIPTION("ASoC TLV320DAC33 codec driver");
-MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@nokia.com>");
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");

+ 1 - 1
sound/soc/codecs/tlv320dac33.h

@@ -1,7 +1,7 @@
 /*
 /*
  * ALSA SoC Texas Instruments TLV320DAC33 codec driver
  * ALSA SoC Texas Instruments TLV320DAC33 codec driver
  *
  *
- * Author:	Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  *
  * Copyright:   (C) 2009 Nokia Corporation
  * Copyright:   (C) 2009 Nokia Corporation
  *
  *

+ 2 - 2
sound/soc/codecs/tpa6130a2.c

@@ -3,7 +3,7 @@
  *
  *
  * Copyright (C) Nokia Corporation
  * Copyright (C) Nokia Corporation
  *
  *
- * Author: Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  *
  * This program is free software; you can redistribute it and/or
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * modify it under the terms of the GNU General Public License
@@ -495,7 +495,7 @@ static void __exit tpa6130a2_exit(void)
 	i2c_del_driver(&tpa6130a2_i2c_driver);
 	i2c_del_driver(&tpa6130a2_i2c_driver);
 }
 }
 
 
-MODULE_AUTHOR("Peter Ujfalusi");
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
 MODULE_DESCRIPTION("TPA6130A2 Headphone amplifier driver");
 MODULE_DESCRIPTION("TPA6130A2 Headphone amplifier driver");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 
 

+ 1 - 1
sound/soc/codecs/tpa6130a2.h

@@ -3,7 +3,7 @@
  *
  *
  * Copyright (C) Nokia Corporation
  * Copyright (C) Nokia Corporation
  *
  *
- * Author: Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  *
  * This program is free software; you can redistribute it and/or
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * modify it under the terms of the GNU General Public License

+ 3 - 3
sound/soc/codecs/twl6040.c

@@ -960,9 +960,9 @@ static DECLARE_TLV_DB_SCALE(mic_amp_tlv, -600, 600, 0);
 
 
 /*
 /*
  * AFMGAIN volume control:
  * AFMGAIN volume control:
- * from 18 to 24 dB in 6 dB steps
+ * from -18 to 24 dB in 6 dB steps
  */
  */
-static DECLARE_TLV_DB_SCALE(afm_amp_tlv, 1800, 600, 0);
+static DECLARE_TLV_DB_SCALE(afm_amp_tlv, -1800, 600, 0);
 
 
 /*
 /*
  * HSGAIN volume control:
  * HSGAIN volume control:
@@ -1049,7 +1049,7 @@ static const struct snd_kcontrol_new twl6040_snd_controls[] = {
 
 
 	/* AFM gains */
 	/* AFM gains */
 	SOC_DOUBLE_TLV("Aux FM Volume",
 	SOC_DOUBLE_TLV("Aux FM Volume",
-		TWL6040_REG_LINEGAIN, 0, 4, 0xF, 0, afm_amp_tlv),
+		TWL6040_REG_LINEGAIN, 0, 3, 7, 0, afm_amp_tlv),
 
 
 	/* Playback gains */
 	/* Playback gains */
 	SOC_TWL6040_DOUBLE_TLV("Headset Playback Volume",
 	SOC_TWL6040_DOUBLE_TLV("Headset Playback Volume",

+ 0 - 2
sound/soc/codecs/uda134x.c

@@ -601,9 +601,7 @@ static struct snd_soc_codec_driver soc_codec_dev_uda134x = {
 	.reg_cache_step = 1,
 	.reg_cache_step = 1,
 	.read = uda134x_read_reg_cache,
 	.read = uda134x_read_reg_cache,
 	.write = uda134x_write,
 	.write = uda134x_write,
-#ifdef POWER_OFF_ON_STANDBY
 	.set_bias_level = uda134x_set_bias_level,
 	.set_bias_level = uda134x_set_bias_level,
-#endif
 };
 };
 
 
 static int __devinit uda134x_codec_probe(struct platform_device *pdev)
 static int __devinit uda134x_codec_probe(struct platform_device *pdev)

+ 108 - 0
sound/soc/codecs/wm1250-ev1.c

@@ -0,0 +1,108 @@
+/*
+ * Driver for the 1250-EV1 audio I/O module
+ *
+ * Copyright 2011 Wolfson Microelectronics plc
+ *
+ *  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.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+static const struct snd_soc_dapm_widget wm1250_ev1_dapm_widgets[] = {
+SND_SOC_DAPM_ADC("ADC", "wm1250-ev1 Capture", SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_DAC("DAC", "wm1250-ev1 Playback", SND_SOC_NOPM, 0, 0),
+
+SND_SOC_DAPM_INPUT("WM1250 Input"),
+SND_SOC_DAPM_INPUT("WM1250 Output"),
+};
+
+static const struct snd_soc_dapm_route wm1250_ev1_dapm_routes[] = {
+	{ "ADC", NULL, "WM1250 Input" },
+	{ "WM1250 Output", NULL, "DAC" },
+};
+
+static struct snd_soc_dai_driver wm1250_ev1_dai = {
+	.name = "wm1250-ev1",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm1250_ev1 = {
+	.dapm_widgets = wm1250_ev1_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm1250_ev1_dapm_widgets),
+	.dapm_routes = wm1250_ev1_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(wm1250_ev1_dapm_routes),
+};
+
+static int __devinit wm1250_ev1_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
+{
+	return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm1250_ev1,
+				      &wm1250_ev1_dai, 1);
+}
+
+static int __devexit wm1250_ev1_remove(struct i2c_client *i2c)
+{
+	snd_soc_unregister_codec(&i2c->dev);
+
+	return 0;
+}
+
+static const struct i2c_device_id wm1250_ev1_i2c_id[] = {
+	{ "wm1250-ev1", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm1250_ev1_i2c_id);
+
+static struct i2c_driver wm1250_ev1_i2c_driver = {
+	.driver = {
+		.name = "wm1250-ev1",
+		.owner = THIS_MODULE,
+	},
+	.probe =    wm1250_ev1_probe,
+	.remove =   __devexit_p(wm1250_ev1_remove),
+	.id_table = wm1250_ev1_i2c_id,
+};
+
+static int __init wm1250_ev1_modinit(void)
+{
+	int ret = 0;
+
+	ret = i2c_add_driver(&wm1250_ev1_i2c_driver);
+	if (ret != 0)
+		pr_err("Failed to register WM1250-EV1 I2C driver: %d\n", ret);
+
+	return ret;
+}
+module_init(wm1250_ev1_modinit);
+
+static void __exit wm1250_ev1_exit(void)
+{
+	i2c_del_driver(&wm1250_ev1_i2c_driver);
+}
+module_exit(wm1250_ev1_exit);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM1250-EV1 audio I/O module driver");
+MODULE_LICENSE("GPL");

+ 5 - 13
sound/soc/codecs/wm8711.c

@@ -77,7 +77,7 @@ SND_SOC_DAPM_OUTPUT("ROUT"),
 SND_SOC_DAPM_OUTPUT("RHPOUT"),
 SND_SOC_DAPM_OUTPUT("RHPOUT"),
 };
 };
 
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route wm8711_intercon[] = {
 	/* output mixer */
 	/* output mixer */
 	{"Output Mixer", "Line Bypass Switch", "Line Input"},
 	{"Output Mixer", "Line Bypass Switch", "Line Input"},
 	{"Output Mixer", "HiFi Playback Switch", "DAC"},
 	{"Output Mixer", "HiFi Playback Switch", "DAC"},
@@ -89,17 +89,6 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"LOUT", NULL, "Output Mixer"},
 	{"LOUT", NULL, "Output Mixer"},
 };
 };
 
 
-static int wm8711_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, wm8711_dapm_widgets,
-				  ARRAY_SIZE(wm8711_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-	return 0;
-}
-
 struct _coeff_div {
 struct _coeff_div {
 	u32 mclk;
 	u32 mclk;
 	u32 rate;
 	u32 rate;
@@ -398,7 +387,6 @@ static int wm8711_probe(struct snd_soc_codec *codec)
 
 
 	snd_soc_add_controls(codec, wm8711_snd_controls,
 	snd_soc_add_controls(codec, wm8711_snd_controls,
 			     ARRAY_SIZE(wm8711_snd_controls));
 			     ARRAY_SIZE(wm8711_snd_controls));
-	wm8711_add_widgets(codec);
 
 
 	return ret;
 	return ret;
 
 
@@ -420,6 +408,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8711 = {
 	.reg_cache_size = ARRAY_SIZE(wm8711_reg),
 	.reg_cache_size = ARRAY_SIZE(wm8711_reg),
 	.reg_word_size = sizeof(u16),
 	.reg_word_size = sizeof(u16),
 	.reg_cache_default = wm8711_reg,
 	.reg_cache_default = wm8711_reg,
+	.dapm_widgets = wm8711_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8711_dapm_widgets),
+	.dapm_routes = wm8711_intercon,
+	.num_dapm_routes = ARRAY_SIZE(wm8711_intercon),
 };
 };
 
 
 #if defined(CONFIG_SPI_MASTER)
 #if defined(CONFIG_SPI_MASTER)

+ 5 - 13
sound/soc/codecs/wm8728.c

@@ -65,22 +65,11 @@ SND_SOC_DAPM_OUTPUT("VOUTL"),
 SND_SOC_DAPM_OUTPUT("VOUTR"),
 SND_SOC_DAPM_OUTPUT("VOUTR"),
 };
 };
 
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route wm8728_intercon[] = {
 	{"VOUTL", NULL, "DAC"},
 	{"VOUTL", NULL, "DAC"},
 	{"VOUTR", NULL, "DAC"},
 	{"VOUTR", NULL, "DAC"},
 };
 };
 
 
-static int wm8728_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, wm8728_dapm_widgets,
-				  ARRAY_SIZE(wm8728_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-	return 0;
-}
-
 static int wm8728_mute(struct snd_soc_dai *dai, int mute)
 static int wm8728_mute(struct snd_soc_dai *dai, int mute)
 {
 {
 	struct snd_soc_codec *codec = dai->codec;
 	struct snd_soc_codec *codec = dai->codec;
@@ -255,7 +244,6 @@ static int wm8728_probe(struct snd_soc_codec *codec)
 
 
 	snd_soc_add_controls(codec, wm8728_snd_controls,
 	snd_soc_add_controls(codec, wm8728_snd_controls,
 				ARRAY_SIZE(wm8728_snd_controls));
 				ARRAY_SIZE(wm8728_snd_controls));
-	wm8728_add_widgets(codec);
 
 
 	return ret;
 	return ret;
 }
 }
@@ -275,6 +263,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8728 = {
 	.reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults),
 	.reg_cache_size = ARRAY_SIZE(wm8728_reg_defaults),
 	.reg_word_size = sizeof(u16),
 	.reg_word_size = sizeof(u16),
 	.reg_cache_default = wm8728_reg_defaults,
 	.reg_cache_default = wm8728_reg_defaults,
+	.dapm_widgets = wm8728_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8728_dapm_widgets),
+	.dapm_routes = wm8728_intercon,
+	.num_dapm_routes = ARRAY_SIZE(wm8728_intercon),
 };
 };
 
 
 #if defined(CONFIG_SPI_MASTER)
 #if defined(CONFIG_SPI_MASTER)

+ 7 - 15
sound/soc/codecs/wm8731.c

@@ -201,7 +201,7 @@ static int wm8731_check_osc(struct snd_soc_dapm_widget *source,
 	return wm8731->sysclk_type == WM8731_SYSCLK_MCLK;
 	return wm8731->sysclk_type == WM8731_SYSCLK_MCLK;
 }
 }
 
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route wm8731_intercon[] = {
 	{"DAC", NULL, "OSC", wm8731_check_osc},
 	{"DAC", NULL, "OSC", wm8731_check_osc},
 	{"ADC", NULL, "OSC", wm8731_check_osc},
 	{"ADC", NULL, "OSC", wm8731_check_osc},
 
 
@@ -227,17 +227,6 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{"Mic Bias", NULL, "MICIN"},
 	{"Mic Bias", NULL, "MICIN"},
 };
 };
 
 
-static int wm8731_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, wm8731_dapm_widgets,
-				  ARRAY_SIZE(wm8731_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-	return 0;
-}
-
 struct _coeff_div {
 struct _coeff_div {
 	u32 mclk;
 	u32 mclk;
 	u32 rate;
 	u32 rate;
@@ -599,7 +588,6 @@ static int wm8731_probe(struct snd_soc_codec *codec)
 
 
 	snd_soc_add_controls(codec, wm8731_snd_controls,
 	snd_soc_add_controls(codec, wm8731_snd_controls,
 			     ARRAY_SIZE(wm8731_snd_controls));
 			     ARRAY_SIZE(wm8731_snd_controls));
-	wm8731_add_widgets(codec);
 
 
 	/* Regulators will have been enabled by bias management */
 	/* Regulators will have been enabled by bias management */
 	regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
 	regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
@@ -636,6 +624,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8731 = {
 	.reg_cache_size = ARRAY_SIZE(wm8731_reg),
 	.reg_cache_size = ARRAY_SIZE(wm8731_reg),
 	.reg_word_size = sizeof(u16),
 	.reg_word_size = sizeof(u16),
 	.reg_cache_default = wm8731_reg,
 	.reg_cache_default = wm8731_reg,
+	.dapm_widgets = wm8731_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
+	.dapm_routes = wm8731_intercon,
+	.num_dapm_routes = ARRAY_SIZE(wm8731_intercon),
 };
 };
 
 
 #if defined(CONFIG_SPI_MASTER)
 #if defined(CONFIG_SPI_MASTER)
@@ -667,7 +659,7 @@ static int __devexit wm8731_spi_remove(struct spi_device *spi)
 
 
 static struct spi_driver wm8731_spi_driver = {
 static struct spi_driver wm8731_spi_driver = {
 	.driver = {
 	.driver = {
-		.name	= "wm8731-codec",
+		.name	= "wm8731",
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,
 	},
 	},
 	.probe		= wm8731_spi_probe,
 	.probe		= wm8731_spi_probe,
@@ -711,7 +703,7 @@ MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id);
 
 
 static struct i2c_driver wm8731_i2c_driver = {
 static struct i2c_driver wm8731_i2c_driver = {
 	.driver = {
 	.driver = {
-		.name = "wm8731-codec",
+		.name = "wm8731",
 		.owner = THIS_MODULE,
 		.owner = THIS_MODULE,
 	},
 	},
 	.probe =    wm8731_i2c_probe,
 	.probe =    wm8731_i2c_probe,

+ 29 - 17
sound/soc/codecs/wm8903.c

@@ -382,7 +382,8 @@ static void wm8903_seq_notifier(struct snd_soc_dapm_context *dapm,
 static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
 static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 			      struct snd_ctl_elem_value *ucontrol)
 {
 {
-	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct snd_soc_codec *codec = widget->codec;
 	struct snd_soc_codec *codec = widget->codec;
 	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
 	struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
 	u16 reg;
 	u16 reg;
@@ -634,6 +635,13 @@ static const struct soc_enum lsidetone_enum =
 static const struct soc_enum rsidetone_enum =
 static const struct soc_enum rsidetone_enum =
 	SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 0, 3, sidetone_text);
 	SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 0, 3, sidetone_text);
 
 
+static const char *adcinput_text[] = {
+	"ADC", "DMIC"
+};
+
+static const struct soc_enum adcinput_enum =
+	SOC_ENUM_SINGLE(WM8903_CLOCK_RATE_TEST_4, 9, 2, adcinput_text);
+
 static const char *aif_text[] = {
 static const char *aif_text[] = {
 	"Left", "Right"
 	"Left", "Right"
 };
 };
@@ -692,7 +700,7 @@ SOC_ENUM("DRC Smoothing Threshold", drc_smoothing),
 SOC_SINGLE_TLV("DRC Startup Volume", WM8903_DRC_0, 6, 18, 0, drc_tlv_startup),
 SOC_SINGLE_TLV("DRC Startup Volume", WM8903_DRC_0, 6, 18, 0, drc_tlv_startup),
 
 
 SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8903_ADC_DIGITAL_VOLUME_LEFT,
 SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8903_ADC_DIGITAL_VOLUME_LEFT,
-		 WM8903_ADC_DIGITAL_VOLUME_RIGHT, 1, 96, 0, digital_tlv),
+		 WM8903_ADC_DIGITAL_VOLUME_RIGHT, 1, 120, 0, digital_tlv),
 SOC_ENUM("ADC Companding Mode", adc_companding),
 SOC_ENUM("ADC Companding Mode", adc_companding),
 SOC_SINGLE("ADC Companding Switch", WM8903_AUDIO_INTERFACE_0, 3, 1, 0),
 SOC_SINGLE("ADC Companding Switch", WM8903_AUDIO_INTERFACE_0, 3, 1, 0),
 
 
@@ -767,6 +775,9 @@ static const struct snd_kcontrol_new lsidetone_mux =
 static const struct snd_kcontrol_new rsidetone_mux =
 static const struct snd_kcontrol_new rsidetone_mux =
 	SOC_DAPM_ENUM("DACR Sidetone Mux", rsidetone_enum);
 	SOC_DAPM_ENUM("DACR Sidetone Mux", rsidetone_enum);
 
 
+static const struct snd_kcontrol_new adcinput_mux =
+	SOC_DAPM_ENUM("ADC Input", adcinput_enum);
+
 static const struct snd_kcontrol_new lcapture_mux =
 static const struct snd_kcontrol_new lcapture_mux =
 	SOC_DAPM_ENUM("Left Capture Mux", lcapture_enum);
 	SOC_DAPM_ENUM("Left Capture Mux", lcapture_enum);
 
 
@@ -817,6 +828,7 @@ SND_SOC_DAPM_INPUT("IN2L"),
 SND_SOC_DAPM_INPUT("IN2R"),
 SND_SOC_DAPM_INPUT("IN2R"),
 SND_SOC_DAPM_INPUT("IN3L"),
 SND_SOC_DAPM_INPUT("IN3L"),
 SND_SOC_DAPM_INPUT("IN3R"),
 SND_SOC_DAPM_INPUT("IN3R"),
+SND_SOC_DAPM_INPUT("DMICDAT"),
 
 
 SND_SOC_DAPM_OUTPUT("HPOUTL"),
 SND_SOC_DAPM_OUTPUT("HPOUTL"),
 SND_SOC_DAPM_OUTPUT("HPOUTR"),
 SND_SOC_DAPM_OUTPUT("HPOUTR"),
@@ -842,6 +854,9 @@ SND_SOC_DAPM_MUX("Right Input Mode Mux", SND_SOC_NOPM, 0, 0, &rinput_mode_mux),
 SND_SOC_DAPM_PGA("Left Input PGA", WM8903_POWER_MANAGEMENT_0, 1, 0, NULL, 0),
 SND_SOC_DAPM_PGA("Left Input PGA", WM8903_POWER_MANAGEMENT_0, 1, 0, NULL, 0),
 SND_SOC_DAPM_PGA("Right Input PGA", WM8903_POWER_MANAGEMENT_0, 0, 0, NULL, 0),
 SND_SOC_DAPM_PGA("Right Input PGA", WM8903_POWER_MANAGEMENT_0, 0, 0, NULL, 0),
 
 
+SND_SOC_DAPM_MUX("Left ADC Input", SND_SOC_NOPM, 0, 0, &adcinput_mux),
+SND_SOC_DAPM_MUX("Right ADC Input", SND_SOC_NOPM, 0, 0, &adcinput_mux),
+
 SND_SOC_DAPM_ADC("ADCL", NULL, WM8903_POWER_MANAGEMENT_6, 1, 0),
 SND_SOC_DAPM_ADC("ADCL", NULL, WM8903_POWER_MANAGEMENT_6, 1, 0),
 SND_SOC_DAPM_ADC("ADCR", NULL, WM8903_POWER_MANAGEMENT_6, 0, 0),
 SND_SOC_DAPM_ADC("ADCR", NULL, WM8903_POWER_MANAGEMENT_6, 0, 0),
 
 
@@ -930,7 +945,7 @@ SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8903_CLOCK_RATES_2, 1, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8903_CLOCK_RATES_2, 2, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8903_CLOCK_RATES_2, 2, 0, NULL, 0),
 };
 };
 
 
-static const struct snd_soc_dapm_route intercon[] = {
+static const struct snd_soc_dapm_route wm8903_intercon[] = {
 
 
 	{ "CLK_DSP", NULL, "CLK_SYS" },
 	{ "CLK_DSP", NULL, "CLK_SYS" },
 	{ "Mic Bias", NULL, "CLK_SYS" },
 	{ "Mic Bias", NULL, "CLK_SYS" },
@@ -979,6 +994,11 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{ "Left Input PGA", NULL, "Left Input Mode Mux" },
 	{ "Left Input PGA", NULL, "Left Input Mode Mux" },
 	{ "Right Input PGA", NULL, "Right Input Mode Mux" },
 	{ "Right Input PGA", NULL, "Right Input Mode Mux" },
 
 
+	{ "Left ADC Input", "ADC", "Left Input PGA" },
+	{ "Left ADC Input", "DMIC", "DMICDAT" },
+	{ "Right ADC Input", "ADC", "Right Input PGA" },
+	{ "Right ADC Input", "DMIC", "DMICDAT" },
+
 	{ "Left Capture Mux", "Left", "ADCL" },
 	{ "Left Capture Mux", "Left", "ADCL" },
 	{ "Left Capture Mux", "Right", "ADCR" },
 	{ "Left Capture Mux", "Right", "ADCR" },
 
 
@@ -988,9 +1008,9 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{ "AIFTXL", NULL, "Left Capture Mux" },
 	{ "AIFTXL", NULL, "Left Capture Mux" },
 	{ "AIFTXR", NULL, "Right Capture Mux" },
 	{ "AIFTXR", NULL, "Right Capture Mux" },
 
 
-	{ "ADCL", NULL, "Left Input PGA" },
+	{ "ADCL", NULL, "Left ADC Input" },
 	{ "ADCL", NULL, "CLK_DSP" },
 	{ "ADCL", NULL, "CLK_DSP" },
-	{ "ADCR", NULL, "Right Input PGA" },
+	{ "ADCR", NULL, "Right ADC Input" },
 	{ "ADCR", NULL, "CLK_DSP" },
 	{ "ADCR", NULL, "CLK_DSP" },
 
 
 	{ "Left Playback Mux", "Left", "AIFRXL" },
 	{ "Left Playback Mux", "Left", "AIFRXL" },
@@ -1087,17 +1107,6 @@ static const struct snd_soc_dapm_route intercon[] = {
 	{ "Right Line Output PGA", NULL, "Charge Pump" },
 	{ "Right Line Output PGA", NULL, "Charge Pump" },
 };
 };
 
 
-static int wm8903_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, wm8903_dapm_widgets,
-				  ARRAY_SIZE(wm8903_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
-	return 0;
-}
-
 static int wm8903_set_bias_level(struct snd_soc_codec *codec,
 static int wm8903_set_bias_level(struct snd_soc_codec *codec,
 				 enum snd_soc_bias_level level)
 				 enum snd_soc_bias_level level)
 {
 {
@@ -2028,7 +2037,6 @@ static int wm8903_probe(struct snd_soc_codec *codec)
 
 
 	snd_soc_add_controls(codec, wm8903_snd_controls,
 	snd_soc_add_controls(codec, wm8903_snd_controls,
 				ARRAY_SIZE(wm8903_snd_controls));
 				ARRAY_SIZE(wm8903_snd_controls));
-	wm8903_add_widgets(codec);
 
 
 	wm8903_init_gpio(codec);
 	wm8903_init_gpio(codec);
 
 
@@ -2054,6 +2062,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8903 = {
 	.reg_cache_default = wm8903_reg_defaults,
 	.reg_cache_default = wm8903_reg_defaults,
 	.volatile_register = wm8903_volatile_register,
 	.volatile_register = wm8903_volatile_register,
 	.seq_notifier = wm8903_seq_notifier,
 	.seq_notifier = wm8903_seq_notifier,
+	.dapm_widgets = wm8903_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8903_dapm_widgets),
+	.dapm_routes = wm8903_intercon,
+	.num_dapm_routes = ARRAY_SIZE(wm8903_intercon),
 };
 };
 
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)

+ 2931 - 0
sound/soc/codecs/wm8915.c

@@ -0,0 +1,2931 @@
+/*
+ * wm8915.c - WM8915 audio codec interface
+ *
+ * Copyright 2011 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.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/gcd.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <trace/events/asoc.h>
+
+#include <sound/wm8915.h>
+#include "wm8915.h"
+
+#define WM8915_AIFS 2
+
+#define HPOUT1L 1
+#define HPOUT1R 2
+#define HPOUT2L 4
+#define HPOUT2R 8
+
+#define WM8915_NUM_SUPPLIES 6
+static const char *wm8915_supply_names[WM8915_NUM_SUPPLIES] = {
+	"DCVDD",
+	"DBVDD",
+	"AVDD1",
+	"AVDD2",
+	"CPVDD",
+	"MICVDD",
+};
+
+struct wm8915_priv {
+	struct snd_soc_codec *codec;
+
+	int ldo1ena;
+
+	int sysclk;
+
+	int fll_src;
+	int fll_fref;
+	int fll_fout;
+
+	struct completion fll_lock;
+
+	u16 dcs_pending;
+	struct completion dcs_done;
+
+	u16 hpout_ena;
+	u16 hpout_pending;
+
+	struct regulator_bulk_data supplies[WM8915_NUM_SUPPLIES];
+	struct notifier_block disable_nb[WM8915_NUM_SUPPLIES];
+
+	struct wm8915_pdata pdata;
+
+	int rx_rate[WM8915_AIFS];
+
+	/* Platform dependant ReTune mobile configuration */
+	int num_retune_mobile_texts;
+	const char **retune_mobile_texts;
+	int retune_mobile_cfg[2];
+	struct soc_enum retune_mobile_enum;
+
+	struct snd_soc_jack *jack;
+	bool detecting;
+	bool jack_mic;
+	wm8915_polarity_fn polarity_cb;
+
+#ifdef CONFIG_GPIOLIB
+	struct gpio_chip gpio_chip;
+#endif
+};
+
+/* We can't use the same notifier block for more than one supply and
+ * there's no way I can see to get from a callback to the caller
+ * except container_of().
+ */
+#define WM8915_REGULATOR_EVENT(n) \
+static int wm8915_regulator_event_##n(struct notifier_block *nb, \
+				    unsigned long event, void *data)	\
+{ \
+	struct wm8915_priv *wm8915 = container_of(nb, struct wm8915_priv, \
+						  disable_nb[n]); \
+	if (event & REGULATOR_EVENT_DISABLE) { \
+		wm8915->codec->cache_sync = 1; \
+	} \
+	return 0; \
+}
+
+WM8915_REGULATOR_EVENT(0)
+WM8915_REGULATOR_EVENT(1)
+WM8915_REGULATOR_EVENT(2)
+WM8915_REGULATOR_EVENT(3)
+WM8915_REGULATOR_EVENT(4)
+WM8915_REGULATOR_EVENT(5)
+
+static const u16 wm8915_reg[WM8915_MAX_REGISTER] = {
+	[WM8915_SOFTWARE_RESET] = 0x8915,
+	[WM8915_POWER_MANAGEMENT_7] = 0x10,
+	[WM8915_DAC1_HPOUT1_VOLUME] = 0x88,
+	[WM8915_DAC2_HPOUT2_VOLUME] = 0x88,
+	[WM8915_DAC1_LEFT_VOLUME] = 0x2c0,
+	[WM8915_DAC1_RIGHT_VOLUME] = 0x2c0,
+	[WM8915_DAC2_LEFT_VOLUME] = 0x2c0,
+	[WM8915_DAC2_RIGHT_VOLUME] = 0x2c0,
+	[WM8915_OUTPUT1_LEFT_VOLUME] = 0x80,
+	[WM8915_OUTPUT1_RIGHT_VOLUME] = 0x80,
+	[WM8915_OUTPUT2_LEFT_VOLUME] = 0x80,
+	[WM8915_OUTPUT2_RIGHT_VOLUME] = 0x80,
+	[WM8915_MICBIAS_1] = 0x39,
+	[WM8915_MICBIAS_2] = 0x39,
+	[WM8915_LDO_1] = 0x3,
+	[WM8915_LDO_2] = 0x13,
+	[WM8915_ACCESSORY_DETECT_MODE_1] = 0x4,
+	[WM8915_HEADPHONE_DETECT_1] = 0x20,
+	[WM8915_MIC_DETECT_1] = 0x7600,
+	[WM8915_MIC_DETECT_2] = 0xbf,
+	[WM8915_CHARGE_PUMP_1] = 0x1f25,
+	[WM8915_CHARGE_PUMP_2] = 0xab19,
+	[WM8915_DC_SERVO_5] = 0x2a2a,
+	[WM8915_CONTROL_INTERFACE_1] = 0x8004,
+	[WM8915_CLOCKING_1] = 0x10,
+	[WM8915_AIF_RATE] = 0x83,
+	[WM8915_FLL_CONTROL_4] = 0x5dc0,
+	[WM8915_FLL_CONTROL_5] = 0xc84,
+	[WM8915_FLL_EFS_2] = 0x2,
+	[WM8915_AIF1_TX_LRCLK_1] = 0x80,
+	[WM8915_AIF1_TX_LRCLK_2] = 0x8,
+	[WM8915_AIF1_RX_LRCLK_1] = 0x80,
+	[WM8915_AIF1TX_DATA_CONFIGURATION_1] = 0x1818,
+	[WM8915_AIF1RX_DATA_CONFIGURATION] = 0x1818,
+	[WM8915_AIF1TX_TEST] = 0x7,
+	[WM8915_AIF2_TX_LRCLK_1] = 0x80,
+	[WM8915_AIF2_TX_LRCLK_2] = 0x8,
+	[WM8915_AIF2_RX_LRCLK_1] = 0x80,
+	[WM8915_AIF2TX_DATA_CONFIGURATION_1] = 0x1818,
+	[WM8915_AIF2RX_DATA_CONFIGURATION] = 0x1818,
+	[WM8915_AIF2TX_TEST] = 0x1,
+	[WM8915_DSP1_TX_LEFT_VOLUME] = 0xc0,
+	[WM8915_DSP1_TX_RIGHT_VOLUME] = 0xc0,
+	[WM8915_DSP1_RX_LEFT_VOLUME] = 0xc0,
+	[WM8915_DSP1_RX_RIGHT_VOLUME] = 0xc0,
+	[WM8915_DSP1_TX_FILTERS] = 0x2000,
+	[WM8915_DSP1_RX_FILTERS_1] = 0x200,
+	[WM8915_DSP1_RX_FILTERS_2] = 0x10,
+	[WM8915_DSP1_DRC_1] = 0x98,
+	[WM8915_DSP1_DRC_2] = 0x845,
+	[WM8915_DSP1_RX_EQ_GAINS_1] = 0x6318,
+	[WM8915_DSP1_RX_EQ_GAINS_2] = 0x6300,
+	[WM8915_DSP1_RX_EQ_BAND_1_A] = 0xfca,
+	[WM8915_DSP1_RX_EQ_BAND_1_B] = 0x400,
+	[WM8915_DSP1_RX_EQ_BAND_1_PG] = 0xd8,
+	[WM8915_DSP1_RX_EQ_BAND_2_A] = 0x1eb5,
+	[WM8915_DSP1_RX_EQ_BAND_2_B] = 0xf145,
+	[WM8915_DSP1_RX_EQ_BAND_2_C] = 0xb75,
+	[WM8915_DSP1_RX_EQ_BAND_2_PG] = 0x1c5,
+	[WM8915_DSP1_RX_EQ_BAND_3_A] = 0x1c58,
+	[WM8915_DSP1_RX_EQ_BAND_3_B] = 0xf373,
+	[WM8915_DSP1_RX_EQ_BAND_3_C] = 0xa54,
+	[WM8915_DSP1_RX_EQ_BAND_3_PG] = 0x558,
+	[WM8915_DSP1_RX_EQ_BAND_4_A] = 0x168e,
+	[WM8915_DSP1_RX_EQ_BAND_4_B] = 0xf829,
+	[WM8915_DSP1_RX_EQ_BAND_4_C] = 0x7ad,
+	[WM8915_DSP1_RX_EQ_BAND_4_PG] = 0x1103,
+	[WM8915_DSP1_RX_EQ_BAND_5_A] = 0x564,
+	[WM8915_DSP1_RX_EQ_BAND_5_B] = 0x559,
+	[WM8915_DSP1_RX_EQ_BAND_5_PG] = 0x4000,
+	[WM8915_DSP2_TX_LEFT_VOLUME] = 0xc0,
+	[WM8915_DSP2_TX_RIGHT_VOLUME] = 0xc0,
+	[WM8915_DSP2_RX_LEFT_VOLUME] = 0xc0,
+	[WM8915_DSP2_RX_RIGHT_VOLUME] = 0xc0,
+	[WM8915_DSP2_TX_FILTERS] = 0x2000,
+	[WM8915_DSP2_RX_FILTERS_1] = 0x200,
+	[WM8915_DSP2_RX_FILTERS_2] = 0x10,
+	[WM8915_DSP2_DRC_1] = 0x98,
+	[WM8915_DSP2_DRC_2] = 0x845,
+	[WM8915_DSP2_RX_EQ_GAINS_1] = 0x6318,
+	[WM8915_DSP2_RX_EQ_GAINS_2] = 0x6300,
+	[WM8915_DSP2_RX_EQ_BAND_1_A] = 0xfca,
+	[WM8915_DSP2_RX_EQ_BAND_1_B] = 0x400,
+	[WM8915_DSP2_RX_EQ_BAND_1_PG] = 0xd8,
+	[WM8915_DSP2_RX_EQ_BAND_2_A] = 0x1eb5,
+	[WM8915_DSP2_RX_EQ_BAND_2_B] = 0xf145,
+	[WM8915_DSP2_RX_EQ_BAND_2_C] = 0xb75,
+	[WM8915_DSP2_RX_EQ_BAND_2_PG] = 0x1c5,
+	[WM8915_DSP2_RX_EQ_BAND_3_A] = 0x1c58,
+	[WM8915_DSP2_RX_EQ_BAND_3_B] = 0xf373,
+	[WM8915_DSP2_RX_EQ_BAND_3_C] = 0xa54,
+	[WM8915_DSP2_RX_EQ_BAND_3_PG] = 0x558,
+	[WM8915_DSP2_RX_EQ_BAND_4_A] = 0x168e,
+	[WM8915_DSP2_RX_EQ_BAND_4_B] = 0xf829,
+	[WM8915_DSP2_RX_EQ_BAND_4_C] = 0x7ad,
+	[WM8915_DSP2_RX_EQ_BAND_4_PG] = 0x1103,
+	[WM8915_DSP2_RX_EQ_BAND_5_A] = 0x564,
+	[WM8915_DSP2_RX_EQ_BAND_5_B] = 0x559,
+	[WM8915_DSP2_RX_EQ_BAND_5_PG] = 0x4000,
+	[WM8915_OVERSAMPLING] = 0xd,
+	[WM8915_SIDETONE] = 0x1040,
+	[WM8915_GPIO_1] = 0xa101,
+	[WM8915_GPIO_2] = 0xa101,
+	[WM8915_GPIO_3] = 0xa101,
+	[WM8915_GPIO_4] = 0xa101,
+	[WM8915_GPIO_5] = 0xa101,
+	[WM8915_PULL_CONTROL_2] = 0x140,
+	[WM8915_INTERRUPT_STATUS_1_MASK] = 0x1f,
+	[WM8915_INTERRUPT_STATUS_2_MASK] = 0x1ecf,
+	[WM8915_RIGHT_PDM_SPEAKER] = 0x1,
+	[WM8915_PDM_SPEAKER_MUTE_SEQUENCE] = 0x69,
+	[WM8915_PDM_SPEAKER_VOLUME] = 0x66,
+	[WM8915_WRITE_SEQUENCER_0] = 0x1,
+	[WM8915_WRITE_SEQUENCER_1] = 0x1,
+	[WM8915_WRITE_SEQUENCER_3] = 0x6,
+	[WM8915_WRITE_SEQUENCER_4] = 0x40,
+	[WM8915_WRITE_SEQUENCER_5] = 0x1,
+	[WM8915_WRITE_SEQUENCER_6] = 0xf,
+	[WM8915_WRITE_SEQUENCER_7] = 0x6,
+	[WM8915_WRITE_SEQUENCER_8] = 0x1,
+	[WM8915_WRITE_SEQUENCER_9] = 0x3,
+	[WM8915_WRITE_SEQUENCER_10] = 0x104,
+	[WM8915_WRITE_SEQUENCER_12] = 0x60,
+	[WM8915_WRITE_SEQUENCER_13] = 0x11,
+	[WM8915_WRITE_SEQUENCER_14] = 0x401,
+	[WM8915_WRITE_SEQUENCER_16] = 0x50,
+	[WM8915_WRITE_SEQUENCER_17] = 0x3,
+	[WM8915_WRITE_SEQUENCER_18] = 0x100,
+	[WM8915_WRITE_SEQUENCER_20] = 0x51,
+	[WM8915_WRITE_SEQUENCER_21] = 0x3,
+	[WM8915_WRITE_SEQUENCER_22] = 0x104,
+	[WM8915_WRITE_SEQUENCER_23] = 0xa,
+	[WM8915_WRITE_SEQUENCER_24] = 0x60,
+	[WM8915_WRITE_SEQUENCER_25] = 0x3b,
+	[WM8915_WRITE_SEQUENCER_26] = 0x502,
+	[WM8915_WRITE_SEQUENCER_27] = 0x100,
+	[WM8915_WRITE_SEQUENCER_28] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_32] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_36] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_40] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_44] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_48] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_52] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_56] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_60] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_64] = 0x1,
+	[WM8915_WRITE_SEQUENCER_65] = 0x1,
+	[WM8915_WRITE_SEQUENCER_67] = 0x6,
+	[WM8915_WRITE_SEQUENCER_68] = 0x40,
+	[WM8915_WRITE_SEQUENCER_69] = 0x1,
+	[WM8915_WRITE_SEQUENCER_70] = 0xf,
+	[WM8915_WRITE_SEQUENCER_71] = 0x6,
+	[WM8915_WRITE_SEQUENCER_72] = 0x1,
+	[WM8915_WRITE_SEQUENCER_73] = 0x3,
+	[WM8915_WRITE_SEQUENCER_74] = 0x104,
+	[WM8915_WRITE_SEQUENCER_76] = 0x60,
+	[WM8915_WRITE_SEQUENCER_77] = 0x11,
+	[WM8915_WRITE_SEQUENCER_78] = 0x401,
+	[WM8915_WRITE_SEQUENCER_80] = 0x50,
+	[WM8915_WRITE_SEQUENCER_81] = 0x3,
+	[WM8915_WRITE_SEQUENCER_82] = 0x100,
+	[WM8915_WRITE_SEQUENCER_84] = 0x60,
+	[WM8915_WRITE_SEQUENCER_85] = 0x3b,
+	[WM8915_WRITE_SEQUENCER_86] = 0x502,
+	[WM8915_WRITE_SEQUENCER_87] = 0x100,
+	[WM8915_WRITE_SEQUENCER_88] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_92] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_96] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_100] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_104] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_108] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_112] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_116] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_120] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_124] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_128] = 0x1,
+	[WM8915_WRITE_SEQUENCER_129] = 0x1,
+	[WM8915_WRITE_SEQUENCER_131] = 0x6,
+	[WM8915_WRITE_SEQUENCER_132] = 0x40,
+	[WM8915_WRITE_SEQUENCER_133] = 0x1,
+	[WM8915_WRITE_SEQUENCER_134] = 0xf,
+	[WM8915_WRITE_SEQUENCER_135] = 0x6,
+	[WM8915_WRITE_SEQUENCER_136] = 0x1,
+	[WM8915_WRITE_SEQUENCER_137] = 0x3,
+	[WM8915_WRITE_SEQUENCER_138] = 0x106,
+	[WM8915_WRITE_SEQUENCER_140] = 0x61,
+	[WM8915_WRITE_SEQUENCER_141] = 0x11,
+	[WM8915_WRITE_SEQUENCER_142] = 0x401,
+	[WM8915_WRITE_SEQUENCER_144] = 0x50,
+	[WM8915_WRITE_SEQUENCER_145] = 0x3,
+	[WM8915_WRITE_SEQUENCER_146] = 0x102,
+	[WM8915_WRITE_SEQUENCER_148] = 0x51,
+	[WM8915_WRITE_SEQUENCER_149] = 0x3,
+	[WM8915_WRITE_SEQUENCER_150] = 0x106,
+	[WM8915_WRITE_SEQUENCER_151] = 0xa,
+	[WM8915_WRITE_SEQUENCER_152] = 0x61,
+	[WM8915_WRITE_SEQUENCER_153] = 0x3b,
+	[WM8915_WRITE_SEQUENCER_154] = 0x502,
+	[WM8915_WRITE_SEQUENCER_155] = 0x100,
+	[WM8915_WRITE_SEQUENCER_156] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_160] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_164] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_168] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_172] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_176] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_180] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_184] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_188] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_192] = 0x1,
+	[WM8915_WRITE_SEQUENCER_193] = 0x1,
+	[WM8915_WRITE_SEQUENCER_195] = 0x6,
+	[WM8915_WRITE_SEQUENCER_196] = 0x40,
+	[WM8915_WRITE_SEQUENCER_197] = 0x1,
+	[WM8915_WRITE_SEQUENCER_198] = 0xf,
+	[WM8915_WRITE_SEQUENCER_199] = 0x6,
+	[WM8915_WRITE_SEQUENCER_200] = 0x1,
+	[WM8915_WRITE_SEQUENCER_201] = 0x3,
+	[WM8915_WRITE_SEQUENCER_202] = 0x106,
+	[WM8915_WRITE_SEQUENCER_204] = 0x61,
+	[WM8915_WRITE_SEQUENCER_205] = 0x11,
+	[WM8915_WRITE_SEQUENCER_206] = 0x401,
+	[WM8915_WRITE_SEQUENCER_208] = 0x50,
+	[WM8915_WRITE_SEQUENCER_209] = 0x3,
+	[WM8915_WRITE_SEQUENCER_210] = 0x102,
+	[WM8915_WRITE_SEQUENCER_212] = 0x61,
+	[WM8915_WRITE_SEQUENCER_213] = 0x3b,
+	[WM8915_WRITE_SEQUENCER_214] = 0x502,
+	[WM8915_WRITE_SEQUENCER_215] = 0x100,
+	[WM8915_WRITE_SEQUENCER_216] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_220] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_224] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_228] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_232] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_236] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_240] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_244] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_248] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_252] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_256] = 0x60,
+	[WM8915_WRITE_SEQUENCER_258] = 0x601,
+	[WM8915_WRITE_SEQUENCER_260] = 0x50,
+	[WM8915_WRITE_SEQUENCER_262] = 0x100,
+	[WM8915_WRITE_SEQUENCER_264] = 0x1,
+	[WM8915_WRITE_SEQUENCER_266] = 0x104,
+	[WM8915_WRITE_SEQUENCER_267] = 0x100,
+	[WM8915_WRITE_SEQUENCER_268] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_272] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_276] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_280] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_284] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_288] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_292] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_296] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_300] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_304] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_308] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_312] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_316] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_320] = 0x61,
+	[WM8915_WRITE_SEQUENCER_322] = 0x601,
+	[WM8915_WRITE_SEQUENCER_324] = 0x50,
+	[WM8915_WRITE_SEQUENCER_326] = 0x102,
+	[WM8915_WRITE_SEQUENCER_328] = 0x1,
+	[WM8915_WRITE_SEQUENCER_330] = 0x106,
+	[WM8915_WRITE_SEQUENCER_331] = 0x100,
+	[WM8915_WRITE_SEQUENCER_332] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_336] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_340] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_344] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_348] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_352] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_356] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_360] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_364] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_368] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_372] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_376] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_380] = 0x2fff,
+	[WM8915_WRITE_SEQUENCER_384] = 0x60,
+	[WM8915_WRITE_SEQUENCER_386] = 0x601,
+	[WM8915_WRITE_SEQUENCER_388] = 0x61,
+	[WM8915_WRITE_SEQUENCER_390] = 0x601,
+	[WM8915_WRITE_SEQUENCER_392] = 0x50,
+	[WM8915_WRITE_SEQUENCER_394] = 0x300,
+	[WM8915_WRITE_SEQUENCER_396] = 0x1,
+	[WM8915_WRITE_SEQUENCER_398] = 0x304,
+	[WM8915_WRITE_SEQUENCER_400] = 0x40,
+	[WM8915_WRITE_SEQUENCER_402] = 0xf,
+	[WM8915_WRITE_SEQUENCER_404] = 0x1,
+	[WM8915_WRITE_SEQUENCER_407] = 0x100,
+};
+
+static const DECLARE_TLV_DB_SCALE(inpga_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -3600, 150, 0);
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
+static const DECLARE_TLV_DB_SCALE(out_digital_tlv, -1200, 150, 0);
+static const DECLARE_TLV_DB_SCALE(out_tlv, -900, 75, 0);
+static const DECLARE_TLV_DB_SCALE(spk_tlv, -900, 150, 0);
+static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+
+static const char *sidetone_hpf_text[] = {
+	"2.9kHz", "1.5kHz", "735Hz", "403Hz", "196Hz", "98Hz", "49Hz"
+};
+
+static const struct soc_enum sidetone_hpf =
+	SOC_ENUM_SINGLE(WM8915_SIDETONE, 7, 6, sidetone_hpf_text);
+
+static const char *hpf_mode_text[] = {
+	"HiFi", "Custom", "Voice"
+};
+
+static const struct soc_enum dsp1tx_hpf_mode =
+	SOC_ENUM_SINGLE(WM8915_DSP1_TX_FILTERS, 3, 3, hpf_mode_text);
+
+static const struct soc_enum dsp2tx_hpf_mode =
+	SOC_ENUM_SINGLE(WM8915_DSP2_TX_FILTERS, 3, 3, hpf_mode_text);
+
+static const char *hpf_cutoff_text[] = {
+	"50Hz", "75Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
+};
+
+static const struct soc_enum dsp1tx_hpf_cutoff =
+	SOC_ENUM_SINGLE(WM8915_DSP1_TX_FILTERS, 0, 7, hpf_cutoff_text);
+
+static const struct soc_enum dsp2tx_hpf_cutoff =
+	SOC_ENUM_SINGLE(WM8915_DSP2_TX_FILTERS, 0, 7, hpf_cutoff_text);
+
+static void wm8915_set_retune_mobile(struct snd_soc_codec *codec, int block)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	struct wm8915_pdata *pdata = &wm8915->pdata;
+	int base, best, best_val, save, i, cfg, iface;
+
+	if (!wm8915->num_retune_mobile_texts)
+		return;
+
+	switch (block) {
+	case 0:
+		base = WM8915_DSP1_RX_EQ_GAINS_1;
+		if (snd_soc_read(codec, WM8915_POWER_MANAGEMENT_8) &
+		    WM8915_DSP1RX_SRC)
+			iface = 1;
+		else
+			iface = 0;
+		break;
+	case 1:
+		base = WM8915_DSP1_RX_EQ_GAINS_2;
+		if (snd_soc_read(codec, WM8915_POWER_MANAGEMENT_8) &
+		    WM8915_DSP2RX_SRC)
+			iface = 1;
+		else
+			iface = 0;
+		break;
+	default:
+		return;
+	}
+
+	/* Find the version of the currently selected configuration
+	 * with the nearest sample rate. */
+	cfg = wm8915->retune_mobile_cfg[block];
+	best = 0;
+	best_val = INT_MAX;
+	for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+		if (strcmp(pdata->retune_mobile_cfgs[i].name,
+			   wm8915->retune_mobile_texts[cfg]) == 0 &&
+		    abs(pdata->retune_mobile_cfgs[i].rate
+			- wm8915->rx_rate[iface]) < best_val) {
+			best = i;
+			best_val = abs(pdata->retune_mobile_cfgs[i].rate
+				       - wm8915->rx_rate[iface]);
+		}
+	}
+
+	dev_dbg(codec->dev, "ReTune Mobile %d %s/%dHz for %dHz sample rate\n",
+		block,
+		pdata->retune_mobile_cfgs[best].name,
+		pdata->retune_mobile_cfgs[best].rate,
+		wm8915->rx_rate[iface]);
+
+	/* The EQ will be disabled while reconfiguring it, remember the
+	 * current configuration. 
+	 */
+	save = snd_soc_read(codec, base);
+	save &= WM8915_DSP1RX_EQ_ENA;
+
+	for (i = 0; i < ARRAY_SIZE(pdata->retune_mobile_cfgs[best].regs); i++)
+		snd_soc_update_bits(codec, base + i, 0xffff,
+				    pdata->retune_mobile_cfgs[best].regs[i]);
+
+	snd_soc_update_bits(codec, base, WM8915_DSP1RX_EQ_ENA, save);
+}
+
+/* Icky as hell but saves code duplication */
+static int wm8915_get_retune_mobile_block(const char *name)
+{
+	if (strcmp(name, "DSP1 EQ Mode") == 0)
+		return 0;
+	if (strcmp(name, "DSP2 EQ Mode") == 0)
+		return 1;
+	return -EINVAL;
+}
+
+static int wm8915_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	struct wm8915_pdata *pdata = &wm8915->pdata;
+	int block = wm8915_get_retune_mobile_block(kcontrol->id.name);
+	int value = ucontrol->value.integer.value[0];
+
+	if (block < 0)
+		return block;
+
+	if (value >= pdata->num_retune_mobile_cfgs)
+		return -EINVAL;
+
+	wm8915->retune_mobile_cfg[block] = value;
+
+	wm8915_set_retune_mobile(codec, block);
+
+	return 0;
+}
+
+static int wm8915_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	int block = wm8915_get_retune_mobile_block(kcontrol->id.name);
+
+	ucontrol->value.enumerated.item[0] = wm8915->retune_mobile_cfg[block];
+
+	return 0;
+}
+
+static const struct snd_kcontrol_new wm8915_snd_controls[] = {
+SOC_DOUBLE_R_TLV("Capture Volume", WM8915_LEFT_LINE_INPUT_VOLUME,
+		 WM8915_RIGHT_LINE_INPUT_VOLUME, 0, 31, 0, inpga_tlv),
+SOC_DOUBLE_R("Capture ZC Switch", WM8915_LEFT_LINE_INPUT_VOLUME,
+	     WM8915_RIGHT_LINE_INPUT_VOLUME, 5, 1, 0),
+
+SOC_DOUBLE_TLV("DAC1 Sidetone Volume", WM8915_DAC1_MIXER_VOLUMES,
+	       0, 5, 24, 0, sidetone_tlv),
+SOC_DOUBLE_TLV("DAC2 Sidetone Volume", WM8915_DAC2_MIXER_VOLUMES,
+	       0, 5, 24, 0, sidetone_tlv),
+SOC_SINGLE("Sidetone LPF Switch", WM8915_SIDETONE, 12, 1, 0),
+SOC_ENUM("Sidetone HPF Cut-off", sidetone_hpf),
+SOC_SINGLE("Sidetone HPF Switch", WM8915_SIDETONE, 6, 1, 0),
+
+SOC_DOUBLE_R_TLV("DSP1 Capture Volume", WM8915_DSP1_TX_LEFT_VOLUME,
+		 WM8915_DSP1_TX_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("DSP2 Capture Volume", WM8915_DSP2_TX_LEFT_VOLUME,
+		 WM8915_DSP2_TX_RIGHT_VOLUME, 1, 96, 0, digital_tlv),
+
+SOC_SINGLE("DSP1 Capture Notch Filter Switch", WM8915_DSP1_TX_FILTERS,
+	   13, 1, 0),
+SOC_DOUBLE("DSP1 Capture HPF Switch", WM8915_DSP1_TX_FILTERS, 12, 11, 1, 0),
+SOC_ENUM("DSP1 Capture HPF Mode", dsp1tx_hpf_mode),
+SOC_ENUM("DSP1 Capture HPF Cutoff", dsp1tx_hpf_cutoff),
+
+SOC_SINGLE("DSP2 Capture Notch Filter Switch", WM8915_DSP2_TX_FILTERS,
+	   13, 1, 0),
+SOC_DOUBLE("DSP2 Capture HPF Switch", WM8915_DSP2_TX_FILTERS, 12, 11, 1, 0),
+SOC_ENUM("DSP2 Capture HPF Mode", dsp2tx_hpf_mode),
+SOC_ENUM("DSP2 Capture HPF Cutoff", dsp2tx_hpf_cutoff),
+
+SOC_DOUBLE_R_TLV("DSP1 Playback Volume", WM8915_DSP1_RX_LEFT_VOLUME,
+		 WM8915_DSP1_RX_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_SINGLE("DSP1 Playback Switch", WM8915_DSP1_RX_FILTERS_1, 9, 1, 1),
+
+SOC_DOUBLE_R_TLV("DSP2 Playback Volume", WM8915_DSP2_RX_LEFT_VOLUME,
+		 WM8915_DSP2_RX_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_SINGLE("DSP2 Playback Switch", WM8915_DSP2_RX_FILTERS_1, 9, 1, 1),
+
+SOC_DOUBLE_R_TLV("DAC1 Volume", WM8915_DAC1_LEFT_VOLUME,
+		 WM8915_DAC1_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_DOUBLE_R("DAC1 Switch", WM8915_DAC1_LEFT_VOLUME,
+	     WM8915_DAC1_RIGHT_VOLUME, 9, 1, 1),
+
+SOC_DOUBLE_R_TLV("DAC2 Volume", WM8915_DAC2_LEFT_VOLUME,
+		 WM8915_DAC2_RIGHT_VOLUME, 1, 112, 0, digital_tlv),
+SOC_DOUBLE_R("DAC2 Switch", WM8915_DAC2_LEFT_VOLUME,
+	     WM8915_DAC2_RIGHT_VOLUME, 9, 1, 1),
+
+SOC_SINGLE("Speaker High Performance Switch", WM8915_OVERSAMPLING, 3, 1, 0),
+SOC_SINGLE("DMIC High Performance Switch", WM8915_OVERSAMPLING, 2, 1, 0),
+SOC_SINGLE("ADC High Performance Switch", WM8915_OVERSAMPLING, 1, 1, 0),
+SOC_SINGLE("DAC High Performance Switch", WM8915_OVERSAMPLING, 0, 1, 0),
+
+SOC_SINGLE("DAC Soft Mute Switch", WM8915_DAC_SOFTMUTE, 1, 1, 0),
+SOC_SINGLE("DAC Slow Soft Mute Switch", WM8915_DAC_SOFTMUTE, 0, 1, 0),
+
+SOC_DOUBLE_TLV("Digital Output 1 Volume", WM8915_DAC1_HPOUT1_VOLUME, 0, 4,
+	       8, 0, out_digital_tlv),
+SOC_DOUBLE_TLV("Digital Output 2 Volume", WM8915_DAC2_HPOUT2_VOLUME, 0, 4,
+	       8, 0, out_digital_tlv),
+
+SOC_DOUBLE_R_TLV("Output 1 Volume", WM8915_OUTPUT1_LEFT_VOLUME,
+		 WM8915_OUTPUT1_RIGHT_VOLUME, 0, 12, 0, out_tlv),
+SOC_DOUBLE_R("Output 1 ZC Switch",  WM8915_OUTPUT1_LEFT_VOLUME,
+	     WM8915_OUTPUT1_RIGHT_VOLUME, 7, 1, 0),
+
+SOC_DOUBLE_R_TLV("Output 2 Volume", WM8915_OUTPUT2_LEFT_VOLUME,
+		 WM8915_OUTPUT2_RIGHT_VOLUME, 0, 12, 0, out_tlv),
+SOC_DOUBLE_R("Output 2 ZC Switch",  WM8915_OUTPUT2_LEFT_VOLUME,
+	     WM8915_OUTPUT2_RIGHT_VOLUME, 7, 1, 0),
+
+SOC_DOUBLE_TLV("Speaker Volume", WM8915_PDM_SPEAKER_VOLUME, 0, 4, 8, 0,
+	       spk_tlv),
+SOC_DOUBLE_R("Speaker Switch", WM8915_LEFT_PDM_SPEAKER,
+	     WM8915_RIGHT_PDM_SPEAKER, 3, 1, 1),
+SOC_DOUBLE_R("Speaker ZC Switch", WM8915_LEFT_PDM_SPEAKER,
+	     WM8915_RIGHT_PDM_SPEAKER, 2, 1, 0),
+
+SOC_SINGLE("DSP1 EQ Switch", WM8915_DSP1_RX_EQ_GAINS_1, 0, 1, 0),
+SOC_SINGLE("DSP2 EQ Switch", WM8915_DSP2_RX_EQ_GAINS_1, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new wm8915_eq_controls[] = {
+SOC_SINGLE_TLV("DSP1 EQ B1 Volume", WM8915_DSP1_RX_EQ_GAINS_1, 11, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B2 Volume", WM8915_DSP1_RX_EQ_GAINS_1, 6, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B3 Volume", WM8915_DSP1_RX_EQ_GAINS_1, 1, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B4 Volume", WM8915_DSP1_RX_EQ_GAINS_2, 11, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP1 EQ B5 Volume", WM8915_DSP1_RX_EQ_GAINS_2, 6, 31, 0,
+	       eq_tlv),
+
+SOC_SINGLE_TLV("DSP2 EQ B1 Volume", WM8915_DSP2_RX_EQ_GAINS_1, 11, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B2 Volume", WM8915_DSP2_RX_EQ_GAINS_1, 6, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B3 Volume", WM8915_DSP2_RX_EQ_GAINS_1, 1, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B4 Volume", WM8915_DSP2_RX_EQ_GAINS_2, 11, 31, 0,
+	       eq_tlv),
+SOC_SINGLE_TLV("DSP2 EQ B5 Volume", WM8915_DSP2_RX_EQ_GAINS_2, 6, 31, 0,
+	       eq_tlv),
+};
+
+static int cp_event(struct snd_soc_dapm_widget *w,
+		    struct snd_kcontrol *kcontrol, int event)
+{
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		msleep(5);
+		break;
+	default:
+		BUG();
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rmv_short_event(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *kcontrol, int event)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(w->codec);
+
+	/* Record which outputs we enabled */
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMD:
+		wm8915->hpout_pending &= ~w->shift;
+		break;
+	case SND_SOC_DAPM_PRE_PMU:
+		wm8915->hpout_pending |= w->shift;
+		break;
+	default:
+		BUG();
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void wait_for_dc_servo(struct snd_soc_codec *codec, u16 mask)
+{
+	struct i2c_client *i2c = to_i2c_client(codec->dev);
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	int i, ret;
+	unsigned long timeout = 200;
+
+	snd_soc_write(codec, WM8915_DC_SERVO_2, mask);
+
+	/* Use the interrupt if possible */
+	do {
+		if (i2c->irq) {
+			timeout = wait_for_completion_timeout(&wm8915->dcs_done,
+							      msecs_to_jiffies(200));
+			if (timeout == 0)
+				dev_err(codec->dev, "DC servo timed out\n");
+
+		} else {
+			msleep(1);
+			if (--i) {
+				timeout = 0;
+				break;
+			}
+		}
+
+		ret = snd_soc_read(codec, WM8915_DC_SERVO_2);
+		dev_dbg(codec->dev, "DC servo state: %x\n", ret);
+	} while (ret & mask);
+
+	if (timeout == 0)
+		dev_err(codec->dev, "DC servo timed out for %x\n", mask);
+	else
+		dev_dbg(codec->dev, "DC servo complete for %x\n", mask);
+}
+
+static void wm8915_seq_notifier(struct snd_soc_dapm_context *dapm,
+				enum snd_soc_dapm_type event, int subseq)
+{
+	struct snd_soc_codec *codec = container_of(dapm,
+						   struct snd_soc_codec, dapm);
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	u16 val, mask;
+
+	/* Complete any pending DC servo starts */
+	if (wm8915->dcs_pending) {
+		dev_dbg(codec->dev, "Starting DC servo for %x\n",
+			wm8915->dcs_pending);
+
+		/* Trigger a startup sequence */
+		wait_for_dc_servo(codec, wm8915->dcs_pending
+				         << WM8915_DCS_TRIG_STARTUP_0_SHIFT);
+
+		wm8915->dcs_pending = 0;
+	}
+
+	if (wm8915->hpout_pending != wm8915->hpout_ena) {
+		dev_dbg(codec->dev, "Applying RMV_SHORTs %x->%x\n",
+			wm8915->hpout_ena, wm8915->hpout_pending);
+
+		val = 0;
+		mask = 0;
+		if (wm8915->hpout_pending & HPOUT1L) {
+			val |= WM8915_HPOUT1L_RMV_SHORT;
+			mask |= WM8915_HPOUT1L_RMV_SHORT;
+		} else {
+			mask |= WM8915_HPOUT1L_RMV_SHORT |
+				WM8915_HPOUT1L_OUTP |
+				WM8915_HPOUT1L_DLY;
+		}
+
+		if (wm8915->hpout_pending & HPOUT1R) {
+			val |= WM8915_HPOUT1R_RMV_SHORT;
+			mask |= WM8915_HPOUT1R_RMV_SHORT;
+		} else {
+			mask |= WM8915_HPOUT1R_RMV_SHORT |
+				WM8915_HPOUT1R_OUTP |
+				WM8915_HPOUT1R_DLY;
+		}
+
+		snd_soc_update_bits(codec, WM8915_ANALOGUE_HP_1, mask, val);
+
+		val = 0;
+		mask = 0;
+		if (wm8915->hpout_pending & HPOUT2L) {
+			val |= WM8915_HPOUT2L_RMV_SHORT;
+			mask |= WM8915_HPOUT2L_RMV_SHORT;
+		} else {
+			mask |= WM8915_HPOUT2L_RMV_SHORT |
+				WM8915_HPOUT2L_OUTP |
+				WM8915_HPOUT2L_DLY;
+		}
+
+		if (wm8915->hpout_pending & HPOUT2R) {
+			val |= WM8915_HPOUT2R_RMV_SHORT;
+			mask |= WM8915_HPOUT2R_RMV_SHORT;
+		} else {
+			mask |= WM8915_HPOUT2R_RMV_SHORT |
+				WM8915_HPOUT2R_OUTP |
+				WM8915_HPOUT2R_DLY;
+		}
+
+		snd_soc_update_bits(codec, WM8915_ANALOGUE_HP_2, mask, val);
+
+		wm8915->hpout_ena = wm8915->hpout_pending;
+	}
+}
+
+static int dcs_start(struct snd_soc_dapm_widget *w,
+		     struct snd_kcontrol *kcontrol, int event)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(w->codec);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		wm8915->dcs_pending |= 1 << w->shift;
+		break;
+	default:
+		BUG();
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const char *sidetone_text[] = {
+	"IN1", "IN2",
+};
+
+static const struct soc_enum left_sidetone_enum =
+	SOC_ENUM_SINGLE(WM8915_SIDETONE, 0, 2, sidetone_text);
+
+static const struct snd_kcontrol_new left_sidetone =
+	SOC_DAPM_ENUM("Left Sidetone", left_sidetone_enum);
+
+static const struct soc_enum right_sidetone_enum =
+	SOC_ENUM_SINGLE(WM8915_SIDETONE, 1, 2, sidetone_text);
+
+static const struct snd_kcontrol_new right_sidetone =
+	SOC_DAPM_ENUM("Right Sidetone", right_sidetone_enum);
+
+static const char *spk_text[] = {
+	"DAC1L", "DAC1R", "DAC2L", "DAC2R"
+};
+
+static const struct soc_enum spkl_enum =
+	SOC_ENUM_SINGLE(WM8915_LEFT_PDM_SPEAKER, 0, 4, spk_text);
+
+static const struct snd_kcontrol_new spkl_mux =
+	SOC_DAPM_ENUM("SPKL", spkl_enum);
+
+static const struct soc_enum spkr_enum =
+	SOC_ENUM_SINGLE(WM8915_RIGHT_PDM_SPEAKER, 0, 4, spk_text);
+
+static const struct snd_kcontrol_new spkr_mux =
+	SOC_DAPM_ENUM("SPKR", spkr_enum);
+
+static const char *dsp1rx_text[] = {
+	"AIF1", "AIF2"
+};
+
+static const struct soc_enum dsp1rx_enum =
+	SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_8, 0, 2, dsp1rx_text);
+
+static const struct snd_kcontrol_new dsp1rx =
+	SOC_DAPM_ENUM("DSP1RX", dsp1rx_enum);
+
+static const char *dsp2rx_text[] = {
+	 "AIF2", "AIF1"
+};
+
+static const struct soc_enum dsp2rx_enum =
+	SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_8, 4, 2, dsp2rx_text);
+
+static const struct snd_kcontrol_new dsp2rx =
+	SOC_DAPM_ENUM("DSP2RX", dsp2rx_enum);
+
+static const char *aif2tx_text[] = {
+	"DSP2", "DSP1", "AIF1"
+};
+
+static const struct soc_enum aif2tx_enum =
+	SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_8, 6, 3, aif2tx_text);
+
+static const struct snd_kcontrol_new aif2tx =
+	SOC_DAPM_ENUM("AIF2TX", aif2tx_enum);
+
+static const char *inmux_text[] = {
+	"ADC", "DMIC1", "DMIC2"
+};
+
+static const struct soc_enum in1_enum =
+	SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_7, 0, 3, inmux_text);
+
+static const struct snd_kcontrol_new in1_mux =
+	SOC_DAPM_ENUM("IN1 Mux", in1_enum);
+
+static const struct soc_enum in2_enum =
+	SOC_ENUM_SINGLE(WM8915_POWER_MANAGEMENT_7, 4, 3, inmux_text);
+
+static const struct snd_kcontrol_new in2_mux =
+	SOC_DAPM_ENUM("IN2 Mux", in2_enum);
+
+static const struct snd_kcontrol_new dac2r_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING,
+		5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING,
+		4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC2_RIGHT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac2l_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC2_LEFT_MIXER_ROUTING,
+		5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC2_LEFT_MIXER_ROUTING,
+		4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC2_LEFT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC2_LEFT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac1r_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING,
+		5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING,
+		4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC1_RIGHT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dac1l_mix[] = {
+SOC_DAPM_SINGLE("Right Sidetone Switch", WM8915_DAC1_LEFT_MIXER_ROUTING,
+		5, 1, 0),
+SOC_DAPM_SINGLE("Left Sidetone Switch", WM8915_DAC1_LEFT_MIXER_ROUTING,
+		4, 1, 0),
+SOC_DAPM_SINGLE("DSP2 Switch", WM8915_DAC1_LEFT_MIXER_ROUTING, 1, 1, 0),
+SOC_DAPM_SINGLE("DSP1 Switch", WM8915_DAC1_LEFT_MIXER_ROUTING, 0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp1txl[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP1_TX_LEFT_MIXER_ROUTING,
+		1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP1_TX_LEFT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp1txr[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP1_TX_RIGHT_MIXER_ROUTING,
+		1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP1_TX_RIGHT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp2txl[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP2_TX_LEFT_MIXER_ROUTING,
+		1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP2_TX_LEFT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+static const struct snd_kcontrol_new dsp2txr[] = {
+SOC_DAPM_SINGLE("IN1 Switch", WM8915_DSP2_TX_RIGHT_MIXER_ROUTING,
+		1, 1, 0),
+SOC_DAPM_SINGLE("DAC Switch", WM8915_DSP2_TX_RIGHT_MIXER_ROUTING,
+		0, 1, 0),
+};
+
+
+static const struct snd_soc_dapm_widget wm8915_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN1LN"),
+SND_SOC_DAPM_INPUT("IN1LP"),
+SND_SOC_DAPM_INPUT("IN1RN"),
+SND_SOC_DAPM_INPUT("IN1RP"),
+
+SND_SOC_DAPM_INPUT("IN2LN"),
+SND_SOC_DAPM_INPUT("IN2LP"),
+SND_SOC_DAPM_INPUT("IN2RN"),
+SND_SOC_DAPM_INPUT("IN2RP"),
+
+SND_SOC_DAPM_INPUT("DMIC1DAT"),
+SND_SOC_DAPM_INPUT("DMIC2DAT"),
+
+SND_SOC_DAPM_SUPPLY_S("SYSCLK", 1, WM8915_AIF_CLOCKING_1, 0, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY_S("SYSDSPCLK", 2, WM8915_CLOCKING_1, 1, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY_S("AIFCLK", 2, WM8915_CLOCKING_1, 2, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY_S("Charge Pump", 2, WM8915_CHARGE_PUMP_1, 15, 0, cp_event,
+		      SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_SUPPLY("LDO2", WM8915_POWER_MANAGEMENT_2, 1, 0, NULL, 0),
+SND_SOC_DAPM_MICBIAS("MICB2", WM8915_POWER_MANAGEMENT_1, 9, 0),
+SND_SOC_DAPM_MICBIAS("MICB1", WM8915_POWER_MANAGEMENT_1, 8, 0),
+
+SND_SOC_DAPM_PGA("IN1L PGA", WM8915_POWER_MANAGEMENT_2, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN1R PGA", WM8915_POWER_MANAGEMENT_2, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("IN1L Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
+SND_SOC_DAPM_MUX("IN1R Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
+SND_SOC_DAPM_MUX("IN2L Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
+SND_SOC_DAPM_MUX("IN2R Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
+
+SND_SOC_DAPM_PGA("IN1L", WM8915_POWER_MANAGEMENT_7, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN1R", WM8915_POWER_MANAGEMENT_7, 3, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN2L", WM8915_POWER_MANAGEMENT_7, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA("IN2R", WM8915_POWER_MANAGEMENT_7, 7, 0, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("DMIC2", WM8915_POWER_MANAGEMENT_7, 9, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("DMIC1", WM8915_POWER_MANAGEMENT_7, 8, 0, NULL, 0),
+
+SND_SOC_DAPM_ADC("DMIC2L", NULL, WM8915_POWER_MANAGEMENT_3, 5, 0),
+SND_SOC_DAPM_ADC("DMIC2R", NULL, WM8915_POWER_MANAGEMENT_3, 4, 0),
+SND_SOC_DAPM_ADC("DMIC1L", NULL, WM8915_POWER_MANAGEMENT_3, 3, 0),
+SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8915_POWER_MANAGEMENT_3, 2, 0),
+
+SND_SOC_DAPM_ADC("ADCL", NULL, WM8915_POWER_MANAGEMENT_3, 1, 0),
+SND_SOC_DAPM_ADC("ADCR", NULL, WM8915_POWER_MANAGEMENT_3, 0, 0),
+
+SND_SOC_DAPM_MUX("Left Sidetone", SND_SOC_NOPM, 0, 0, &left_sidetone),
+SND_SOC_DAPM_MUX("Right Sidetone", SND_SOC_NOPM, 0, 0, &right_sidetone),
+
+SND_SOC_DAPM_AIF_IN("DSP2RXL", NULL, 0, WM8915_POWER_MANAGEMENT_3, 11, 0),
+SND_SOC_DAPM_AIF_IN("DSP2RXR", NULL, 1, WM8915_POWER_MANAGEMENT_3, 10, 0),
+SND_SOC_DAPM_AIF_IN("DSP1RXL", NULL, 0, WM8915_POWER_MANAGEMENT_3, 9, 0),
+SND_SOC_DAPM_AIF_IN("DSP1RXR", NULL, 1, WM8915_POWER_MANAGEMENT_3, 8, 0),
+
+SND_SOC_DAPM_MIXER("DSP2TXL", WM8915_POWER_MANAGEMENT_5, 11, 0,
+		   dsp2txl, ARRAY_SIZE(dsp2txl)),
+SND_SOC_DAPM_MIXER("DSP2TXR", WM8915_POWER_MANAGEMENT_5, 10, 0,
+		   dsp2txr, ARRAY_SIZE(dsp2txr)),
+SND_SOC_DAPM_MIXER("DSP1TXL", WM8915_POWER_MANAGEMENT_5, 9, 0,
+		   dsp1txl, ARRAY_SIZE(dsp1txl)),
+SND_SOC_DAPM_MIXER("DSP1TXR", WM8915_POWER_MANAGEMENT_5, 8, 0,
+		   dsp1txr, ARRAY_SIZE(dsp1txr)),
+
+SND_SOC_DAPM_MIXER("DAC2L Mixer", SND_SOC_NOPM, 0, 0,
+		   dac2l_mix, ARRAY_SIZE(dac2l_mix)),
+SND_SOC_DAPM_MIXER("DAC2R Mixer", SND_SOC_NOPM, 0, 0,
+		   dac2r_mix, ARRAY_SIZE(dac2r_mix)),
+SND_SOC_DAPM_MIXER("DAC1L Mixer", SND_SOC_NOPM, 0, 0,
+		   dac1l_mix, ARRAY_SIZE(dac1l_mix)),
+SND_SOC_DAPM_MIXER("DAC1R Mixer", SND_SOC_NOPM, 0, 0,
+		   dac1r_mix, ARRAY_SIZE(dac1r_mix)),
+
+SND_SOC_DAPM_DAC("DAC2L", NULL, WM8915_POWER_MANAGEMENT_5, 3, 0),
+SND_SOC_DAPM_DAC("DAC2R", NULL, WM8915_POWER_MANAGEMENT_5, 2, 0),
+SND_SOC_DAPM_DAC("DAC1L", NULL, WM8915_POWER_MANAGEMENT_5, 1, 0),
+SND_SOC_DAPM_DAC("DAC1R", NULL, WM8915_POWER_MANAGEMENT_5, 0, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2RX1", "AIF2 Playback", 1,
+		    WM8915_POWER_MANAGEMENT_4, 9, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX0", "AIF2 Playback", 2,
+		    WM8915_POWER_MANAGEMENT_4, 8, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2TX1", "AIF2 Capture", 1,
+		    WM8915_POWER_MANAGEMENT_6, 9, 0),
+SND_SOC_DAPM_AIF_IN("AIF2TX0", "AIF2 Capture", 2,
+		    WM8915_POWER_MANAGEMENT_6, 8, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX5", "AIF1 Playback", 5,
+		    WM8915_POWER_MANAGEMENT_4, 5, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", "AIF1 Playback", 4,
+		    WM8915_POWER_MANAGEMENT_4, 4, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", "AIF1 Playback", 3,
+		    WM8915_POWER_MANAGEMENT_4, 3, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", "AIF1 Playback", 2,
+		    WM8915_POWER_MANAGEMENT_4, 2, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX1", "AIF1 Playback", 1,
+		    WM8915_POWER_MANAGEMENT_4, 1, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX0", "AIF1 Playback", 0,
+		    WM8915_POWER_MANAGEMENT_4, 0, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", "AIF1 Capture", 5,
+		     WM8915_POWER_MANAGEMENT_6, 5, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", "AIF1 Capture", 4,
+		     WM8915_POWER_MANAGEMENT_6, 4, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", "AIF1 Capture", 3,
+		     WM8915_POWER_MANAGEMENT_6, 3, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", "AIF1 Capture", 2,
+		     WM8915_POWER_MANAGEMENT_6, 2, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", "AIF1 Capture", 1,
+		     WM8915_POWER_MANAGEMENT_6, 1, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX0", "AIF1 Capture", 0,
+		     WM8915_POWER_MANAGEMENT_6, 0, 0),
+
+/* We route as stereo pairs so define some dummy widgets to squash
+ * things down for now.  RXA = 0,1, RXB = 2,3 and so on */
+SND_SOC_DAPM_PGA("AIF1RXA", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("AIF1RXB", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("AIF1RXC", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("AIF2RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("DSP2TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("DSP1RX", SND_SOC_NOPM, 0, 0, &dsp1rx),
+SND_SOC_DAPM_MUX("DSP2RX", SND_SOC_NOPM, 0, 0, &dsp2rx),
+SND_SOC_DAPM_MUX("AIF2TX", SND_SOC_NOPM, 0, 0, &aif2tx),
+
+SND_SOC_DAPM_MUX("SPKL", SND_SOC_NOPM, 0, 0, &spkl_mux),
+SND_SOC_DAPM_MUX("SPKR", SND_SOC_NOPM, 0, 0, &spkr_mux),
+SND_SOC_DAPM_PGA("SPKL PGA", WM8915_LEFT_PDM_SPEAKER, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA("SPKR PGA", WM8915_RIGHT_PDM_SPEAKER, 4, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA_S("HPOUT2L PGA", 0, WM8915_POWER_MANAGEMENT_1, 7, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2L_DLY", 1, WM8915_ANALOGUE_HP_2, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2L_DCS", 2, WM8915_DC_SERVO_1, 2, 0, dcs_start,
+		   SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT2L_OUTP", 3, WM8915_ANALOGUE_HP_2, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2L_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT2L, 0,
+		   rmv_short_event,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_PGA_S("HPOUT2R PGA", 0, WM8915_POWER_MANAGEMENT_1, 6, 0,NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2R_DLY", 1, WM8915_ANALOGUE_HP_2, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2R_DCS", 2, WM8915_DC_SERVO_1, 3, 0, dcs_start,
+		   SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT2R_OUTP", 3, WM8915_ANALOGUE_HP_2, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT2R_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT2R, 0,
+		   rmv_short_event,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_PGA_S("HPOUT1L PGA", 0, WM8915_POWER_MANAGEMENT_1, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1L_DLY", 1, WM8915_ANALOGUE_HP_1, 5, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1L_DCS", 2, WM8915_DC_SERVO_1, 0, 0, dcs_start,
+		   SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT1L_OUTP", 3, WM8915_ANALOGUE_HP_1, 6, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1L_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT1L, 0,
+		   rmv_short_event,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_PGA_S("HPOUT1R PGA", 0, WM8915_POWER_MANAGEMENT_1, 4, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1R_DLY", 1, WM8915_ANALOGUE_HP_1, 1, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1R_DCS", 2, WM8915_DC_SERVO_1, 1, 0, dcs_start,
+		   SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_S("HPOUT1R_OUTP", 3, WM8915_ANALOGUE_HP_1, 2, 0, NULL, 0),
+SND_SOC_DAPM_PGA_S("HPOUT1R_RMV_SHORT", 3, SND_SOC_NOPM, HPOUT1R, 0,
+		   rmv_short_event,
+		   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_OUTPUT("HPOUT1L"),
+SND_SOC_DAPM_OUTPUT("HPOUT1R"),
+SND_SOC_DAPM_OUTPUT("HPOUT2L"),
+SND_SOC_DAPM_OUTPUT("HPOUT2R"),
+SND_SOC_DAPM_OUTPUT("SPKDAT"),
+};
+
+static const struct snd_soc_dapm_route wm8915_dapm_routes[] = {
+	{ "AIFCLK", NULL, "SYSCLK" },
+	{ "SYSDSPCLK", NULL, "SYSCLK" },
+	{ "Charge Pump", NULL, "SYSCLK" },
+
+	{ "MICB1", NULL, "LDO2" },
+	{ "MICB2", NULL, "LDO2" },
+
+	{ "IN1L PGA", NULL, "IN2LN" },
+	{ "IN1L PGA", NULL, "IN2LP" },
+	{ "IN1L PGA", NULL, "IN1LN" },
+	{ "IN1L PGA", NULL, "IN1LP" },
+
+	{ "IN1R PGA", NULL, "IN2RN" },
+	{ "IN1R PGA", NULL, "IN2RP" },
+	{ "IN1R PGA", NULL, "IN1RN" },
+	{ "IN1R PGA", NULL, "IN1RP" },
+
+	{ "ADCL", NULL, "IN1L PGA" },
+
+	{ "ADCR", NULL, "IN1R PGA" },
+
+	{ "DMIC1L", NULL, "DMIC1DAT" },
+	{ "DMIC1R", NULL, "DMIC1DAT" },
+	{ "DMIC2L", NULL, "DMIC2DAT" },
+	{ "DMIC2R", NULL, "DMIC2DAT" },
+
+	{ "DMIC2L", NULL, "DMIC2" },
+	{ "DMIC2R", NULL, "DMIC2" },
+	{ "DMIC1L", NULL, "DMIC1" },
+	{ "DMIC1R", NULL, "DMIC1" },
+
+	{ "IN1L Mux", "ADC", "ADCL" },
+	{ "IN1L Mux", "DMIC1", "DMIC1L" },
+	{ "IN1L Mux", "DMIC2", "DMIC2L" },
+
+	{ "IN1R Mux", "ADC", "ADCR" },
+	{ "IN1R Mux", "DMIC1", "DMIC1R" },
+	{ "IN1R Mux", "DMIC2", "DMIC2R" },
+
+	{ "IN2L Mux", "ADC", "ADCL" },
+	{ "IN2L Mux", "DMIC1", "DMIC1L" },
+	{ "IN2L Mux", "DMIC2", "DMIC2L" },
+
+	{ "IN2R Mux", "ADC", "ADCR" },
+	{ "IN2R Mux", "DMIC1", "DMIC1R" },
+	{ "IN2R Mux", "DMIC2", "DMIC2R" },
+
+	{ "Left Sidetone", "IN1", "IN1L Mux" },
+	{ "Left Sidetone", "IN2", "IN2L Mux" },
+
+	{ "Right Sidetone", "IN1", "IN1R Mux" },
+	{ "Right Sidetone", "IN2", "IN2R Mux" },
+
+	{ "DSP1TXL", "IN1 Switch", "IN1L Mux" },
+	{ "DSP1TXR", "IN1 Switch", "IN1R Mux" },
+
+	{ "DSP2TXL", "IN1 Switch", "IN2L Mux" },
+	{ "DSP2TXR", "IN1 Switch", "IN2R Mux" },
+
+	{ "AIF1TX0", NULL, "DSP1TXL" },
+	{ "AIF1TX1", NULL, "DSP1TXR" },
+	{ "AIF1TX2", NULL, "DSP2TXL" },
+	{ "AIF1TX3", NULL, "DSP2TXR" },
+	{ "AIF1TX4", NULL, "AIF2RX0" },
+	{ "AIF1TX5", NULL, "AIF2RX1" },
+
+	{ "AIF1RX0", NULL, "AIFCLK" },
+	{ "AIF1RX1", NULL, "AIFCLK" },
+	{ "AIF1RX2", NULL, "AIFCLK" },
+	{ "AIF1RX3", NULL, "AIFCLK" },
+	{ "AIF1RX4", NULL, "AIFCLK" },
+	{ "AIF1RX5", NULL, "AIFCLK" },
+
+	{ "AIF2RX0", NULL, "AIFCLK" },
+	{ "AIF2RX1", NULL, "AIFCLK" },
+
+	{ "DSP1RXL", NULL, "SYSDSPCLK" },
+	{ "DSP1RXR", NULL, "SYSDSPCLK" },
+	{ "DSP2RXL", NULL, "SYSDSPCLK" },
+	{ "DSP2RXR", NULL, "SYSDSPCLK" },
+	{ "DSP1TXL", NULL, "SYSDSPCLK" },
+	{ "DSP1TXR", NULL, "SYSDSPCLK" },
+	{ "DSP2TXL", NULL, "SYSDSPCLK" },
+	{ "DSP2TXR", NULL, "SYSDSPCLK" },
+
+	{ "AIF1RXA", NULL, "AIF1RX0" },
+	{ "AIF1RXA", NULL, "AIF1RX1" },
+	{ "AIF1RXB", NULL, "AIF1RX2" },
+	{ "AIF1RXB", NULL, "AIF1RX3" },
+	{ "AIF1RXC", NULL, "AIF1RX4" },
+	{ "AIF1RXC", NULL, "AIF1RX5" },
+
+	{ "AIF2RX", NULL, "AIF2RX0" },
+	{ "AIF2RX", NULL, "AIF2RX1" },
+
+	{ "AIF2TX", "DSP2", "DSP2TX" },
+	{ "AIF2TX", "DSP1", "DSP1RX" },
+	{ "AIF2TX", "AIF1", "AIF1RXC" },
+
+	{ "DSP1RXL", NULL, "DSP1RX" },
+	{ "DSP1RXR", NULL, "DSP1RX" },
+	{ "DSP2RXL", NULL, "DSP2RX" },
+	{ "DSP2RXR", NULL, "DSP2RX" },
+
+	{ "DSP2TX", NULL, "DSP2TXL" },
+	{ "DSP2TX", NULL, "DSP2TXR" },
+
+	{ "DSP1RX", "AIF1", "AIF1RXA" },
+	{ "DSP1RX", "AIF2", "AIF2RX" },
+
+	{ "DSP2RX", "AIF1", "AIF1RXB" },
+	{ "DSP2RX", "AIF2", "AIF2RX" },
+
+	{ "DAC2L Mixer", "DSP2 Switch", "DSP2RXL" },
+	{ "DAC2L Mixer", "DSP1 Switch", "DSP1RXL" },
+	{ "DAC2L Mixer", "Right Sidetone Switch", "Right Sidetone" },
+	{ "DAC2L Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+	{ "DAC2R Mixer", "DSP2 Switch", "DSP2RXR" },
+	{ "DAC2R Mixer", "DSP1 Switch", "DSP1RXR" },
+	{ "DAC2R Mixer", "Right Sidetone Switch", "Right Sidetone" },
+	{ "DAC2R Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+	{ "DAC1L Mixer", "DSP2 Switch", "DSP2RXL" },
+	{ "DAC1L Mixer", "DSP1 Switch", "DSP1RXL" },
+	{ "DAC1L Mixer", "Right Sidetone Switch", "Right Sidetone" },
+	{ "DAC1L Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+	{ "DAC1R Mixer", "DSP2 Switch", "DSP2RXR" },
+	{ "DAC1R Mixer", "DSP1 Switch", "DSP1RXR" },
+	{ "DAC1R Mixer", "Right Sidetone Switch", "Right Sidetone" },
+	{ "DAC1R Mixer", "Left Sidetone Switch", "Left Sidetone" },
+
+	{ "DAC1L", NULL, "DAC1L Mixer" },
+	{ "DAC1R", NULL, "DAC1R Mixer" },
+	{ "DAC2L", NULL, "DAC2L Mixer" },
+	{ "DAC2R", NULL, "DAC2R Mixer" },
+
+	{ "HPOUT2L PGA", NULL, "Charge Pump" },
+	{ "HPOUT2L PGA", NULL, "DAC2L" },
+	{ "HPOUT2L_DLY", NULL, "HPOUT2L PGA" },
+	{ "HPOUT2L_DCS", NULL, "HPOUT2L_DLY" },
+	{ "HPOUT2L_OUTP", NULL, "HPOUT2L_DCS" },
+	{ "HPOUT2L_RMV_SHORT", NULL, "HPOUT2L_OUTP" },
+
+	{ "HPOUT2R PGA", NULL, "Charge Pump" },
+	{ "HPOUT2R PGA", NULL, "DAC2R" },
+	{ "HPOUT2R_DLY", NULL, "HPOUT2R PGA" },
+	{ "HPOUT2R_DCS", NULL, "HPOUT2R_DLY" },
+	{ "HPOUT2R_OUTP", NULL, "HPOUT2R_DCS" },
+	{ "HPOUT2R_RMV_SHORT", NULL, "HPOUT2R_OUTP" },
+
+	{ "HPOUT1L PGA", NULL, "Charge Pump" },
+	{ "HPOUT1L PGA", NULL, "DAC1L" },
+	{ "HPOUT1L_DLY", NULL, "HPOUT1L PGA" },
+	{ "HPOUT1L_DCS", NULL, "HPOUT1L_DLY" },
+	{ "HPOUT1L_OUTP", NULL, "HPOUT1L_DCS" },
+	{ "HPOUT1L_RMV_SHORT", NULL, "HPOUT1L_OUTP" },
+
+	{ "HPOUT1R PGA", NULL, "Charge Pump" },
+	{ "HPOUT1R PGA", NULL, "DAC1R" },
+	{ "HPOUT1R_DLY", NULL, "HPOUT1R PGA" },
+	{ "HPOUT1R_DCS", NULL, "HPOUT1R_DLY" },
+	{ "HPOUT1R_OUTP", NULL, "HPOUT1R_DCS" },
+	{ "HPOUT1R_RMV_SHORT", NULL, "HPOUT1R_OUTP" },
+
+	{ "HPOUT2L", NULL, "HPOUT2L_RMV_SHORT" },
+	{ "HPOUT2R", NULL, "HPOUT2R_RMV_SHORT" },
+	{ "HPOUT1L", NULL, "HPOUT1L_RMV_SHORT" },
+	{ "HPOUT1R", NULL, "HPOUT1R_RMV_SHORT" },
+
+	{ "SPKL", "DAC1L", "DAC1L" },
+	{ "SPKL", "DAC1R", "DAC1R" },
+	{ "SPKL", "DAC2L", "DAC2L" },
+	{ "SPKL", "DAC2R", "DAC2R" },
+
+	{ "SPKR", "DAC1L", "DAC1L" },
+	{ "SPKR", "DAC1R", "DAC1R" },
+	{ "SPKR", "DAC2L", "DAC2L" },
+	{ "SPKR", "DAC2R", "DAC2R" },
+
+	{ "SPKL PGA", NULL, "SPKL" },
+	{ "SPKR PGA", NULL, "SPKR" },
+
+	{ "SPKDAT", NULL, "SPKL PGA" },
+	{ "SPKDAT", NULL, "SPKR PGA" },
+};
+
+static int wm8915_readable_register(struct snd_soc_codec *codec,
+				    unsigned int reg)
+{
+	/* Due to the sparseness of the register map the compiler
+	 * output from an explicit switch statement ends up being much
+	 * more efficient than a table.
+	 */
+	switch (reg) {
+	case WM8915_SOFTWARE_RESET:
+	case WM8915_POWER_MANAGEMENT_1:
+	case WM8915_POWER_MANAGEMENT_2:
+	case WM8915_POWER_MANAGEMENT_3:
+	case WM8915_POWER_MANAGEMENT_4:
+	case WM8915_POWER_MANAGEMENT_5:
+	case WM8915_POWER_MANAGEMENT_6:
+	case WM8915_POWER_MANAGEMENT_7:
+	case WM8915_POWER_MANAGEMENT_8:
+	case WM8915_LEFT_LINE_INPUT_VOLUME:
+	case WM8915_RIGHT_LINE_INPUT_VOLUME:
+	case WM8915_LINE_INPUT_CONTROL:
+	case WM8915_DAC1_HPOUT1_VOLUME:
+	case WM8915_DAC2_HPOUT2_VOLUME:
+	case WM8915_DAC1_LEFT_VOLUME:
+	case WM8915_DAC1_RIGHT_VOLUME:
+	case WM8915_DAC2_LEFT_VOLUME:
+	case WM8915_DAC2_RIGHT_VOLUME:
+	case WM8915_OUTPUT1_LEFT_VOLUME:
+	case WM8915_OUTPUT1_RIGHT_VOLUME:
+	case WM8915_OUTPUT2_LEFT_VOLUME:
+	case WM8915_OUTPUT2_RIGHT_VOLUME:
+	case WM8915_MICBIAS_1:
+	case WM8915_MICBIAS_2:
+	case WM8915_LDO_1:
+	case WM8915_LDO_2:
+	case WM8915_ACCESSORY_DETECT_MODE_1:
+	case WM8915_ACCESSORY_DETECT_MODE_2:
+	case WM8915_HEADPHONE_DETECT_1:
+	case WM8915_HEADPHONE_DETECT_2:
+	case WM8915_MIC_DETECT_1:
+	case WM8915_MIC_DETECT_2:
+	case WM8915_MIC_DETECT_3:
+	case WM8915_CHARGE_PUMP_1:
+	case WM8915_CHARGE_PUMP_2:
+	case WM8915_DC_SERVO_1:
+	case WM8915_DC_SERVO_2:
+	case WM8915_DC_SERVO_3:
+	case WM8915_DC_SERVO_5:
+	case WM8915_DC_SERVO_6:
+	case WM8915_DC_SERVO_7:
+	case WM8915_DC_SERVO_READBACK_0:
+	case WM8915_ANALOGUE_HP_1:
+	case WM8915_ANALOGUE_HP_2:
+	case WM8915_CHIP_REVISION:
+	case WM8915_CONTROL_INTERFACE_1:
+	case WM8915_WRITE_SEQUENCER_CTRL_1:
+	case WM8915_WRITE_SEQUENCER_CTRL_2:
+	case WM8915_AIF_CLOCKING_1:
+	case WM8915_AIF_CLOCKING_2:
+	case WM8915_CLOCKING_1:
+	case WM8915_CLOCKING_2:
+	case WM8915_AIF_RATE:
+	case WM8915_FLL_CONTROL_1:
+	case WM8915_FLL_CONTROL_2:
+	case WM8915_FLL_CONTROL_3:
+	case WM8915_FLL_CONTROL_4:
+	case WM8915_FLL_CONTROL_5:
+	case WM8915_FLL_CONTROL_6:
+	case WM8915_FLL_EFS_1:
+	case WM8915_FLL_EFS_2:
+	case WM8915_AIF1_CONTROL:
+	case WM8915_AIF1_BCLK:
+	case WM8915_AIF1_TX_LRCLK_1:
+	case WM8915_AIF1_TX_LRCLK_2:
+	case WM8915_AIF1_RX_LRCLK_1:
+	case WM8915_AIF1_RX_LRCLK_2:
+	case WM8915_AIF1TX_DATA_CONFIGURATION_1:
+	case WM8915_AIF1TX_DATA_CONFIGURATION_2:
+	case WM8915_AIF1RX_DATA_CONFIGURATION:
+	case WM8915_AIF1TX_CHANNEL_0_CONFIGURATION:
+	case WM8915_AIF1TX_CHANNEL_1_CONFIGURATION:
+	case WM8915_AIF1TX_CHANNEL_2_CONFIGURATION:
+	case WM8915_AIF1TX_CHANNEL_3_CONFIGURATION:
+	case WM8915_AIF1TX_CHANNEL_4_CONFIGURATION:
+	case WM8915_AIF1TX_CHANNEL_5_CONFIGURATION:
+	case WM8915_AIF1RX_CHANNEL_0_CONFIGURATION:
+	case WM8915_AIF1RX_CHANNEL_1_CONFIGURATION:
+	case WM8915_AIF1RX_CHANNEL_2_CONFIGURATION:
+	case WM8915_AIF1RX_CHANNEL_3_CONFIGURATION:
+	case WM8915_AIF1RX_CHANNEL_4_CONFIGURATION:
+	case WM8915_AIF1RX_CHANNEL_5_CONFIGURATION:
+	case WM8915_AIF1RX_MONO_CONFIGURATION:
+	case WM8915_AIF1TX_TEST:
+	case WM8915_AIF2_CONTROL:
+	case WM8915_AIF2_BCLK:
+	case WM8915_AIF2_TX_LRCLK_1:
+	case WM8915_AIF2_TX_LRCLK_2:
+	case WM8915_AIF2_RX_LRCLK_1:
+	case WM8915_AIF2_RX_LRCLK_2:
+	case WM8915_AIF2TX_DATA_CONFIGURATION_1:
+	case WM8915_AIF2TX_DATA_CONFIGURATION_2:
+	case WM8915_AIF2RX_DATA_CONFIGURATION:
+	case WM8915_AIF2TX_CHANNEL_0_CONFIGURATION:
+	case WM8915_AIF2TX_CHANNEL_1_CONFIGURATION:
+	case WM8915_AIF2RX_CHANNEL_0_CONFIGURATION:
+	case WM8915_AIF2RX_CHANNEL_1_CONFIGURATION:
+	case WM8915_AIF2RX_MONO_CONFIGURATION:
+	case WM8915_AIF2TX_TEST:
+	case WM8915_DSP1_TX_LEFT_VOLUME:
+	case WM8915_DSP1_TX_RIGHT_VOLUME:
+	case WM8915_DSP1_RX_LEFT_VOLUME:
+	case WM8915_DSP1_RX_RIGHT_VOLUME:
+	case WM8915_DSP1_TX_FILTERS:
+	case WM8915_DSP1_RX_FILTERS_1:
+	case WM8915_DSP1_RX_FILTERS_2:
+	case WM8915_DSP1_DRC_1:
+	case WM8915_DSP1_DRC_2:
+	case WM8915_DSP1_DRC_3:
+	case WM8915_DSP1_DRC_4:
+	case WM8915_DSP1_DRC_5:
+	case WM8915_DSP1_RX_EQ_GAINS_1:
+	case WM8915_DSP1_RX_EQ_GAINS_2:
+	case WM8915_DSP1_RX_EQ_BAND_1_A:
+	case WM8915_DSP1_RX_EQ_BAND_1_B:
+	case WM8915_DSP1_RX_EQ_BAND_1_PG:
+	case WM8915_DSP1_RX_EQ_BAND_2_A:
+	case WM8915_DSP1_RX_EQ_BAND_2_B:
+	case WM8915_DSP1_RX_EQ_BAND_2_C:
+	case WM8915_DSP1_RX_EQ_BAND_2_PG:
+	case WM8915_DSP1_RX_EQ_BAND_3_A:
+	case WM8915_DSP1_RX_EQ_BAND_3_B:
+	case WM8915_DSP1_RX_EQ_BAND_3_C:
+	case WM8915_DSP1_RX_EQ_BAND_3_PG:
+	case WM8915_DSP1_RX_EQ_BAND_4_A:
+	case WM8915_DSP1_RX_EQ_BAND_4_B:
+	case WM8915_DSP1_RX_EQ_BAND_4_C:
+	case WM8915_DSP1_RX_EQ_BAND_4_PG:
+	case WM8915_DSP1_RX_EQ_BAND_5_A:
+	case WM8915_DSP1_RX_EQ_BAND_5_B:
+	case WM8915_DSP1_RX_EQ_BAND_5_PG:
+	case WM8915_DSP2_TX_LEFT_VOLUME:
+	case WM8915_DSP2_TX_RIGHT_VOLUME:
+	case WM8915_DSP2_RX_LEFT_VOLUME:
+	case WM8915_DSP2_RX_RIGHT_VOLUME:
+	case WM8915_DSP2_TX_FILTERS:
+	case WM8915_DSP2_RX_FILTERS_1:
+	case WM8915_DSP2_RX_FILTERS_2:
+	case WM8915_DSP2_DRC_1:
+	case WM8915_DSP2_DRC_2:
+	case WM8915_DSP2_DRC_3:
+	case WM8915_DSP2_DRC_4:
+	case WM8915_DSP2_DRC_5:
+	case WM8915_DSP2_RX_EQ_GAINS_1:
+	case WM8915_DSP2_RX_EQ_GAINS_2:
+	case WM8915_DSP2_RX_EQ_BAND_1_A:
+	case WM8915_DSP2_RX_EQ_BAND_1_B:
+	case WM8915_DSP2_RX_EQ_BAND_1_PG:
+	case WM8915_DSP2_RX_EQ_BAND_2_A:
+	case WM8915_DSP2_RX_EQ_BAND_2_B:
+	case WM8915_DSP2_RX_EQ_BAND_2_C:
+	case WM8915_DSP2_RX_EQ_BAND_2_PG:
+	case WM8915_DSP2_RX_EQ_BAND_3_A:
+	case WM8915_DSP2_RX_EQ_BAND_3_B:
+	case WM8915_DSP2_RX_EQ_BAND_3_C:
+	case WM8915_DSP2_RX_EQ_BAND_3_PG:
+	case WM8915_DSP2_RX_EQ_BAND_4_A:
+	case WM8915_DSP2_RX_EQ_BAND_4_B:
+	case WM8915_DSP2_RX_EQ_BAND_4_C:
+	case WM8915_DSP2_RX_EQ_BAND_4_PG:
+	case WM8915_DSP2_RX_EQ_BAND_5_A:
+	case WM8915_DSP2_RX_EQ_BAND_5_B:
+	case WM8915_DSP2_RX_EQ_BAND_5_PG:
+	case WM8915_DAC1_MIXER_VOLUMES:
+	case WM8915_DAC1_LEFT_MIXER_ROUTING:
+	case WM8915_DAC1_RIGHT_MIXER_ROUTING:
+	case WM8915_DAC2_MIXER_VOLUMES:
+	case WM8915_DAC2_LEFT_MIXER_ROUTING:
+	case WM8915_DAC2_RIGHT_MIXER_ROUTING:
+	case WM8915_DSP1_TX_LEFT_MIXER_ROUTING:
+	case WM8915_DSP1_TX_RIGHT_MIXER_ROUTING:
+	case WM8915_DSP2_TX_LEFT_MIXER_ROUTING:
+	case WM8915_DSP2_TX_RIGHT_MIXER_ROUTING:
+	case WM8915_DSP_TX_MIXER_SELECT:
+	case WM8915_DAC_SOFTMUTE:
+	case WM8915_OVERSAMPLING:
+	case WM8915_SIDETONE:
+	case WM8915_GPIO_1:
+	case WM8915_GPIO_2:
+	case WM8915_GPIO_3:
+	case WM8915_GPIO_4:
+	case WM8915_GPIO_5:
+	case WM8915_PULL_CONTROL_1:
+	case WM8915_PULL_CONTROL_2:
+	case WM8915_INTERRUPT_STATUS_1:
+	case WM8915_INTERRUPT_STATUS_2:
+	case WM8915_INTERRUPT_RAW_STATUS_2:
+	case WM8915_INTERRUPT_STATUS_1_MASK:
+	case WM8915_INTERRUPT_STATUS_2_MASK:
+	case WM8915_INTERRUPT_CONTROL:
+	case WM8915_LEFT_PDM_SPEAKER:
+	case WM8915_RIGHT_PDM_SPEAKER:
+	case WM8915_PDM_SPEAKER_MUTE_SEQUENCE:
+	case WM8915_PDM_SPEAKER_VOLUME:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static int wm8915_volatile_register(struct snd_soc_codec *codec,
+				    unsigned int reg)
+{
+	switch (reg) {
+	case WM8915_SOFTWARE_RESET:
+	case WM8915_CHIP_REVISION:
+	case WM8915_LDO_1:
+	case WM8915_LDO_2:
+	case WM8915_INTERRUPT_STATUS_1:
+	case WM8915_INTERRUPT_STATUS_2:
+	case WM8915_INTERRUPT_RAW_STATUS_2:
+	case WM8915_DC_SERVO_READBACK_0:
+	case WM8915_DC_SERVO_2:
+	case WM8915_DC_SERVO_6:
+	case WM8915_DC_SERVO_7:
+	case WM8915_FLL_CONTROL_6:
+	case WM8915_MIC_DETECT_3:
+	case WM8915_HEADPHONE_DETECT_1:
+	case WM8915_HEADPHONE_DETECT_2:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static int wm8915_reset(struct snd_soc_codec *codec)
+{
+	return snd_soc_write(codec, WM8915_SOFTWARE_RESET, 0x8915);
+}
+
+static int wm8915_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
+			snd_soc_update_bits(codec, WM8915_POWER_MANAGEMENT_1,
+					    WM8915_BG_ENA, WM8915_BG_ENA);
+			msleep(2);
+		}
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			ret = regulator_bulk_enable(ARRAY_SIZE(wm8915->supplies),
+						    wm8915->supplies);
+			if (ret != 0) {
+				dev_err(codec->dev,
+					"Failed to enable supplies: %d\n",
+					ret);
+				return ret;
+			}
+
+			if (wm8915->pdata.ldo_ena >= 0) {
+				gpio_set_value_cansleep(wm8915->pdata.ldo_ena,
+							1);
+				msleep(5);
+			}
+
+			codec->cache_only = false;
+			snd_soc_cache_sync(codec);
+		}
+
+		snd_soc_update_bits(codec, WM8915_POWER_MANAGEMENT_1,
+				    WM8915_BG_ENA, 0);
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		codec->cache_only = true;
+		if (wm8915->pdata.ldo_ena >= 0)
+			gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 0);
+		regulator_bulk_disable(ARRAY_SIZE(wm8915->supplies),
+				       wm8915->supplies);
+		break;
+	}
+
+	codec->dapm.bias_level = level;
+
+	return 0;
+}
+
+static int wm8915_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	int aifctrl = 0;
+	int bclk = 0;
+	int lrclk_tx = 0;
+	int lrclk_rx = 0;
+	int aifctrl_reg, bclk_reg, lrclk_tx_reg, lrclk_rx_reg;
+
+	switch (dai->id) {
+	case 0:
+		aifctrl_reg = WM8915_AIF1_CONTROL;
+		bclk_reg = WM8915_AIF1_BCLK;
+		lrclk_tx_reg = WM8915_AIF1_TX_LRCLK_2;
+		lrclk_rx_reg = WM8915_AIF1_RX_LRCLK_2;
+		break;
+	case 1:
+		aifctrl_reg = WM8915_AIF2_CONTROL;
+		bclk_reg = WM8915_AIF2_BCLK;
+		lrclk_tx_reg = WM8915_AIF2_TX_LRCLK_2;
+		lrclk_rx_reg = WM8915_AIF2_RX_LRCLK_2;
+		break;
+	default:
+		BUG();
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		bclk |= WM8915_AIF1_BCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		lrclk_tx |= WM8915_AIF1TX_LRCLK_INV;
+		lrclk_rx |= WM8915_AIF1RX_LRCLK_INV;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		bclk |= WM8915_AIF1_BCLK_INV;
+		lrclk_tx |= WM8915_AIF1TX_LRCLK_INV;
+		lrclk_rx |= WM8915_AIF1RX_LRCLK_INV;
+		break;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+		lrclk_tx |= WM8915_AIF1TX_LRCLK_MSTR;
+		lrclk_rx |= WM8915_AIF1RX_LRCLK_MSTR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		bclk |= WM8915_AIF1_BCLK_MSTR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		bclk |= WM8915_AIF1_BCLK_MSTR;
+		lrclk_tx |= WM8915_AIF1TX_LRCLK_MSTR;
+		lrclk_rx |= WM8915_AIF1RX_LRCLK_MSTR;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		aifctrl |= 1;
+		break;
+	case SND_SOC_DAIFMT_I2S:
+		aifctrl |= 2;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aifctrl |= 3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, aifctrl_reg, WM8915_AIF1_FMT_MASK, aifctrl);
+	snd_soc_update_bits(codec, bclk_reg,
+			    WM8915_AIF1_BCLK_INV | WM8915_AIF1_BCLK_MSTR,
+			    bclk);
+	snd_soc_update_bits(codec, lrclk_tx_reg,
+			    WM8915_AIF1TX_LRCLK_INV |
+			    WM8915_AIF1TX_LRCLK_MSTR,
+			    lrclk_tx);
+	snd_soc_update_bits(codec, lrclk_rx_reg,
+			    WM8915_AIF1RX_LRCLK_INV |
+			    WM8915_AIF1RX_LRCLK_MSTR,
+			    lrclk_rx);
+
+	return 0;
+}
+
+static const int bclk_divs[] = {
+	1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96
+};
+
+static const int dsp_divs[] = {
+	48000, 32000, 16000, 8000
+};
+
+static int wm8915_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 wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	int bits, i, bclk_rate, best, cur_val;
+	int aifdata = 0;
+	int bclk = 0;
+	int lrclk = 0;
+	int dsp = 0;
+	int aifdata_reg, bclk_reg, lrclk_reg, dsp_shift;
+
+	if (!wm8915->sysclk) {
+		dev_err(codec->dev, "SYSCLK not configured\n");
+		return -EINVAL;
+	}
+
+	switch (dai->id) {
+	case 0:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+		    (snd_soc_read(codec, WM8915_GPIO_1)) & WM8915_GP1_FN_MASK) {
+			aifdata_reg = WM8915_AIF1RX_DATA_CONFIGURATION;
+			lrclk_reg = WM8915_AIF1_RX_LRCLK_1;
+		} else {
+			aifdata_reg = WM8915_AIF1TX_DATA_CONFIGURATION_1;
+			lrclk_reg = WM8915_AIF1_TX_LRCLK_1;
+		}
+		bclk_reg = WM8915_AIF1_BCLK;
+		dsp_shift = 0;
+		break;
+	case 1:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+		    (snd_soc_read(codec, WM8915_GPIO_2)) & WM8915_GP2_FN_MASK) {
+			aifdata_reg = WM8915_AIF2RX_DATA_CONFIGURATION;
+			lrclk_reg = WM8915_AIF2_RX_LRCLK_1;
+		} else {
+			aifdata_reg = WM8915_AIF2TX_DATA_CONFIGURATION_1;
+			lrclk_reg = WM8915_AIF2_TX_LRCLK_1;
+		}
+		bclk_reg = WM8915_AIF2_BCLK;
+		dsp_shift = WM8915_DSP2_DIV_SHIFT;
+		break;
+	default:
+		BUG();
+		return -EINVAL;
+	}
+
+	bclk_rate = snd_soc_params_to_bclk(params);
+	if (bclk_rate < 0) {
+		dev_err(codec->dev, "Unsupported BCLK rate: %d\n", bclk_rate);
+		return bclk_rate;
+	}
+
+	/* Needs looking at for TDM */
+	bits = snd_pcm_format_width(params_format(params));
+	if (bits < 0)
+		return bits;
+	aifdata |= (bits << WM8915_AIF1TX_WL_SHIFT) | bits;
+
+	for (i = 0; i < ARRAY_SIZE(dsp_divs); i++) {
+		if (dsp_divs[i] == params_rate(params))
+			break;
+	}
+	if (i == ARRAY_SIZE(dsp_divs)) {
+		dev_err(codec->dev, "Unsupported sample rate %dHz\n",
+			params_rate(params));
+		return -EINVAL;
+	}
+	dsp |= i << dsp_shift;
+
+	/* Pick a divisor for BCLK as close as we can get to ideal */
+	best = 0;
+	for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+		cur_val = (wm8915->sysclk / bclk_divs[i]) - bclk_rate;
+		if (cur_val < 0) /* BCLK table is sorted */
+			break;
+		best = i;
+	}
+	bclk_rate = wm8915->sysclk / bclk_divs[best];
+	dev_dbg(dai->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n",
+		bclk_divs[best], bclk_rate);
+	bclk |= best;
+
+	lrclk = bclk_rate / params_rate(params);
+	dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n",
+		lrclk, bclk_rate / lrclk);
+
+	snd_soc_update_bits(codec, aifdata_reg,
+			    WM8915_AIF1TX_WL_MASK |
+			    WM8915_AIF1TX_SLOT_LEN_MASK,
+			    aifdata);
+	snd_soc_update_bits(codec, bclk_reg, WM8915_AIF1_BCLK_DIV_MASK, bclk);
+	snd_soc_update_bits(codec, lrclk_reg, WM8915_AIF1RX_RATE_MASK,
+			    lrclk);
+	snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_2,
+			    WM8915_DSP1_DIV_SHIFT << dsp_shift, dsp);
+
+	wm8915->rx_rate[dai->id] = params_rate(params);
+
+	return 0;
+}
+
+static int wm8915_set_sysclk(struct snd_soc_dai *dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	int lfclk = 0;
+	int ratediv = 0;
+	int src;
+	int old;
+
+	/* Disable SYSCLK while we reconfigure */
+	old = snd_soc_read(codec, WM8915_AIF_CLOCKING_1);
+	snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
+			    WM8915_SYSCLK_ENA, 0);
+
+	switch (clk_id) {
+	case WM8915_SYSCLK_MCLK1:
+		wm8915->sysclk = freq;
+		src = 0;
+		break;
+	case WM8915_SYSCLK_MCLK2:
+		wm8915->sysclk = freq;
+		src = 1;
+		break;
+	case WM8915_SYSCLK_FLL:
+		wm8915->sysclk = freq;
+		src = 2;
+		break;
+	default:
+		dev_err(codec->dev, "Unsupported clock source %d\n", clk_id);
+		return -EINVAL;
+	}
+
+	switch (wm8915->sysclk) {
+	case 6144000:
+		snd_soc_update_bits(codec, WM8915_AIF_RATE,
+				    WM8915_SYSCLK_RATE, 0);
+		break;
+	case 24576000:
+		ratediv = WM8915_SYSCLK_DIV;
+	case 12288000:
+		snd_soc_update_bits(codec, WM8915_AIF_RATE,
+				    WM8915_SYSCLK_RATE, WM8915_SYSCLK_RATE);
+		break;
+	case 32000:
+	case 32768:
+		lfclk = WM8915_LFCLK_ENA;
+		break;
+	default:
+		dev_warn(codec->dev, "Unsupported clock rate %dHz\n",
+			 wm8915->sysclk);
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
+			    WM8915_SYSCLK_SRC_MASK | WM8915_SYSCLK_DIV_MASK,
+			    src << WM8915_SYSCLK_SRC_SHIFT | ratediv);
+	snd_soc_update_bits(codec, WM8915_CLOCKING_1, WM8915_LFCLK_ENA, lfclk);
+	snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1,
+			    WM8915_SYSCLK_ENA, old);
+
+	return 0;
+}
+
+struct _fll_div {
+	u16 fll_fratio;
+	u16 fll_outdiv;
+	u16 fll_refclk_div;
+	u16 fll_loop_gain;
+	u16 fll_ref_freq;
+	u16 n;
+	u16 theta;
+	u16 lambda;
+};
+
+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)
+{
+	unsigned int target;
+	unsigned int div;
+	unsigned int fratio, gcd_fll;
+	int i;
+
+	/* Fref must be <=13.5MHz */
+	div = 1;
+	fll_div->fll_refclk_div = 0;
+	while ((Fref / div) > 13500000) {
+		div *= 2;
+		fll_div->fll_refclk_div++;
+
+		if (div > 8) {
+			pr_err("Can't scale %dMHz input down to <=13.5MHz\n",
+			       Fref);
+			return -EINVAL;
+		}
+	}
+
+	pr_debug("FLL Fref=%u Fout=%u\n", Fref, Fout);
+
+	/* Apply the division for our remaining calculations */
+	Fref /= div;
+
+	if (Fref >= 3000000)
+		fll_div->fll_loop_gain = 5;
+	else
+		fll_div->fll_loop_gain = 0;
+
+	if (Fref >= 48000)
+		fll_div->fll_ref_freq = 0;
+	else
+		fll_div->fll_ref_freq = 1;
+
+	/* Fvco should be 90-100MHz; don't check the upper bound */
+	div = 2;
+	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("FLL 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;
+			fratio = 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;
+	}
+
+	fll_div->n = target / (fratio * Fref);
+
+	if (target % Fref == 0) {
+		fll_div->theta = 0;
+		fll_div->lambda = 0;
+	} else {
+		gcd_fll = gcd(target, fratio * Fref);
+
+		fll_div->theta = (target - (fll_div->n * fratio * Fref))
+			/ gcd_fll;
+		fll_div->lambda = (fratio * Fref) / gcd_fll;
+	}
+
+	pr_debug("FLL N=%x THETA=%x LAMBDA=%x\n",
+		 fll_div->n, fll_div->theta, fll_div->lambda);
+	pr_debug("FLL_FRATIO=%x FLL_OUTDIV=%x FLL_REFCLK_DIV=%x\n",
+		 fll_div->fll_fratio, fll_div->fll_outdiv,
+		 fll_div->fll_refclk_div);
+
+	return 0;
+}
+
+static int wm8915_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+			  unsigned int Fref, unsigned int Fout)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	struct _fll_div fll_div;
+	unsigned long timeout;
+	int ret, reg;
+
+	/* Any change? */
+	if (source == wm8915->fll_src && Fref == wm8915->fll_fref &&
+	    Fout == wm8915->fll_fout)
+		return 0;
+
+	if (Fout == 0) {
+		dev_dbg(codec->dev, "FLL disabled\n");
+
+		wm8915->fll_fref = 0;
+		wm8915->fll_fout = 0;
+
+		snd_soc_update_bits(codec, WM8915_FLL_CONTROL_1,
+				    WM8915_FLL_ENA, 0);
+
+		return 0;
+	}
+
+	ret = fll_factors(&fll_div, Fref, Fout);
+	if (ret != 0)
+		return ret;
+
+	switch (source) {
+	case WM8915_FLL_MCLK1:
+		reg = 0;
+		break;
+	case WM8915_FLL_MCLK2:
+		reg = 1;
+	case WM8915_FLL_DACLRCLK1:
+		reg = 2;
+		break;
+	case WM8915_FLL_BCLK1:
+		reg = 3;
+		break;
+	default:
+		dev_err(codec->dev, "Unknown FLL source %d\n", ret);
+		return -EINVAL;
+	}
+
+	reg |= fll_div.fll_refclk_div << WM8915_FLL_REFCLK_DIV_SHIFT;
+	reg |= fll_div.fll_ref_freq << WM8915_FLL_REF_FREQ_SHIFT;
+
+	snd_soc_update_bits(codec, WM8915_FLL_CONTROL_5,
+			    WM8915_FLL_REFCLK_DIV_MASK | WM8915_FLL_REF_FREQ |
+			    WM8915_FLL_REFCLK_SRC_MASK, reg);
+
+	reg = 0;
+	if (fll_div.theta || fll_div.lambda)
+		reg |= WM8915_FLL_EFS_ENA | (3 << WM8915_FLL_LFSR_SEL_SHIFT);
+	else
+		reg |= 1 << WM8915_FLL_LFSR_SEL_SHIFT;
+	snd_soc_write(codec, WM8915_FLL_EFS_2, reg);
+
+	snd_soc_update_bits(codec, WM8915_FLL_CONTROL_2,
+			    WM8915_FLL_OUTDIV_MASK |
+			    WM8915_FLL_FRATIO_MASK,
+			    (fll_div.fll_outdiv << WM8915_FLL_OUTDIV_SHIFT) |
+			    (fll_div.fll_fratio));
+
+	snd_soc_write(codec, WM8915_FLL_CONTROL_3, fll_div.theta);
+
+	snd_soc_update_bits(codec, WM8915_FLL_CONTROL_4,
+			    WM8915_FLL_N_MASK | WM8915_FLL_LOOP_GAIN_MASK,
+			    (fll_div.n << WM8915_FLL_N_SHIFT) |
+			    fll_div.fll_loop_gain);
+
+	snd_soc_write(codec, WM8915_FLL_EFS_1, fll_div.lambda);
+
+	snd_soc_update_bits(codec, WM8915_FLL_CONTROL_1,
+			    WM8915_FLL_ENA, WM8915_FLL_ENA);
+
+	/* The FLL supports live reconfiguration - kick that in case we were
+	 * already enabled.
+	 */
+	snd_soc_write(codec, WM8915_FLL_CONTROL_6, WM8915_FLL_SWITCH_CLK);
+
+	/* Wait for the FLL to lock, using the interrupt if possible */
+	if (Fref > 1000000)
+		timeout = usecs_to_jiffies(300);
+	else
+		timeout = msecs_to_jiffies(2);
+
+	wait_for_completion_timeout(&wm8915->fll_lock, timeout);
+
+	dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
+
+	wm8915->fll_fref = Fref;
+	wm8915->fll_fout = Fout;
+	wm8915->fll_src = source;
+
+	return 0;
+}
+
+#ifdef CONFIG_GPIOLIB
+static inline struct wm8915_priv *gpio_to_wm8915(struct gpio_chip *chip)
+{
+	return container_of(chip, struct wm8915_priv, gpio_chip);
+}
+
+static void wm8915_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct wm8915_priv *wm8915 = gpio_to_wm8915(chip);
+	struct snd_soc_codec *codec = wm8915->codec;
+
+	snd_soc_update_bits(codec, WM8915_GPIO_1 + offset,
+			    WM8915_GP1_LVL, !!value << WM8915_GP1_LVL_SHIFT);
+}
+
+static int wm8915_gpio_direction_out(struct gpio_chip *chip,
+				     unsigned offset, int value)
+{
+	struct wm8915_priv *wm8915 = gpio_to_wm8915(chip);
+	struct snd_soc_codec *codec = wm8915->codec;
+	int val;
+
+	val = (1 << WM8915_GP1_FN_SHIFT) | (!!value << WM8915_GP1_LVL_SHIFT);
+
+	return snd_soc_update_bits(codec, WM8915_GPIO_1 + offset,
+				   WM8915_GP1_FN_MASK | WM8915_GP1_DIR |
+				   WM8915_GP1_LVL, val);
+}
+
+static int wm8915_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct wm8915_priv *wm8915 = gpio_to_wm8915(chip);
+	struct snd_soc_codec *codec = wm8915->codec;
+	int ret;
+
+	ret = snd_soc_read(codec, WM8915_GPIO_1 + offset);
+	if (ret < 0)
+		return ret;
+
+	return (ret & WM8915_GP1_LVL) != 0;
+}
+
+static int wm8915_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+	struct wm8915_priv *wm8915 = gpio_to_wm8915(chip);
+	struct snd_soc_codec *codec = wm8915->codec;
+
+	return snd_soc_update_bits(codec, WM8915_GPIO_1 + offset,
+				   WM8915_GP1_FN_MASK | WM8915_GP1_DIR,
+				   (1 << WM8915_GP1_FN_SHIFT) |
+				   (1 << WM8915_GP1_DIR_SHIFT));
+}
+
+static struct gpio_chip wm8915_template_chip = {
+	.label			= "wm8915",
+	.owner			= THIS_MODULE,
+	.direction_output	= wm8915_gpio_direction_out,
+	.set			= wm8915_gpio_set,
+	.direction_input	= wm8915_gpio_direction_in,
+	.get			= wm8915_gpio_get,
+	.can_sleep		= 1,
+};
+
+static void wm8915_init_gpio(struct snd_soc_codec *codec)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	wm8915->gpio_chip = wm8915_template_chip;
+	wm8915->gpio_chip.ngpio = 5;
+	wm8915->gpio_chip.dev = codec->dev;
+
+	if (wm8915->pdata.gpio_base)
+		wm8915->gpio_chip.base = wm8915->pdata.gpio_base;
+	else
+		wm8915->gpio_chip.base = -1;
+
+	ret = gpiochip_add(&wm8915->gpio_chip);
+	if (ret != 0)
+		dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret);
+}
+
+static void wm8915_free_gpio(struct snd_soc_codec *codec)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	ret = gpiochip_remove(&wm8915->gpio_chip);
+	if (ret != 0)
+		dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret);
+}
+#else
+static void wm8915_init_gpio(struct snd_soc_codec *codec)
+{
+}
+
+static void wm8915_free_gpio(struct snd_soc_codec *codec)
+{
+}
+#endif
+
+/**
+ * wm8915_detect - Enable default WM8915 jack detection
+ *
+ * The WM8915 has advanced accessory detection support for headsets.
+ * This function provides a default implementation which integrates
+ * the majority of this functionality with minimal user configuration.
+ *
+ * This will detect headset, headphone and short circuit button and
+ * will also detect inverted microphone ground connections and update
+ * the polarity of the connections.
+ */
+int wm8915_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
+		  wm8915_polarity_fn polarity_cb)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+
+	wm8915->jack = jack;
+	wm8915->detecting = true;
+	wm8915->polarity_cb = polarity_cb;
+
+	if (wm8915->polarity_cb)
+		wm8915->polarity_cb(codec, 0);
+
+	/* Clear discarge to avoid noise during detection */
+	snd_soc_update_bits(codec, WM8915_MICBIAS_1,
+			    WM8915_MICB1_DISCH, 0);
+	snd_soc_update_bits(codec, WM8915_MICBIAS_2,
+			    WM8915_MICB2_DISCH, 0);
+
+	/* LDO2 powers the microphones, SYSCLK clocks detection */
+	snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
+	snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK");
+
+	/* We start off just enabling microphone detection - even a
+	 * plain headphone will trigger detection.
+	 */
+	snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
+			    WM8915_MICD_ENA, WM8915_MICD_ENA);
+
+	/* Slowest detection rate, gives debounce for initial detection */
+	snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
+			    WM8915_MICD_RATE_MASK,
+			    WM8915_MICD_RATE_MASK);
+
+	/* Enable interrupts and we're off */
+	snd_soc_update_bits(codec, WM8915_INTERRUPT_STATUS_2_MASK,
+			    WM8915_IM_MICD_EINT, 0);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(wm8915_detect);
+
+static void wm8915_micd(struct snd_soc_codec *codec)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	int val, reg;
+
+	val = snd_soc_read(codec, WM8915_MIC_DETECT_3);
+
+	dev_dbg(codec->dev, "Microphone event: %x\n", val);
+
+	if (!(val & WM8915_MICD_VALID)) {
+		dev_warn(codec->dev, "Microphone detection state invalid\n");
+		return;
+	}
+
+	/* No accessory, reset everything and report removal */
+	if (!(val & WM8915_MICD_STS)) {
+		dev_dbg(codec->dev, "Jack removal detected\n");
+		wm8915->jack_mic = false;
+		wm8915->detecting = true;
+		snd_soc_jack_report(wm8915->jack, 0,
+				    SND_JACK_HEADSET | SND_JACK_BTN_0);
+		snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
+				    WM8915_MICD_RATE_MASK,
+				    WM8915_MICD_RATE_MASK);
+		return;
+	}
+
+	/* If the measurement is very high we've got a microphone but
+	 * do a little debounce to account for mechanical issues.
+	 */
+	if (val & 0x400) {
+		dev_dbg(codec->dev, "Microphone detected\n");
+		snd_soc_jack_report(wm8915->jack, SND_JACK_HEADSET,
+				    SND_JACK_HEADSET | SND_JACK_BTN_0);
+		wm8915->jack_mic = true;
+		wm8915->detecting = false;
+	}
+
+	/* If we detected a lower impedence during initial startup
+	 * then we probably have the wrong polarity, flip it.  Don't
+	 * do this for the lowest impedences to speed up detection of
+	 * plain headphones.
+	 */
+	if (wm8915->detecting && (val & 0x3f0)) {
+		reg = snd_soc_read(codec, WM8915_ACCESSORY_DETECT_MODE_2);
+		reg ^= WM8915_HPOUT1FB_SRC | WM8915_MICD_SRC |
+			WM8915_MICD_BIAS_SRC;
+		snd_soc_update_bits(codec, WM8915_ACCESSORY_DETECT_MODE_2,
+				    WM8915_HPOUT1FB_SRC | WM8915_MICD_SRC |
+				    WM8915_MICD_BIAS_SRC, reg);
+
+		if (wm8915->polarity_cb)
+			wm8915->polarity_cb(codec,
+					    (reg & WM8915_MICD_SRC) != 0);
+
+		dev_dbg(codec->dev, "Set microphone polarity to %d\n",
+			(reg & WM8915_MICD_SRC) != 0);
+
+		return;
+	}
+
+	/* Don't distinguish between buttons, just report any low
+	 * impedence as BTN_0.
+	 */
+	if (val & 0x3fc) {
+		if (wm8915->jack_mic) {
+			dev_dbg(codec->dev, "Mic button detected\n");
+			snd_soc_jack_report(wm8915->jack,
+					    SND_JACK_HEADSET | SND_JACK_BTN_0,
+					    SND_JACK_HEADSET | SND_JACK_BTN_0);
+		} else {
+			dev_dbg(codec->dev, "Headphone detected\n");
+			snd_soc_jack_report(wm8915->jack,
+					    SND_JACK_HEADPHONE,
+					    SND_JACK_HEADSET |
+					    SND_JACK_BTN_0);
+			wm8915->detecting = false;
+		}
+	}
+
+	/* Increase poll rate to give better responsiveness for buttons */
+	if (!wm8915->detecting)
+		snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
+				    WM8915_MICD_RATE_MASK,
+				    5 << WM8915_MICD_RATE_SHIFT);
+}
+
+static irqreturn_t wm8915_irq(int irq, void *data)
+{
+	struct snd_soc_codec *codec = data;
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	int irq_val;
+
+	irq_val = snd_soc_read(codec, WM8915_INTERRUPT_STATUS_2);
+	if (irq_val < 0) {
+		dev_err(codec->dev, "Failed to read IRQ status: %d\n",
+			irq_val);
+		return IRQ_NONE;
+	}
+	irq_val &= ~snd_soc_read(codec, WM8915_INTERRUPT_STATUS_2_MASK);
+
+	if (irq_val & (WM8915_DCS_DONE_01_EINT | WM8915_DCS_DONE_23_EINT)) {
+		dev_dbg(codec->dev, "DC servo IRQ\n");
+		complete(&wm8915->dcs_done);
+	}
+
+	if (irq_val & WM8915_FIFOS_ERR_EINT)
+		dev_err(codec->dev, "Digital core FIFO error\n");
+
+	if (irq_val & WM8915_FLL_LOCK_EINT) {
+		dev_dbg(codec->dev, "FLL locked\n");
+		complete(&wm8915->fll_lock);
+	}
+
+	if (irq_val & WM8915_MICD_EINT)
+		wm8915_micd(codec);
+
+	if (irq_val) {
+		snd_soc_write(codec, WM8915_INTERRUPT_STATUS_2, irq_val);
+
+		return IRQ_HANDLED;
+	} else {
+		return IRQ_NONE;
+	}
+}
+
+static void wm8915_retune_mobile_pdata(struct snd_soc_codec *codec)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	struct wm8915_pdata *pdata = &wm8915->pdata;
+
+	struct snd_kcontrol_new controls[] = {
+		SOC_ENUM_EXT("DSP1 EQ Mode",
+			     wm8915->retune_mobile_enum,
+			     wm8915_get_retune_mobile_enum,
+			     wm8915_put_retune_mobile_enum),
+		SOC_ENUM_EXT("DSP2 EQ Mode",
+			     wm8915->retune_mobile_enum,
+			     wm8915_get_retune_mobile_enum,
+			     wm8915_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. */
+	wm8915->num_retune_mobile_texts = 0;
+	wm8915->retune_mobile_texts = NULL;
+	for (i = 0; i < pdata->num_retune_mobile_cfgs; i++) {
+		for (j = 0; j < wm8915->num_retune_mobile_texts; j++) {
+			if (strcmp(pdata->retune_mobile_cfgs[i].name,
+				   wm8915->retune_mobile_texts[j]) == 0)
+				break;
+		}
+
+		if (j != wm8915->num_retune_mobile_texts)
+			continue;
+
+		/* Expand the array... */
+		t = krealloc(wm8915->retune_mobile_texts,
+			     sizeof(char *) * 
+			     (wm8915->num_retune_mobile_texts + 1),
+			     GFP_KERNEL);
+		if (t == NULL)
+			continue;
+
+		/* ...store the new entry... */
+		t[wm8915->num_retune_mobile_texts] = 
+			pdata->retune_mobile_cfgs[i].name;
+
+		/* ...and remember the new version. */
+		wm8915->num_retune_mobile_texts++;
+		wm8915->retune_mobile_texts = t;
+	}
+
+	dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n",
+		wm8915->num_retune_mobile_texts);
+
+	wm8915->retune_mobile_enum.max = wm8915->num_retune_mobile_texts;
+	wm8915->retune_mobile_enum.texts = wm8915->retune_mobile_texts;
+
+	ret = snd_soc_add_controls(codec, controls, ARRAY_SIZE(controls));
+	if (ret != 0)
+		dev_err(codec->dev,
+			"Failed to add ReTune Mobile controls: %d\n", ret);
+}
+
+static int wm8915_probe(struct snd_soc_codec *codec)
+{
+	int ret;
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	struct i2c_client *i2c = to_i2c_client(codec->dev);
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	int i, irq_flags;
+
+	wm8915->codec = codec;
+
+	init_completion(&wm8915->dcs_done);
+	init_completion(&wm8915->fll_lock);
+
+	dapm->idle_bias_off = true;
+	dapm->bias_level = SND_SOC_BIAS_OFF;
+
+	ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		goto err;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++)
+		wm8915->supplies[i].supply = wm8915_supply_names[i];
+
+	ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8915->supplies),
+				 wm8915->supplies);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
+		goto err;
+	}
+
+	wm8915->disable_nb[0].notifier_call = wm8915_regulator_event_0;
+	wm8915->disable_nb[1].notifier_call = wm8915_regulator_event_1;
+	wm8915->disable_nb[2].notifier_call = wm8915_regulator_event_2;
+	wm8915->disable_nb[3].notifier_call = wm8915_regulator_event_3;
+	wm8915->disable_nb[4].notifier_call = wm8915_regulator_event_4;
+	wm8915->disable_nb[5].notifier_call = wm8915_regulator_event_5;
+
+	/* This should really be moved into the regulator core */
+	for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++) {
+		ret = regulator_register_notifier(wm8915->supplies[i].consumer,
+						  &wm8915->disable_nb[i]);
+		if (ret != 0) {
+			dev_err(codec->dev,
+				"Failed to register regulator notifier: %d\n",
+				ret);
+		}
+	}
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(wm8915->supplies),
+				    wm8915->supplies);
+	if (ret != 0) {
+		dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
+		goto err_get;
+	}
+
+	if (wm8915->pdata.ldo_ena >= 0) {
+		gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 1);
+		msleep(5);
+	}
+
+	ret = snd_soc_read(codec, WM8915_SOFTWARE_RESET);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to read ID register: %d\n", ret);
+		goto err_enable;
+	}
+	if (ret != 0x8915) {
+		dev_err(codec->dev, "Device is not a WM8915, ID %x\n", ret);
+		ret = -EINVAL;
+		goto err_enable;
+	}
+
+	ret = snd_soc_read(codec, WM8915_CHIP_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 & WM8915_CHIP_REV_MASK) + 'A');
+
+	if (wm8915->pdata.ldo_ena >= 0) {
+		gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 0);
+	} else {
+		ret = wm8915_reset(codec);
+		if (ret < 0) {
+			dev_err(codec->dev, "Failed to issue reset\n");
+			goto err_enable;
+		}
+	}
+
+	codec->cache_only = true;
+
+	/* Apply platform data settings */
+	snd_soc_update_bits(codec, WM8915_LINE_INPUT_CONTROL,
+			    WM8915_INL_MODE_MASK | WM8915_INR_MODE_MASK,
+			    wm8915->pdata.inl_mode << WM8915_INL_MODE_SHIFT |
+			    wm8915->pdata.inr_mode);
+
+	for (i = 0; i < ARRAY_SIZE(wm8915->pdata.gpio_default); i++) {
+		if (!wm8915->pdata.gpio_default[i])
+			continue;
+
+		snd_soc_write(codec, WM8915_GPIO_1 + i,
+			      wm8915->pdata.gpio_default[i] & 0xffff);
+	}
+
+	if (wm8915->pdata.spkmute_seq)
+		snd_soc_update_bits(codec, WM8915_PDM_SPEAKER_MUTE_SEQUENCE,
+				    WM8915_SPK_MUTE_ENDIAN |
+				    WM8915_SPK_MUTE_SEQ1_MASK,
+				    wm8915->pdata.spkmute_seq);
+
+	snd_soc_update_bits(codec, WM8915_ACCESSORY_DETECT_MODE_2,
+			    WM8915_MICD_BIAS_SRC | WM8915_HPOUT1FB_SRC |
+			    WM8915_MICD_SRC, wm8915->pdata.micdet_def);
+
+	/* Latch volume update bits */
+	snd_soc_update_bits(codec, WM8915_LEFT_LINE_INPUT_VOLUME,
+			    WM8915_IN1_VU, WM8915_IN1_VU);
+	snd_soc_update_bits(codec, WM8915_RIGHT_LINE_INPUT_VOLUME,
+			    WM8915_IN1_VU, WM8915_IN1_VU);
+
+	snd_soc_update_bits(codec, WM8915_DAC1_LEFT_VOLUME,
+			    WM8915_DAC1_VU, WM8915_DAC1_VU);
+	snd_soc_update_bits(codec, WM8915_DAC1_RIGHT_VOLUME,
+			    WM8915_DAC1_VU, WM8915_DAC1_VU);
+	snd_soc_update_bits(codec, WM8915_DAC2_LEFT_VOLUME,
+			    WM8915_DAC2_VU, WM8915_DAC2_VU);
+	snd_soc_update_bits(codec, WM8915_DAC2_RIGHT_VOLUME,
+			    WM8915_DAC2_VU, WM8915_DAC2_VU);
+
+	snd_soc_update_bits(codec, WM8915_OUTPUT1_LEFT_VOLUME,
+			    WM8915_DAC1_VU, WM8915_DAC1_VU);
+	snd_soc_update_bits(codec, WM8915_OUTPUT1_RIGHT_VOLUME,
+			    WM8915_DAC1_VU, WM8915_DAC1_VU);
+	snd_soc_update_bits(codec, WM8915_OUTPUT2_LEFT_VOLUME,
+			    WM8915_DAC2_VU, WM8915_DAC2_VU);
+	snd_soc_update_bits(codec, WM8915_OUTPUT2_RIGHT_VOLUME,
+			    WM8915_DAC2_VU, WM8915_DAC2_VU);
+
+	snd_soc_update_bits(codec, WM8915_DSP1_TX_LEFT_VOLUME,
+			    WM8915_DSP1TX_VU, WM8915_DSP1TX_VU);
+	snd_soc_update_bits(codec, WM8915_DSP1_TX_RIGHT_VOLUME,
+			    WM8915_DSP1TX_VU, WM8915_DSP1TX_VU);
+	snd_soc_update_bits(codec, WM8915_DSP2_TX_LEFT_VOLUME,
+			    WM8915_DSP2TX_VU, WM8915_DSP2TX_VU);
+	snd_soc_update_bits(codec, WM8915_DSP2_TX_RIGHT_VOLUME,
+			    WM8915_DSP2TX_VU, WM8915_DSP2TX_VU);
+
+	snd_soc_update_bits(codec, WM8915_DSP1_RX_LEFT_VOLUME,
+			    WM8915_DSP1RX_VU, WM8915_DSP1RX_VU);
+	snd_soc_update_bits(codec, WM8915_DSP1_RX_RIGHT_VOLUME,
+			    WM8915_DSP1RX_VU, WM8915_DSP1RX_VU);
+	snd_soc_update_bits(codec, WM8915_DSP2_RX_LEFT_VOLUME,
+			    WM8915_DSP2RX_VU, WM8915_DSP2RX_VU);
+	snd_soc_update_bits(codec, WM8915_DSP2_RX_RIGHT_VOLUME,
+			    WM8915_DSP2RX_VU, WM8915_DSP2RX_VU);
+
+	/* No support currently for the underclocked TDM modes and
+	 * pick a default TDM layout with each channel pair working with
+	 * slots 0 and 1. */
+	snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_0_CONFIGURATION,
+			    WM8915_AIF1RX_CHAN0_SLOTS_MASK |
+			    WM8915_AIF1RX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF1RX_CHAN0_SLOTS_SHIFT | 0);
+	snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_1_CONFIGURATION,
+			    WM8915_AIF1RX_CHAN1_SLOTS_MASK |
+			    WM8915_AIF1RX_CHAN1_START_SLOT_MASK,
+			    1 << WM8915_AIF1RX_CHAN1_SLOTS_SHIFT | 1);
+	snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_2_CONFIGURATION,
+			    WM8915_AIF1RX_CHAN2_SLOTS_MASK |
+			    WM8915_AIF1RX_CHAN2_START_SLOT_MASK,
+			    1 << WM8915_AIF1RX_CHAN2_SLOTS_SHIFT | 0);
+	snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_3_CONFIGURATION,
+			    WM8915_AIF1RX_CHAN3_SLOTS_MASK |
+			    WM8915_AIF1RX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF1RX_CHAN3_SLOTS_SHIFT | 1);
+	snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_4_CONFIGURATION,
+			    WM8915_AIF1RX_CHAN4_SLOTS_MASK |
+			    WM8915_AIF1RX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF1RX_CHAN4_SLOTS_SHIFT | 0);
+	snd_soc_update_bits(codec, WM8915_AIF1RX_CHANNEL_5_CONFIGURATION,
+			    WM8915_AIF1RX_CHAN5_SLOTS_MASK |
+			    WM8915_AIF1RX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF1RX_CHAN5_SLOTS_SHIFT | 1);
+
+	snd_soc_update_bits(codec, WM8915_AIF2RX_CHANNEL_0_CONFIGURATION,
+			    WM8915_AIF2RX_CHAN0_SLOTS_MASK |
+			    WM8915_AIF2RX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF2RX_CHAN0_SLOTS_SHIFT | 0);
+	snd_soc_update_bits(codec, WM8915_AIF2RX_CHANNEL_1_CONFIGURATION,
+			    WM8915_AIF2RX_CHAN1_SLOTS_MASK |
+			    WM8915_AIF2RX_CHAN1_START_SLOT_MASK,
+			    1 << WM8915_AIF2RX_CHAN1_SLOTS_SHIFT | 1);
+
+	snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_0_CONFIGURATION,
+			    WM8915_AIF1TX_CHAN0_SLOTS_MASK |
+			    WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF1TX_CHAN0_SLOTS_SHIFT | 0);
+	snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_1_CONFIGURATION,
+			    WM8915_AIF1TX_CHAN1_SLOTS_MASK |
+			    WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
+	snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_2_CONFIGURATION,
+			    WM8915_AIF1TX_CHAN2_SLOTS_MASK |
+			    WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF1TX_CHAN2_SLOTS_SHIFT | 0);
+	snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_3_CONFIGURATION,
+			    WM8915_AIF1TX_CHAN3_SLOTS_MASK |
+			    WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF1TX_CHAN3_SLOTS_SHIFT | 1);
+	snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_4_CONFIGURATION,
+			    WM8915_AIF1TX_CHAN4_SLOTS_MASK |
+			    WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF1TX_CHAN4_SLOTS_SHIFT | 0);
+	snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_5_CONFIGURATION,
+			    WM8915_AIF1TX_CHAN5_SLOTS_MASK |
+			    WM8915_AIF1TX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF1TX_CHAN5_SLOTS_SHIFT | 1);
+
+	snd_soc_update_bits(codec, WM8915_AIF2TX_CHANNEL_0_CONFIGURATION,
+			    WM8915_AIF2TX_CHAN0_SLOTS_MASK |
+			    WM8915_AIF2TX_CHAN0_START_SLOT_MASK,
+			    1 << WM8915_AIF2TX_CHAN0_SLOTS_SHIFT | 0);
+	snd_soc_update_bits(codec, WM8915_AIF1TX_CHANNEL_1_CONFIGURATION,
+			    WM8915_AIF2TX_CHAN1_SLOTS_MASK |
+			    WM8915_AIF2TX_CHAN1_START_SLOT_MASK,
+			    1 << WM8915_AIF1TX_CHAN1_SLOTS_SHIFT | 1);
+
+	if (wm8915->pdata.num_retune_mobile_cfgs)
+		wm8915_retune_mobile_pdata(codec);
+	else
+		snd_soc_add_controls(codec, wm8915_eq_controls,
+				     ARRAY_SIZE(wm8915_eq_controls));
+
+	/* If the TX LRCLK pins are not in LRCLK mode configure the
+	 * AIFs to source their clocks from the RX LRCLKs.
+	 */
+	if ((snd_soc_read(codec, WM8915_GPIO_1)))
+		snd_soc_update_bits(codec, WM8915_AIF1_TX_LRCLK_2,
+				    WM8915_AIF1TX_LRCLK_MODE,
+				    WM8915_AIF1TX_LRCLK_MODE);
+
+	if ((snd_soc_read(codec, WM8915_GPIO_2)))
+		snd_soc_update_bits(codec, WM8915_AIF2_TX_LRCLK_2,
+				    WM8915_AIF2TX_LRCLK_MODE,
+				    WM8915_AIF2TX_LRCLK_MODE);
+
+	regulator_bulk_disable(ARRAY_SIZE(wm8915->supplies), wm8915->supplies);
+
+	wm8915_init_gpio(codec);
+
+	if (i2c->irq) {
+		if (wm8915->pdata.irq_flags)
+			irq_flags = wm8915->pdata.irq_flags;
+		else
+			irq_flags = IRQF_TRIGGER_LOW;
+
+		irq_flags |= IRQF_ONESHOT;
+
+		ret = request_threaded_irq(i2c->irq, NULL, wm8915_irq,
+					   irq_flags, "wm8915", codec);
+		if (ret == 0) {
+			/* Unmask the interrupt */
+			snd_soc_update_bits(codec, WM8915_INTERRUPT_CONTROL,
+					    WM8915_IM_IRQ, 0);
+
+			/* Enable error reporting and DC servo status */
+			snd_soc_update_bits(codec,
+					    WM8915_INTERRUPT_STATUS_2_MASK,
+					    WM8915_IM_DCS_DONE_23_EINT |
+					    WM8915_IM_DCS_DONE_01_EINT |
+					    WM8915_IM_FLL_LOCK_EINT |
+					    WM8915_IM_FIFOS_ERR_EINT,
+					    0);
+		} else {
+			dev_err(codec->dev, "Failed to request IRQ: %d\n",
+				ret);
+		}
+	}
+
+	return 0;
+
+err_enable:
+	if (wm8915->pdata.ldo_ena >= 0)
+		gpio_set_value_cansleep(wm8915->pdata.ldo_ena, 0);
+
+	regulator_bulk_disable(ARRAY_SIZE(wm8915->supplies), wm8915->supplies);
+err_get:
+	regulator_bulk_free(ARRAY_SIZE(wm8915->supplies), wm8915->supplies);
+err:
+	return ret;
+}
+
+static int wm8915_remove(struct snd_soc_codec *codec)
+{
+	struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
+	struct i2c_client *i2c = to_i2c_client(codec->dev);
+	int i;
+
+	snd_soc_update_bits(codec, WM8915_INTERRUPT_CONTROL,
+			    WM8915_IM_IRQ, WM8915_IM_IRQ);
+
+	if (i2c->irq)
+		free_irq(i2c->irq, codec);
+
+	wm8915_free_gpio(codec);
+
+	for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++)
+		regulator_unregister_notifier(wm8915->supplies[i].consumer,
+					      &wm8915->disable_nb[i]);
+	regulator_bulk_free(ARRAY_SIZE(wm8915->supplies), wm8915->supplies);
+
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8915 = {
+	.probe =	wm8915_probe,
+	.remove =	wm8915_remove,
+	.set_bias_level = wm8915_set_bias_level,
+	.seq_notifier = wm8915_seq_notifier,
+	.reg_cache_size = WM8915_MAX_REGISTER + 1,
+	.reg_word_size = sizeof(u16),
+	.reg_cache_default = wm8915_reg,
+	.volatile_register = wm8915_volatile_register,
+	.readable_register = wm8915_readable_register,
+	.compress_type = SND_SOC_RBTREE_COMPRESSION,
+	.controls = wm8915_snd_controls,
+	.num_controls = ARRAY_SIZE(wm8915_snd_controls),
+	.dapm_widgets = wm8915_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8915_dapm_widgets),
+	.dapm_routes = wm8915_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(wm8915_dapm_routes),
+	.set_pll = wm8915_set_fll,
+};
+
+#define WM8915_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+		      SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+#define WM8915_FORMATS (SNDRV_PCM_FMTBIT_S8 | 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 wm8915_dai_ops = {
+	.set_fmt = wm8915_set_fmt,
+	.hw_params = wm8915_hw_params,
+	.set_sysclk = wm8915_set_sysclk,
+};
+
+static struct snd_soc_dai_driver wm8915_dai[] = {
+	{
+		.name = "wm8915-aif1",
+		.playback = {
+			.stream_name = "AIF1 Playback",
+			.channels_min = 1,
+			.channels_max = 6,
+			.rates = WM8915_RATES,
+			.formats = WM8915_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF1 Capture",
+			 .channels_min = 1,
+			 .channels_max = 6,
+			 .rates = WM8915_RATES,
+			 .formats = WM8915_FORMATS,
+		 },
+		.ops = &wm8915_dai_ops,
+	},
+	{
+		.name = "wm8915-aif2",
+		.playback = {
+			.stream_name = "AIF2 Playback",
+			.channels_min = 1,
+			.channels_max = 2,
+			.rates = WM8915_RATES,
+			.formats = WM8915_FORMATS,
+		},
+		.capture = {
+			 .stream_name = "AIF2 Capture",
+			 .channels_min = 1,
+			 .channels_max = 2,
+			 .rates = WM8915_RATES,
+			 .formats = WM8915_FORMATS,
+		 },
+		.ops = &wm8915_dai_ops,
+	},
+};
+
+static __devinit int wm8915_i2c_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
+{
+	struct wm8915_priv *wm8915;
+	int ret;
+
+	wm8915 = kzalloc(sizeof(struct wm8915_priv), GFP_KERNEL);
+	if (wm8915 == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, wm8915);
+
+	if (dev_get_platdata(&i2c->dev))
+		memcpy(&wm8915->pdata, dev_get_platdata(&i2c->dev),
+		       sizeof(wm8915->pdata));
+
+	if (wm8915->pdata.ldo_ena > 0) {
+		ret = gpio_request_one(wm8915->pdata.ldo_ena,
+				       GPIOF_OUT_INIT_LOW, "WM8915 ENA");
+		if (ret < 0) {
+			dev_err(&i2c->dev, "Failed to request GPIO %d: %d\n",
+				wm8915->pdata.ldo_ena, ret);
+			goto err;
+		}
+	}
+
+	ret = snd_soc_register_codec(&i2c->dev,
+				     &soc_codec_dev_wm8915, wm8915_dai,
+				     ARRAY_SIZE(wm8915_dai));
+	if (ret < 0)
+		goto err_gpio;
+
+	return ret;
+
+err_gpio:
+	if (wm8915->pdata.ldo_ena > 0)
+		gpio_free(wm8915->pdata.ldo_ena);
+err:
+	kfree(wm8915);
+
+	return ret;
+}
+
+static __devexit int wm8915_i2c_remove(struct i2c_client *client)
+{
+	struct wm8915_priv *wm8915 = i2c_get_clientdata(client);
+
+	snd_soc_unregister_codec(&client->dev);
+	if (wm8915->pdata.ldo_ena > 0)
+		gpio_free(wm8915->pdata.ldo_ena);
+	kfree(i2c_get_clientdata(client));
+	return 0;
+}
+
+static const struct i2c_device_id wm8915_i2c_id[] = {
+	{ "wm8915", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, wm8915_i2c_id);
+
+static struct i2c_driver wm8915_i2c_driver = {
+	.driver = {
+		.name = "wm8915",
+		.owner = THIS_MODULE,
+	},
+	.probe =    wm8915_i2c_probe,
+	.remove =   __devexit_p(wm8915_i2c_remove),
+	.id_table = wm8915_i2c_id,
+};
+
+static int __init wm8915_modinit(void)
+{
+	int ret;
+
+	ret = i2c_add_driver(&wm8915_i2c_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register WM8915 I2C driver: %d\n",
+		       ret);
+	}
+
+	return ret;
+}
+module_init(wm8915_modinit);
+
+static void __exit wm8915_exit(void)
+{
+	i2c_del_driver(&wm8915_i2c_driver);
+}
+module_exit(wm8915_exit);
+
+MODULE_DESCRIPTION("ASoC WM8915 driver");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");

+ 3717 - 0
sound/soc/codecs/wm8915.h

@@ -0,0 +1,3717 @@
+/*
+ * wm8915.h - WM8915 audio codec interface
+ *
+ * Copyright 2011 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 _WM8915_H
+#define _WM8915_H
+
+#define WM8915_SYSCLK_MCLK1 1
+#define WM8915_SYSCLK_MCLK2 2
+#define WM8915_SYSCLK_FLL   3
+
+#define WM8915_FLL_MCLK1      1
+#define WM8915_FLL_MCLK2      2
+#define WM8915_FLL_DACLRCLK1  3
+#define WM8915_FLL_BCLK1      4
+
+typedef void (*wm8915_polarity_fn)(struct snd_soc_codec *codec, int polarity);
+
+int wm8915_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
+		  wm8915_polarity_fn polarity_cb);
+
+/*
+ * Register values.
+ */
+#define WM8915_SOFTWARE_RESET                   0x00
+#define WM8915_POWER_MANAGEMENT_1               0x01
+#define WM8915_POWER_MANAGEMENT_2               0x02
+#define WM8915_POWER_MANAGEMENT_3               0x03
+#define WM8915_POWER_MANAGEMENT_4               0x04
+#define WM8915_POWER_MANAGEMENT_5               0x05
+#define WM8915_POWER_MANAGEMENT_6               0x06
+#define WM8915_POWER_MANAGEMENT_7               0x07
+#define WM8915_POWER_MANAGEMENT_8               0x08
+#define WM8915_LEFT_LINE_INPUT_VOLUME           0x10
+#define WM8915_RIGHT_LINE_INPUT_VOLUME          0x11
+#define WM8915_LINE_INPUT_CONTROL               0x12
+#define WM8915_DAC1_HPOUT1_VOLUME               0x15
+#define WM8915_DAC2_HPOUT2_VOLUME               0x16
+#define WM8915_DAC1_LEFT_VOLUME                 0x18
+#define WM8915_DAC1_RIGHT_VOLUME                0x19
+#define WM8915_DAC2_LEFT_VOLUME                 0x1A
+#define WM8915_DAC2_RIGHT_VOLUME                0x1B
+#define WM8915_OUTPUT1_LEFT_VOLUME              0x1C
+#define WM8915_OUTPUT1_RIGHT_VOLUME             0x1D
+#define WM8915_OUTPUT2_LEFT_VOLUME              0x1E
+#define WM8915_OUTPUT2_RIGHT_VOLUME             0x1F
+#define WM8915_MICBIAS_1                        0x20
+#define WM8915_MICBIAS_2                        0x21
+#define WM8915_LDO_1                            0x28
+#define WM8915_LDO_2                            0x29
+#define WM8915_ACCESSORY_DETECT_MODE_1          0x30
+#define WM8915_ACCESSORY_DETECT_MODE_2          0x31
+#define WM8915_HEADPHONE_DETECT_1               0x34
+#define WM8915_HEADPHONE_DETECT_2               0x35
+#define WM8915_MIC_DETECT_1                     0x38
+#define WM8915_MIC_DETECT_2                     0x39
+#define WM8915_MIC_DETECT_3                     0x3A
+#define WM8915_CHARGE_PUMP_1                    0x40
+#define WM8915_CHARGE_PUMP_2                    0x41
+#define WM8915_DC_SERVO_1                       0x50
+#define WM8915_DC_SERVO_2                       0x51
+#define WM8915_DC_SERVO_3                       0x52
+#define WM8915_DC_SERVO_5                       0x54
+#define WM8915_DC_SERVO_6                       0x55
+#define WM8915_DC_SERVO_7                       0x56
+#define WM8915_DC_SERVO_READBACK_0              0x57
+#define WM8915_ANALOGUE_HP_1                    0x60
+#define WM8915_ANALOGUE_HP_2                    0x61
+#define WM8915_CHIP_REVISION                    0x100
+#define WM8915_CONTROL_INTERFACE_1              0x101
+#define WM8915_WRITE_SEQUENCER_CTRL_1           0x110
+#define WM8915_WRITE_SEQUENCER_CTRL_2           0x111
+#define WM8915_AIF_CLOCKING_1                   0x200
+#define WM8915_AIF_CLOCKING_2                   0x201
+#define WM8915_CLOCKING_1                       0x208
+#define WM8915_CLOCKING_2                       0x209
+#define WM8915_AIF_RATE                         0x210
+#define WM8915_FLL_CONTROL_1                    0x220
+#define WM8915_FLL_CONTROL_2                    0x221
+#define WM8915_FLL_CONTROL_3                    0x222
+#define WM8915_FLL_CONTROL_4                    0x223
+#define WM8915_FLL_CONTROL_5                    0x224
+#define WM8915_FLL_CONTROL_6                    0x225
+#define WM8915_FLL_EFS_1                        0x226
+#define WM8915_FLL_EFS_2                        0x227
+#define WM8915_AIF1_CONTROL                     0x300
+#define WM8915_AIF1_BCLK                        0x301
+#define WM8915_AIF1_TX_LRCLK_1                  0x302
+#define WM8915_AIF1_TX_LRCLK_2                  0x303
+#define WM8915_AIF1_RX_LRCLK_1                  0x304
+#define WM8915_AIF1_RX_LRCLK_2                  0x305
+#define WM8915_AIF1TX_DATA_CONFIGURATION_1      0x306
+#define WM8915_AIF1TX_DATA_CONFIGURATION_2      0x307
+#define WM8915_AIF1RX_DATA_CONFIGURATION        0x308
+#define WM8915_AIF1TX_CHANNEL_0_CONFIGURATION   0x309
+#define WM8915_AIF1TX_CHANNEL_1_CONFIGURATION   0x30A
+#define WM8915_AIF1TX_CHANNEL_2_CONFIGURATION   0x30B
+#define WM8915_AIF1TX_CHANNEL_3_CONFIGURATION   0x30C
+#define WM8915_AIF1TX_CHANNEL_4_CONFIGURATION   0x30D
+#define WM8915_AIF1TX_CHANNEL_5_CONFIGURATION   0x30E
+#define WM8915_AIF1RX_CHANNEL_0_CONFIGURATION   0x30F
+#define WM8915_AIF1RX_CHANNEL_1_CONFIGURATION   0x310
+#define WM8915_AIF1RX_CHANNEL_2_CONFIGURATION   0x311
+#define WM8915_AIF1RX_CHANNEL_3_CONFIGURATION   0x312
+#define WM8915_AIF1RX_CHANNEL_4_CONFIGURATION   0x313
+#define WM8915_AIF1RX_CHANNEL_5_CONFIGURATION   0x314
+#define WM8915_AIF1RX_MONO_CONFIGURATION        0x315
+#define WM8915_AIF1TX_TEST                      0x31A
+#define WM8915_AIF2_CONTROL                     0x320
+#define WM8915_AIF2_BCLK                        0x321
+#define WM8915_AIF2_TX_LRCLK_1                  0x322
+#define WM8915_AIF2_TX_LRCLK_2                  0x323
+#define WM8915_AIF2_RX_LRCLK_1                  0x324
+#define WM8915_AIF2_RX_LRCLK_2                  0x325
+#define WM8915_AIF2TX_DATA_CONFIGURATION_1      0x326
+#define WM8915_AIF2TX_DATA_CONFIGURATION_2      0x327
+#define WM8915_AIF2RX_DATA_CONFIGURATION        0x328
+#define WM8915_AIF2TX_CHANNEL_0_CONFIGURATION   0x329
+#define WM8915_AIF2TX_CHANNEL_1_CONFIGURATION   0x32A
+#define WM8915_AIF2RX_CHANNEL_0_CONFIGURATION   0x32B
+#define WM8915_AIF2RX_CHANNEL_1_CONFIGURATION   0x32C
+#define WM8915_AIF2RX_MONO_CONFIGURATION        0x32D
+#define WM8915_AIF2TX_TEST                      0x32F
+#define WM8915_DSP1_TX_LEFT_VOLUME              0x400
+#define WM8915_DSP1_TX_RIGHT_VOLUME             0x401
+#define WM8915_DSP1_RX_LEFT_VOLUME              0x402
+#define WM8915_DSP1_RX_RIGHT_VOLUME             0x403
+#define WM8915_DSP1_TX_FILTERS                  0x410
+#define WM8915_DSP1_RX_FILTERS_1                0x420
+#define WM8915_DSP1_RX_FILTERS_2                0x421
+#define WM8915_DSP1_DRC_1                       0x440
+#define WM8915_DSP1_DRC_2                       0x441
+#define WM8915_DSP1_DRC_3                       0x442
+#define WM8915_DSP1_DRC_4                       0x443
+#define WM8915_DSP1_DRC_5                       0x444
+#define WM8915_DSP1_RX_EQ_GAINS_1               0x480
+#define WM8915_DSP1_RX_EQ_GAINS_2               0x481
+#define WM8915_DSP1_RX_EQ_BAND_1_A              0x482
+#define WM8915_DSP1_RX_EQ_BAND_1_B              0x483
+#define WM8915_DSP1_RX_EQ_BAND_1_PG             0x484
+#define WM8915_DSP1_RX_EQ_BAND_2_A              0x485
+#define WM8915_DSP1_RX_EQ_BAND_2_B              0x486
+#define WM8915_DSP1_RX_EQ_BAND_2_C              0x487
+#define WM8915_DSP1_RX_EQ_BAND_2_PG             0x488
+#define WM8915_DSP1_RX_EQ_BAND_3_A              0x489
+#define WM8915_DSP1_RX_EQ_BAND_3_B              0x48A
+#define WM8915_DSP1_RX_EQ_BAND_3_C              0x48B
+#define WM8915_DSP1_RX_EQ_BAND_3_PG             0x48C
+#define WM8915_DSP1_RX_EQ_BAND_4_A              0x48D
+#define WM8915_DSP1_RX_EQ_BAND_4_B              0x48E
+#define WM8915_DSP1_RX_EQ_BAND_4_C              0x48F
+#define WM8915_DSP1_RX_EQ_BAND_4_PG             0x490
+#define WM8915_DSP1_RX_EQ_BAND_5_A              0x491
+#define WM8915_DSP1_RX_EQ_BAND_5_B              0x492
+#define WM8915_DSP1_RX_EQ_BAND_5_PG             0x493
+#define WM8915_DSP2_TX_LEFT_VOLUME              0x500
+#define WM8915_DSP2_TX_RIGHT_VOLUME             0x501
+#define WM8915_DSP2_RX_LEFT_VOLUME              0x502
+#define WM8915_DSP2_RX_RIGHT_VOLUME             0x503
+#define WM8915_DSP2_TX_FILTERS                  0x510
+#define WM8915_DSP2_RX_FILTERS_1                0x520
+#define WM8915_DSP2_RX_FILTERS_2                0x521
+#define WM8915_DSP2_DRC_1                       0x540
+#define WM8915_DSP2_DRC_2                       0x541
+#define WM8915_DSP2_DRC_3                       0x542
+#define WM8915_DSP2_DRC_4                       0x543
+#define WM8915_DSP2_DRC_5                       0x544
+#define WM8915_DSP2_RX_EQ_GAINS_1               0x580
+#define WM8915_DSP2_RX_EQ_GAINS_2               0x581
+#define WM8915_DSP2_RX_EQ_BAND_1_A              0x582
+#define WM8915_DSP2_RX_EQ_BAND_1_B              0x583
+#define WM8915_DSP2_RX_EQ_BAND_1_PG             0x584
+#define WM8915_DSP2_RX_EQ_BAND_2_A              0x585
+#define WM8915_DSP2_RX_EQ_BAND_2_B              0x586
+#define WM8915_DSP2_RX_EQ_BAND_2_C              0x587
+#define WM8915_DSP2_RX_EQ_BAND_2_PG             0x588
+#define WM8915_DSP2_RX_EQ_BAND_3_A              0x589
+#define WM8915_DSP2_RX_EQ_BAND_3_B              0x58A
+#define WM8915_DSP2_RX_EQ_BAND_3_C              0x58B
+#define WM8915_DSP2_RX_EQ_BAND_3_PG             0x58C
+#define WM8915_DSP2_RX_EQ_BAND_4_A              0x58D
+#define WM8915_DSP2_RX_EQ_BAND_4_B              0x58E
+#define WM8915_DSP2_RX_EQ_BAND_4_C              0x58F
+#define WM8915_DSP2_RX_EQ_BAND_4_PG             0x590
+#define WM8915_DSP2_RX_EQ_BAND_5_A              0x591
+#define WM8915_DSP2_RX_EQ_BAND_5_B              0x592
+#define WM8915_DSP2_RX_EQ_BAND_5_PG             0x593
+#define WM8915_DAC1_MIXER_VOLUMES               0x600
+#define WM8915_DAC1_LEFT_MIXER_ROUTING          0x601
+#define WM8915_DAC1_RIGHT_MIXER_ROUTING         0x602
+#define WM8915_DAC2_MIXER_VOLUMES               0x603
+#define WM8915_DAC2_LEFT_MIXER_ROUTING          0x604
+#define WM8915_DAC2_RIGHT_MIXER_ROUTING         0x605
+#define WM8915_DSP1_TX_LEFT_MIXER_ROUTING       0x606
+#define WM8915_DSP1_TX_RIGHT_MIXER_ROUTING      0x607
+#define WM8915_DSP2_TX_LEFT_MIXER_ROUTING       0x608
+#define WM8915_DSP2_TX_RIGHT_MIXER_ROUTING      0x609
+#define WM8915_DSP_TX_MIXER_SELECT              0x60A
+#define WM8915_DAC_SOFTMUTE                     0x610
+#define WM8915_OVERSAMPLING                     0x620
+#define WM8915_SIDETONE                         0x621
+#define WM8915_GPIO_1                           0x700
+#define WM8915_GPIO_2                           0x701
+#define WM8915_GPIO_3                           0x702
+#define WM8915_GPIO_4                           0x703
+#define WM8915_GPIO_5                           0x704
+#define WM8915_PULL_CONTROL_1                   0x720
+#define WM8915_PULL_CONTROL_2                   0x721
+#define WM8915_INTERRUPT_STATUS_1               0x730
+#define WM8915_INTERRUPT_STATUS_2               0x731
+#define WM8915_INTERRUPT_RAW_STATUS_2           0x732
+#define WM8915_INTERRUPT_STATUS_1_MASK          0x738
+#define WM8915_INTERRUPT_STATUS_2_MASK          0x739
+#define WM8915_INTERRUPT_CONTROL                0x740
+#define WM8915_LEFT_PDM_SPEAKER                 0x800
+#define WM8915_RIGHT_PDM_SPEAKER                0x801
+#define WM8915_PDM_SPEAKER_MUTE_SEQUENCE        0x802
+#define WM8915_PDM_SPEAKER_VOLUME               0x803
+#define WM8915_WRITE_SEQUENCER_0                0x3000
+#define WM8915_WRITE_SEQUENCER_1                0x3001
+#define WM8915_WRITE_SEQUENCER_2                0x3002
+#define WM8915_WRITE_SEQUENCER_3                0x3003
+#define WM8915_WRITE_SEQUENCER_4                0x3004
+#define WM8915_WRITE_SEQUENCER_5                0x3005
+#define WM8915_WRITE_SEQUENCER_6                0x3006
+#define WM8915_WRITE_SEQUENCER_7                0x3007
+#define WM8915_WRITE_SEQUENCER_8                0x3008
+#define WM8915_WRITE_SEQUENCER_9                0x3009
+#define WM8915_WRITE_SEQUENCER_10               0x300A
+#define WM8915_WRITE_SEQUENCER_11               0x300B
+#define WM8915_WRITE_SEQUENCER_12               0x300C
+#define WM8915_WRITE_SEQUENCER_13               0x300D
+#define WM8915_WRITE_SEQUENCER_14               0x300E
+#define WM8915_WRITE_SEQUENCER_15               0x300F
+#define WM8915_WRITE_SEQUENCER_16               0x3010
+#define WM8915_WRITE_SEQUENCER_17               0x3011
+#define WM8915_WRITE_SEQUENCER_18               0x3012
+#define WM8915_WRITE_SEQUENCER_19               0x3013
+#define WM8915_WRITE_SEQUENCER_20               0x3014
+#define WM8915_WRITE_SEQUENCER_21               0x3015
+#define WM8915_WRITE_SEQUENCER_22               0x3016
+#define WM8915_WRITE_SEQUENCER_23               0x3017
+#define WM8915_WRITE_SEQUENCER_24               0x3018
+#define WM8915_WRITE_SEQUENCER_25               0x3019
+#define WM8915_WRITE_SEQUENCER_26               0x301A
+#define WM8915_WRITE_SEQUENCER_27               0x301B
+#define WM8915_WRITE_SEQUENCER_28               0x301C
+#define WM8915_WRITE_SEQUENCER_29               0x301D
+#define WM8915_WRITE_SEQUENCER_30               0x301E
+#define WM8915_WRITE_SEQUENCER_31               0x301F
+#define WM8915_WRITE_SEQUENCER_32               0x3020
+#define WM8915_WRITE_SEQUENCER_33               0x3021
+#define WM8915_WRITE_SEQUENCER_34               0x3022
+#define WM8915_WRITE_SEQUENCER_35               0x3023
+#define WM8915_WRITE_SEQUENCER_36               0x3024
+#define WM8915_WRITE_SEQUENCER_37               0x3025
+#define WM8915_WRITE_SEQUENCER_38               0x3026
+#define WM8915_WRITE_SEQUENCER_39               0x3027
+#define WM8915_WRITE_SEQUENCER_40               0x3028
+#define WM8915_WRITE_SEQUENCER_41               0x3029
+#define WM8915_WRITE_SEQUENCER_42               0x302A
+#define WM8915_WRITE_SEQUENCER_43               0x302B
+#define WM8915_WRITE_SEQUENCER_44               0x302C
+#define WM8915_WRITE_SEQUENCER_45               0x302D
+#define WM8915_WRITE_SEQUENCER_46               0x302E
+#define WM8915_WRITE_SEQUENCER_47               0x302F
+#define WM8915_WRITE_SEQUENCER_48               0x3030
+#define WM8915_WRITE_SEQUENCER_49               0x3031
+#define WM8915_WRITE_SEQUENCER_50               0x3032
+#define WM8915_WRITE_SEQUENCER_51               0x3033
+#define WM8915_WRITE_SEQUENCER_52               0x3034
+#define WM8915_WRITE_SEQUENCER_53               0x3035
+#define WM8915_WRITE_SEQUENCER_54               0x3036
+#define WM8915_WRITE_SEQUENCER_55               0x3037
+#define WM8915_WRITE_SEQUENCER_56               0x3038
+#define WM8915_WRITE_SEQUENCER_57               0x3039
+#define WM8915_WRITE_SEQUENCER_58               0x303A
+#define WM8915_WRITE_SEQUENCER_59               0x303B
+#define WM8915_WRITE_SEQUENCER_60               0x303C
+#define WM8915_WRITE_SEQUENCER_61               0x303D
+#define WM8915_WRITE_SEQUENCER_62               0x303E
+#define WM8915_WRITE_SEQUENCER_63               0x303F
+#define WM8915_WRITE_SEQUENCER_64               0x3040
+#define WM8915_WRITE_SEQUENCER_65               0x3041
+#define WM8915_WRITE_SEQUENCER_66               0x3042
+#define WM8915_WRITE_SEQUENCER_67               0x3043
+#define WM8915_WRITE_SEQUENCER_68               0x3044
+#define WM8915_WRITE_SEQUENCER_69               0x3045
+#define WM8915_WRITE_SEQUENCER_70               0x3046
+#define WM8915_WRITE_SEQUENCER_71               0x3047
+#define WM8915_WRITE_SEQUENCER_72               0x3048
+#define WM8915_WRITE_SEQUENCER_73               0x3049
+#define WM8915_WRITE_SEQUENCER_74               0x304A
+#define WM8915_WRITE_SEQUENCER_75               0x304B
+#define WM8915_WRITE_SEQUENCER_76               0x304C
+#define WM8915_WRITE_SEQUENCER_77               0x304D
+#define WM8915_WRITE_SEQUENCER_78               0x304E
+#define WM8915_WRITE_SEQUENCER_79               0x304F
+#define WM8915_WRITE_SEQUENCER_80               0x3050
+#define WM8915_WRITE_SEQUENCER_81               0x3051
+#define WM8915_WRITE_SEQUENCER_82               0x3052
+#define WM8915_WRITE_SEQUENCER_83               0x3053
+#define WM8915_WRITE_SEQUENCER_84               0x3054
+#define WM8915_WRITE_SEQUENCER_85               0x3055
+#define WM8915_WRITE_SEQUENCER_86               0x3056
+#define WM8915_WRITE_SEQUENCER_87               0x3057
+#define WM8915_WRITE_SEQUENCER_88               0x3058
+#define WM8915_WRITE_SEQUENCER_89               0x3059
+#define WM8915_WRITE_SEQUENCER_90               0x305A
+#define WM8915_WRITE_SEQUENCER_91               0x305B
+#define WM8915_WRITE_SEQUENCER_92               0x305C
+#define WM8915_WRITE_SEQUENCER_93               0x305D
+#define WM8915_WRITE_SEQUENCER_94               0x305E
+#define WM8915_WRITE_SEQUENCER_95               0x305F
+#define WM8915_WRITE_SEQUENCER_96               0x3060
+#define WM8915_WRITE_SEQUENCER_97               0x3061
+#define WM8915_WRITE_SEQUENCER_98               0x3062
+#define WM8915_WRITE_SEQUENCER_99               0x3063
+#define WM8915_WRITE_SEQUENCER_100              0x3064
+#define WM8915_WRITE_SEQUENCER_101              0x3065
+#define WM8915_WRITE_SEQUENCER_102              0x3066
+#define WM8915_WRITE_SEQUENCER_103              0x3067
+#define WM8915_WRITE_SEQUENCER_104              0x3068
+#define WM8915_WRITE_SEQUENCER_105              0x3069
+#define WM8915_WRITE_SEQUENCER_106              0x306A
+#define WM8915_WRITE_SEQUENCER_107              0x306B
+#define WM8915_WRITE_SEQUENCER_108              0x306C
+#define WM8915_WRITE_SEQUENCER_109              0x306D
+#define WM8915_WRITE_SEQUENCER_110              0x306E
+#define WM8915_WRITE_SEQUENCER_111              0x306F
+#define WM8915_WRITE_SEQUENCER_112              0x3070
+#define WM8915_WRITE_SEQUENCER_113              0x3071
+#define WM8915_WRITE_SEQUENCER_114              0x3072
+#define WM8915_WRITE_SEQUENCER_115              0x3073
+#define WM8915_WRITE_SEQUENCER_116              0x3074
+#define WM8915_WRITE_SEQUENCER_117              0x3075
+#define WM8915_WRITE_SEQUENCER_118              0x3076
+#define WM8915_WRITE_SEQUENCER_119              0x3077
+#define WM8915_WRITE_SEQUENCER_120              0x3078
+#define WM8915_WRITE_SEQUENCER_121              0x3079
+#define WM8915_WRITE_SEQUENCER_122              0x307A
+#define WM8915_WRITE_SEQUENCER_123              0x307B
+#define WM8915_WRITE_SEQUENCER_124              0x307C
+#define WM8915_WRITE_SEQUENCER_125              0x307D
+#define WM8915_WRITE_SEQUENCER_126              0x307E
+#define WM8915_WRITE_SEQUENCER_127              0x307F
+#define WM8915_WRITE_SEQUENCER_128              0x3080
+#define WM8915_WRITE_SEQUENCER_129              0x3081
+#define WM8915_WRITE_SEQUENCER_130              0x3082
+#define WM8915_WRITE_SEQUENCER_131              0x3083
+#define WM8915_WRITE_SEQUENCER_132              0x3084
+#define WM8915_WRITE_SEQUENCER_133              0x3085
+#define WM8915_WRITE_SEQUENCER_134              0x3086
+#define WM8915_WRITE_SEQUENCER_135              0x3087
+#define WM8915_WRITE_SEQUENCER_136              0x3088
+#define WM8915_WRITE_SEQUENCER_137              0x3089
+#define WM8915_WRITE_SEQUENCER_138              0x308A
+#define WM8915_WRITE_SEQUENCER_139              0x308B
+#define WM8915_WRITE_SEQUENCER_140              0x308C
+#define WM8915_WRITE_SEQUENCER_141              0x308D
+#define WM8915_WRITE_SEQUENCER_142              0x308E
+#define WM8915_WRITE_SEQUENCER_143              0x308F
+#define WM8915_WRITE_SEQUENCER_144              0x3090
+#define WM8915_WRITE_SEQUENCER_145              0x3091
+#define WM8915_WRITE_SEQUENCER_146              0x3092
+#define WM8915_WRITE_SEQUENCER_147              0x3093
+#define WM8915_WRITE_SEQUENCER_148              0x3094
+#define WM8915_WRITE_SEQUENCER_149              0x3095
+#define WM8915_WRITE_SEQUENCER_150              0x3096
+#define WM8915_WRITE_SEQUENCER_151              0x3097
+#define WM8915_WRITE_SEQUENCER_152              0x3098
+#define WM8915_WRITE_SEQUENCER_153              0x3099
+#define WM8915_WRITE_SEQUENCER_154              0x309A
+#define WM8915_WRITE_SEQUENCER_155              0x309B
+#define WM8915_WRITE_SEQUENCER_156              0x309C
+#define WM8915_WRITE_SEQUENCER_157              0x309D
+#define WM8915_WRITE_SEQUENCER_158              0x309E
+#define WM8915_WRITE_SEQUENCER_159              0x309F
+#define WM8915_WRITE_SEQUENCER_160              0x30A0
+#define WM8915_WRITE_SEQUENCER_161              0x30A1
+#define WM8915_WRITE_SEQUENCER_162              0x30A2
+#define WM8915_WRITE_SEQUENCER_163              0x30A3
+#define WM8915_WRITE_SEQUENCER_164              0x30A4
+#define WM8915_WRITE_SEQUENCER_165              0x30A5
+#define WM8915_WRITE_SEQUENCER_166              0x30A6
+#define WM8915_WRITE_SEQUENCER_167              0x30A7
+#define WM8915_WRITE_SEQUENCER_168              0x30A8
+#define WM8915_WRITE_SEQUENCER_169              0x30A9
+#define WM8915_WRITE_SEQUENCER_170              0x30AA
+#define WM8915_WRITE_SEQUENCER_171              0x30AB
+#define WM8915_WRITE_SEQUENCER_172              0x30AC
+#define WM8915_WRITE_SEQUENCER_173              0x30AD
+#define WM8915_WRITE_SEQUENCER_174              0x30AE
+#define WM8915_WRITE_SEQUENCER_175              0x30AF
+#define WM8915_WRITE_SEQUENCER_176              0x30B0
+#define WM8915_WRITE_SEQUENCER_177              0x30B1
+#define WM8915_WRITE_SEQUENCER_178              0x30B2
+#define WM8915_WRITE_SEQUENCER_179              0x30B3
+#define WM8915_WRITE_SEQUENCER_180              0x30B4
+#define WM8915_WRITE_SEQUENCER_181              0x30B5
+#define WM8915_WRITE_SEQUENCER_182              0x30B6
+#define WM8915_WRITE_SEQUENCER_183              0x30B7
+#define WM8915_WRITE_SEQUENCER_184              0x30B8
+#define WM8915_WRITE_SEQUENCER_185              0x30B9
+#define WM8915_WRITE_SEQUENCER_186              0x30BA
+#define WM8915_WRITE_SEQUENCER_187              0x30BB
+#define WM8915_WRITE_SEQUENCER_188              0x30BC
+#define WM8915_WRITE_SEQUENCER_189              0x30BD
+#define WM8915_WRITE_SEQUENCER_190              0x30BE
+#define WM8915_WRITE_SEQUENCER_191              0x30BF
+#define WM8915_WRITE_SEQUENCER_192              0x30C0
+#define WM8915_WRITE_SEQUENCER_193              0x30C1
+#define WM8915_WRITE_SEQUENCER_194              0x30C2
+#define WM8915_WRITE_SEQUENCER_195              0x30C3
+#define WM8915_WRITE_SEQUENCER_196              0x30C4
+#define WM8915_WRITE_SEQUENCER_197              0x30C5
+#define WM8915_WRITE_SEQUENCER_198              0x30C6
+#define WM8915_WRITE_SEQUENCER_199              0x30C7
+#define WM8915_WRITE_SEQUENCER_200              0x30C8
+#define WM8915_WRITE_SEQUENCER_201              0x30C9
+#define WM8915_WRITE_SEQUENCER_202              0x30CA
+#define WM8915_WRITE_SEQUENCER_203              0x30CB
+#define WM8915_WRITE_SEQUENCER_204              0x30CC
+#define WM8915_WRITE_SEQUENCER_205              0x30CD
+#define WM8915_WRITE_SEQUENCER_206              0x30CE
+#define WM8915_WRITE_SEQUENCER_207              0x30CF
+#define WM8915_WRITE_SEQUENCER_208              0x30D0
+#define WM8915_WRITE_SEQUENCER_209              0x30D1
+#define WM8915_WRITE_SEQUENCER_210              0x30D2
+#define WM8915_WRITE_SEQUENCER_211              0x30D3
+#define WM8915_WRITE_SEQUENCER_212              0x30D4
+#define WM8915_WRITE_SEQUENCER_213              0x30D5
+#define WM8915_WRITE_SEQUENCER_214              0x30D6
+#define WM8915_WRITE_SEQUENCER_215              0x30D7
+#define WM8915_WRITE_SEQUENCER_216              0x30D8
+#define WM8915_WRITE_SEQUENCER_217              0x30D9
+#define WM8915_WRITE_SEQUENCER_218              0x30DA
+#define WM8915_WRITE_SEQUENCER_219              0x30DB
+#define WM8915_WRITE_SEQUENCER_220              0x30DC
+#define WM8915_WRITE_SEQUENCER_221              0x30DD
+#define WM8915_WRITE_SEQUENCER_222              0x30DE
+#define WM8915_WRITE_SEQUENCER_223              0x30DF
+#define WM8915_WRITE_SEQUENCER_224              0x30E0
+#define WM8915_WRITE_SEQUENCER_225              0x30E1
+#define WM8915_WRITE_SEQUENCER_226              0x30E2
+#define WM8915_WRITE_SEQUENCER_227              0x30E3
+#define WM8915_WRITE_SEQUENCER_228              0x30E4
+#define WM8915_WRITE_SEQUENCER_229              0x30E5
+#define WM8915_WRITE_SEQUENCER_230              0x30E6
+#define WM8915_WRITE_SEQUENCER_231              0x30E7
+#define WM8915_WRITE_SEQUENCER_232              0x30E8
+#define WM8915_WRITE_SEQUENCER_233              0x30E9
+#define WM8915_WRITE_SEQUENCER_234              0x30EA
+#define WM8915_WRITE_SEQUENCER_235              0x30EB
+#define WM8915_WRITE_SEQUENCER_236              0x30EC
+#define WM8915_WRITE_SEQUENCER_237              0x30ED
+#define WM8915_WRITE_SEQUENCER_238              0x30EE
+#define WM8915_WRITE_SEQUENCER_239              0x30EF
+#define WM8915_WRITE_SEQUENCER_240              0x30F0
+#define WM8915_WRITE_SEQUENCER_241              0x30F1
+#define WM8915_WRITE_SEQUENCER_242              0x30F2
+#define WM8915_WRITE_SEQUENCER_243              0x30F3
+#define WM8915_WRITE_SEQUENCER_244              0x30F4
+#define WM8915_WRITE_SEQUENCER_245              0x30F5
+#define WM8915_WRITE_SEQUENCER_246              0x30F6
+#define WM8915_WRITE_SEQUENCER_247              0x30F7
+#define WM8915_WRITE_SEQUENCER_248              0x30F8
+#define WM8915_WRITE_SEQUENCER_249              0x30F9
+#define WM8915_WRITE_SEQUENCER_250              0x30FA
+#define WM8915_WRITE_SEQUENCER_251              0x30FB
+#define WM8915_WRITE_SEQUENCER_252              0x30FC
+#define WM8915_WRITE_SEQUENCER_253              0x30FD
+#define WM8915_WRITE_SEQUENCER_254              0x30FE
+#define WM8915_WRITE_SEQUENCER_255              0x30FF
+#define WM8915_WRITE_SEQUENCER_256              0x3100
+#define WM8915_WRITE_SEQUENCER_257              0x3101
+#define WM8915_WRITE_SEQUENCER_258              0x3102
+#define WM8915_WRITE_SEQUENCER_259              0x3103
+#define WM8915_WRITE_SEQUENCER_260              0x3104
+#define WM8915_WRITE_SEQUENCER_261              0x3105
+#define WM8915_WRITE_SEQUENCER_262              0x3106
+#define WM8915_WRITE_SEQUENCER_263              0x3107
+#define WM8915_WRITE_SEQUENCER_264              0x3108
+#define WM8915_WRITE_SEQUENCER_265              0x3109
+#define WM8915_WRITE_SEQUENCER_266              0x310A
+#define WM8915_WRITE_SEQUENCER_267              0x310B
+#define WM8915_WRITE_SEQUENCER_268              0x310C
+#define WM8915_WRITE_SEQUENCER_269              0x310D
+#define WM8915_WRITE_SEQUENCER_270              0x310E
+#define WM8915_WRITE_SEQUENCER_271              0x310F
+#define WM8915_WRITE_SEQUENCER_272              0x3110
+#define WM8915_WRITE_SEQUENCER_273              0x3111
+#define WM8915_WRITE_SEQUENCER_274              0x3112
+#define WM8915_WRITE_SEQUENCER_275              0x3113
+#define WM8915_WRITE_SEQUENCER_276              0x3114
+#define WM8915_WRITE_SEQUENCER_277              0x3115
+#define WM8915_WRITE_SEQUENCER_278              0x3116
+#define WM8915_WRITE_SEQUENCER_279              0x3117
+#define WM8915_WRITE_SEQUENCER_280              0x3118
+#define WM8915_WRITE_SEQUENCER_281              0x3119
+#define WM8915_WRITE_SEQUENCER_282              0x311A
+#define WM8915_WRITE_SEQUENCER_283              0x311B
+#define WM8915_WRITE_SEQUENCER_284              0x311C
+#define WM8915_WRITE_SEQUENCER_285              0x311D
+#define WM8915_WRITE_SEQUENCER_286              0x311E
+#define WM8915_WRITE_SEQUENCER_287              0x311F
+#define WM8915_WRITE_SEQUENCER_288              0x3120
+#define WM8915_WRITE_SEQUENCER_289              0x3121
+#define WM8915_WRITE_SEQUENCER_290              0x3122
+#define WM8915_WRITE_SEQUENCER_291              0x3123
+#define WM8915_WRITE_SEQUENCER_292              0x3124
+#define WM8915_WRITE_SEQUENCER_293              0x3125
+#define WM8915_WRITE_SEQUENCER_294              0x3126
+#define WM8915_WRITE_SEQUENCER_295              0x3127
+#define WM8915_WRITE_SEQUENCER_296              0x3128
+#define WM8915_WRITE_SEQUENCER_297              0x3129
+#define WM8915_WRITE_SEQUENCER_298              0x312A
+#define WM8915_WRITE_SEQUENCER_299              0x312B
+#define WM8915_WRITE_SEQUENCER_300              0x312C
+#define WM8915_WRITE_SEQUENCER_301              0x312D
+#define WM8915_WRITE_SEQUENCER_302              0x312E
+#define WM8915_WRITE_SEQUENCER_303              0x312F
+#define WM8915_WRITE_SEQUENCER_304              0x3130
+#define WM8915_WRITE_SEQUENCER_305              0x3131
+#define WM8915_WRITE_SEQUENCER_306              0x3132
+#define WM8915_WRITE_SEQUENCER_307              0x3133
+#define WM8915_WRITE_SEQUENCER_308              0x3134
+#define WM8915_WRITE_SEQUENCER_309              0x3135
+#define WM8915_WRITE_SEQUENCER_310              0x3136
+#define WM8915_WRITE_SEQUENCER_311              0x3137
+#define WM8915_WRITE_SEQUENCER_312              0x3138
+#define WM8915_WRITE_SEQUENCER_313              0x3139
+#define WM8915_WRITE_SEQUENCER_314              0x313A
+#define WM8915_WRITE_SEQUENCER_315              0x313B
+#define WM8915_WRITE_SEQUENCER_316              0x313C
+#define WM8915_WRITE_SEQUENCER_317              0x313D
+#define WM8915_WRITE_SEQUENCER_318              0x313E
+#define WM8915_WRITE_SEQUENCER_319              0x313F
+#define WM8915_WRITE_SEQUENCER_320              0x3140
+#define WM8915_WRITE_SEQUENCER_321              0x3141
+#define WM8915_WRITE_SEQUENCER_322              0x3142
+#define WM8915_WRITE_SEQUENCER_323              0x3143
+#define WM8915_WRITE_SEQUENCER_324              0x3144
+#define WM8915_WRITE_SEQUENCER_325              0x3145
+#define WM8915_WRITE_SEQUENCER_326              0x3146
+#define WM8915_WRITE_SEQUENCER_327              0x3147
+#define WM8915_WRITE_SEQUENCER_328              0x3148
+#define WM8915_WRITE_SEQUENCER_329              0x3149
+#define WM8915_WRITE_SEQUENCER_330              0x314A
+#define WM8915_WRITE_SEQUENCER_331              0x314B
+#define WM8915_WRITE_SEQUENCER_332              0x314C
+#define WM8915_WRITE_SEQUENCER_333              0x314D
+#define WM8915_WRITE_SEQUENCER_334              0x314E
+#define WM8915_WRITE_SEQUENCER_335              0x314F
+#define WM8915_WRITE_SEQUENCER_336              0x3150
+#define WM8915_WRITE_SEQUENCER_337              0x3151
+#define WM8915_WRITE_SEQUENCER_338              0x3152
+#define WM8915_WRITE_SEQUENCER_339              0x3153
+#define WM8915_WRITE_SEQUENCER_340              0x3154
+#define WM8915_WRITE_SEQUENCER_341              0x3155
+#define WM8915_WRITE_SEQUENCER_342              0x3156
+#define WM8915_WRITE_SEQUENCER_343              0x3157
+#define WM8915_WRITE_SEQUENCER_344              0x3158
+#define WM8915_WRITE_SEQUENCER_345              0x3159
+#define WM8915_WRITE_SEQUENCER_346              0x315A
+#define WM8915_WRITE_SEQUENCER_347              0x315B
+#define WM8915_WRITE_SEQUENCER_348              0x315C
+#define WM8915_WRITE_SEQUENCER_349              0x315D
+#define WM8915_WRITE_SEQUENCER_350              0x315E
+#define WM8915_WRITE_SEQUENCER_351              0x315F
+#define WM8915_WRITE_SEQUENCER_352              0x3160
+#define WM8915_WRITE_SEQUENCER_353              0x3161
+#define WM8915_WRITE_SEQUENCER_354              0x3162
+#define WM8915_WRITE_SEQUENCER_355              0x3163
+#define WM8915_WRITE_SEQUENCER_356              0x3164
+#define WM8915_WRITE_SEQUENCER_357              0x3165
+#define WM8915_WRITE_SEQUENCER_358              0x3166
+#define WM8915_WRITE_SEQUENCER_359              0x3167
+#define WM8915_WRITE_SEQUENCER_360              0x3168
+#define WM8915_WRITE_SEQUENCER_361              0x3169
+#define WM8915_WRITE_SEQUENCER_362              0x316A
+#define WM8915_WRITE_SEQUENCER_363              0x316B
+#define WM8915_WRITE_SEQUENCER_364              0x316C
+#define WM8915_WRITE_SEQUENCER_365              0x316D
+#define WM8915_WRITE_SEQUENCER_366              0x316E
+#define WM8915_WRITE_SEQUENCER_367              0x316F
+#define WM8915_WRITE_SEQUENCER_368              0x3170
+#define WM8915_WRITE_SEQUENCER_369              0x3171
+#define WM8915_WRITE_SEQUENCER_370              0x3172
+#define WM8915_WRITE_SEQUENCER_371              0x3173
+#define WM8915_WRITE_SEQUENCER_372              0x3174
+#define WM8915_WRITE_SEQUENCER_373              0x3175
+#define WM8915_WRITE_SEQUENCER_374              0x3176
+#define WM8915_WRITE_SEQUENCER_375              0x3177
+#define WM8915_WRITE_SEQUENCER_376              0x3178
+#define WM8915_WRITE_SEQUENCER_377              0x3179
+#define WM8915_WRITE_SEQUENCER_378              0x317A
+#define WM8915_WRITE_SEQUENCER_379              0x317B
+#define WM8915_WRITE_SEQUENCER_380              0x317C
+#define WM8915_WRITE_SEQUENCER_381              0x317D
+#define WM8915_WRITE_SEQUENCER_382              0x317E
+#define WM8915_WRITE_SEQUENCER_383              0x317F
+#define WM8915_WRITE_SEQUENCER_384              0x3180
+#define WM8915_WRITE_SEQUENCER_385              0x3181
+#define WM8915_WRITE_SEQUENCER_386              0x3182
+#define WM8915_WRITE_SEQUENCER_387              0x3183
+#define WM8915_WRITE_SEQUENCER_388              0x3184
+#define WM8915_WRITE_SEQUENCER_389              0x3185
+#define WM8915_WRITE_SEQUENCER_390              0x3186
+#define WM8915_WRITE_SEQUENCER_391              0x3187
+#define WM8915_WRITE_SEQUENCER_392              0x3188
+#define WM8915_WRITE_SEQUENCER_393              0x3189
+#define WM8915_WRITE_SEQUENCER_394              0x318A
+#define WM8915_WRITE_SEQUENCER_395              0x318B
+#define WM8915_WRITE_SEQUENCER_396              0x318C
+#define WM8915_WRITE_SEQUENCER_397              0x318D
+#define WM8915_WRITE_SEQUENCER_398              0x318E
+#define WM8915_WRITE_SEQUENCER_399              0x318F
+#define WM8915_WRITE_SEQUENCER_400              0x3190
+#define WM8915_WRITE_SEQUENCER_401              0x3191
+#define WM8915_WRITE_SEQUENCER_402              0x3192
+#define WM8915_WRITE_SEQUENCER_403              0x3193
+#define WM8915_WRITE_SEQUENCER_404              0x3194
+#define WM8915_WRITE_SEQUENCER_405              0x3195
+#define WM8915_WRITE_SEQUENCER_406              0x3196
+#define WM8915_WRITE_SEQUENCER_407              0x3197
+#define WM8915_WRITE_SEQUENCER_408              0x3198
+#define WM8915_WRITE_SEQUENCER_409              0x3199
+#define WM8915_WRITE_SEQUENCER_410              0x319A
+#define WM8915_WRITE_SEQUENCER_411              0x319B
+#define WM8915_WRITE_SEQUENCER_412              0x319C
+#define WM8915_WRITE_SEQUENCER_413              0x319D
+#define WM8915_WRITE_SEQUENCER_414              0x319E
+#define WM8915_WRITE_SEQUENCER_415              0x319F
+#define WM8915_WRITE_SEQUENCER_416              0x31A0
+#define WM8915_WRITE_SEQUENCER_417              0x31A1
+#define WM8915_WRITE_SEQUENCER_418              0x31A2
+#define WM8915_WRITE_SEQUENCER_419              0x31A3
+#define WM8915_WRITE_SEQUENCER_420              0x31A4
+#define WM8915_WRITE_SEQUENCER_421              0x31A5
+#define WM8915_WRITE_SEQUENCER_422              0x31A6
+#define WM8915_WRITE_SEQUENCER_423              0x31A7
+#define WM8915_WRITE_SEQUENCER_424              0x31A8
+#define WM8915_WRITE_SEQUENCER_425              0x31A9
+#define WM8915_WRITE_SEQUENCER_426              0x31AA
+#define WM8915_WRITE_SEQUENCER_427              0x31AB
+#define WM8915_WRITE_SEQUENCER_428              0x31AC
+#define WM8915_WRITE_SEQUENCER_429              0x31AD
+#define WM8915_WRITE_SEQUENCER_430              0x31AE
+#define WM8915_WRITE_SEQUENCER_431              0x31AF
+#define WM8915_WRITE_SEQUENCER_432              0x31B0
+#define WM8915_WRITE_SEQUENCER_433              0x31B1
+#define WM8915_WRITE_SEQUENCER_434              0x31B2
+#define WM8915_WRITE_SEQUENCER_435              0x31B3
+#define WM8915_WRITE_SEQUENCER_436              0x31B4
+#define WM8915_WRITE_SEQUENCER_437              0x31B5
+#define WM8915_WRITE_SEQUENCER_438              0x31B6
+#define WM8915_WRITE_SEQUENCER_439              0x31B7
+#define WM8915_WRITE_SEQUENCER_440              0x31B8
+#define WM8915_WRITE_SEQUENCER_441              0x31B9
+#define WM8915_WRITE_SEQUENCER_442              0x31BA
+#define WM8915_WRITE_SEQUENCER_443              0x31BB
+#define WM8915_WRITE_SEQUENCER_444              0x31BC
+#define WM8915_WRITE_SEQUENCER_445              0x31BD
+#define WM8915_WRITE_SEQUENCER_446              0x31BE
+#define WM8915_WRITE_SEQUENCER_447              0x31BF
+#define WM8915_WRITE_SEQUENCER_448              0x31C0
+#define WM8915_WRITE_SEQUENCER_449              0x31C1
+#define WM8915_WRITE_SEQUENCER_450              0x31C2
+#define WM8915_WRITE_SEQUENCER_451              0x31C3
+#define WM8915_WRITE_SEQUENCER_452              0x31C4
+#define WM8915_WRITE_SEQUENCER_453              0x31C5
+#define WM8915_WRITE_SEQUENCER_454              0x31C6
+#define WM8915_WRITE_SEQUENCER_455              0x31C7
+#define WM8915_WRITE_SEQUENCER_456              0x31C8
+#define WM8915_WRITE_SEQUENCER_457              0x31C9
+#define WM8915_WRITE_SEQUENCER_458              0x31CA
+#define WM8915_WRITE_SEQUENCER_459              0x31CB
+#define WM8915_WRITE_SEQUENCER_460              0x31CC
+#define WM8915_WRITE_SEQUENCER_461              0x31CD
+#define WM8915_WRITE_SEQUENCER_462              0x31CE
+#define WM8915_WRITE_SEQUENCER_463              0x31CF
+#define WM8915_WRITE_SEQUENCER_464              0x31D0
+#define WM8915_WRITE_SEQUENCER_465              0x31D1
+#define WM8915_WRITE_SEQUENCER_466              0x31D2
+#define WM8915_WRITE_SEQUENCER_467              0x31D3
+#define WM8915_WRITE_SEQUENCER_468              0x31D4
+#define WM8915_WRITE_SEQUENCER_469              0x31D5
+#define WM8915_WRITE_SEQUENCER_470              0x31D6
+#define WM8915_WRITE_SEQUENCER_471              0x31D7
+#define WM8915_WRITE_SEQUENCER_472              0x31D8
+#define WM8915_WRITE_SEQUENCER_473              0x31D9
+#define WM8915_WRITE_SEQUENCER_474              0x31DA
+#define WM8915_WRITE_SEQUENCER_475              0x31DB
+#define WM8915_WRITE_SEQUENCER_476              0x31DC
+#define WM8915_WRITE_SEQUENCER_477              0x31DD
+#define WM8915_WRITE_SEQUENCER_478              0x31DE
+#define WM8915_WRITE_SEQUENCER_479              0x31DF
+#define WM8915_WRITE_SEQUENCER_480              0x31E0
+#define WM8915_WRITE_SEQUENCER_481              0x31E1
+#define WM8915_WRITE_SEQUENCER_482              0x31E2
+#define WM8915_WRITE_SEQUENCER_483              0x31E3
+#define WM8915_WRITE_SEQUENCER_484              0x31E4
+#define WM8915_WRITE_SEQUENCER_485              0x31E5
+#define WM8915_WRITE_SEQUENCER_486              0x31E6
+#define WM8915_WRITE_SEQUENCER_487              0x31E7
+#define WM8915_WRITE_SEQUENCER_488              0x31E8
+#define WM8915_WRITE_SEQUENCER_489              0x31E9
+#define WM8915_WRITE_SEQUENCER_490              0x31EA
+#define WM8915_WRITE_SEQUENCER_491              0x31EB
+#define WM8915_WRITE_SEQUENCER_492              0x31EC
+#define WM8915_WRITE_SEQUENCER_493              0x31ED
+#define WM8915_WRITE_SEQUENCER_494              0x31EE
+#define WM8915_WRITE_SEQUENCER_495              0x31EF
+#define WM8915_WRITE_SEQUENCER_496              0x31F0
+#define WM8915_WRITE_SEQUENCER_497              0x31F1
+#define WM8915_WRITE_SEQUENCER_498              0x31F2
+#define WM8915_WRITE_SEQUENCER_499              0x31F3
+#define WM8915_WRITE_SEQUENCER_500              0x31F4
+#define WM8915_WRITE_SEQUENCER_501              0x31F5
+#define WM8915_WRITE_SEQUENCER_502              0x31F6
+#define WM8915_WRITE_SEQUENCER_503              0x31F7
+#define WM8915_WRITE_SEQUENCER_504              0x31F8
+#define WM8915_WRITE_SEQUENCER_505              0x31F9
+#define WM8915_WRITE_SEQUENCER_506              0x31FA
+#define WM8915_WRITE_SEQUENCER_507              0x31FB
+#define WM8915_WRITE_SEQUENCER_508              0x31FC
+#define WM8915_WRITE_SEQUENCER_509              0x31FD
+#define WM8915_WRITE_SEQUENCER_510              0x31FE
+#define WM8915_WRITE_SEQUENCER_511              0x31FF
+
+#define WM8915_REGISTER_COUNT                   706
+#define WM8915_MAX_REGISTER                     0x31FF
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Software Reset
+ */
+#define WM8915_SW_RESET_MASK                    0xFFFF  /* SW_RESET - [15:0] */
+#define WM8915_SW_RESET_SHIFT                        0  /* SW_RESET - [15:0] */
+#define WM8915_SW_RESET_WIDTH                       16  /* SW_RESET - [15:0] */
+
+/*
+ * R1 (0x01) - Power Management (1)
+ */
+#define WM8915_MICB2_ENA                        0x0200  /* MICB2_ENA */
+#define WM8915_MICB2_ENA_MASK                   0x0200  /* MICB2_ENA */
+#define WM8915_MICB2_ENA_SHIFT                       9  /* MICB2_ENA */
+#define WM8915_MICB2_ENA_WIDTH                       1  /* MICB2_ENA */
+#define WM8915_MICB1_ENA                        0x0100  /* MICB1_ENA */
+#define WM8915_MICB1_ENA_MASK                   0x0100  /* MICB1_ENA */
+#define WM8915_MICB1_ENA_SHIFT                       8  /* MICB1_ENA */
+#define WM8915_MICB1_ENA_WIDTH                       1  /* MICB1_ENA */
+#define WM8915_HPOUT2L_ENA                      0x0080  /* HPOUT2L_ENA */
+#define WM8915_HPOUT2L_ENA_MASK                 0x0080  /* HPOUT2L_ENA */
+#define WM8915_HPOUT2L_ENA_SHIFT                     7  /* HPOUT2L_ENA */
+#define WM8915_HPOUT2L_ENA_WIDTH                     1  /* HPOUT2L_ENA */
+#define WM8915_HPOUT2R_ENA                      0x0040  /* HPOUT2R_ENA */
+#define WM8915_HPOUT2R_ENA_MASK                 0x0040  /* HPOUT2R_ENA */
+#define WM8915_HPOUT2R_ENA_SHIFT                     6  /* HPOUT2R_ENA */
+#define WM8915_HPOUT2R_ENA_WIDTH                     1  /* HPOUT2R_ENA */
+#define WM8915_HPOUT1L_ENA                      0x0020  /* HPOUT1L_ENA */
+#define WM8915_HPOUT1L_ENA_MASK                 0x0020  /* HPOUT1L_ENA */
+#define WM8915_HPOUT1L_ENA_SHIFT                     5  /* HPOUT1L_ENA */
+#define WM8915_HPOUT1L_ENA_WIDTH                     1  /* HPOUT1L_ENA */
+#define WM8915_HPOUT1R_ENA                      0x0010  /* HPOUT1R_ENA */
+#define WM8915_HPOUT1R_ENA_MASK                 0x0010  /* HPOUT1R_ENA */
+#define WM8915_HPOUT1R_ENA_SHIFT                     4  /* HPOUT1R_ENA */
+#define WM8915_HPOUT1R_ENA_WIDTH                     1  /* HPOUT1R_ENA */
+#define WM8915_BG_ENA                           0x0001  /* BG_ENA */
+#define WM8915_BG_ENA_MASK                      0x0001  /* BG_ENA */
+#define WM8915_BG_ENA_SHIFT                          0  /* BG_ENA */
+#define WM8915_BG_ENA_WIDTH                          1  /* BG_ENA */
+
+/*
+ * R2 (0x02) - Power Management (2)
+ */
+#define WM8915_OPCLK_ENA                        0x0800  /* OPCLK_ENA */
+#define WM8915_OPCLK_ENA_MASK                   0x0800  /* OPCLK_ENA */
+#define WM8915_OPCLK_ENA_SHIFT                      11  /* OPCLK_ENA */
+#define WM8915_OPCLK_ENA_WIDTH                       1  /* OPCLK_ENA */
+#define WM8915_INL_ENA                          0x0020  /* INL_ENA */
+#define WM8915_INL_ENA_MASK                     0x0020  /* INL_ENA */
+#define WM8915_INL_ENA_SHIFT                         5  /* INL_ENA */
+#define WM8915_INL_ENA_WIDTH                         1  /* INL_ENA */
+#define WM8915_INR_ENA                          0x0010  /* INR_ENA */
+#define WM8915_INR_ENA_MASK                     0x0010  /* INR_ENA */
+#define WM8915_INR_ENA_SHIFT                         4  /* INR_ENA */
+#define WM8915_INR_ENA_WIDTH                         1  /* INR_ENA */
+#define WM8915_LDO2_ENA                         0x0002  /* LDO2_ENA */
+#define WM8915_LDO2_ENA_MASK                    0x0002  /* LDO2_ENA */
+#define WM8915_LDO2_ENA_SHIFT                        1  /* LDO2_ENA */
+#define WM8915_LDO2_ENA_WIDTH                        1  /* LDO2_ENA */
+
+/*
+ * R3 (0x03) - Power Management (3)
+ */
+#define WM8915_DSP2RXL_ENA                      0x0800  /* DSP2RXL_ENA */
+#define WM8915_DSP2RXL_ENA_MASK                 0x0800  /* DSP2RXL_ENA */
+#define WM8915_DSP2RXL_ENA_SHIFT                    11  /* DSP2RXL_ENA */
+#define WM8915_DSP2RXL_ENA_WIDTH                     1  /* DSP2RXL_ENA */
+#define WM8915_DSP2RXR_ENA                      0x0400  /* DSP2RXR_ENA */
+#define WM8915_DSP2RXR_ENA_MASK                 0x0400  /* DSP2RXR_ENA */
+#define WM8915_DSP2RXR_ENA_SHIFT                    10  /* DSP2RXR_ENA */
+#define WM8915_DSP2RXR_ENA_WIDTH                     1  /* DSP2RXR_ENA */
+#define WM8915_DSP1RXL_ENA                      0x0200  /* DSP1RXL_ENA */
+#define WM8915_DSP1RXL_ENA_MASK                 0x0200  /* DSP1RXL_ENA */
+#define WM8915_DSP1RXL_ENA_SHIFT                     9  /* DSP1RXL_ENA */
+#define WM8915_DSP1RXL_ENA_WIDTH                     1  /* DSP1RXL_ENA */
+#define WM8915_DSP1RXR_ENA                      0x0100  /* DSP1RXR_ENA */
+#define WM8915_DSP1RXR_ENA_MASK                 0x0100  /* DSP1RXR_ENA */
+#define WM8915_DSP1RXR_ENA_SHIFT                     8  /* DSP1RXR_ENA */
+#define WM8915_DSP1RXR_ENA_WIDTH                     1  /* DSP1RXR_ENA */
+#define WM8915_DMIC2L_ENA                       0x0020  /* DMIC2L_ENA */
+#define WM8915_DMIC2L_ENA_MASK                  0x0020  /* DMIC2L_ENA */
+#define WM8915_DMIC2L_ENA_SHIFT                      5  /* DMIC2L_ENA */
+#define WM8915_DMIC2L_ENA_WIDTH                      1  /* DMIC2L_ENA */
+#define WM8915_DMIC2R_ENA                       0x0010  /* DMIC2R_ENA */
+#define WM8915_DMIC2R_ENA_MASK                  0x0010  /* DMIC2R_ENA */
+#define WM8915_DMIC2R_ENA_SHIFT                      4  /* DMIC2R_ENA */
+#define WM8915_DMIC2R_ENA_WIDTH                      1  /* DMIC2R_ENA */
+#define WM8915_DMIC1L_ENA                       0x0008  /* DMIC1L_ENA */
+#define WM8915_DMIC1L_ENA_MASK                  0x0008  /* DMIC1L_ENA */
+#define WM8915_DMIC1L_ENA_SHIFT                      3  /* DMIC1L_ENA */
+#define WM8915_DMIC1L_ENA_WIDTH                      1  /* DMIC1L_ENA */
+#define WM8915_DMIC1R_ENA                       0x0004  /* DMIC1R_ENA */
+#define WM8915_DMIC1R_ENA_MASK                  0x0004  /* DMIC1R_ENA */
+#define WM8915_DMIC1R_ENA_SHIFT                      2  /* DMIC1R_ENA */
+#define WM8915_DMIC1R_ENA_WIDTH                      1  /* DMIC1R_ENA */
+#define WM8915_ADCL_ENA                         0x0002  /* ADCL_ENA */
+#define WM8915_ADCL_ENA_MASK                    0x0002  /* ADCL_ENA */
+#define WM8915_ADCL_ENA_SHIFT                        1  /* ADCL_ENA */
+#define WM8915_ADCL_ENA_WIDTH                        1  /* ADCL_ENA */
+#define WM8915_ADCR_ENA                         0x0001  /* ADCR_ENA */
+#define WM8915_ADCR_ENA_MASK                    0x0001  /* ADCR_ENA */
+#define WM8915_ADCR_ENA_SHIFT                        0  /* ADCR_ENA */
+#define WM8915_ADCR_ENA_WIDTH                        1  /* ADCR_ENA */
+
+/*
+ * R4 (0x04) - Power Management (4)
+ */
+#define WM8915_AIF2RX_CHAN1_ENA                 0x0200  /* AIF2RX_CHAN1_ENA */
+#define WM8915_AIF2RX_CHAN1_ENA_MASK            0x0200  /* AIF2RX_CHAN1_ENA */
+#define WM8915_AIF2RX_CHAN1_ENA_SHIFT                9  /* AIF2RX_CHAN1_ENA */
+#define WM8915_AIF2RX_CHAN1_ENA_WIDTH                1  /* AIF2RX_CHAN1_ENA */
+#define WM8915_AIF2RX_CHAN0_ENA                 0x0100  /* AIF2RX_CHAN0_ENA */
+#define WM8915_AIF2RX_CHAN0_ENA_MASK            0x0100  /* AIF2RX_CHAN0_ENA */
+#define WM8915_AIF2RX_CHAN0_ENA_SHIFT                8  /* AIF2RX_CHAN0_ENA */
+#define WM8915_AIF2RX_CHAN0_ENA_WIDTH                1  /* AIF2RX_CHAN0_ENA */
+#define WM8915_AIF1RX_CHAN5_ENA                 0x0020  /* AIF1RX_CHAN5_ENA */
+#define WM8915_AIF1RX_CHAN5_ENA_MASK            0x0020  /* AIF1RX_CHAN5_ENA */
+#define WM8915_AIF1RX_CHAN5_ENA_SHIFT                5  /* AIF1RX_CHAN5_ENA */
+#define WM8915_AIF1RX_CHAN5_ENA_WIDTH                1  /* AIF1RX_CHAN5_ENA */
+#define WM8915_AIF1RX_CHAN4_ENA                 0x0010  /* AIF1RX_CHAN4_ENA */
+#define WM8915_AIF1RX_CHAN4_ENA_MASK            0x0010  /* AIF1RX_CHAN4_ENA */
+#define WM8915_AIF1RX_CHAN4_ENA_SHIFT                4  /* AIF1RX_CHAN4_ENA */
+#define WM8915_AIF1RX_CHAN4_ENA_WIDTH                1  /* AIF1RX_CHAN4_ENA */
+#define WM8915_AIF1RX_CHAN3_ENA                 0x0008  /* AIF1RX_CHAN3_ENA */
+#define WM8915_AIF1RX_CHAN3_ENA_MASK            0x0008  /* AIF1RX_CHAN3_ENA */
+#define WM8915_AIF1RX_CHAN3_ENA_SHIFT                3  /* AIF1RX_CHAN3_ENA */
+#define WM8915_AIF1RX_CHAN3_ENA_WIDTH                1  /* AIF1RX_CHAN3_ENA */
+#define WM8915_AIF1RX_CHAN2_ENA                 0x0004  /* AIF1RX_CHAN2_ENA */
+#define WM8915_AIF1RX_CHAN2_ENA_MASK            0x0004  /* AIF1RX_CHAN2_ENA */
+#define WM8915_AIF1RX_CHAN2_ENA_SHIFT                2  /* AIF1RX_CHAN2_ENA */
+#define WM8915_AIF1RX_CHAN2_ENA_WIDTH                1  /* AIF1RX_CHAN2_ENA */
+#define WM8915_AIF1RX_CHAN1_ENA                 0x0002  /* AIF1RX_CHAN1_ENA */
+#define WM8915_AIF1RX_CHAN1_ENA_MASK            0x0002  /* AIF1RX_CHAN1_ENA */
+#define WM8915_AIF1RX_CHAN1_ENA_SHIFT                1  /* AIF1RX_CHAN1_ENA */
+#define WM8915_AIF1RX_CHAN1_ENA_WIDTH                1  /* AIF1RX_CHAN1_ENA */
+#define WM8915_AIF1RX_CHAN0_ENA                 0x0001  /* AIF1RX_CHAN0_ENA */
+#define WM8915_AIF1RX_CHAN0_ENA_MASK            0x0001  /* AIF1RX_CHAN0_ENA */
+#define WM8915_AIF1RX_CHAN0_ENA_SHIFT                0  /* AIF1RX_CHAN0_ENA */
+#define WM8915_AIF1RX_CHAN0_ENA_WIDTH                1  /* AIF1RX_CHAN0_ENA */
+
+/*
+ * R5 (0x05) - Power Management (5)
+ */
+#define WM8915_DSP2TXL_ENA                      0x0800  /* DSP2TXL_ENA */
+#define WM8915_DSP2TXL_ENA_MASK                 0x0800  /* DSP2TXL_ENA */
+#define WM8915_DSP2TXL_ENA_SHIFT                    11  /* DSP2TXL_ENA */
+#define WM8915_DSP2TXL_ENA_WIDTH                     1  /* DSP2TXL_ENA */
+#define WM8915_DSP2TXR_ENA                      0x0400  /* DSP2TXR_ENA */
+#define WM8915_DSP2TXR_ENA_MASK                 0x0400  /* DSP2TXR_ENA */
+#define WM8915_DSP2TXR_ENA_SHIFT                    10  /* DSP2TXR_ENA */
+#define WM8915_DSP2TXR_ENA_WIDTH                     1  /* DSP2TXR_ENA */
+#define WM8915_DSP1TXL_ENA                      0x0200  /* DSP1TXL_ENA */
+#define WM8915_DSP1TXL_ENA_MASK                 0x0200  /* DSP1TXL_ENA */
+#define WM8915_DSP1TXL_ENA_SHIFT                     9  /* DSP1TXL_ENA */
+#define WM8915_DSP1TXL_ENA_WIDTH                     1  /* DSP1TXL_ENA */
+#define WM8915_DSP1TXR_ENA                      0x0100  /* DSP1TXR_ENA */
+#define WM8915_DSP1TXR_ENA_MASK                 0x0100  /* DSP1TXR_ENA */
+#define WM8915_DSP1TXR_ENA_SHIFT                     8  /* DSP1TXR_ENA */
+#define WM8915_DSP1TXR_ENA_WIDTH                     1  /* DSP1TXR_ENA */
+#define WM8915_DAC2L_ENA                        0x0008  /* DAC2L_ENA */
+#define WM8915_DAC2L_ENA_MASK                   0x0008  /* DAC2L_ENA */
+#define WM8915_DAC2L_ENA_SHIFT                       3  /* DAC2L_ENA */
+#define WM8915_DAC2L_ENA_WIDTH                       1  /* DAC2L_ENA */
+#define WM8915_DAC2R_ENA                        0x0004  /* DAC2R_ENA */
+#define WM8915_DAC2R_ENA_MASK                   0x0004  /* DAC2R_ENA */
+#define WM8915_DAC2R_ENA_SHIFT                       2  /* DAC2R_ENA */
+#define WM8915_DAC2R_ENA_WIDTH                       1  /* DAC2R_ENA */
+#define WM8915_DAC1L_ENA                        0x0002  /* DAC1L_ENA */
+#define WM8915_DAC1L_ENA_MASK                   0x0002  /* DAC1L_ENA */
+#define WM8915_DAC1L_ENA_SHIFT                       1  /* DAC1L_ENA */
+#define WM8915_DAC1L_ENA_WIDTH                       1  /* DAC1L_ENA */
+#define WM8915_DAC1R_ENA                        0x0001  /* DAC1R_ENA */
+#define WM8915_DAC1R_ENA_MASK                   0x0001  /* DAC1R_ENA */
+#define WM8915_DAC1R_ENA_SHIFT                       0  /* DAC1R_ENA */
+#define WM8915_DAC1R_ENA_WIDTH                       1  /* DAC1R_ENA */
+
+/*
+ * R6 (0x06) - Power Management (6)
+ */
+#define WM8915_AIF2TX_CHAN1_ENA                 0x0200  /* AIF2TX_CHAN1_ENA */
+#define WM8915_AIF2TX_CHAN1_ENA_MASK            0x0200  /* AIF2TX_CHAN1_ENA */
+#define WM8915_AIF2TX_CHAN1_ENA_SHIFT                9  /* AIF2TX_CHAN1_ENA */
+#define WM8915_AIF2TX_CHAN1_ENA_WIDTH                1  /* AIF2TX_CHAN1_ENA */
+#define WM8915_AIF2TX_CHAN0_ENA                 0x0100  /* AIF2TX_CHAN0_ENA */
+#define WM8915_AIF2TX_CHAN0_ENA_MASK            0x0100  /* AIF2TX_CHAN0_ENA */
+#define WM8915_AIF2TX_CHAN0_ENA_SHIFT                8  /* AIF2TX_CHAN0_ENA */
+#define WM8915_AIF2TX_CHAN0_ENA_WIDTH                1  /* AIF2TX_CHAN0_ENA */
+#define WM8915_AIF1TX_CHAN5_ENA                 0x0020  /* AIF1TX_CHAN5_ENA */
+#define WM8915_AIF1TX_CHAN5_ENA_MASK            0x0020  /* AIF1TX_CHAN5_ENA */
+#define WM8915_AIF1TX_CHAN5_ENA_SHIFT                5  /* AIF1TX_CHAN5_ENA */
+#define WM8915_AIF1TX_CHAN5_ENA_WIDTH                1  /* AIF1TX_CHAN5_ENA */
+#define WM8915_AIF1TX_CHAN4_ENA                 0x0010  /* AIF1TX_CHAN4_ENA */
+#define WM8915_AIF1TX_CHAN4_ENA_MASK            0x0010  /* AIF1TX_CHAN4_ENA */
+#define WM8915_AIF1TX_CHAN4_ENA_SHIFT                4  /* AIF1TX_CHAN4_ENA */
+#define WM8915_AIF1TX_CHAN4_ENA_WIDTH                1  /* AIF1TX_CHAN4_ENA */
+#define WM8915_AIF1TX_CHAN3_ENA                 0x0008  /* AIF1TX_CHAN3_ENA */
+#define WM8915_AIF1TX_CHAN3_ENA_MASK            0x0008  /* AIF1TX_CHAN3_ENA */
+#define WM8915_AIF1TX_CHAN3_ENA_SHIFT                3  /* AIF1TX_CHAN3_ENA */
+#define WM8915_AIF1TX_CHAN3_ENA_WIDTH                1  /* AIF1TX_CHAN3_ENA */
+#define WM8915_AIF1TX_CHAN2_ENA                 0x0004  /* AIF1TX_CHAN2_ENA */
+#define WM8915_AIF1TX_CHAN2_ENA_MASK            0x0004  /* AIF1TX_CHAN2_ENA */
+#define WM8915_AIF1TX_CHAN2_ENA_SHIFT                2  /* AIF1TX_CHAN2_ENA */
+#define WM8915_AIF1TX_CHAN2_ENA_WIDTH                1  /* AIF1TX_CHAN2_ENA */
+#define WM8915_AIF1TX_CHAN1_ENA                 0x0002  /* AIF1TX_CHAN1_ENA */
+#define WM8915_AIF1TX_CHAN1_ENA_MASK            0x0002  /* AIF1TX_CHAN1_ENA */
+#define WM8915_AIF1TX_CHAN1_ENA_SHIFT                1  /* AIF1TX_CHAN1_ENA */
+#define WM8915_AIF1TX_CHAN1_ENA_WIDTH                1  /* AIF1TX_CHAN1_ENA */
+#define WM8915_AIF1TX_CHAN0_ENA                 0x0001  /* AIF1TX_CHAN0_ENA */
+#define WM8915_AIF1TX_CHAN0_ENA_MASK            0x0001  /* AIF1TX_CHAN0_ENA */
+#define WM8915_AIF1TX_CHAN0_ENA_SHIFT                0  /* AIF1TX_CHAN0_ENA */
+#define WM8915_AIF1TX_CHAN0_ENA_WIDTH                1  /* AIF1TX_CHAN0_ENA */
+
+/*
+ * R7 (0x07) - Power Management (7)
+ */
+#define WM8915_DMIC2_FN                         0x0200  /* DMIC2_FN */
+#define WM8915_DMIC2_FN_MASK                    0x0200  /* DMIC2_FN */
+#define WM8915_DMIC2_FN_SHIFT                        9  /* DMIC2_FN */
+#define WM8915_DMIC2_FN_WIDTH                        1  /* DMIC2_FN */
+#define WM8915_DMIC1_FN                         0x0100  /* DMIC1_FN */
+#define WM8915_DMIC1_FN_MASK                    0x0100  /* DMIC1_FN */
+#define WM8915_DMIC1_FN_SHIFT                        8  /* DMIC1_FN */
+#define WM8915_DMIC1_FN_WIDTH                        1  /* DMIC1_FN */
+#define WM8915_ADC_DMIC_DSP2R_ENA               0x0080  /* ADC_DMIC_DSP2R_ENA */
+#define WM8915_ADC_DMIC_DSP2R_ENA_MASK          0x0080  /* ADC_DMIC_DSP2R_ENA */
+#define WM8915_ADC_DMIC_DSP2R_ENA_SHIFT              7  /* ADC_DMIC_DSP2R_ENA */
+#define WM8915_ADC_DMIC_DSP2R_ENA_WIDTH              1  /* ADC_DMIC_DSP2R_ENA */
+#define WM8915_ADC_DMIC_DSP2L_ENA               0x0040  /* ADC_DMIC_DSP2L_ENA */
+#define WM8915_ADC_DMIC_DSP2L_ENA_MASK          0x0040  /* ADC_DMIC_DSP2L_ENA */
+#define WM8915_ADC_DMIC_DSP2L_ENA_SHIFT              6  /* ADC_DMIC_DSP2L_ENA */
+#define WM8915_ADC_DMIC_DSP2L_ENA_WIDTH              1  /* ADC_DMIC_DSP2L_ENA */
+#define WM8915_ADC_DMIC_SRC2_MASK               0x0030  /* ADC_DMIC_SRC2 - [5:4] */
+#define WM8915_ADC_DMIC_SRC2_SHIFT                   4  /* ADC_DMIC_SRC2 - [5:4] */
+#define WM8915_ADC_DMIC_SRC2_WIDTH                   2  /* ADC_DMIC_SRC2 - [5:4] */
+#define WM8915_ADC_DMIC_DSP1R_ENA               0x0008  /* ADC_DMIC_DSP1R_ENA */
+#define WM8915_ADC_DMIC_DSP1R_ENA_MASK          0x0008  /* ADC_DMIC_DSP1R_ENA */
+#define WM8915_ADC_DMIC_DSP1R_ENA_SHIFT              3  /* ADC_DMIC_DSP1R_ENA */
+#define WM8915_ADC_DMIC_DSP1R_ENA_WIDTH              1  /* ADC_DMIC_DSP1R_ENA */
+#define WM8915_ADC_DMIC_DSP1L_ENA               0x0004  /* ADC_DMIC_DSP1L_ENA */
+#define WM8915_ADC_DMIC_DSP1L_ENA_MASK          0x0004  /* ADC_DMIC_DSP1L_ENA */
+#define WM8915_ADC_DMIC_DSP1L_ENA_SHIFT              2  /* ADC_DMIC_DSP1L_ENA */
+#define WM8915_ADC_DMIC_DSP1L_ENA_WIDTH              1  /* ADC_DMIC_DSP1L_ENA */
+#define WM8915_ADC_DMIC_SRC1_MASK               0x0003  /* ADC_DMIC_SRC1 - [1:0] */
+#define WM8915_ADC_DMIC_SRC1_SHIFT                   0  /* ADC_DMIC_SRC1 - [1:0] */
+#define WM8915_ADC_DMIC_SRC1_WIDTH                   2  /* ADC_DMIC_SRC1 - [1:0] */
+
+/*
+ * R8 (0x08) - Power Management (8)
+ */
+#define WM8915_AIF2TX_SRC_MASK                  0x00C0  /* AIF2TX_SRC - [7:6] */
+#define WM8915_AIF2TX_SRC_SHIFT                      6  /* AIF2TX_SRC - [7:6] */
+#define WM8915_AIF2TX_SRC_WIDTH                      2  /* AIF2TX_SRC - [7:6] */
+#define WM8915_DSP2RX_SRC                       0x0010  /* DSP2RX_SRC */
+#define WM8915_DSP2RX_SRC_MASK                  0x0010  /* DSP2RX_SRC */
+#define WM8915_DSP2RX_SRC_SHIFT                      4  /* DSP2RX_SRC */
+#define WM8915_DSP2RX_SRC_WIDTH                      1  /* DSP2RX_SRC */
+#define WM8915_DSP1RX_SRC                       0x0001  /* DSP1RX_SRC */
+#define WM8915_DSP1RX_SRC_MASK                  0x0001  /* DSP1RX_SRC */
+#define WM8915_DSP1RX_SRC_SHIFT                      0  /* DSP1RX_SRC */
+#define WM8915_DSP1RX_SRC_WIDTH                      1  /* DSP1RX_SRC */
+
+/*
+ * R16 (0x10) - Left Line Input Volume
+ */
+#define WM8915_IN1_VU                           0x0080  /* IN1_VU */
+#define WM8915_IN1_VU_MASK                      0x0080  /* IN1_VU */
+#define WM8915_IN1_VU_SHIFT                          7  /* IN1_VU */
+#define WM8915_IN1_VU_WIDTH                          1  /* IN1_VU */
+#define WM8915_IN1L_ZC                          0x0020  /* IN1L_ZC */
+#define WM8915_IN1L_ZC_MASK                     0x0020  /* IN1L_ZC */
+#define WM8915_IN1L_ZC_SHIFT                         5  /* IN1L_ZC */
+#define WM8915_IN1L_ZC_WIDTH                         1  /* IN1L_ZC */
+#define WM8915_IN1L_VOL_MASK                    0x001F  /* IN1L_VOL - [4:0] */
+#define WM8915_IN1L_VOL_SHIFT                        0  /* IN1L_VOL - [4:0] */
+#define WM8915_IN1L_VOL_WIDTH                        5  /* IN1L_VOL - [4:0] */
+
+/*
+ * R17 (0x11) - Right Line Input Volume
+ */
+#define WM8915_IN1_VU                           0x0080  /* IN1_VU */
+#define WM8915_IN1_VU_MASK                      0x0080  /* IN1_VU */
+#define WM8915_IN1_VU_SHIFT                          7  /* IN1_VU */
+#define WM8915_IN1_VU_WIDTH                          1  /* IN1_VU */
+#define WM8915_IN1R_ZC                          0x0020  /* IN1R_ZC */
+#define WM8915_IN1R_ZC_MASK                     0x0020  /* IN1R_ZC */
+#define WM8915_IN1R_ZC_SHIFT                         5  /* IN1R_ZC */
+#define WM8915_IN1R_ZC_WIDTH                         1  /* IN1R_ZC */
+#define WM8915_IN1R_VOL_MASK                    0x001F  /* IN1R_VOL - [4:0] */
+#define WM8915_IN1R_VOL_SHIFT                        0  /* IN1R_VOL - [4:0] */
+#define WM8915_IN1R_VOL_WIDTH                        5  /* IN1R_VOL - [4:0] */
+
+/*
+ * R18 (0x12) - Line Input Control
+ */
+#define WM8915_INL_MODE_MASK                    0x000C  /* INL_MODE - [3:2] */
+#define WM8915_INL_MODE_SHIFT                        2  /* INL_MODE - [3:2] */
+#define WM8915_INL_MODE_WIDTH                        2  /* INL_MODE - [3:2] */
+#define WM8915_INR_MODE_MASK                    0x0003  /* INR_MODE - [1:0] */
+#define WM8915_INR_MODE_SHIFT                        0  /* INR_MODE - [1:0] */
+#define WM8915_INR_MODE_WIDTH                        2  /* INR_MODE - [1:0] */
+
+/*
+ * R21 (0x15) - DAC1 HPOUT1 Volume
+ */
+#define WM8915_DAC1R_HPOUT1R_VOL_MASK           0x00F0  /* DAC1R_HPOUT1R_VOL - [7:4] */
+#define WM8915_DAC1R_HPOUT1R_VOL_SHIFT               4  /* DAC1R_HPOUT1R_VOL - [7:4] */
+#define WM8915_DAC1R_HPOUT1R_VOL_WIDTH               4  /* DAC1R_HPOUT1R_VOL - [7:4] */
+#define WM8915_DAC1L_HPOUT1L_VOL_MASK           0x000F  /* DAC1L_HPOUT1L_VOL - [3:0] */
+#define WM8915_DAC1L_HPOUT1L_VOL_SHIFT               0  /* DAC1L_HPOUT1L_VOL - [3:0] */
+#define WM8915_DAC1L_HPOUT1L_VOL_WIDTH               4  /* DAC1L_HPOUT1L_VOL - [3:0] */
+
+/*
+ * R22 (0x16) - DAC2 HPOUT2 Volume
+ */
+#define WM8915_DAC2R_HPOUT2R_VOL_MASK           0x00F0  /* DAC2R_HPOUT2R_VOL - [7:4] */
+#define WM8915_DAC2R_HPOUT2R_VOL_SHIFT               4  /* DAC2R_HPOUT2R_VOL - [7:4] */
+#define WM8915_DAC2R_HPOUT2R_VOL_WIDTH               4  /* DAC2R_HPOUT2R_VOL - [7:4] */
+#define WM8915_DAC2L_HPOUT2L_VOL_MASK           0x000F  /* DAC2L_HPOUT2L_VOL - [3:0] */
+#define WM8915_DAC2L_HPOUT2L_VOL_SHIFT               0  /* DAC2L_HPOUT2L_VOL - [3:0] */
+#define WM8915_DAC2L_HPOUT2L_VOL_WIDTH               4  /* DAC2L_HPOUT2L_VOL - [3:0] */
+
+/*
+ * R24 (0x18) - DAC1 Left Volume
+ */
+#define WM8915_DAC1L_MUTE                       0x0200  /* DAC1L_MUTE */
+#define WM8915_DAC1L_MUTE_MASK                  0x0200  /* DAC1L_MUTE */
+#define WM8915_DAC1L_MUTE_SHIFT                      9  /* DAC1L_MUTE */
+#define WM8915_DAC1L_MUTE_WIDTH                      1  /* DAC1L_MUTE */
+#define WM8915_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8915_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8915_DAC1L_VOL_MASK                   0x00FF  /* DAC1L_VOL - [7:0] */
+#define WM8915_DAC1L_VOL_SHIFT                       0  /* DAC1L_VOL - [7:0] */
+#define WM8915_DAC1L_VOL_WIDTH                       8  /* DAC1L_VOL - [7:0] */
+
+/*
+ * R25 (0x19) - DAC1 Right Volume
+ */
+#define WM8915_DAC1R_MUTE                       0x0200  /* DAC1R_MUTE */
+#define WM8915_DAC1R_MUTE_MASK                  0x0200  /* DAC1R_MUTE */
+#define WM8915_DAC1R_MUTE_SHIFT                      9  /* DAC1R_MUTE */
+#define WM8915_DAC1R_MUTE_WIDTH                      1  /* DAC1R_MUTE */
+#define WM8915_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8915_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8915_DAC1R_VOL_MASK                   0x00FF  /* DAC1R_VOL - [7:0] */
+#define WM8915_DAC1R_VOL_SHIFT                       0  /* DAC1R_VOL - [7:0] */
+#define WM8915_DAC1R_VOL_WIDTH                       8  /* DAC1R_VOL - [7:0] */
+
+/*
+ * R26 (0x1A) - DAC2 Left Volume
+ */
+#define WM8915_DAC2L_MUTE                       0x0200  /* DAC2L_MUTE */
+#define WM8915_DAC2L_MUTE_MASK                  0x0200  /* DAC2L_MUTE */
+#define WM8915_DAC2L_MUTE_SHIFT                      9  /* DAC2L_MUTE */
+#define WM8915_DAC2L_MUTE_WIDTH                      1  /* DAC2L_MUTE */
+#define WM8915_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8915_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8915_DAC2L_VOL_MASK                   0x00FF  /* DAC2L_VOL - [7:0] */
+#define WM8915_DAC2L_VOL_SHIFT                       0  /* DAC2L_VOL - [7:0] */
+#define WM8915_DAC2L_VOL_WIDTH                       8  /* DAC2L_VOL - [7:0] */
+
+/*
+ * R27 (0x1B) - DAC2 Right Volume
+ */
+#define WM8915_DAC2R_MUTE                       0x0200  /* DAC2R_MUTE */
+#define WM8915_DAC2R_MUTE_MASK                  0x0200  /* DAC2R_MUTE */
+#define WM8915_DAC2R_MUTE_SHIFT                      9  /* DAC2R_MUTE */
+#define WM8915_DAC2R_MUTE_WIDTH                      1  /* DAC2R_MUTE */
+#define WM8915_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8915_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8915_DAC2R_VOL_MASK                   0x00FF  /* DAC2R_VOL - [7:0] */
+#define WM8915_DAC2R_VOL_SHIFT                       0  /* DAC2R_VOL - [7:0] */
+#define WM8915_DAC2R_VOL_WIDTH                       8  /* DAC2R_VOL - [7:0] */
+
+/*
+ * R28 (0x1C) - Output1 Left Volume
+ */
+#define WM8915_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8915_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8915_HPOUT1L_ZC                       0x0080  /* HPOUT1L_ZC */
+#define WM8915_HPOUT1L_ZC_MASK                  0x0080  /* HPOUT1L_ZC */
+#define WM8915_HPOUT1L_ZC_SHIFT                      7  /* HPOUT1L_ZC */
+#define WM8915_HPOUT1L_ZC_WIDTH                      1  /* HPOUT1L_ZC */
+#define WM8915_HPOUT1L_VOL_MASK                 0x000F  /* HPOUT1L_VOL - [3:0] */
+#define WM8915_HPOUT1L_VOL_SHIFT                     0  /* HPOUT1L_VOL - [3:0] */
+#define WM8915_HPOUT1L_VOL_WIDTH                     4  /* HPOUT1L_VOL - [3:0] */
+
+/*
+ * R29 (0x1D) - Output1 Right Volume
+ */
+#define WM8915_DAC1_VU                          0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_MASK                     0x0100  /* DAC1_VU */
+#define WM8915_DAC1_VU_SHIFT                         8  /* DAC1_VU */
+#define WM8915_DAC1_VU_WIDTH                         1  /* DAC1_VU */
+#define WM8915_HPOUT1R_ZC                       0x0080  /* HPOUT1R_ZC */
+#define WM8915_HPOUT1R_ZC_MASK                  0x0080  /* HPOUT1R_ZC */
+#define WM8915_HPOUT1R_ZC_SHIFT                      7  /* HPOUT1R_ZC */
+#define WM8915_HPOUT1R_ZC_WIDTH                      1  /* HPOUT1R_ZC */
+#define WM8915_HPOUT1R_VOL_MASK                 0x000F  /* HPOUT1R_VOL - [3:0] */
+#define WM8915_HPOUT1R_VOL_SHIFT                     0  /* HPOUT1R_VOL - [3:0] */
+#define WM8915_HPOUT1R_VOL_WIDTH                     4  /* HPOUT1R_VOL - [3:0] */
+
+/*
+ * R30 (0x1E) - Output2 Left Volume
+ */
+#define WM8915_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8915_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8915_HPOUT2L_ZC                       0x0080  /* HPOUT2L_ZC */
+#define WM8915_HPOUT2L_ZC_MASK                  0x0080  /* HPOUT2L_ZC */
+#define WM8915_HPOUT2L_ZC_SHIFT                      7  /* HPOUT2L_ZC */
+#define WM8915_HPOUT2L_ZC_WIDTH                      1  /* HPOUT2L_ZC */
+#define WM8915_HPOUT2L_VOL_MASK                 0x000F  /* HPOUT2L_VOL - [3:0] */
+#define WM8915_HPOUT2L_VOL_SHIFT                     0  /* HPOUT2L_VOL - [3:0] */
+#define WM8915_HPOUT2L_VOL_WIDTH                     4  /* HPOUT2L_VOL - [3:0] */
+
+/*
+ * R31 (0x1F) - Output2 Right Volume
+ */
+#define WM8915_DAC2_VU                          0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_MASK                     0x0100  /* DAC2_VU */
+#define WM8915_DAC2_VU_SHIFT                         8  /* DAC2_VU */
+#define WM8915_DAC2_VU_WIDTH                         1  /* DAC2_VU */
+#define WM8915_HPOUT2R_ZC                       0x0080  /* HPOUT2R_ZC */
+#define WM8915_HPOUT2R_ZC_MASK                  0x0080  /* HPOUT2R_ZC */
+#define WM8915_HPOUT2R_ZC_SHIFT                      7  /* HPOUT2R_ZC */
+#define WM8915_HPOUT2R_ZC_WIDTH                      1  /* HPOUT2R_ZC */
+#define WM8915_HPOUT2R_VOL_MASK                 0x000F  /* HPOUT2R_VOL - [3:0] */
+#define WM8915_HPOUT2R_VOL_SHIFT                     0  /* HPOUT2R_VOL - [3:0] */
+#define WM8915_HPOUT2R_VOL_WIDTH                     4  /* HPOUT2R_VOL - [3:0] */
+
+/*
+ * R32 (0x20) - MICBIAS (1)
+ */
+#define WM8915_MICB1_RATE                       0x0020  /* MICB1_RATE */
+#define WM8915_MICB1_RATE_MASK                  0x0020  /* MICB1_RATE */
+#define WM8915_MICB1_RATE_SHIFT                      5  /* MICB1_RATE */
+#define WM8915_MICB1_RATE_WIDTH                      1  /* MICB1_RATE */
+#define WM8915_MICB1_MODE                       0x0010  /* MICB1_MODE */
+#define WM8915_MICB1_MODE_MASK                  0x0010  /* MICB1_MODE */
+#define WM8915_MICB1_MODE_SHIFT                      4  /* MICB1_MODE */
+#define WM8915_MICB1_MODE_WIDTH                      1  /* MICB1_MODE */
+#define WM8915_MICB1_LVL_MASK                   0x000E  /* MICB1_LVL - [3:1] */
+#define WM8915_MICB1_LVL_SHIFT                       1  /* MICB1_LVL - [3:1] */
+#define WM8915_MICB1_LVL_WIDTH                       3  /* MICB1_LVL - [3:1] */
+#define WM8915_MICB1_DISCH                      0x0001  /* MICB1_DISCH */
+#define WM8915_MICB1_DISCH_MASK                 0x0001  /* MICB1_DISCH */
+#define WM8915_MICB1_DISCH_SHIFT                     0  /* MICB1_DISCH */
+#define WM8915_MICB1_DISCH_WIDTH                     1  /* MICB1_DISCH */
+
+/*
+ * R33 (0x21) - MICBIAS (2)
+ */
+#define WM8915_MICB2_RATE                       0x0020  /* MICB2_RATE */
+#define WM8915_MICB2_RATE_MASK                  0x0020  /* MICB2_RATE */
+#define WM8915_MICB2_RATE_SHIFT                      5  /* MICB2_RATE */
+#define WM8915_MICB2_RATE_WIDTH                      1  /* MICB2_RATE */
+#define WM8915_MICB2_MODE                       0x0010  /* MICB2_MODE */
+#define WM8915_MICB2_MODE_MASK                  0x0010  /* MICB2_MODE */
+#define WM8915_MICB2_MODE_SHIFT                      4  /* MICB2_MODE */
+#define WM8915_MICB2_MODE_WIDTH                      1  /* MICB2_MODE */
+#define WM8915_MICB2_LVL_MASK                   0x000E  /* MICB2_LVL - [3:1] */
+#define WM8915_MICB2_LVL_SHIFT                       1  /* MICB2_LVL - [3:1] */
+#define WM8915_MICB2_LVL_WIDTH                       3  /* MICB2_LVL - [3:1] */
+#define WM8915_MICB2_DISCH                      0x0001  /* MICB2_DISCH */
+#define WM8915_MICB2_DISCH_MASK                 0x0001  /* MICB2_DISCH */
+#define WM8915_MICB2_DISCH_SHIFT                     0  /* MICB2_DISCH */
+#define WM8915_MICB2_DISCH_WIDTH                     1  /* MICB2_DISCH */
+
+/*
+ * R40 (0x28) - LDO 1
+ */
+#define WM8915_LDO1_MODE                        0x0020  /* LDO1_MODE */
+#define WM8915_LDO1_MODE_MASK                   0x0020  /* LDO1_MODE */
+#define WM8915_LDO1_MODE_SHIFT                       5  /* LDO1_MODE */
+#define WM8915_LDO1_MODE_WIDTH                       1  /* LDO1_MODE */
+#define WM8915_LDO1_VSEL_MASK                   0x0006  /* LDO1_VSEL - [2:1] */
+#define WM8915_LDO1_VSEL_SHIFT                       1  /* LDO1_VSEL - [2:1] */
+#define WM8915_LDO1_VSEL_WIDTH                       2  /* LDO1_VSEL - [2:1] */
+#define WM8915_LDO1_DISCH                       0x0001  /* LDO1_DISCH */
+#define WM8915_LDO1_DISCH_MASK                  0x0001  /* LDO1_DISCH */
+#define WM8915_LDO1_DISCH_SHIFT                      0  /* LDO1_DISCH */
+#define WM8915_LDO1_DISCH_WIDTH                      1  /* LDO1_DISCH */
+
+/*
+ * R41 (0x29) - LDO 2
+ */
+#define WM8915_LDO2_MODE                        0x0020  /* LDO2_MODE */
+#define WM8915_LDO2_MODE_MASK                   0x0020  /* LDO2_MODE */
+#define WM8915_LDO2_MODE_SHIFT                       5  /* LDO2_MODE */
+#define WM8915_LDO2_MODE_WIDTH                       1  /* LDO2_MODE */
+#define WM8915_LDO2_VSEL_MASK                   0x001E  /* LDO2_VSEL - [4:1] */
+#define WM8915_LDO2_VSEL_SHIFT                       1  /* LDO2_VSEL - [4:1] */
+#define WM8915_LDO2_VSEL_WIDTH                       4  /* LDO2_VSEL - [4:1] */
+#define WM8915_LDO2_DISCH                       0x0001  /* LDO2_DISCH */
+#define WM8915_LDO2_DISCH_MASK                  0x0001  /* LDO2_DISCH */
+#define WM8915_LDO2_DISCH_SHIFT                      0  /* LDO2_DISCH */
+#define WM8915_LDO2_DISCH_WIDTH                      1  /* LDO2_DISCH */
+
+/*
+ * R48 (0x30) - Accessory Detect Mode 1
+ */
+#define WM8915_JD_MODE_MASK                     0x0003  /* JD_MODE - [1:0] */
+#define WM8915_JD_MODE_SHIFT                         0  /* JD_MODE - [1:0] */
+#define WM8915_JD_MODE_WIDTH                         2  /* JD_MODE - [1:0] */
+
+/*
+ * R49 (0x31) - Accessory Detect Mode 2
+ */
+#define WM8915_HPOUT1FB_SRC                     0x0004  /* HPOUT1FB_SRC */
+#define WM8915_HPOUT1FB_SRC_MASK                0x0004  /* HPOUT1FB_SRC */
+#define WM8915_HPOUT1FB_SRC_SHIFT                    2  /* HPOUT1FB_SRC */
+#define WM8915_HPOUT1FB_SRC_WIDTH                    1  /* HPOUT1FB_SRC */
+#define WM8915_MICD_SRC                         0x0002  /* MICD_SRC */
+#define WM8915_MICD_SRC_MASK                    0x0002  /* MICD_SRC */
+#define WM8915_MICD_SRC_SHIFT                        1  /* MICD_SRC */
+#define WM8915_MICD_SRC_WIDTH                        1  /* MICD_SRC */
+#define WM8915_MICD_BIAS_SRC                    0x0001  /* MICD_BIAS_SRC */
+#define WM8915_MICD_BIAS_SRC_MASK               0x0001  /* MICD_BIAS_SRC */
+#define WM8915_MICD_BIAS_SRC_SHIFT                   0  /* MICD_BIAS_SRC */
+#define WM8915_MICD_BIAS_SRC_WIDTH                   1  /* MICD_BIAS_SRC */
+
+/*
+ * R52 (0x34) - Headphone Detect 1
+ */
+#define WM8915_HP_HOLDTIME_MASK                 0x00E0  /* HP_HOLDTIME - [7:5] */
+#define WM8915_HP_HOLDTIME_SHIFT                     5  /* HP_HOLDTIME - [7:5] */
+#define WM8915_HP_HOLDTIME_WIDTH                     3  /* HP_HOLDTIME - [7:5] */
+#define WM8915_HP_CLK_DIV_MASK                  0x0018  /* HP_CLK_DIV - [4:3] */
+#define WM8915_HP_CLK_DIV_SHIFT                      3  /* HP_CLK_DIV - [4:3] */
+#define WM8915_HP_CLK_DIV_WIDTH                      2  /* HP_CLK_DIV - [4:3] */
+#define WM8915_HP_STEP_SIZE                     0x0002  /* HP_STEP_SIZE */
+#define WM8915_HP_STEP_SIZE_MASK                0x0002  /* HP_STEP_SIZE */
+#define WM8915_HP_STEP_SIZE_SHIFT                    1  /* HP_STEP_SIZE */
+#define WM8915_HP_STEP_SIZE_WIDTH                    1  /* HP_STEP_SIZE */
+#define WM8915_HP_POLL                          0x0001  /* HP_POLL */
+#define WM8915_HP_POLL_MASK                     0x0001  /* HP_POLL */
+#define WM8915_HP_POLL_SHIFT                         0  /* HP_POLL */
+#define WM8915_HP_POLL_WIDTH                         1  /* HP_POLL */
+
+/*
+ * R53 (0x35) - Headphone Detect 2
+ */
+#define WM8915_HP_DONE                          0x0080  /* HP_DONE */
+#define WM8915_HP_DONE_MASK                     0x0080  /* HP_DONE */
+#define WM8915_HP_DONE_SHIFT                         7  /* HP_DONE */
+#define WM8915_HP_DONE_WIDTH                         1  /* HP_DONE */
+#define WM8915_HP_LVL_MASK                      0x007F  /* HP_LVL - [6:0] */
+#define WM8915_HP_LVL_SHIFT                          0  /* HP_LVL - [6:0] */
+#define WM8915_HP_LVL_WIDTH                          7  /* HP_LVL - [6:0] */
+
+/*
+ * R56 (0x38) - Mic Detect 1
+ */
+#define WM8915_MICD_BIAS_STARTTIME_MASK         0xF000  /* MICD_BIAS_STARTTIME - [15:12] */
+#define WM8915_MICD_BIAS_STARTTIME_SHIFT            12  /* MICD_BIAS_STARTTIME - [15:12] */
+#define WM8915_MICD_BIAS_STARTTIME_WIDTH             4  /* MICD_BIAS_STARTTIME - [15:12] */
+#define WM8915_MICD_RATE_MASK                   0x0F00  /* MICD_RATE - [11:8] */
+#define WM8915_MICD_RATE_SHIFT                       8  /* MICD_RATE - [11:8] */
+#define WM8915_MICD_RATE_WIDTH                       4  /* MICD_RATE - [11:8] */
+#define WM8915_MICD_DBTIME                      0x0002  /* MICD_DBTIME */
+#define WM8915_MICD_DBTIME_MASK                 0x0002  /* MICD_DBTIME */
+#define WM8915_MICD_DBTIME_SHIFT                     1  /* MICD_DBTIME */
+#define WM8915_MICD_DBTIME_WIDTH                     1  /* MICD_DBTIME */
+#define WM8915_MICD_ENA                         0x0001  /* MICD_ENA */
+#define WM8915_MICD_ENA_MASK                    0x0001  /* MICD_ENA */
+#define WM8915_MICD_ENA_SHIFT                        0  /* MICD_ENA */
+#define WM8915_MICD_ENA_WIDTH                        1  /* MICD_ENA */
+
+/*
+ * R57 (0x39) - Mic Detect 2
+ */
+#define WM8915_MICD_LVL_SEL_MASK                0x00FF  /* MICD_LVL_SEL - [7:0] */
+#define WM8915_MICD_LVL_SEL_SHIFT                    0  /* MICD_LVL_SEL - [7:0] */
+#define WM8915_MICD_LVL_SEL_WIDTH                    8  /* MICD_LVL_SEL - [7:0] */
+
+/*
+ * R58 (0x3A) - Mic Detect 3
+ */
+#define WM8915_MICD_LVL_MASK                    0x07FC  /* MICD_LVL - [10:2] */
+#define WM8915_MICD_LVL_SHIFT                        2  /* MICD_LVL - [10:2] */
+#define WM8915_MICD_LVL_WIDTH                        9  /* MICD_LVL - [10:2] */
+#define WM8915_MICD_VALID                       0x0002  /* MICD_VALID */
+#define WM8915_MICD_VALID_MASK                  0x0002  /* MICD_VALID */
+#define WM8915_MICD_VALID_SHIFT                      1  /* MICD_VALID */
+#define WM8915_MICD_VALID_WIDTH                      1  /* MICD_VALID */
+#define WM8915_MICD_STS                         0x0001  /* MICD_STS */
+#define WM8915_MICD_STS_MASK                    0x0001  /* MICD_STS */
+#define WM8915_MICD_STS_SHIFT                        0  /* MICD_STS */
+#define WM8915_MICD_STS_WIDTH                        1  /* MICD_STS */
+
+/*
+ * R64 (0x40) - Charge Pump (1)
+ */
+#define WM8915_CP_ENA                           0x8000  /* CP_ENA */
+#define WM8915_CP_ENA_MASK                      0x8000  /* CP_ENA */
+#define WM8915_CP_ENA_SHIFT                         15  /* CP_ENA */
+#define WM8915_CP_ENA_WIDTH                          1  /* CP_ENA */
+
+/*
+ * R65 (0x41) - Charge Pump (2)
+ */
+#define WM8915_CP_DISCH                         0x8000  /* CP_DISCH */
+#define WM8915_CP_DISCH_MASK                    0x8000  /* CP_DISCH */
+#define WM8915_CP_DISCH_SHIFT                       15  /* CP_DISCH */
+#define WM8915_CP_DISCH_WIDTH                        1  /* CP_DISCH */
+
+/*
+ * R80 (0x50) - DC Servo (1)
+ */
+#define WM8915_DCS_ENA_CHAN_3                   0x0008  /* DCS_ENA_CHAN_3 */
+#define WM8915_DCS_ENA_CHAN_3_MASK              0x0008  /* DCS_ENA_CHAN_3 */
+#define WM8915_DCS_ENA_CHAN_3_SHIFT                  3  /* DCS_ENA_CHAN_3 */
+#define WM8915_DCS_ENA_CHAN_3_WIDTH                  1  /* DCS_ENA_CHAN_3 */
+#define WM8915_DCS_ENA_CHAN_2                   0x0004  /* DCS_ENA_CHAN_2 */
+#define WM8915_DCS_ENA_CHAN_2_MASK              0x0004  /* DCS_ENA_CHAN_2 */
+#define WM8915_DCS_ENA_CHAN_2_SHIFT                  2  /* DCS_ENA_CHAN_2 */
+#define WM8915_DCS_ENA_CHAN_2_WIDTH                  1  /* DCS_ENA_CHAN_2 */
+#define WM8915_DCS_ENA_CHAN_1                   0x0002  /* DCS_ENA_CHAN_1 */
+#define WM8915_DCS_ENA_CHAN_1_MASK              0x0002  /* DCS_ENA_CHAN_1 */
+#define WM8915_DCS_ENA_CHAN_1_SHIFT                  1  /* DCS_ENA_CHAN_1 */
+#define WM8915_DCS_ENA_CHAN_1_WIDTH                  1  /* DCS_ENA_CHAN_1 */
+#define WM8915_DCS_ENA_CHAN_0                   0x0001  /* DCS_ENA_CHAN_0 */
+#define WM8915_DCS_ENA_CHAN_0_MASK              0x0001  /* DCS_ENA_CHAN_0 */
+#define WM8915_DCS_ENA_CHAN_0_SHIFT                  0  /* DCS_ENA_CHAN_0 */
+#define WM8915_DCS_ENA_CHAN_0_WIDTH                  1  /* DCS_ENA_CHAN_0 */
+
+/*
+ * R81 (0x51) - DC Servo (2)
+ */
+#define WM8915_DCS_TRIG_SINGLE_3                0x8000  /* DCS_TRIG_SINGLE_3 */
+#define WM8915_DCS_TRIG_SINGLE_3_MASK           0x8000  /* DCS_TRIG_SINGLE_3 */
+#define WM8915_DCS_TRIG_SINGLE_3_SHIFT              15  /* DCS_TRIG_SINGLE_3 */
+#define WM8915_DCS_TRIG_SINGLE_3_WIDTH               1  /* DCS_TRIG_SINGLE_3 */
+#define WM8915_DCS_TRIG_SINGLE_2                0x4000  /* DCS_TRIG_SINGLE_2 */
+#define WM8915_DCS_TRIG_SINGLE_2_MASK           0x4000  /* DCS_TRIG_SINGLE_2 */
+#define WM8915_DCS_TRIG_SINGLE_2_SHIFT              14  /* DCS_TRIG_SINGLE_2 */
+#define WM8915_DCS_TRIG_SINGLE_2_WIDTH               1  /* DCS_TRIG_SINGLE_2 */
+#define WM8915_DCS_TRIG_SINGLE_1                0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM8915_DCS_TRIG_SINGLE_1_MASK           0x2000  /* DCS_TRIG_SINGLE_1 */
+#define WM8915_DCS_TRIG_SINGLE_1_SHIFT              13  /* DCS_TRIG_SINGLE_1 */
+#define WM8915_DCS_TRIG_SINGLE_1_WIDTH               1  /* DCS_TRIG_SINGLE_1 */
+#define WM8915_DCS_TRIG_SINGLE_0                0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM8915_DCS_TRIG_SINGLE_0_MASK           0x1000  /* DCS_TRIG_SINGLE_0 */
+#define WM8915_DCS_TRIG_SINGLE_0_SHIFT              12  /* DCS_TRIG_SINGLE_0 */
+#define WM8915_DCS_TRIG_SINGLE_0_WIDTH               1  /* DCS_TRIG_SINGLE_0 */
+#define WM8915_DCS_TRIG_SERIES_3                0x0800  /* DCS_TRIG_SERIES_3 */
+#define WM8915_DCS_TRIG_SERIES_3_MASK           0x0800  /* DCS_TRIG_SERIES_3 */
+#define WM8915_DCS_TRIG_SERIES_3_SHIFT              11  /* DCS_TRIG_SERIES_3 */
+#define WM8915_DCS_TRIG_SERIES_3_WIDTH               1  /* DCS_TRIG_SERIES_3 */
+#define WM8915_DCS_TRIG_SERIES_2                0x0400  /* DCS_TRIG_SERIES_2 */
+#define WM8915_DCS_TRIG_SERIES_2_MASK           0x0400  /* DCS_TRIG_SERIES_2 */
+#define WM8915_DCS_TRIG_SERIES_2_SHIFT              10  /* DCS_TRIG_SERIES_2 */
+#define WM8915_DCS_TRIG_SERIES_2_WIDTH               1  /* DCS_TRIG_SERIES_2 */
+#define WM8915_DCS_TRIG_SERIES_1                0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM8915_DCS_TRIG_SERIES_1_MASK           0x0200  /* DCS_TRIG_SERIES_1 */
+#define WM8915_DCS_TRIG_SERIES_1_SHIFT               9  /* DCS_TRIG_SERIES_1 */
+#define WM8915_DCS_TRIG_SERIES_1_WIDTH               1  /* DCS_TRIG_SERIES_1 */
+#define WM8915_DCS_TRIG_SERIES_0                0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM8915_DCS_TRIG_SERIES_0_MASK           0x0100  /* DCS_TRIG_SERIES_0 */
+#define WM8915_DCS_TRIG_SERIES_0_SHIFT               8  /* DCS_TRIG_SERIES_0 */
+#define WM8915_DCS_TRIG_SERIES_0_WIDTH               1  /* DCS_TRIG_SERIES_0 */
+#define WM8915_DCS_TRIG_STARTUP_3               0x0080  /* DCS_TRIG_STARTUP_3 */
+#define WM8915_DCS_TRIG_STARTUP_3_MASK          0x0080  /* DCS_TRIG_STARTUP_3 */
+#define WM8915_DCS_TRIG_STARTUP_3_SHIFT              7  /* DCS_TRIG_STARTUP_3 */
+#define WM8915_DCS_TRIG_STARTUP_3_WIDTH              1  /* DCS_TRIG_STARTUP_3 */
+#define WM8915_DCS_TRIG_STARTUP_2               0x0040  /* DCS_TRIG_STARTUP_2 */
+#define WM8915_DCS_TRIG_STARTUP_2_MASK          0x0040  /* DCS_TRIG_STARTUP_2 */
+#define WM8915_DCS_TRIG_STARTUP_2_SHIFT              6  /* DCS_TRIG_STARTUP_2 */
+#define WM8915_DCS_TRIG_STARTUP_2_WIDTH              1  /* DCS_TRIG_STARTUP_2 */
+#define WM8915_DCS_TRIG_STARTUP_1               0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM8915_DCS_TRIG_STARTUP_1_MASK          0x0020  /* DCS_TRIG_STARTUP_1 */
+#define WM8915_DCS_TRIG_STARTUP_1_SHIFT              5  /* DCS_TRIG_STARTUP_1 */
+#define WM8915_DCS_TRIG_STARTUP_1_WIDTH              1  /* DCS_TRIG_STARTUP_1 */
+#define WM8915_DCS_TRIG_STARTUP_0               0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM8915_DCS_TRIG_STARTUP_0_MASK          0x0010  /* DCS_TRIG_STARTUP_0 */
+#define WM8915_DCS_TRIG_STARTUP_0_SHIFT              4  /* DCS_TRIG_STARTUP_0 */
+#define WM8915_DCS_TRIG_STARTUP_0_WIDTH              1  /* DCS_TRIG_STARTUP_0 */
+#define WM8915_DCS_TRIG_DAC_WR_3                0x0008  /* DCS_TRIG_DAC_WR_3 */
+#define WM8915_DCS_TRIG_DAC_WR_3_MASK           0x0008  /* DCS_TRIG_DAC_WR_3 */
+#define WM8915_DCS_TRIG_DAC_WR_3_SHIFT               3  /* DCS_TRIG_DAC_WR_3 */
+#define WM8915_DCS_TRIG_DAC_WR_3_WIDTH               1  /* DCS_TRIG_DAC_WR_3 */
+#define WM8915_DCS_TRIG_DAC_WR_2                0x0004  /* DCS_TRIG_DAC_WR_2 */
+#define WM8915_DCS_TRIG_DAC_WR_2_MASK           0x0004  /* DCS_TRIG_DAC_WR_2 */
+#define WM8915_DCS_TRIG_DAC_WR_2_SHIFT               2  /* DCS_TRIG_DAC_WR_2 */
+#define WM8915_DCS_TRIG_DAC_WR_2_WIDTH               1  /* DCS_TRIG_DAC_WR_2 */
+#define WM8915_DCS_TRIG_DAC_WR_1                0x0002  /* DCS_TRIG_DAC_WR_1 */
+#define WM8915_DCS_TRIG_DAC_WR_1_MASK           0x0002  /* DCS_TRIG_DAC_WR_1 */
+#define WM8915_DCS_TRIG_DAC_WR_1_SHIFT               1  /* DCS_TRIG_DAC_WR_1 */
+#define WM8915_DCS_TRIG_DAC_WR_1_WIDTH               1  /* DCS_TRIG_DAC_WR_1 */
+#define WM8915_DCS_TRIG_DAC_WR_0                0x0001  /* DCS_TRIG_DAC_WR_0 */
+#define WM8915_DCS_TRIG_DAC_WR_0_MASK           0x0001  /* DCS_TRIG_DAC_WR_0 */
+#define WM8915_DCS_TRIG_DAC_WR_0_SHIFT               0  /* DCS_TRIG_DAC_WR_0 */
+#define WM8915_DCS_TRIG_DAC_WR_0_WIDTH               1  /* DCS_TRIG_DAC_WR_0 */
+
+/*
+ * R82 (0x52) - DC Servo (3)
+ */
+#define WM8915_DCS_TIMER_PERIOD_23_MASK         0x0F00  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8915_DCS_TIMER_PERIOD_23_SHIFT             8  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8915_DCS_TIMER_PERIOD_23_WIDTH             4  /* DCS_TIMER_PERIOD_23 - [11:8] */
+#define WM8915_DCS_TIMER_PERIOD_01_MASK         0x000F  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8915_DCS_TIMER_PERIOD_01_SHIFT             0  /* DCS_TIMER_PERIOD_01 - [3:0] */
+#define WM8915_DCS_TIMER_PERIOD_01_WIDTH             4  /* DCS_TIMER_PERIOD_01 - [3:0] */
+
+/*
+ * R84 (0x54) - DC Servo (5)
+ */
+#define WM8915_DCS_SERIES_NO_23_MASK            0x7F00  /* DCS_SERIES_NO_23 - [14:8] */
+#define WM8915_DCS_SERIES_NO_23_SHIFT                8  /* DCS_SERIES_NO_23 - [14:8] */
+#define WM8915_DCS_SERIES_NO_23_WIDTH                7  /* DCS_SERIES_NO_23 - [14:8] */
+#define WM8915_DCS_SERIES_NO_01_MASK            0x007F  /* DCS_SERIES_NO_01 - [6:0] */
+#define WM8915_DCS_SERIES_NO_01_SHIFT                0  /* DCS_SERIES_NO_01 - [6:0] */
+#define WM8915_DCS_SERIES_NO_01_WIDTH                7  /* DCS_SERIES_NO_01 - [6:0] */
+
+/*
+ * R85 (0x55) - DC Servo (6)
+ */
+#define WM8915_DCS_DAC_WR_VAL_3_MASK            0xFF00  /* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8915_DCS_DAC_WR_VAL_3_SHIFT                8  /* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8915_DCS_DAC_WR_VAL_3_WIDTH                8  /* DCS_DAC_WR_VAL_3 - [15:8] */
+#define WM8915_DCS_DAC_WR_VAL_2_MASK            0x00FF  /* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8915_DCS_DAC_WR_VAL_2_SHIFT                0  /* DCS_DAC_WR_VAL_2 - [7:0] */
+#define WM8915_DCS_DAC_WR_VAL_2_WIDTH                8  /* DCS_DAC_WR_VAL_2 - [7:0] */
+
+/*
+ * R86 (0x56) - DC Servo (7)
+ */
+#define WM8915_DCS_DAC_WR_VAL_1_MASK            0xFF00  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8915_DCS_DAC_WR_VAL_1_SHIFT                8  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8915_DCS_DAC_WR_VAL_1_WIDTH                8  /* DCS_DAC_WR_VAL_1 - [15:8] */
+#define WM8915_DCS_DAC_WR_VAL_0_MASK            0x00FF  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8915_DCS_DAC_WR_VAL_0_SHIFT                0  /* DCS_DAC_WR_VAL_0 - [7:0] */
+#define WM8915_DCS_DAC_WR_VAL_0_WIDTH                8  /* DCS_DAC_WR_VAL_0 - [7:0] */
+
+/*
+ * R87 (0x57) - DC Servo Readback 0
+ */
+#define WM8915_DCS_CAL_COMPLETE_MASK            0x0F00  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8915_DCS_CAL_COMPLETE_SHIFT                8  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8915_DCS_CAL_COMPLETE_WIDTH                4  /* DCS_CAL_COMPLETE - [11:8] */
+#define WM8915_DCS_DAC_WR_COMPLETE_MASK         0x00F0  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8915_DCS_DAC_WR_COMPLETE_SHIFT             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8915_DCS_DAC_WR_COMPLETE_WIDTH             4  /* DCS_DAC_WR_COMPLETE - [7:4] */
+#define WM8915_DCS_STARTUP_COMPLETE_MASK        0x000F  /* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8915_DCS_STARTUP_COMPLETE_SHIFT            0  /* DCS_STARTUP_COMPLETE - [3:0] */
+#define WM8915_DCS_STARTUP_COMPLETE_WIDTH            4  /* DCS_STARTUP_COMPLETE - [3:0] */
+
+/*
+ * R96 (0x60) - Analogue HP (1)
+ */
+#define WM8915_HPOUT1L_RMV_SHORT                0x0080  /* HPOUT1L_RMV_SHORT */
+#define WM8915_HPOUT1L_RMV_SHORT_MASK           0x0080  /* HPOUT1L_RMV_SHORT */
+#define WM8915_HPOUT1L_RMV_SHORT_SHIFT               7  /* HPOUT1L_RMV_SHORT */
+#define WM8915_HPOUT1L_RMV_SHORT_WIDTH               1  /* HPOUT1L_RMV_SHORT */
+#define WM8915_HPOUT1L_OUTP                     0x0040  /* HPOUT1L_OUTP */
+#define WM8915_HPOUT1L_OUTP_MASK                0x0040  /* HPOUT1L_OUTP */
+#define WM8915_HPOUT1L_OUTP_SHIFT                    6  /* HPOUT1L_OUTP */
+#define WM8915_HPOUT1L_OUTP_WIDTH                    1  /* HPOUT1L_OUTP */
+#define WM8915_HPOUT1L_DLY                      0x0020  /* HPOUT1L_DLY */
+#define WM8915_HPOUT1L_DLY_MASK                 0x0020  /* HPOUT1L_DLY */
+#define WM8915_HPOUT1L_DLY_SHIFT                     5  /* HPOUT1L_DLY */
+#define WM8915_HPOUT1L_DLY_WIDTH                     1  /* HPOUT1L_DLY */
+#define WM8915_HPOUT1R_RMV_SHORT                0x0008  /* HPOUT1R_RMV_SHORT */
+#define WM8915_HPOUT1R_RMV_SHORT_MASK           0x0008  /* HPOUT1R_RMV_SHORT */
+#define WM8915_HPOUT1R_RMV_SHORT_SHIFT               3  /* HPOUT1R_RMV_SHORT */
+#define WM8915_HPOUT1R_RMV_SHORT_WIDTH               1  /* HPOUT1R_RMV_SHORT */
+#define WM8915_HPOUT1R_OUTP                     0x0004  /* HPOUT1R_OUTP */
+#define WM8915_HPOUT1R_OUTP_MASK                0x0004  /* HPOUT1R_OUTP */
+#define WM8915_HPOUT1R_OUTP_SHIFT                    2  /* HPOUT1R_OUTP */
+#define WM8915_HPOUT1R_OUTP_WIDTH                    1  /* HPOUT1R_OUTP */
+#define WM8915_HPOUT1R_DLY                      0x0002  /* HPOUT1R_DLY */
+#define WM8915_HPOUT1R_DLY_MASK                 0x0002  /* HPOUT1R_DLY */
+#define WM8915_HPOUT1R_DLY_SHIFT                     1  /* HPOUT1R_DLY */
+#define WM8915_HPOUT1R_DLY_WIDTH                     1  /* HPOUT1R_DLY */
+
+/*
+ * R97 (0x61) - Analogue HP (2)
+ */
+#define WM8915_HPOUT2L_RMV_SHORT                0x0080  /* HPOUT2L_RMV_SHORT */
+#define WM8915_HPOUT2L_RMV_SHORT_MASK           0x0080  /* HPOUT2L_RMV_SHORT */
+#define WM8915_HPOUT2L_RMV_SHORT_SHIFT               7  /* HPOUT2L_RMV_SHORT */
+#define WM8915_HPOUT2L_RMV_SHORT_WIDTH               1  /* HPOUT2L_RMV_SHORT */
+#define WM8915_HPOUT2L_OUTP                     0x0040  /* HPOUT2L_OUTP */
+#define WM8915_HPOUT2L_OUTP_MASK                0x0040  /* HPOUT2L_OUTP */
+#define WM8915_HPOUT2L_OUTP_SHIFT                    6  /* HPOUT2L_OUTP */
+#define WM8915_HPOUT2L_OUTP_WIDTH                    1  /* HPOUT2L_OUTP */
+#define WM8915_HPOUT2L_DLY                      0x0020  /* HPOUT2L_DLY */
+#define WM8915_HPOUT2L_DLY_MASK                 0x0020  /* HPOUT2L_DLY */
+#define WM8915_HPOUT2L_DLY_SHIFT                     5  /* HPOUT2L_DLY */
+#define WM8915_HPOUT2L_DLY_WIDTH                     1  /* HPOUT2L_DLY */
+#define WM8915_HPOUT2R_RMV_SHORT                0x0008  /* HPOUT2R_RMV_SHORT */
+#define WM8915_HPOUT2R_RMV_SHORT_MASK           0x0008  /* HPOUT2R_RMV_SHORT */
+#define WM8915_HPOUT2R_RMV_SHORT_SHIFT               3  /* HPOUT2R_RMV_SHORT */
+#define WM8915_HPOUT2R_RMV_SHORT_WIDTH               1  /* HPOUT2R_RMV_SHORT */
+#define WM8915_HPOUT2R_OUTP                     0x0004  /* HPOUT2R_OUTP */
+#define WM8915_HPOUT2R_OUTP_MASK                0x0004  /* HPOUT2R_OUTP */
+#define WM8915_HPOUT2R_OUTP_SHIFT                    2  /* HPOUT2R_OUTP */
+#define WM8915_HPOUT2R_OUTP_WIDTH                    1  /* HPOUT2R_OUTP */
+#define WM8915_HPOUT2R_DLY                      0x0002  /* HPOUT2R_DLY */
+#define WM8915_HPOUT2R_DLY_MASK                 0x0002  /* HPOUT2R_DLY */
+#define WM8915_HPOUT2R_DLY_SHIFT                     1  /* HPOUT2R_DLY */
+#define WM8915_HPOUT2R_DLY_WIDTH                     1  /* HPOUT2R_DLY */
+
+/*
+ * R256 (0x100) - Chip Revision
+ */
+#define WM8915_CHIP_REV_MASK                    0x000F  /* CHIP_REV - [3:0] */
+#define WM8915_CHIP_REV_SHIFT                        0  /* CHIP_REV - [3:0] */
+#define WM8915_CHIP_REV_WIDTH                        4  /* CHIP_REV - [3:0] */
+
+/*
+ * R257 (0x101) - Control Interface (1)
+ */
+#define WM8915_AUTO_INC                         0x0004  /* AUTO_INC */
+#define WM8915_AUTO_INC_MASK                    0x0004  /* AUTO_INC */
+#define WM8915_AUTO_INC_SHIFT                        2  /* AUTO_INC */
+#define WM8915_AUTO_INC_WIDTH                        1  /* AUTO_INC */
+
+/*
+ * R272 (0x110) - Write Sequencer Ctrl (1)
+ */
+#define WM8915_WSEQ_ENA                         0x8000  /* WSEQ_ENA */
+#define WM8915_WSEQ_ENA_MASK                    0x8000  /* WSEQ_ENA */
+#define WM8915_WSEQ_ENA_SHIFT                       15  /* WSEQ_ENA */
+#define WM8915_WSEQ_ENA_WIDTH                        1  /* WSEQ_ENA */
+#define WM8915_WSEQ_ABORT                       0x0200  /* WSEQ_ABORT */
+#define WM8915_WSEQ_ABORT_MASK                  0x0200  /* WSEQ_ABORT */
+#define WM8915_WSEQ_ABORT_SHIFT                      9  /* WSEQ_ABORT */
+#define WM8915_WSEQ_ABORT_WIDTH                      1  /* WSEQ_ABORT */
+#define WM8915_WSEQ_START                       0x0100  /* WSEQ_START */
+#define WM8915_WSEQ_START_MASK                  0x0100  /* WSEQ_START */
+#define WM8915_WSEQ_START_SHIFT                      8  /* WSEQ_START */
+#define WM8915_WSEQ_START_WIDTH                      1  /* WSEQ_START */
+#define WM8915_WSEQ_START_INDEX_MASK            0x007F  /* WSEQ_START_INDEX - [6:0] */
+#define WM8915_WSEQ_START_INDEX_SHIFT                0  /* WSEQ_START_INDEX - [6:0] */
+#define WM8915_WSEQ_START_INDEX_WIDTH                7  /* WSEQ_START_INDEX - [6:0] */
+
+/*
+ * R273 (0x111) - Write Sequencer Ctrl (2)
+ */
+#define WM8915_WSEQ_BUSY                        0x0100  /* WSEQ_BUSY */
+#define WM8915_WSEQ_BUSY_MASK                   0x0100  /* WSEQ_BUSY */
+#define WM8915_WSEQ_BUSY_SHIFT                       8  /* WSEQ_BUSY */
+#define WM8915_WSEQ_BUSY_WIDTH                       1  /* WSEQ_BUSY */
+#define WM8915_WSEQ_CURRENT_INDEX_MASK          0x007F  /* WSEQ_CURRENT_INDEX - [6:0] */
+#define WM8915_WSEQ_CURRENT_INDEX_SHIFT              0  /* WSEQ_CURRENT_INDEX - [6:0] */
+#define WM8915_WSEQ_CURRENT_INDEX_WIDTH              7  /* WSEQ_CURRENT_INDEX - [6:0] */
+
+/*
+ * R512 (0x200) - AIF Clocking (1)
+ */
+#define WM8915_SYSCLK_SRC_MASK                  0x0018  /* SYSCLK_SRC - [4:3] */
+#define WM8915_SYSCLK_SRC_SHIFT                      3  /* SYSCLK_SRC - [4:3] */
+#define WM8915_SYSCLK_SRC_WIDTH                      2  /* SYSCLK_SRC - [4:3] */
+#define WM8915_SYSCLK_INV                       0x0004  /* SYSCLK_INV */
+#define WM8915_SYSCLK_INV_MASK                  0x0004  /* SYSCLK_INV */
+#define WM8915_SYSCLK_INV_SHIFT                      2  /* SYSCLK_INV */
+#define WM8915_SYSCLK_INV_WIDTH                      1  /* SYSCLK_INV */
+#define WM8915_SYSCLK_DIV                       0x0002  /* SYSCLK_DIV */
+#define WM8915_SYSCLK_DIV_MASK                  0x0002  /* SYSCLK_DIV */
+#define WM8915_SYSCLK_DIV_SHIFT                      1  /* SYSCLK_DIV */
+#define WM8915_SYSCLK_DIV_WIDTH                      1  /* SYSCLK_DIV */
+#define WM8915_SYSCLK_ENA                       0x0001  /* SYSCLK_ENA */
+#define WM8915_SYSCLK_ENA_MASK                  0x0001  /* SYSCLK_ENA */
+#define WM8915_SYSCLK_ENA_SHIFT                      0  /* SYSCLK_ENA */
+#define WM8915_SYSCLK_ENA_WIDTH                      1  /* SYSCLK_ENA */
+
+/*
+ * R513 (0x201) - AIF Clocking (2)
+ */
+#define WM8915_DSP2_DIV_MASK                    0x0018  /* DSP2_DIV - [4:3] */
+#define WM8915_DSP2_DIV_SHIFT                        3  /* DSP2_DIV - [4:3] */
+#define WM8915_DSP2_DIV_WIDTH                        2  /* DSP2_DIV - [4:3] */
+#define WM8915_DSP1_DIV_MASK                    0x0003  /* DSP1_DIV - [1:0] */
+#define WM8915_DSP1_DIV_SHIFT                        0  /* DSP1_DIV - [1:0] */
+#define WM8915_DSP1_DIV_WIDTH                        2  /* DSP1_DIV - [1:0] */
+
+/*
+ * R520 (0x208) - Clocking (1)
+ */
+#define WM8915_LFCLK_ENA                        0x0020  /* LFCLK_ENA */
+#define WM8915_LFCLK_ENA_MASK                   0x0020  /* LFCLK_ENA */
+#define WM8915_LFCLK_ENA_SHIFT                       5  /* LFCLK_ENA */
+#define WM8915_LFCLK_ENA_WIDTH                       1  /* LFCLK_ENA */
+#define WM8915_TOCLK_ENA                        0x0010  /* TOCLK_ENA */
+#define WM8915_TOCLK_ENA_MASK                   0x0010  /* TOCLK_ENA */
+#define WM8915_TOCLK_ENA_SHIFT                       4  /* TOCLK_ENA */
+#define WM8915_TOCLK_ENA_WIDTH                       1  /* TOCLK_ENA */
+#define WM8915_AIFCLK_ENA                       0x0004  /* AIFCLK_ENA */
+#define WM8915_AIFCLK_ENA_MASK                  0x0004  /* AIFCLK_ENA */
+#define WM8915_AIFCLK_ENA_SHIFT                      2  /* AIFCLK_ENA */
+#define WM8915_AIFCLK_ENA_WIDTH                      1  /* AIFCLK_ENA */
+#define WM8915_SYSDSPCLK_ENA                    0x0002  /* SYSDSPCLK_ENA */
+#define WM8915_SYSDSPCLK_ENA_MASK               0x0002  /* SYSDSPCLK_ENA */
+#define WM8915_SYSDSPCLK_ENA_SHIFT                   1  /* SYSDSPCLK_ENA */
+#define WM8915_SYSDSPCLK_ENA_WIDTH                   1  /* SYSDSPCLK_ENA */
+
+/*
+ * R521 (0x209) - Clocking (2)
+ */
+#define WM8915_TOCLK_DIV_MASK                   0x0700  /* TOCLK_DIV - [10:8] */
+#define WM8915_TOCLK_DIV_SHIFT                       8  /* TOCLK_DIV - [10:8] */
+#define WM8915_TOCLK_DIV_WIDTH                       3  /* TOCLK_DIV - [10:8] */
+#define WM8915_DBCLK_DIV_MASK                   0x00F0  /* DBCLK_DIV - [7:4] */
+#define WM8915_DBCLK_DIV_SHIFT                       4  /* DBCLK_DIV - [7:4] */
+#define WM8915_DBCLK_DIV_WIDTH                       4  /* DBCLK_DIV - [7:4] */
+#define WM8915_OPCLK_DIV_MASK                   0x0007  /* OPCLK_DIV - [2:0] */
+#define WM8915_OPCLK_DIV_SHIFT                       0  /* OPCLK_DIV - [2:0] */
+#define WM8915_OPCLK_DIV_WIDTH                       3  /* OPCLK_DIV - [2:0] */
+
+/*
+ * R528 (0x210) - AIF Rate
+ */
+#define WM8915_SYSCLK_RATE                      0x0001  /* SYSCLK_RATE */
+#define WM8915_SYSCLK_RATE_MASK                 0x0001  /* SYSCLK_RATE */
+#define WM8915_SYSCLK_RATE_SHIFT                     0  /* SYSCLK_RATE */
+#define WM8915_SYSCLK_RATE_WIDTH                     1  /* SYSCLK_RATE */
+
+/*
+ * R544 (0x220) - FLL Control (1)
+ */
+#define WM8915_FLL_OSC_ENA                      0x0002  /* FLL_OSC_ENA */
+#define WM8915_FLL_OSC_ENA_MASK                 0x0002  /* FLL_OSC_ENA */
+#define WM8915_FLL_OSC_ENA_SHIFT                     1  /* FLL_OSC_ENA */
+#define WM8915_FLL_OSC_ENA_WIDTH                     1  /* FLL_OSC_ENA */
+#define WM8915_FLL_ENA                          0x0001  /* FLL_ENA */
+#define WM8915_FLL_ENA_MASK                     0x0001  /* FLL_ENA */
+#define WM8915_FLL_ENA_SHIFT                         0  /* FLL_ENA */
+#define WM8915_FLL_ENA_WIDTH                         1  /* FLL_ENA */
+
+/*
+ * R545 (0x221) - FLL Control (2)
+ */
+#define WM8915_FLL_OUTDIV_MASK                  0x3F00  /* FLL_OUTDIV - [13:8] */
+#define WM8915_FLL_OUTDIV_SHIFT                      8  /* FLL_OUTDIV - [13:8] */
+#define WM8915_FLL_OUTDIV_WIDTH                      6  /* FLL_OUTDIV - [13:8] */
+#define WM8915_FLL_FRATIO_MASK                  0x0007  /* FLL_FRATIO - [2:0] */
+#define WM8915_FLL_FRATIO_SHIFT                      0  /* FLL_FRATIO - [2:0] */
+#define WM8915_FLL_FRATIO_WIDTH                      3  /* FLL_FRATIO - [2:0] */
+
+/*
+ * R546 (0x222) - FLL Control (3)
+ */
+#define WM8915_FLL_THETA_MASK                   0xFFFF  /* FLL_THETA - [15:0] */
+#define WM8915_FLL_THETA_SHIFT                       0  /* FLL_THETA - [15:0] */
+#define WM8915_FLL_THETA_WIDTH                      16  /* FLL_THETA - [15:0] */
+
+/*
+ * R547 (0x223) - FLL Control (4)
+ */
+#define WM8915_FLL_N_MASK                       0x7FE0  /* FLL_N - [14:5] */
+#define WM8915_FLL_N_SHIFT                           5  /* FLL_N - [14:5] */
+#define WM8915_FLL_N_WIDTH                          10  /* FLL_N - [14:5] */
+#define WM8915_FLL_LOOP_GAIN_MASK               0x000F  /* FLL_LOOP_GAIN - [3:0] */
+#define WM8915_FLL_LOOP_GAIN_SHIFT                   0  /* FLL_LOOP_GAIN - [3:0] */
+#define WM8915_FLL_LOOP_GAIN_WIDTH                   4  /* FLL_LOOP_GAIN - [3:0] */
+
+/*
+ * R548 (0x224) - FLL Control (5)
+ */
+#define WM8915_FLL_FRC_NCO_VAL_MASK             0x1F80  /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8915_FLL_FRC_NCO_VAL_SHIFT                 7  /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8915_FLL_FRC_NCO_VAL_WIDTH                 6  /* FLL_FRC_NCO_VAL - [12:7] */
+#define WM8915_FLL_FRC_NCO                      0x0040  /* FLL_FRC_NCO */
+#define WM8915_FLL_FRC_NCO_MASK                 0x0040  /* FLL_FRC_NCO */
+#define WM8915_FLL_FRC_NCO_SHIFT                     6  /* FLL_FRC_NCO */
+#define WM8915_FLL_FRC_NCO_WIDTH                     1  /* FLL_FRC_NCO */
+#define WM8915_FLL_REFCLK_DIV_MASK              0x0018  /* FLL_REFCLK_DIV - [4:3] */
+#define WM8915_FLL_REFCLK_DIV_SHIFT                  3  /* FLL_REFCLK_DIV - [4:3] */
+#define WM8915_FLL_REFCLK_DIV_WIDTH                  2  /* FLL_REFCLK_DIV - [4:3] */
+#define WM8915_FLL_REF_FREQ                     0x0004  /* FLL_REF_FREQ */
+#define WM8915_FLL_REF_FREQ_MASK                0x0004  /* FLL_REF_FREQ */
+#define WM8915_FLL_REF_FREQ_SHIFT                    2  /* FLL_REF_FREQ */
+#define WM8915_FLL_REF_FREQ_WIDTH                    1  /* FLL_REF_FREQ */
+#define WM8915_FLL_REFCLK_SRC_MASK              0x0003  /* FLL_REFCLK_SRC - [1:0] */
+#define WM8915_FLL_REFCLK_SRC_SHIFT                  0  /* FLL_REFCLK_SRC - [1:0] */
+#define WM8915_FLL_REFCLK_SRC_WIDTH                  2  /* FLL_REFCLK_SRC - [1:0] */
+
+/*
+ * R549 (0x225) - FLL Control (6)
+ */
+#define WM8915_FLL_REFCLK_SRC_STS_MASK          0x000C  /* FLL_REFCLK_SRC_STS - [3:2] */
+#define WM8915_FLL_REFCLK_SRC_STS_SHIFT              2  /* FLL_REFCLK_SRC_STS - [3:2] */
+#define WM8915_FLL_REFCLK_SRC_STS_WIDTH              2  /* FLL_REFCLK_SRC_STS - [3:2] */
+#define WM8915_FLL_SWITCH_CLK                   0x0001  /* FLL_SWITCH_CLK */
+#define WM8915_FLL_SWITCH_CLK_MASK              0x0001  /* FLL_SWITCH_CLK */
+#define WM8915_FLL_SWITCH_CLK_SHIFT                  0  /* FLL_SWITCH_CLK */
+#define WM8915_FLL_SWITCH_CLK_WIDTH                  1  /* FLL_SWITCH_CLK */
+
+/*
+ * R550 (0x226) - FLL EFS 1
+ */
+#define WM8915_FLL_LAMBDA_MASK                  0xFFFF  /* FLL_LAMBDA - [15:0] */
+#define WM8915_FLL_LAMBDA_SHIFT                      0  /* FLL_LAMBDA - [15:0] */
+#define WM8915_FLL_LAMBDA_WIDTH                     16  /* FLL_LAMBDA - [15:0] */
+
+/*
+ * R551 (0x227) - FLL EFS 2
+ */
+#define WM8915_FLL_LFSR_SEL_MASK                0x0006  /* FLL_LFSR_SEL - [2:1] */
+#define WM8915_FLL_LFSR_SEL_SHIFT                    1  /* FLL_LFSR_SEL - [2:1] */
+#define WM8915_FLL_LFSR_SEL_WIDTH                    2  /* FLL_LFSR_SEL - [2:1] */
+#define WM8915_FLL_EFS_ENA                      0x0001  /* FLL_EFS_ENA */
+#define WM8915_FLL_EFS_ENA_MASK                 0x0001  /* FLL_EFS_ENA */
+#define WM8915_FLL_EFS_ENA_SHIFT                     0  /* FLL_EFS_ENA */
+#define WM8915_FLL_EFS_ENA_WIDTH                     1  /* FLL_EFS_ENA */
+
+/*
+ * R768 (0x300) - AIF1 Control
+ */
+#define WM8915_AIF1_TRI                         0x0004  /* AIF1_TRI */
+#define WM8915_AIF1_TRI_MASK                    0x0004  /* AIF1_TRI */
+#define WM8915_AIF1_TRI_SHIFT                        2  /* AIF1_TRI */
+#define WM8915_AIF1_TRI_WIDTH                        1  /* AIF1_TRI */
+#define WM8915_AIF1_FMT_MASK                    0x0003  /* AIF1_FMT - [1:0] */
+#define WM8915_AIF1_FMT_SHIFT                        0  /* AIF1_FMT - [1:0] */
+#define WM8915_AIF1_FMT_WIDTH                        2  /* AIF1_FMT - [1:0] */
+
+/*
+ * R769 (0x301) - AIF1 BCLK
+ */
+#define WM8915_AIF1_BCLK_INV                    0x0400  /* AIF1_BCLK_INV */
+#define WM8915_AIF1_BCLK_INV_MASK               0x0400  /* AIF1_BCLK_INV */
+#define WM8915_AIF1_BCLK_INV_SHIFT                  10  /* AIF1_BCLK_INV */
+#define WM8915_AIF1_BCLK_INV_WIDTH                   1  /* AIF1_BCLK_INV */
+#define WM8915_AIF1_BCLK_FRC                    0x0200  /* AIF1_BCLK_FRC */
+#define WM8915_AIF1_BCLK_FRC_MASK               0x0200  /* AIF1_BCLK_FRC */
+#define WM8915_AIF1_BCLK_FRC_SHIFT                   9  /* AIF1_BCLK_FRC */
+#define WM8915_AIF1_BCLK_FRC_WIDTH                   1  /* AIF1_BCLK_FRC */
+#define WM8915_AIF1_BCLK_MSTR                   0x0100  /* AIF1_BCLK_MSTR */
+#define WM8915_AIF1_BCLK_MSTR_MASK              0x0100  /* AIF1_BCLK_MSTR */
+#define WM8915_AIF1_BCLK_MSTR_SHIFT                  8  /* AIF1_BCLK_MSTR */
+#define WM8915_AIF1_BCLK_MSTR_WIDTH                  1  /* AIF1_BCLK_MSTR */
+#define WM8915_AIF1_BCLK_DIV_MASK               0x000F  /* AIF1_BCLK_DIV - [3:0] */
+#define WM8915_AIF1_BCLK_DIV_SHIFT                   0  /* AIF1_BCLK_DIV - [3:0] */
+#define WM8915_AIF1_BCLK_DIV_WIDTH                   4  /* AIF1_BCLK_DIV - [3:0] */
+
+/*
+ * R770 (0x302) - AIF1 TX LRCLK(1)
+ */
+#define WM8915_AIF1TX_RATE_MASK                 0x07FF  /* AIF1TX_RATE - [10:0] */
+#define WM8915_AIF1TX_RATE_SHIFT                     0  /* AIF1TX_RATE - [10:0] */
+#define WM8915_AIF1TX_RATE_WIDTH                    11  /* AIF1TX_RATE - [10:0] */
+
+/*
+ * R771 (0x303) - AIF1 TX LRCLK(2)
+ */
+#define WM8915_AIF1TX_LRCLK_MODE                0x0008  /* AIF1TX_LRCLK_MODE */
+#define WM8915_AIF1TX_LRCLK_MODE_MASK           0x0008  /* AIF1TX_LRCLK_MODE */
+#define WM8915_AIF1TX_LRCLK_MODE_SHIFT               3  /* AIF1TX_LRCLK_MODE */
+#define WM8915_AIF1TX_LRCLK_MODE_WIDTH               1  /* AIF1TX_LRCLK_MODE */
+#define WM8915_AIF1TX_LRCLK_INV                 0x0004  /* AIF1TX_LRCLK_INV */
+#define WM8915_AIF1TX_LRCLK_INV_MASK            0x0004  /* AIF1TX_LRCLK_INV */
+#define WM8915_AIF1TX_LRCLK_INV_SHIFT                2  /* AIF1TX_LRCLK_INV */
+#define WM8915_AIF1TX_LRCLK_INV_WIDTH                1  /* AIF1TX_LRCLK_INV */
+#define WM8915_AIF1TX_LRCLK_FRC                 0x0002  /* AIF1TX_LRCLK_FRC */
+#define WM8915_AIF1TX_LRCLK_FRC_MASK            0x0002  /* AIF1TX_LRCLK_FRC */
+#define WM8915_AIF1TX_LRCLK_FRC_SHIFT                1  /* AIF1TX_LRCLK_FRC */
+#define WM8915_AIF1TX_LRCLK_FRC_WIDTH                1  /* AIF1TX_LRCLK_FRC */
+#define WM8915_AIF1TX_LRCLK_MSTR                0x0001  /* AIF1TX_LRCLK_MSTR */
+#define WM8915_AIF1TX_LRCLK_MSTR_MASK           0x0001  /* AIF1TX_LRCLK_MSTR */
+#define WM8915_AIF1TX_LRCLK_MSTR_SHIFT               0  /* AIF1TX_LRCLK_MSTR */
+#define WM8915_AIF1TX_LRCLK_MSTR_WIDTH               1  /* AIF1TX_LRCLK_MSTR */
+
+/*
+ * R772 (0x304) - AIF1 RX LRCLK(1)
+ */
+#define WM8915_AIF1RX_RATE_MASK                 0x07FF  /* AIF1RX_RATE - [10:0] */
+#define WM8915_AIF1RX_RATE_SHIFT                     0  /* AIF1RX_RATE - [10:0] */
+#define WM8915_AIF1RX_RATE_WIDTH                    11  /* AIF1RX_RATE - [10:0] */
+
+/*
+ * R773 (0x305) - AIF1 RX LRCLK(2)
+ */
+#define WM8915_AIF1RX_LRCLK_INV                 0x0004  /* AIF1RX_LRCLK_INV */
+#define WM8915_AIF1RX_LRCLK_INV_MASK            0x0004  /* AIF1RX_LRCLK_INV */
+#define WM8915_AIF1RX_LRCLK_INV_SHIFT                2  /* AIF1RX_LRCLK_INV */
+#define WM8915_AIF1RX_LRCLK_INV_WIDTH                1  /* AIF1RX_LRCLK_INV */
+#define WM8915_AIF1RX_LRCLK_FRC                 0x0002  /* AIF1RX_LRCLK_FRC */
+#define WM8915_AIF1RX_LRCLK_FRC_MASK            0x0002  /* AIF1RX_LRCLK_FRC */
+#define WM8915_AIF1RX_LRCLK_FRC_SHIFT                1  /* AIF1RX_LRCLK_FRC */
+#define WM8915_AIF1RX_LRCLK_FRC_WIDTH                1  /* AIF1RX_LRCLK_FRC */
+#define WM8915_AIF1RX_LRCLK_MSTR                0x0001  /* AIF1RX_LRCLK_MSTR */
+#define WM8915_AIF1RX_LRCLK_MSTR_MASK           0x0001  /* AIF1RX_LRCLK_MSTR */
+#define WM8915_AIF1RX_LRCLK_MSTR_SHIFT               0  /* AIF1RX_LRCLK_MSTR */
+#define WM8915_AIF1RX_LRCLK_MSTR_WIDTH               1  /* AIF1RX_LRCLK_MSTR */
+
+/*
+ * R774 (0x306) - AIF1TX Data Configuration (1)
+ */
+#define WM8915_AIF1TX_WL_MASK                   0xFF00  /* AIF1TX_WL - [15:8] */
+#define WM8915_AIF1TX_WL_SHIFT                       8  /* AIF1TX_WL - [15:8] */
+#define WM8915_AIF1TX_WL_WIDTH                       8  /* AIF1TX_WL - [15:8] */
+#define WM8915_AIF1TX_SLOT_LEN_MASK             0x00FF  /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM8915_AIF1TX_SLOT_LEN_SHIFT                 0  /* AIF1TX_SLOT_LEN - [7:0] */
+#define WM8915_AIF1TX_SLOT_LEN_WIDTH                 8  /* AIF1TX_SLOT_LEN - [7:0] */
+
+/*
+ * R775 (0x307) - AIF1TX Data Configuration (2)
+ */
+#define WM8915_AIF1TX_DAT_TRI                   0x0001  /* AIF1TX_DAT_TRI */
+#define WM8915_AIF1TX_DAT_TRI_MASK              0x0001  /* AIF1TX_DAT_TRI */
+#define WM8915_AIF1TX_DAT_TRI_SHIFT                  0  /* AIF1TX_DAT_TRI */
+#define WM8915_AIF1TX_DAT_TRI_WIDTH                  1  /* AIF1TX_DAT_TRI */
+
+/*
+ * R776 (0x308) - AIF1RX Data Configuration
+ */
+#define WM8915_AIF1RX_WL_MASK                   0xFF00  /* AIF1RX_WL - [15:8] */
+#define WM8915_AIF1RX_WL_SHIFT                       8  /* AIF1RX_WL - [15:8] */
+#define WM8915_AIF1RX_WL_WIDTH                       8  /* AIF1RX_WL - [15:8] */
+#define WM8915_AIF1RX_SLOT_LEN_MASK             0x00FF  /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM8915_AIF1RX_SLOT_LEN_SHIFT                 0  /* AIF1RX_SLOT_LEN - [7:0] */
+#define WM8915_AIF1RX_SLOT_LEN_WIDTH                 8  /* AIF1RX_SLOT_LEN - [7:0] */
+
+/*
+ * R777 (0x309) - AIF1TX Channel 0 Configuration
+ */
+#define WM8915_AIF1TX_CHAN0_DAT_INV             0x8000  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8915_AIF1TX_CHAN0_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8915_AIF1TX_CHAN0_DAT_INV_SHIFT           15  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8915_AIF1TX_CHAN0_DAT_INV_WIDTH            1  /* AIF1TX_CHAN0_DAT_INV */
+#define WM8915_AIF1TX_CHAN0_SPACING_MASK        0x7E00  /* AIF1TX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN0_SPACING_SHIFT            9  /* AIF1TX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN0_SPACING_WIDTH            6  /* AIF1TX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN0_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN0_SLOTS_SHIFT              6  /* AIF1TX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN0_SLOTS_WIDTH              3  /* AIF1TX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN0_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN0_START_SLOT_SHIFT         0  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN0_START_SLOT_WIDTH         6  /* AIF1TX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R778 (0x30A) - AIF1TX Channel 1 Configuration
+ */
+#define WM8915_AIF1TX_CHAN1_DAT_INV             0x8000  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8915_AIF1TX_CHAN1_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8915_AIF1TX_CHAN1_DAT_INV_SHIFT           15  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8915_AIF1TX_CHAN1_DAT_INV_WIDTH            1  /* AIF1TX_CHAN1_DAT_INV */
+#define WM8915_AIF1TX_CHAN1_SPACING_MASK        0x7E00  /* AIF1TX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN1_SPACING_SHIFT            9  /* AIF1TX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN1_SPACING_WIDTH            6  /* AIF1TX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN1_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN1_SLOTS_SHIFT              6  /* AIF1TX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN1_SLOTS_WIDTH              3  /* AIF1TX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN1_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN1_START_SLOT_SHIFT         0  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN1_START_SLOT_WIDTH         6  /* AIF1TX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R779 (0x30B) - AIF1TX Channel 2 Configuration
+ */
+#define WM8915_AIF1TX_CHAN2_DAT_INV             0x8000  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8915_AIF1TX_CHAN2_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8915_AIF1TX_CHAN2_DAT_INV_SHIFT           15  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8915_AIF1TX_CHAN2_DAT_INV_WIDTH            1  /* AIF1TX_CHAN2_DAT_INV */
+#define WM8915_AIF1TX_CHAN2_SPACING_MASK        0x7E00  /* AIF1TX_CHAN2_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN2_SPACING_SHIFT            9  /* AIF1TX_CHAN2_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN2_SPACING_WIDTH            6  /* AIF1TX_CHAN2_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN2_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN2_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN2_SLOTS_SHIFT              6  /* AIF1TX_CHAN2_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN2_SLOTS_WIDTH              3  /* AIF1TX_CHAN2_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN2_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN2_START_SLOT_SHIFT         0  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN2_START_SLOT_WIDTH         6  /* AIF1TX_CHAN2_START_SLOT - [5:0] */
+
+/*
+ * R780 (0x30C) - AIF1TX Channel 3 Configuration
+ */
+#define WM8915_AIF1TX_CHAN3_DAT_INV             0x8000  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8915_AIF1TX_CHAN3_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8915_AIF1TX_CHAN3_DAT_INV_SHIFT           15  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8915_AIF1TX_CHAN3_DAT_INV_WIDTH            1  /* AIF1TX_CHAN3_DAT_INV */
+#define WM8915_AIF1TX_CHAN3_SPACING_MASK        0x7E00  /* AIF1TX_CHAN3_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN3_SPACING_SHIFT            9  /* AIF1TX_CHAN3_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN3_SPACING_WIDTH            6  /* AIF1TX_CHAN3_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN3_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN3_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN3_SLOTS_SHIFT              6  /* AIF1TX_CHAN3_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN3_SLOTS_WIDTH              3  /* AIF1TX_CHAN3_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN3_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN3_START_SLOT_SHIFT         0  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN3_START_SLOT_WIDTH         6  /* AIF1TX_CHAN3_START_SLOT - [5:0] */
+
+/*
+ * R781 (0x30D) - AIF1TX Channel 4 Configuration
+ */
+#define WM8915_AIF1TX_CHAN4_DAT_INV             0x8000  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8915_AIF1TX_CHAN4_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8915_AIF1TX_CHAN4_DAT_INV_SHIFT           15  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8915_AIF1TX_CHAN4_DAT_INV_WIDTH            1  /* AIF1TX_CHAN4_DAT_INV */
+#define WM8915_AIF1TX_CHAN4_SPACING_MASK        0x7E00  /* AIF1TX_CHAN4_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN4_SPACING_SHIFT            9  /* AIF1TX_CHAN4_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN4_SPACING_WIDTH            6  /* AIF1TX_CHAN4_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN4_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN4_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN4_SLOTS_SHIFT              6  /* AIF1TX_CHAN4_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN4_SLOTS_WIDTH              3  /* AIF1TX_CHAN4_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN4_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN4_START_SLOT_SHIFT         0  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN4_START_SLOT_WIDTH         6  /* AIF1TX_CHAN4_START_SLOT - [5:0] */
+
+/*
+ * R782 (0x30E) - AIF1TX Channel 5 Configuration
+ */
+#define WM8915_AIF1TX_CHAN5_DAT_INV             0x8000  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8915_AIF1TX_CHAN5_DAT_INV_MASK        0x8000  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8915_AIF1TX_CHAN5_DAT_INV_SHIFT           15  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8915_AIF1TX_CHAN5_DAT_INV_WIDTH            1  /* AIF1TX_CHAN5_DAT_INV */
+#define WM8915_AIF1TX_CHAN5_SPACING_MASK        0x7E00  /* AIF1TX_CHAN5_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN5_SPACING_SHIFT            9  /* AIF1TX_CHAN5_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN5_SPACING_WIDTH            6  /* AIF1TX_CHAN5_SPACING - [14:9] */
+#define WM8915_AIF1TX_CHAN5_SLOTS_MASK          0x01C0  /* AIF1TX_CHAN5_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN5_SLOTS_SHIFT              6  /* AIF1TX_CHAN5_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN5_SLOTS_WIDTH              3  /* AIF1TX_CHAN5_SLOTS - [8:6] */
+#define WM8915_AIF1TX_CHAN5_START_SLOT_MASK     0x003F  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN5_START_SLOT_SHIFT         0  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
+#define WM8915_AIF1TX_CHAN5_START_SLOT_WIDTH         6  /* AIF1TX_CHAN5_START_SLOT - [5:0] */
+
+/*
+ * R783 (0x30F) - AIF1RX Channel 0 Configuration
+ */
+#define WM8915_AIF1RX_CHAN0_DAT_INV             0x8000  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8915_AIF1RX_CHAN0_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8915_AIF1RX_CHAN0_DAT_INV_SHIFT           15  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8915_AIF1RX_CHAN0_DAT_INV_WIDTH            1  /* AIF1RX_CHAN0_DAT_INV */
+#define WM8915_AIF1RX_CHAN0_SPACING_MASK        0x7E00  /* AIF1RX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN0_SPACING_SHIFT            9  /* AIF1RX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN0_SPACING_WIDTH            6  /* AIF1RX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN0_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN0_SLOTS_SHIFT              6  /* AIF1RX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN0_SLOTS_WIDTH              3  /* AIF1RX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN0_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN0_START_SLOT_SHIFT         0  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN0_START_SLOT_WIDTH         6  /* AIF1RX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R784 (0x310) - AIF1RX Channel 1 Configuration
+ */
+#define WM8915_AIF1RX_CHAN1_DAT_INV             0x8000  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8915_AIF1RX_CHAN1_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8915_AIF1RX_CHAN1_DAT_INV_SHIFT           15  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8915_AIF1RX_CHAN1_DAT_INV_WIDTH            1  /* AIF1RX_CHAN1_DAT_INV */
+#define WM8915_AIF1RX_CHAN1_SPACING_MASK        0x7E00  /* AIF1RX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN1_SPACING_SHIFT            9  /* AIF1RX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN1_SPACING_WIDTH            6  /* AIF1RX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN1_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN1_SLOTS_SHIFT              6  /* AIF1RX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN1_SLOTS_WIDTH              3  /* AIF1RX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN1_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN1_START_SLOT_SHIFT         0  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN1_START_SLOT_WIDTH         6  /* AIF1RX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R785 (0x311) - AIF1RX Channel 2 Configuration
+ */
+#define WM8915_AIF1RX_CHAN2_DAT_INV             0x8000  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8915_AIF1RX_CHAN2_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8915_AIF1RX_CHAN2_DAT_INV_SHIFT           15  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8915_AIF1RX_CHAN2_DAT_INV_WIDTH            1  /* AIF1RX_CHAN2_DAT_INV */
+#define WM8915_AIF1RX_CHAN2_SPACING_MASK        0x7E00  /* AIF1RX_CHAN2_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN2_SPACING_SHIFT            9  /* AIF1RX_CHAN2_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN2_SPACING_WIDTH            6  /* AIF1RX_CHAN2_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN2_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN2_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN2_SLOTS_SHIFT              6  /* AIF1RX_CHAN2_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN2_SLOTS_WIDTH              3  /* AIF1RX_CHAN2_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN2_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN2_START_SLOT_SHIFT         0  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN2_START_SLOT_WIDTH         6  /* AIF1RX_CHAN2_START_SLOT - [5:0] */
+
+/*
+ * R786 (0x312) - AIF1RX Channel 3 Configuration
+ */
+#define WM8915_AIF1RX_CHAN3_DAT_INV             0x8000  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8915_AIF1RX_CHAN3_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8915_AIF1RX_CHAN3_DAT_INV_SHIFT           15  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8915_AIF1RX_CHAN3_DAT_INV_WIDTH            1  /* AIF1RX_CHAN3_DAT_INV */
+#define WM8915_AIF1RX_CHAN3_SPACING_MASK        0x7E00  /* AIF1RX_CHAN3_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN3_SPACING_SHIFT            9  /* AIF1RX_CHAN3_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN3_SPACING_WIDTH            6  /* AIF1RX_CHAN3_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN3_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN3_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN3_SLOTS_SHIFT              6  /* AIF1RX_CHAN3_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN3_SLOTS_WIDTH              3  /* AIF1RX_CHAN3_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN3_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN3_START_SLOT_SHIFT         0  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN3_START_SLOT_WIDTH         6  /* AIF1RX_CHAN3_START_SLOT - [5:0] */
+
+/*
+ * R787 (0x313) - AIF1RX Channel 4 Configuration
+ */
+#define WM8915_AIF1RX_CHAN4_DAT_INV             0x8000  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8915_AIF1RX_CHAN4_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8915_AIF1RX_CHAN4_DAT_INV_SHIFT           15  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8915_AIF1RX_CHAN4_DAT_INV_WIDTH            1  /* AIF1RX_CHAN4_DAT_INV */
+#define WM8915_AIF1RX_CHAN4_SPACING_MASK        0x7E00  /* AIF1RX_CHAN4_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN4_SPACING_SHIFT            9  /* AIF1RX_CHAN4_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN4_SPACING_WIDTH            6  /* AIF1RX_CHAN4_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN4_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN4_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN4_SLOTS_SHIFT              6  /* AIF1RX_CHAN4_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN4_SLOTS_WIDTH              3  /* AIF1RX_CHAN4_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN4_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN4_START_SLOT_SHIFT         0  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN4_START_SLOT_WIDTH         6  /* AIF1RX_CHAN4_START_SLOT - [5:0] */
+
+/*
+ * R788 (0x314) - AIF1RX Channel 5 Configuration
+ */
+#define WM8915_AIF1RX_CHAN5_DAT_INV             0x8000  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8915_AIF1RX_CHAN5_DAT_INV_MASK        0x8000  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8915_AIF1RX_CHAN5_DAT_INV_SHIFT           15  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8915_AIF1RX_CHAN5_DAT_INV_WIDTH            1  /* AIF1RX_CHAN5_DAT_INV */
+#define WM8915_AIF1RX_CHAN5_SPACING_MASK        0x7E00  /* AIF1RX_CHAN5_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN5_SPACING_SHIFT            9  /* AIF1RX_CHAN5_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN5_SPACING_WIDTH            6  /* AIF1RX_CHAN5_SPACING - [14:9] */
+#define WM8915_AIF1RX_CHAN5_SLOTS_MASK          0x01C0  /* AIF1RX_CHAN5_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN5_SLOTS_SHIFT              6  /* AIF1RX_CHAN5_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN5_SLOTS_WIDTH              3  /* AIF1RX_CHAN5_SLOTS - [8:6] */
+#define WM8915_AIF1RX_CHAN5_START_SLOT_MASK     0x003F  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN5_START_SLOT_SHIFT         0  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
+#define WM8915_AIF1RX_CHAN5_START_SLOT_WIDTH         6  /* AIF1RX_CHAN5_START_SLOT - [5:0] */
+
+/*
+ * R789 (0x315) - AIF1RX Mono Configuration
+ */
+#define WM8915_AIF1RX_CHAN4_MONO_MODE           0x0004  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8915_AIF1RX_CHAN4_MONO_MODE_MASK      0x0004  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8915_AIF1RX_CHAN4_MONO_MODE_SHIFT          2  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8915_AIF1RX_CHAN4_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN4_MONO_MODE */
+#define WM8915_AIF1RX_CHAN2_MONO_MODE           0x0002  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8915_AIF1RX_CHAN2_MONO_MODE_MASK      0x0002  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8915_AIF1RX_CHAN2_MONO_MODE_SHIFT          1  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8915_AIF1RX_CHAN2_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN2_MONO_MODE */
+#define WM8915_AIF1RX_CHAN0_MONO_MODE           0x0001  /* AIF1RX_CHAN0_MONO_MODE */
+#define WM8915_AIF1RX_CHAN0_MONO_MODE_MASK      0x0001  /* AIF1RX_CHAN0_MONO_MODE */
+#define WM8915_AIF1RX_CHAN0_MONO_MODE_SHIFT          0  /* AIF1RX_CHAN0_MONO_MODE */
+#define WM8915_AIF1RX_CHAN0_MONO_MODE_WIDTH          1  /* AIF1RX_CHAN0_MONO_MODE */
+
+/*
+ * R794 (0x31A) - AIF1TX Test
+ */
+#define WM8915_AIF1TX45_DITHER_ENA              0x0004  /* AIF1TX45_DITHER_ENA */
+#define WM8915_AIF1TX45_DITHER_ENA_MASK         0x0004  /* AIF1TX45_DITHER_ENA */
+#define WM8915_AIF1TX45_DITHER_ENA_SHIFT             2  /* AIF1TX45_DITHER_ENA */
+#define WM8915_AIF1TX45_DITHER_ENA_WIDTH             1  /* AIF1TX45_DITHER_ENA */
+#define WM8915_AIF1TX23_DITHER_ENA              0x0002  /* AIF1TX23_DITHER_ENA */
+#define WM8915_AIF1TX23_DITHER_ENA_MASK         0x0002  /* AIF1TX23_DITHER_ENA */
+#define WM8915_AIF1TX23_DITHER_ENA_SHIFT             1  /* AIF1TX23_DITHER_ENA */
+#define WM8915_AIF1TX23_DITHER_ENA_WIDTH             1  /* AIF1TX23_DITHER_ENA */
+#define WM8915_AIF1TX01_DITHER_ENA              0x0001  /* AIF1TX01_DITHER_ENA */
+#define WM8915_AIF1TX01_DITHER_ENA_MASK         0x0001  /* AIF1TX01_DITHER_ENA */
+#define WM8915_AIF1TX01_DITHER_ENA_SHIFT             0  /* AIF1TX01_DITHER_ENA */
+#define WM8915_AIF1TX01_DITHER_ENA_WIDTH             1  /* AIF1TX01_DITHER_ENA */
+
+/*
+ * R800 (0x320) - AIF2 Control
+ */
+#define WM8915_AIF2_TRI                         0x0004  /* AIF2_TRI */
+#define WM8915_AIF2_TRI_MASK                    0x0004  /* AIF2_TRI */
+#define WM8915_AIF2_TRI_SHIFT                        2  /* AIF2_TRI */
+#define WM8915_AIF2_TRI_WIDTH                        1  /* AIF2_TRI */
+#define WM8915_AIF2_FMT_MASK                    0x0003  /* AIF2_FMT - [1:0] */
+#define WM8915_AIF2_FMT_SHIFT                        0  /* AIF2_FMT - [1:0] */
+#define WM8915_AIF2_FMT_WIDTH                        2  /* AIF2_FMT - [1:0] */
+
+/*
+ * R801 (0x321) - AIF2 BCLK
+ */
+#define WM8915_AIF2_BCLK_INV                    0x0400  /* AIF2_BCLK_INV */
+#define WM8915_AIF2_BCLK_INV_MASK               0x0400  /* AIF2_BCLK_INV */
+#define WM8915_AIF2_BCLK_INV_SHIFT                  10  /* AIF2_BCLK_INV */
+#define WM8915_AIF2_BCLK_INV_WIDTH                   1  /* AIF2_BCLK_INV */
+#define WM8915_AIF2_BCLK_FRC                    0x0200  /* AIF2_BCLK_FRC */
+#define WM8915_AIF2_BCLK_FRC_MASK               0x0200  /* AIF2_BCLK_FRC */
+#define WM8915_AIF2_BCLK_FRC_SHIFT                   9  /* AIF2_BCLK_FRC */
+#define WM8915_AIF2_BCLK_FRC_WIDTH                   1  /* AIF2_BCLK_FRC */
+#define WM8915_AIF2_BCLK_MSTR                   0x0100  /* AIF2_BCLK_MSTR */
+#define WM8915_AIF2_BCLK_MSTR_MASK              0x0100  /* AIF2_BCLK_MSTR */
+#define WM8915_AIF2_BCLK_MSTR_SHIFT                  8  /* AIF2_BCLK_MSTR */
+#define WM8915_AIF2_BCLK_MSTR_WIDTH                  1  /* AIF2_BCLK_MSTR */
+#define WM8915_AIF2_BCLK_DIV_MASK               0x000F  /* AIF2_BCLK_DIV - [3:0] */
+#define WM8915_AIF2_BCLK_DIV_SHIFT                   0  /* AIF2_BCLK_DIV - [3:0] */
+#define WM8915_AIF2_BCLK_DIV_WIDTH                   4  /* AIF2_BCLK_DIV - [3:0] */
+
+/*
+ * R802 (0x322) - AIF2 TX LRCLK(1)
+ */
+#define WM8915_AIF2TX_RATE_MASK                 0x07FF  /* AIF2TX_RATE - [10:0] */
+#define WM8915_AIF2TX_RATE_SHIFT                     0  /* AIF2TX_RATE - [10:0] */
+#define WM8915_AIF2TX_RATE_WIDTH                    11  /* AIF2TX_RATE - [10:0] */
+
+/*
+ * R803 (0x323) - AIF2 TX LRCLK(2)
+ */
+#define WM8915_AIF2TX_LRCLK_MODE                0x0008  /* AIF2TX_LRCLK_MODE */
+#define WM8915_AIF2TX_LRCLK_MODE_MASK           0x0008  /* AIF2TX_LRCLK_MODE */
+#define WM8915_AIF2TX_LRCLK_MODE_SHIFT               3  /* AIF2TX_LRCLK_MODE */
+#define WM8915_AIF2TX_LRCLK_MODE_WIDTH               1  /* AIF2TX_LRCLK_MODE */
+#define WM8915_AIF2TX_LRCLK_INV                 0x0004  /* AIF2TX_LRCLK_INV */
+#define WM8915_AIF2TX_LRCLK_INV_MASK            0x0004  /* AIF2TX_LRCLK_INV */
+#define WM8915_AIF2TX_LRCLK_INV_SHIFT                2  /* AIF2TX_LRCLK_INV */
+#define WM8915_AIF2TX_LRCLK_INV_WIDTH                1  /* AIF2TX_LRCLK_INV */
+#define WM8915_AIF2TX_LRCLK_FRC                 0x0002  /* AIF2TX_LRCLK_FRC */
+#define WM8915_AIF2TX_LRCLK_FRC_MASK            0x0002  /* AIF2TX_LRCLK_FRC */
+#define WM8915_AIF2TX_LRCLK_FRC_SHIFT                1  /* AIF2TX_LRCLK_FRC */
+#define WM8915_AIF2TX_LRCLK_FRC_WIDTH                1  /* AIF2TX_LRCLK_FRC */
+#define WM8915_AIF2TX_LRCLK_MSTR                0x0001  /* AIF2TX_LRCLK_MSTR */
+#define WM8915_AIF2TX_LRCLK_MSTR_MASK           0x0001  /* AIF2TX_LRCLK_MSTR */
+#define WM8915_AIF2TX_LRCLK_MSTR_SHIFT               0  /* AIF2TX_LRCLK_MSTR */
+#define WM8915_AIF2TX_LRCLK_MSTR_WIDTH               1  /* AIF2TX_LRCLK_MSTR */
+
+/*
+ * R804 (0x324) - AIF2 RX LRCLK(1)
+ */
+#define WM8915_AIF2RX_RATE_MASK                 0x07FF  /* AIF2RX_RATE - [10:0] */
+#define WM8915_AIF2RX_RATE_SHIFT                     0  /* AIF2RX_RATE - [10:0] */
+#define WM8915_AIF2RX_RATE_WIDTH                    11  /* AIF2RX_RATE - [10:0] */
+
+/*
+ * R805 (0x325) - AIF2 RX LRCLK(2)
+ */
+#define WM8915_AIF2RX_LRCLK_INV                 0x0004  /* AIF2RX_LRCLK_INV */
+#define WM8915_AIF2RX_LRCLK_INV_MASK            0x0004  /* AIF2RX_LRCLK_INV */
+#define WM8915_AIF2RX_LRCLK_INV_SHIFT                2  /* AIF2RX_LRCLK_INV */
+#define WM8915_AIF2RX_LRCLK_INV_WIDTH                1  /* AIF2RX_LRCLK_INV */
+#define WM8915_AIF2RX_LRCLK_FRC                 0x0002  /* AIF2RX_LRCLK_FRC */
+#define WM8915_AIF2RX_LRCLK_FRC_MASK            0x0002  /* AIF2RX_LRCLK_FRC */
+#define WM8915_AIF2RX_LRCLK_FRC_SHIFT                1  /* AIF2RX_LRCLK_FRC */
+#define WM8915_AIF2RX_LRCLK_FRC_WIDTH                1  /* AIF2RX_LRCLK_FRC */
+#define WM8915_AIF2RX_LRCLK_MSTR                0x0001  /* AIF2RX_LRCLK_MSTR */
+#define WM8915_AIF2RX_LRCLK_MSTR_MASK           0x0001  /* AIF2RX_LRCLK_MSTR */
+#define WM8915_AIF2RX_LRCLK_MSTR_SHIFT               0  /* AIF2RX_LRCLK_MSTR */
+#define WM8915_AIF2RX_LRCLK_MSTR_WIDTH               1  /* AIF2RX_LRCLK_MSTR */
+
+/*
+ * R806 (0x326) - AIF2TX Data Configuration (1)
+ */
+#define WM8915_AIF2TX_WL_MASK                   0xFF00  /* AIF2TX_WL - [15:8] */
+#define WM8915_AIF2TX_WL_SHIFT                       8  /* AIF2TX_WL - [15:8] */
+#define WM8915_AIF2TX_WL_WIDTH                       8  /* AIF2TX_WL - [15:8] */
+#define WM8915_AIF2TX_SLOT_LEN_MASK             0x00FF  /* AIF2TX_SLOT_LEN - [7:0] */
+#define WM8915_AIF2TX_SLOT_LEN_SHIFT                 0  /* AIF2TX_SLOT_LEN - [7:0] */
+#define WM8915_AIF2TX_SLOT_LEN_WIDTH                 8  /* AIF2TX_SLOT_LEN - [7:0] */
+
+/*
+ * R807 (0x327) - AIF2TX Data Configuration (2)
+ */
+#define WM8915_AIF2TX_DAT_TRI                   0x0001  /* AIF2TX_DAT_TRI */
+#define WM8915_AIF2TX_DAT_TRI_MASK              0x0001  /* AIF2TX_DAT_TRI */
+#define WM8915_AIF2TX_DAT_TRI_SHIFT                  0  /* AIF2TX_DAT_TRI */
+#define WM8915_AIF2TX_DAT_TRI_WIDTH                  1  /* AIF2TX_DAT_TRI */
+
+/*
+ * R808 (0x328) - AIF2RX Data Configuration
+ */
+#define WM8915_AIF2RX_WL_MASK                   0xFF00  /* AIF2RX_WL - [15:8] */
+#define WM8915_AIF2RX_WL_SHIFT                       8  /* AIF2RX_WL - [15:8] */
+#define WM8915_AIF2RX_WL_WIDTH                       8  /* AIF2RX_WL - [15:8] */
+#define WM8915_AIF2RX_SLOT_LEN_MASK             0x00FF  /* AIF2RX_SLOT_LEN - [7:0] */
+#define WM8915_AIF2RX_SLOT_LEN_SHIFT                 0  /* AIF2RX_SLOT_LEN - [7:0] */
+#define WM8915_AIF2RX_SLOT_LEN_WIDTH                 8  /* AIF2RX_SLOT_LEN - [7:0] */
+
+/*
+ * R809 (0x329) - AIF2TX Channel 0 Configuration
+ */
+#define WM8915_AIF2TX_CHAN0_DAT_INV             0x8000  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8915_AIF2TX_CHAN0_DAT_INV_MASK        0x8000  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8915_AIF2TX_CHAN0_DAT_INV_SHIFT           15  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8915_AIF2TX_CHAN0_DAT_INV_WIDTH            1  /* AIF2TX_CHAN0_DAT_INV */
+#define WM8915_AIF2TX_CHAN0_SPACING_MASK        0x7E00  /* AIF2TX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF2TX_CHAN0_SPACING_SHIFT            9  /* AIF2TX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF2TX_CHAN0_SPACING_WIDTH            6  /* AIF2TX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF2TX_CHAN0_SLOTS_MASK          0x01C0  /* AIF2TX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF2TX_CHAN0_SLOTS_SHIFT              6  /* AIF2TX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF2TX_CHAN0_SLOTS_WIDTH              3  /* AIF2TX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF2TX_CHAN0_START_SLOT_MASK     0x003F  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF2TX_CHAN0_START_SLOT_SHIFT         0  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF2TX_CHAN0_START_SLOT_WIDTH         6  /* AIF2TX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R810 (0x32A) - AIF2TX Channel 1 Configuration
+ */
+#define WM8915_AIF2TX_CHAN1_DAT_INV             0x8000  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8915_AIF2TX_CHAN1_DAT_INV_MASK        0x8000  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8915_AIF2TX_CHAN1_DAT_INV_SHIFT           15  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8915_AIF2TX_CHAN1_DAT_INV_WIDTH            1  /* AIF2TX_CHAN1_DAT_INV */
+#define WM8915_AIF2TX_CHAN1_SPACING_MASK        0x7E00  /* AIF2TX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF2TX_CHAN1_SPACING_SHIFT            9  /* AIF2TX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF2TX_CHAN1_SPACING_WIDTH            6  /* AIF2TX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF2TX_CHAN1_SLOTS_MASK          0x01C0  /* AIF2TX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF2TX_CHAN1_SLOTS_SHIFT              6  /* AIF2TX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF2TX_CHAN1_SLOTS_WIDTH              3  /* AIF2TX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF2TX_CHAN1_START_SLOT_MASK     0x003F  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF2TX_CHAN1_START_SLOT_SHIFT         0  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF2TX_CHAN1_START_SLOT_WIDTH         6  /* AIF2TX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R811 (0x32B) - AIF2RX Channel 0 Configuration
+ */
+#define WM8915_AIF2RX_CHAN0_DAT_INV             0x8000  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8915_AIF2RX_CHAN0_DAT_INV_MASK        0x8000  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8915_AIF2RX_CHAN0_DAT_INV_SHIFT           15  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8915_AIF2RX_CHAN0_DAT_INV_WIDTH            1  /* AIF2RX_CHAN0_DAT_INV */
+#define WM8915_AIF2RX_CHAN0_SPACING_MASK        0x7E00  /* AIF2RX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF2RX_CHAN0_SPACING_SHIFT            9  /* AIF2RX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF2RX_CHAN0_SPACING_WIDTH            6  /* AIF2RX_CHAN0_SPACING - [14:9] */
+#define WM8915_AIF2RX_CHAN0_SLOTS_MASK          0x01C0  /* AIF2RX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF2RX_CHAN0_SLOTS_SHIFT              6  /* AIF2RX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF2RX_CHAN0_SLOTS_WIDTH              3  /* AIF2RX_CHAN0_SLOTS - [8:6] */
+#define WM8915_AIF2RX_CHAN0_START_SLOT_MASK     0x003F  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF2RX_CHAN0_START_SLOT_SHIFT         0  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
+#define WM8915_AIF2RX_CHAN0_START_SLOT_WIDTH         6  /* AIF2RX_CHAN0_START_SLOT - [5:0] */
+
+/*
+ * R812 (0x32C) - AIF2RX Channel 1 Configuration
+ */
+#define WM8915_AIF2RX_CHAN1_DAT_INV             0x8000  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8915_AIF2RX_CHAN1_DAT_INV_MASK        0x8000  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8915_AIF2RX_CHAN1_DAT_INV_SHIFT           15  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8915_AIF2RX_CHAN1_DAT_INV_WIDTH            1  /* AIF2RX_CHAN1_DAT_INV */
+#define WM8915_AIF2RX_CHAN1_SPACING_MASK        0x7E00  /* AIF2RX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF2RX_CHAN1_SPACING_SHIFT            9  /* AIF2RX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF2RX_CHAN1_SPACING_WIDTH            6  /* AIF2RX_CHAN1_SPACING - [14:9] */
+#define WM8915_AIF2RX_CHAN1_SLOTS_MASK          0x01C0  /* AIF2RX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF2RX_CHAN1_SLOTS_SHIFT              6  /* AIF2RX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF2RX_CHAN1_SLOTS_WIDTH              3  /* AIF2RX_CHAN1_SLOTS - [8:6] */
+#define WM8915_AIF2RX_CHAN1_START_SLOT_MASK     0x003F  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF2RX_CHAN1_START_SLOT_SHIFT         0  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
+#define WM8915_AIF2RX_CHAN1_START_SLOT_WIDTH         6  /* AIF2RX_CHAN1_START_SLOT - [5:0] */
+
+/*
+ * R813 (0x32D) - AIF2RX Mono Configuration
+ */
+#define WM8915_AIF2RX_CHAN0_MONO_MODE           0x0001  /* AIF2RX_CHAN0_MONO_MODE */
+#define WM8915_AIF2RX_CHAN0_MONO_MODE_MASK      0x0001  /* AIF2RX_CHAN0_MONO_MODE */
+#define WM8915_AIF2RX_CHAN0_MONO_MODE_SHIFT          0  /* AIF2RX_CHAN0_MONO_MODE */
+#define WM8915_AIF2RX_CHAN0_MONO_MODE_WIDTH          1  /* AIF2RX_CHAN0_MONO_MODE */
+
+/*
+ * R815 (0x32F) - AIF2TX Test
+ */
+#define WM8915_AIF2TX_DITHER_ENA                0x0001  /* AIF2TX_DITHER_ENA */
+#define WM8915_AIF2TX_DITHER_ENA_MASK           0x0001  /* AIF2TX_DITHER_ENA */
+#define WM8915_AIF2TX_DITHER_ENA_SHIFT               0  /* AIF2TX_DITHER_ENA */
+#define WM8915_AIF2TX_DITHER_ENA_WIDTH               1  /* AIF2TX_DITHER_ENA */
+
+/*
+ * R1024 (0x400) - DSP1 TX Left Volume
+ */
+#define WM8915_DSP1TX_VU                        0x0100  /* DSP1TX_VU */
+#define WM8915_DSP1TX_VU_MASK                   0x0100  /* DSP1TX_VU */
+#define WM8915_DSP1TX_VU_SHIFT                       8  /* DSP1TX_VU */
+#define WM8915_DSP1TX_VU_WIDTH                       1  /* DSP1TX_VU */
+#define WM8915_DSP1TXL_VOL_MASK                 0x00FF  /* DSP1TXL_VOL - [7:0] */
+#define WM8915_DSP1TXL_VOL_SHIFT                     0  /* DSP1TXL_VOL - [7:0] */
+#define WM8915_DSP1TXL_VOL_WIDTH                     8  /* DSP1TXL_VOL - [7:0] */
+
+/*
+ * R1025 (0x401) - DSP1 TX Right Volume
+ */
+#define WM8915_DSP1TX_VU                        0x0100  /* DSP1TX_VU */
+#define WM8915_DSP1TX_VU_MASK                   0x0100  /* DSP1TX_VU */
+#define WM8915_DSP1TX_VU_SHIFT                       8  /* DSP1TX_VU */
+#define WM8915_DSP1TX_VU_WIDTH                       1  /* DSP1TX_VU */
+#define WM8915_DSP1TXR_VOL_MASK                 0x00FF  /* DSP1TXR_VOL - [7:0] */
+#define WM8915_DSP1TXR_VOL_SHIFT                     0  /* DSP1TXR_VOL - [7:0] */
+#define WM8915_DSP1TXR_VOL_WIDTH                     8  /* DSP1TXR_VOL - [7:0] */
+
+/*
+ * R1026 (0x402) - DSP1 RX Left Volume
+ */
+#define WM8915_DSP1RX_VU                        0x0100  /* DSP1RX_VU */
+#define WM8915_DSP1RX_VU_MASK                   0x0100  /* DSP1RX_VU */
+#define WM8915_DSP1RX_VU_SHIFT                       8  /* DSP1RX_VU */
+#define WM8915_DSP1RX_VU_WIDTH                       1  /* DSP1RX_VU */
+#define WM8915_DSP1RXL_VOL_MASK                 0x00FF  /* DSP1RXL_VOL - [7:0] */
+#define WM8915_DSP1RXL_VOL_SHIFT                     0  /* DSP1RXL_VOL - [7:0] */
+#define WM8915_DSP1RXL_VOL_WIDTH                     8  /* DSP1RXL_VOL - [7:0] */
+
+/*
+ * R1027 (0x403) - DSP1 RX Right Volume
+ */
+#define WM8915_DSP1RX_VU                        0x0100  /* DSP1RX_VU */
+#define WM8915_DSP1RX_VU_MASK                   0x0100  /* DSP1RX_VU */
+#define WM8915_DSP1RX_VU_SHIFT                       8  /* DSP1RX_VU */
+#define WM8915_DSP1RX_VU_WIDTH                       1  /* DSP1RX_VU */
+#define WM8915_DSP1RXR_VOL_MASK                 0x00FF  /* DSP1RXR_VOL - [7:0] */
+#define WM8915_DSP1RXR_VOL_SHIFT                     0  /* DSP1RXR_VOL - [7:0] */
+#define WM8915_DSP1RXR_VOL_WIDTH                     8  /* DSP1RXR_VOL - [7:0] */
+
+/*
+ * R1040 (0x410) - DSP1 TX Filters
+ */
+#define WM8915_DSP1TX_NF                        0x2000  /* DSP1TX_NF */
+#define WM8915_DSP1TX_NF_MASK                   0x2000  /* DSP1TX_NF */
+#define WM8915_DSP1TX_NF_SHIFT                      13  /* DSP1TX_NF */
+#define WM8915_DSP1TX_NF_WIDTH                       1  /* DSP1TX_NF */
+#define WM8915_DSP1TXL_HPF                      0x1000  /* DSP1TXL_HPF */
+#define WM8915_DSP1TXL_HPF_MASK                 0x1000  /* DSP1TXL_HPF */
+#define WM8915_DSP1TXL_HPF_SHIFT                    12  /* DSP1TXL_HPF */
+#define WM8915_DSP1TXL_HPF_WIDTH                     1  /* DSP1TXL_HPF */
+#define WM8915_DSP1TXR_HPF                      0x0800  /* DSP1TXR_HPF */
+#define WM8915_DSP1TXR_HPF_MASK                 0x0800  /* DSP1TXR_HPF */
+#define WM8915_DSP1TXR_HPF_SHIFT                    11  /* DSP1TXR_HPF */
+#define WM8915_DSP1TXR_HPF_WIDTH                     1  /* DSP1TXR_HPF */
+#define WM8915_DSP1TX_HPF_MODE_MASK             0x0018  /* DSP1TX_HPF_MODE - [4:3] */
+#define WM8915_DSP1TX_HPF_MODE_SHIFT                 3  /* DSP1TX_HPF_MODE - [4:3] */
+#define WM8915_DSP1TX_HPF_MODE_WIDTH                 2  /* DSP1TX_HPF_MODE - [4:3] */
+#define WM8915_DSP1TX_HPF_CUT_MASK              0x0007  /* DSP1TX_HPF_CUT - [2:0] */
+#define WM8915_DSP1TX_HPF_CUT_SHIFT                  0  /* DSP1TX_HPF_CUT - [2:0] */
+#define WM8915_DSP1TX_HPF_CUT_WIDTH                  3  /* DSP1TX_HPF_CUT - [2:0] */
+
+/*
+ * R1056 (0x420) - DSP1 RX Filters (1)
+ */
+#define WM8915_DSP1RX_MUTE                      0x0200  /* DSP1RX_MUTE */
+#define WM8915_DSP1RX_MUTE_MASK                 0x0200  /* DSP1RX_MUTE */
+#define WM8915_DSP1RX_MUTE_SHIFT                     9  /* DSP1RX_MUTE */
+#define WM8915_DSP1RX_MUTE_WIDTH                     1  /* DSP1RX_MUTE */
+#define WM8915_DSP1RX_MONO                      0x0080  /* DSP1RX_MONO */
+#define WM8915_DSP1RX_MONO_MASK                 0x0080  /* DSP1RX_MONO */
+#define WM8915_DSP1RX_MONO_SHIFT                     7  /* DSP1RX_MONO */
+#define WM8915_DSP1RX_MONO_WIDTH                     1  /* DSP1RX_MONO */
+#define WM8915_DSP1RX_MUTERATE                  0x0020  /* DSP1RX_MUTERATE */
+#define WM8915_DSP1RX_MUTERATE_MASK             0x0020  /* DSP1RX_MUTERATE */
+#define WM8915_DSP1RX_MUTERATE_SHIFT                 5  /* DSP1RX_MUTERATE */
+#define WM8915_DSP1RX_MUTERATE_WIDTH                 1  /* DSP1RX_MUTERATE */
+#define WM8915_DSP1RX_UNMUTE_RAMP               0x0010  /* DSP1RX_UNMUTE_RAMP */
+#define WM8915_DSP1RX_UNMUTE_RAMP_MASK          0x0010  /* DSP1RX_UNMUTE_RAMP */
+#define WM8915_DSP1RX_UNMUTE_RAMP_SHIFT              4  /* DSP1RX_UNMUTE_RAMP */
+#define WM8915_DSP1RX_UNMUTE_RAMP_WIDTH              1  /* DSP1RX_UNMUTE_RAMP */
+
+/*
+ * R1057 (0x421) - DSP1 RX Filters (2)
+ */
+#define WM8915_DSP1RX_3D_GAIN_MASK              0x3E00  /* DSP1RX_3D_GAIN - [13:9] */
+#define WM8915_DSP1RX_3D_GAIN_SHIFT                  9  /* DSP1RX_3D_GAIN - [13:9] */
+#define WM8915_DSP1RX_3D_GAIN_WIDTH                  5  /* DSP1RX_3D_GAIN - [13:9] */
+#define WM8915_DSP1RX_3D_ENA                    0x0100  /* DSP1RX_3D_ENA */
+#define WM8915_DSP1RX_3D_ENA_MASK               0x0100  /* DSP1RX_3D_ENA */
+#define WM8915_DSP1RX_3D_ENA_SHIFT                   8  /* DSP1RX_3D_ENA */
+#define WM8915_DSP1RX_3D_ENA_WIDTH                   1  /* DSP1RX_3D_ENA */
+
+/*
+ * R1088 (0x440) - DSP1 DRC (1)
+ */
+#define WM8915_DSP1DRC_SIG_DET_RMS_MASK         0xF800  /* DSP1DRC_SIG_DET_RMS - [15:11] */
+#define WM8915_DSP1DRC_SIG_DET_RMS_SHIFT            11  /* DSP1DRC_SIG_DET_RMS - [15:11] */
+#define WM8915_DSP1DRC_SIG_DET_RMS_WIDTH             5  /* DSP1DRC_SIG_DET_RMS - [15:11] */
+#define WM8915_DSP1DRC_SIG_DET_PK_MASK          0x0600  /* DSP1DRC_SIG_DET_PK - [10:9] */
+#define WM8915_DSP1DRC_SIG_DET_PK_SHIFT              9  /* DSP1DRC_SIG_DET_PK - [10:9] */
+#define WM8915_DSP1DRC_SIG_DET_PK_WIDTH              2  /* DSP1DRC_SIG_DET_PK - [10:9] */
+#define WM8915_DSP1DRC_NG_ENA                   0x0100  /* DSP1DRC_NG_ENA */
+#define WM8915_DSP1DRC_NG_ENA_MASK              0x0100  /* DSP1DRC_NG_ENA */
+#define WM8915_DSP1DRC_NG_ENA_SHIFT                  8  /* DSP1DRC_NG_ENA */
+#define WM8915_DSP1DRC_NG_ENA_WIDTH                  1  /* DSP1DRC_NG_ENA */
+#define WM8915_DSP1DRC_SIG_DET_MODE             0x0080  /* DSP1DRC_SIG_DET_MODE */
+#define WM8915_DSP1DRC_SIG_DET_MODE_MASK        0x0080  /* DSP1DRC_SIG_DET_MODE */
+#define WM8915_DSP1DRC_SIG_DET_MODE_SHIFT            7  /* DSP1DRC_SIG_DET_MODE */
+#define WM8915_DSP1DRC_SIG_DET_MODE_WIDTH            1  /* DSP1DRC_SIG_DET_MODE */
+#define WM8915_DSP1DRC_SIG_DET                  0x0040  /* DSP1DRC_SIG_DET */
+#define WM8915_DSP1DRC_SIG_DET_MASK             0x0040  /* DSP1DRC_SIG_DET */
+#define WM8915_DSP1DRC_SIG_DET_SHIFT                 6  /* DSP1DRC_SIG_DET */
+#define WM8915_DSP1DRC_SIG_DET_WIDTH                 1  /* DSP1DRC_SIG_DET */
+#define WM8915_DSP1DRC_KNEE2_OP_ENA             0x0020  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8915_DSP1DRC_KNEE2_OP_ENA_MASK        0x0020  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8915_DSP1DRC_KNEE2_OP_ENA_SHIFT            5  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8915_DSP1DRC_KNEE2_OP_ENA_WIDTH            1  /* DSP1DRC_KNEE2_OP_ENA */
+#define WM8915_DSP1DRC_QR                       0x0010  /* DSP1DRC_QR */
+#define WM8915_DSP1DRC_QR_MASK                  0x0010  /* DSP1DRC_QR */
+#define WM8915_DSP1DRC_QR_SHIFT                      4  /* DSP1DRC_QR */
+#define WM8915_DSP1DRC_QR_WIDTH                      1  /* DSP1DRC_QR */
+#define WM8915_DSP1DRC_ANTICLIP                 0x0008  /* DSP1DRC_ANTICLIP */
+#define WM8915_DSP1DRC_ANTICLIP_MASK            0x0008  /* DSP1DRC_ANTICLIP */
+#define WM8915_DSP1DRC_ANTICLIP_SHIFT                3  /* DSP1DRC_ANTICLIP */
+#define WM8915_DSP1DRC_ANTICLIP_WIDTH                1  /* DSP1DRC_ANTICLIP */
+#define WM8915_DSP1RX_DRC_ENA                   0x0004  /* DSP1RX_DRC_ENA */
+#define WM8915_DSP1RX_DRC_ENA_MASK              0x0004  /* DSP1RX_DRC_ENA */
+#define WM8915_DSP1RX_DRC_ENA_SHIFT                  2  /* DSP1RX_DRC_ENA */
+#define WM8915_DSP1RX_DRC_ENA_WIDTH                  1  /* DSP1RX_DRC_ENA */
+#define WM8915_DSP1TXL_DRC_ENA                  0x0002  /* DSP1TXL_DRC_ENA */
+#define WM8915_DSP1TXL_DRC_ENA_MASK             0x0002  /* DSP1TXL_DRC_ENA */
+#define WM8915_DSP1TXL_DRC_ENA_SHIFT                 1  /* DSP1TXL_DRC_ENA */
+#define WM8915_DSP1TXL_DRC_ENA_WIDTH                 1  /* DSP1TXL_DRC_ENA */
+#define WM8915_DSP1TXR_DRC_ENA                  0x0001  /* DSP1TXR_DRC_ENA */
+#define WM8915_DSP1TXR_DRC_ENA_MASK             0x0001  /* DSP1TXR_DRC_ENA */
+#define WM8915_DSP1TXR_DRC_ENA_SHIFT                 0  /* DSP1TXR_DRC_ENA */
+#define WM8915_DSP1TXR_DRC_ENA_WIDTH                 1  /* DSP1TXR_DRC_ENA */
+
+/*
+ * R1089 (0x441) - DSP1 DRC (2)
+ */
+#define WM8915_DSP1DRC_ATK_MASK                 0x1E00  /* DSP1DRC_ATK - [12:9] */
+#define WM8915_DSP1DRC_ATK_SHIFT                     9  /* DSP1DRC_ATK - [12:9] */
+#define WM8915_DSP1DRC_ATK_WIDTH                     4  /* DSP1DRC_ATK - [12:9] */
+#define WM8915_DSP1DRC_DCY_MASK                 0x01E0  /* DSP1DRC_DCY - [8:5] */
+#define WM8915_DSP1DRC_DCY_SHIFT                     5  /* DSP1DRC_DCY - [8:5] */
+#define WM8915_DSP1DRC_DCY_WIDTH                     4  /* DSP1DRC_DCY - [8:5] */
+#define WM8915_DSP1DRC_MINGAIN_MASK             0x001C  /* DSP1DRC_MINGAIN - [4:2] */
+#define WM8915_DSP1DRC_MINGAIN_SHIFT                 2  /* DSP1DRC_MINGAIN - [4:2] */
+#define WM8915_DSP1DRC_MINGAIN_WIDTH                 3  /* DSP1DRC_MINGAIN - [4:2] */
+#define WM8915_DSP1DRC_MAXGAIN_MASK             0x0003  /* DSP1DRC_MAXGAIN - [1:0] */
+#define WM8915_DSP1DRC_MAXGAIN_SHIFT                 0  /* DSP1DRC_MAXGAIN - [1:0] */
+#define WM8915_DSP1DRC_MAXGAIN_WIDTH                 2  /* DSP1DRC_MAXGAIN - [1:0] */
+
+/*
+ * R1090 (0x442) - DSP1 DRC (3)
+ */
+#define WM8915_DSP1DRC_NG_MINGAIN_MASK          0xF000  /* DSP1DRC_NG_MINGAIN - [15:12] */
+#define WM8915_DSP1DRC_NG_MINGAIN_SHIFT             12  /* DSP1DRC_NG_MINGAIN - [15:12] */
+#define WM8915_DSP1DRC_NG_MINGAIN_WIDTH              4  /* DSP1DRC_NG_MINGAIN - [15:12] */
+#define WM8915_DSP1DRC_NG_EXP_MASK              0x0C00  /* DSP1DRC_NG_EXP - [11:10] */
+#define WM8915_DSP1DRC_NG_EXP_SHIFT                 10  /* DSP1DRC_NG_EXP - [11:10] */
+#define WM8915_DSP1DRC_NG_EXP_WIDTH                  2  /* DSP1DRC_NG_EXP - [11:10] */
+#define WM8915_DSP1DRC_QR_THR_MASK              0x0300  /* DSP1DRC_QR_THR - [9:8] */
+#define WM8915_DSP1DRC_QR_THR_SHIFT                  8  /* DSP1DRC_QR_THR - [9:8] */
+#define WM8915_DSP1DRC_QR_THR_WIDTH                  2  /* DSP1DRC_QR_THR - [9:8] */
+#define WM8915_DSP1DRC_QR_DCY_MASK              0x00C0  /* DSP1DRC_QR_DCY - [7:6] */
+#define WM8915_DSP1DRC_QR_DCY_SHIFT                  6  /* DSP1DRC_QR_DCY - [7:6] */
+#define WM8915_DSP1DRC_QR_DCY_WIDTH                  2  /* DSP1DRC_QR_DCY - [7:6] */
+#define WM8915_DSP1DRC_HI_COMP_MASK             0x0038  /* DSP1DRC_HI_COMP - [5:3] */
+#define WM8915_DSP1DRC_HI_COMP_SHIFT                 3  /* DSP1DRC_HI_COMP - [5:3] */
+#define WM8915_DSP1DRC_HI_COMP_WIDTH                 3  /* DSP1DRC_HI_COMP - [5:3] */
+#define WM8915_DSP1DRC_LO_COMP_MASK             0x0007  /* DSP1DRC_LO_COMP - [2:0] */
+#define WM8915_DSP1DRC_LO_COMP_SHIFT                 0  /* DSP1DRC_LO_COMP - [2:0] */
+#define WM8915_DSP1DRC_LO_COMP_WIDTH                 3  /* DSP1DRC_LO_COMP - [2:0] */
+
+/*
+ * R1091 (0x443) - DSP1 DRC (4)
+ */
+#define WM8915_DSP1DRC_KNEE_IP_MASK             0x07E0  /* DSP1DRC_KNEE_IP - [10:5] */
+#define WM8915_DSP1DRC_KNEE_IP_SHIFT                 5  /* DSP1DRC_KNEE_IP - [10:5] */
+#define WM8915_DSP1DRC_KNEE_IP_WIDTH                 6  /* DSP1DRC_KNEE_IP - [10:5] */
+#define WM8915_DSP1DRC_KNEE_OP_MASK             0x001F  /* DSP1DRC_KNEE_OP - [4:0] */
+#define WM8915_DSP1DRC_KNEE_OP_SHIFT                 0  /* DSP1DRC_KNEE_OP - [4:0] */
+#define WM8915_DSP1DRC_KNEE_OP_WIDTH                 5  /* DSP1DRC_KNEE_OP - [4:0] */
+
+/*
+ * R1092 (0x444) - DSP1 DRC (5)
+ */
+#define WM8915_DSP1DRC_KNEE2_IP_MASK            0x03E0  /* DSP1DRC_KNEE2_IP - [9:5] */
+#define WM8915_DSP1DRC_KNEE2_IP_SHIFT                5  /* DSP1DRC_KNEE2_IP - [9:5] */
+#define WM8915_DSP1DRC_KNEE2_IP_WIDTH                5  /* DSP1DRC_KNEE2_IP - [9:5] */
+#define WM8915_DSP1DRC_KNEE2_OP_MASK            0x001F  /* DSP1DRC_KNEE2_OP - [4:0] */
+#define WM8915_DSP1DRC_KNEE2_OP_SHIFT                0  /* DSP1DRC_KNEE2_OP - [4:0] */
+#define WM8915_DSP1DRC_KNEE2_OP_WIDTH                5  /* DSP1DRC_KNEE2_OP - [4:0] */
+
+/*
+ * R1152 (0x480) - DSP1 RX EQ Gains (1)
+ */
+#define WM8915_DSP1RX_EQ_B1_GAIN_MASK           0xF800  /* DSP1RX_EQ_B1_GAIN - [15:11] */
+#define WM8915_DSP1RX_EQ_B1_GAIN_SHIFT              11  /* DSP1RX_EQ_B1_GAIN - [15:11] */
+#define WM8915_DSP1RX_EQ_B1_GAIN_WIDTH               5  /* DSP1RX_EQ_B1_GAIN - [15:11] */
+#define WM8915_DSP1RX_EQ_B2_GAIN_MASK           0x07C0  /* DSP1RX_EQ_B2_GAIN - [10:6] */
+#define WM8915_DSP1RX_EQ_B2_GAIN_SHIFT               6  /* DSP1RX_EQ_B2_GAIN - [10:6] */
+#define WM8915_DSP1RX_EQ_B2_GAIN_WIDTH               5  /* DSP1RX_EQ_B2_GAIN - [10:6] */
+#define WM8915_DSP1RX_EQ_B3_GAIN_MASK           0x003E  /* DSP1RX_EQ_B3_GAIN - [5:1] */
+#define WM8915_DSP1RX_EQ_B3_GAIN_SHIFT               1  /* DSP1RX_EQ_B3_GAIN - [5:1] */
+#define WM8915_DSP1RX_EQ_B3_GAIN_WIDTH               5  /* DSP1RX_EQ_B3_GAIN - [5:1] */
+#define WM8915_DSP1RX_EQ_ENA                    0x0001  /* DSP1RX_EQ_ENA */
+#define WM8915_DSP1RX_EQ_ENA_MASK               0x0001  /* DSP1RX_EQ_ENA */
+#define WM8915_DSP1RX_EQ_ENA_SHIFT                   0  /* DSP1RX_EQ_ENA */
+#define WM8915_DSP1RX_EQ_ENA_WIDTH                   1  /* DSP1RX_EQ_ENA */
+
+/*
+ * R1153 (0x481) - DSP1 RX EQ Gains (2)
+ */
+#define WM8915_DSP1RX_EQ_B4_GAIN_MASK           0xF800  /* DSP1RX_EQ_B4_GAIN - [15:11] */
+#define WM8915_DSP1RX_EQ_B4_GAIN_SHIFT              11  /* DSP1RX_EQ_B4_GAIN - [15:11] */
+#define WM8915_DSP1RX_EQ_B4_GAIN_WIDTH               5  /* DSP1RX_EQ_B4_GAIN - [15:11] */
+#define WM8915_DSP1RX_EQ_B5_GAIN_MASK           0x07C0  /* DSP1RX_EQ_B5_GAIN - [10:6] */
+#define WM8915_DSP1RX_EQ_B5_GAIN_SHIFT               6  /* DSP1RX_EQ_B5_GAIN - [10:6] */
+#define WM8915_DSP1RX_EQ_B5_GAIN_WIDTH               5  /* DSP1RX_EQ_B5_GAIN - [10:6] */
+
+/*
+ * R1154 (0x482) - DSP1 RX EQ Band 1 A
+ */
+#define WM8915_DSP1RX_EQ_B1_A_MASK              0xFFFF  /* DSP1RX_EQ_B1_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B1_A_SHIFT                  0  /* DSP1RX_EQ_B1_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B1_A_WIDTH                 16  /* DSP1RX_EQ_B1_A - [15:0] */
+
+/*
+ * R1155 (0x483) - DSP1 RX EQ Band 1 B
+ */
+#define WM8915_DSP1RX_EQ_B1_B_MASK              0xFFFF  /* DSP1RX_EQ_B1_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B1_B_SHIFT                  0  /* DSP1RX_EQ_B1_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B1_B_WIDTH                 16  /* DSP1RX_EQ_B1_B - [15:0] */
+
+/*
+ * R1156 (0x484) - DSP1 RX EQ Band 1 PG
+ */
+#define WM8915_DSP1RX_EQ_B1_PG_MASK             0xFFFF  /* DSP1RX_EQ_B1_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B1_PG_SHIFT                 0  /* DSP1RX_EQ_B1_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B1_PG_WIDTH                16  /* DSP1RX_EQ_B1_PG - [15:0] */
+
+/*
+ * R1157 (0x485) - DSP1 RX EQ Band 2 A
+ */
+#define WM8915_DSP1RX_EQ_B2_A_MASK              0xFFFF  /* DSP1RX_EQ_B2_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_A_SHIFT                  0  /* DSP1RX_EQ_B2_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_A_WIDTH                 16  /* DSP1RX_EQ_B2_A - [15:0] */
+
+/*
+ * R1158 (0x486) - DSP1 RX EQ Band 2 B
+ */
+#define WM8915_DSP1RX_EQ_B2_B_MASK              0xFFFF  /* DSP1RX_EQ_B2_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_B_SHIFT                  0  /* DSP1RX_EQ_B2_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_B_WIDTH                 16  /* DSP1RX_EQ_B2_B - [15:0] */
+
+/*
+ * R1159 (0x487) - DSP1 RX EQ Band 2 C
+ */
+#define WM8915_DSP1RX_EQ_B2_C_MASK              0xFFFF  /* DSP1RX_EQ_B2_C - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_C_SHIFT                  0  /* DSP1RX_EQ_B2_C - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_C_WIDTH                 16  /* DSP1RX_EQ_B2_C - [15:0] */
+
+/*
+ * R1160 (0x488) - DSP1 RX EQ Band 2 PG
+ */
+#define WM8915_DSP1RX_EQ_B2_PG_MASK             0xFFFF  /* DSP1RX_EQ_B2_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_PG_SHIFT                 0  /* DSP1RX_EQ_B2_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B2_PG_WIDTH                16  /* DSP1RX_EQ_B2_PG - [15:0] */
+
+/*
+ * R1161 (0x489) - DSP1 RX EQ Band 3 A
+ */
+#define WM8915_DSP1RX_EQ_B3_A_MASK              0xFFFF  /* DSP1RX_EQ_B3_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_A_SHIFT                  0  /* DSP1RX_EQ_B3_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_A_WIDTH                 16  /* DSP1RX_EQ_B3_A - [15:0] */
+
+/*
+ * R1162 (0x48A) - DSP1 RX EQ Band 3 B
+ */
+#define WM8915_DSP1RX_EQ_B3_B_MASK              0xFFFF  /* DSP1RX_EQ_B3_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_B_SHIFT                  0  /* DSP1RX_EQ_B3_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_B_WIDTH                 16  /* DSP1RX_EQ_B3_B - [15:0] */
+
+/*
+ * R1163 (0x48B) - DSP1 RX EQ Band 3 C
+ */
+#define WM8915_DSP1RX_EQ_B3_C_MASK              0xFFFF  /* DSP1RX_EQ_B3_C - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_C_SHIFT                  0  /* DSP1RX_EQ_B3_C - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_C_WIDTH                 16  /* DSP1RX_EQ_B3_C - [15:0] */
+
+/*
+ * R1164 (0x48C) - DSP1 RX EQ Band 3 PG
+ */
+#define WM8915_DSP1RX_EQ_B3_PG_MASK             0xFFFF  /* DSP1RX_EQ_B3_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_PG_SHIFT                 0  /* DSP1RX_EQ_B3_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B3_PG_WIDTH                16  /* DSP1RX_EQ_B3_PG - [15:0] */
+
+/*
+ * R1165 (0x48D) - DSP1 RX EQ Band 4 A
+ */
+#define WM8915_DSP1RX_EQ_B4_A_MASK              0xFFFF  /* DSP1RX_EQ_B4_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_A_SHIFT                  0  /* DSP1RX_EQ_B4_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_A_WIDTH                 16  /* DSP1RX_EQ_B4_A - [15:0] */
+
+/*
+ * R1166 (0x48E) - DSP1 RX EQ Band 4 B
+ */
+#define WM8915_DSP1RX_EQ_B4_B_MASK              0xFFFF  /* DSP1RX_EQ_B4_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_B_SHIFT                  0  /* DSP1RX_EQ_B4_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_B_WIDTH                 16  /* DSP1RX_EQ_B4_B - [15:0] */
+
+/*
+ * R1167 (0x48F) - DSP1 RX EQ Band 4 C
+ */
+#define WM8915_DSP1RX_EQ_B4_C_MASK              0xFFFF  /* DSP1RX_EQ_B4_C - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_C_SHIFT                  0  /* DSP1RX_EQ_B4_C - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_C_WIDTH                 16  /* DSP1RX_EQ_B4_C - [15:0] */
+
+/*
+ * R1168 (0x490) - DSP1 RX EQ Band 4 PG
+ */
+#define WM8915_DSP1RX_EQ_B4_PG_MASK             0xFFFF  /* DSP1RX_EQ_B4_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_PG_SHIFT                 0  /* DSP1RX_EQ_B4_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B4_PG_WIDTH                16  /* DSP1RX_EQ_B4_PG - [15:0] */
+
+/*
+ * R1169 (0x491) - DSP1 RX EQ Band 5 A
+ */
+#define WM8915_DSP1RX_EQ_B5_A_MASK              0xFFFF  /* DSP1RX_EQ_B5_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B5_A_SHIFT                  0  /* DSP1RX_EQ_B5_A - [15:0] */
+#define WM8915_DSP1RX_EQ_B5_A_WIDTH                 16  /* DSP1RX_EQ_B5_A - [15:0] */
+
+/*
+ * R1170 (0x492) - DSP1 RX EQ Band 5 B
+ */
+#define WM8915_DSP1RX_EQ_B5_B_MASK              0xFFFF  /* DSP1RX_EQ_B5_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B5_B_SHIFT                  0  /* DSP1RX_EQ_B5_B - [15:0] */
+#define WM8915_DSP1RX_EQ_B5_B_WIDTH                 16  /* DSP1RX_EQ_B5_B - [15:0] */
+
+/*
+ * R1171 (0x493) - DSP1 RX EQ Band 5 PG
+ */
+#define WM8915_DSP1RX_EQ_B5_PG_MASK             0xFFFF  /* DSP1RX_EQ_B5_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B5_PG_SHIFT                 0  /* DSP1RX_EQ_B5_PG - [15:0] */
+#define WM8915_DSP1RX_EQ_B5_PG_WIDTH                16  /* DSP1RX_EQ_B5_PG - [15:0] */
+
+/*
+ * R1280 (0x500) - DSP2 TX Left Volume
+ */
+#define WM8915_DSP2TX_VU                        0x0100  /* DSP2TX_VU */
+#define WM8915_DSP2TX_VU_MASK                   0x0100  /* DSP2TX_VU */
+#define WM8915_DSP2TX_VU_SHIFT                       8  /* DSP2TX_VU */
+#define WM8915_DSP2TX_VU_WIDTH                       1  /* DSP2TX_VU */
+#define WM8915_DSP2TXL_VOL_MASK                 0x00FF  /* DSP2TXL_VOL - [7:0] */
+#define WM8915_DSP2TXL_VOL_SHIFT                     0  /* DSP2TXL_VOL - [7:0] */
+#define WM8915_DSP2TXL_VOL_WIDTH                     8  /* DSP2TXL_VOL - [7:0] */
+
+/*
+ * R1281 (0x501) - DSP2 TX Right Volume
+ */
+#define WM8915_DSP2TX_VU                        0x0100  /* DSP2TX_VU */
+#define WM8915_DSP2TX_VU_MASK                   0x0100  /* DSP2TX_VU */
+#define WM8915_DSP2TX_VU_SHIFT                       8  /* DSP2TX_VU */
+#define WM8915_DSP2TX_VU_WIDTH                       1  /* DSP2TX_VU */
+#define WM8915_DSP2TXR_VOL_MASK                 0x00FF  /* DSP2TXR_VOL - [7:0] */
+#define WM8915_DSP2TXR_VOL_SHIFT                     0  /* DSP2TXR_VOL - [7:0] */
+#define WM8915_DSP2TXR_VOL_WIDTH                     8  /* DSP2TXR_VOL - [7:0] */
+
+/*
+ * R1282 (0x502) - DSP2 RX Left Volume
+ */
+#define WM8915_DSP2RX_VU                        0x0100  /* DSP2RX_VU */
+#define WM8915_DSP2RX_VU_MASK                   0x0100  /* DSP2RX_VU */
+#define WM8915_DSP2RX_VU_SHIFT                       8  /* DSP2RX_VU */
+#define WM8915_DSP2RX_VU_WIDTH                       1  /* DSP2RX_VU */
+#define WM8915_DSP2RXL_VOL_MASK                 0x00FF  /* DSP2RXL_VOL - [7:0] */
+#define WM8915_DSP2RXL_VOL_SHIFT                     0  /* DSP2RXL_VOL - [7:0] */
+#define WM8915_DSP2RXL_VOL_WIDTH                     8  /* DSP2RXL_VOL - [7:0] */
+
+/*
+ * R1283 (0x503) - DSP2 RX Right Volume
+ */
+#define WM8915_DSP2RX_VU                        0x0100  /* DSP2RX_VU */
+#define WM8915_DSP2RX_VU_MASK                   0x0100  /* DSP2RX_VU */
+#define WM8915_DSP2RX_VU_SHIFT                       8  /* DSP2RX_VU */
+#define WM8915_DSP2RX_VU_WIDTH                       1  /* DSP2RX_VU */
+#define WM8915_DSP2RXR_VOL_MASK                 0x00FF  /* DSP2RXR_VOL - [7:0] */
+#define WM8915_DSP2RXR_VOL_SHIFT                     0  /* DSP2RXR_VOL - [7:0] */
+#define WM8915_DSP2RXR_VOL_WIDTH                     8  /* DSP2RXR_VOL - [7:0] */
+
+/*
+ * R1296 (0x510) - DSP2 TX Filters
+ */
+#define WM8915_DSP2TX_NF                        0x2000  /* DSP2TX_NF */
+#define WM8915_DSP2TX_NF_MASK                   0x2000  /* DSP2TX_NF */
+#define WM8915_DSP2TX_NF_SHIFT                      13  /* DSP2TX_NF */
+#define WM8915_DSP2TX_NF_WIDTH                       1  /* DSP2TX_NF */
+#define WM8915_DSP2TXL_HPF                      0x1000  /* DSP2TXL_HPF */
+#define WM8915_DSP2TXL_HPF_MASK                 0x1000  /* DSP2TXL_HPF */
+#define WM8915_DSP2TXL_HPF_SHIFT                    12  /* DSP2TXL_HPF */
+#define WM8915_DSP2TXL_HPF_WIDTH                     1  /* DSP2TXL_HPF */
+#define WM8915_DSP2TXR_HPF                      0x0800  /* DSP2TXR_HPF */
+#define WM8915_DSP2TXR_HPF_MASK                 0x0800  /* DSP2TXR_HPF */
+#define WM8915_DSP2TXR_HPF_SHIFT                    11  /* DSP2TXR_HPF */
+#define WM8915_DSP2TXR_HPF_WIDTH                     1  /* DSP2TXR_HPF */
+#define WM8915_DSP2TX_HPF_MODE_MASK             0x0018  /* DSP2TX_HPF_MODE - [4:3] */
+#define WM8915_DSP2TX_HPF_MODE_SHIFT                 3  /* DSP2TX_HPF_MODE - [4:3] */
+#define WM8915_DSP2TX_HPF_MODE_WIDTH                 2  /* DSP2TX_HPF_MODE - [4:3] */
+#define WM8915_DSP2TX_HPF_CUT_MASK              0x0007  /* DSP2TX_HPF_CUT - [2:0] */
+#define WM8915_DSP2TX_HPF_CUT_SHIFT                  0  /* DSP2TX_HPF_CUT - [2:0] */
+#define WM8915_DSP2TX_HPF_CUT_WIDTH                  3  /* DSP2TX_HPF_CUT - [2:0] */
+
+/*
+ * R1312 (0x520) - DSP2 RX Filters (1)
+ */
+#define WM8915_DSP2RX_MUTE                      0x0200  /* DSP2RX_MUTE */
+#define WM8915_DSP2RX_MUTE_MASK                 0x0200  /* DSP2RX_MUTE */
+#define WM8915_DSP2RX_MUTE_SHIFT                     9  /* DSP2RX_MUTE */
+#define WM8915_DSP2RX_MUTE_WIDTH                     1  /* DSP2RX_MUTE */
+#define WM8915_DSP2RX_MONO                      0x0080  /* DSP2RX_MONO */
+#define WM8915_DSP2RX_MONO_MASK                 0x0080  /* DSP2RX_MONO */
+#define WM8915_DSP2RX_MONO_SHIFT                     7  /* DSP2RX_MONO */
+#define WM8915_DSP2RX_MONO_WIDTH                     1  /* DSP2RX_MONO */
+#define WM8915_DSP2RX_MUTERATE                  0x0020  /* DSP2RX_MUTERATE */
+#define WM8915_DSP2RX_MUTERATE_MASK             0x0020  /* DSP2RX_MUTERATE */
+#define WM8915_DSP2RX_MUTERATE_SHIFT                 5  /* DSP2RX_MUTERATE */
+#define WM8915_DSP2RX_MUTERATE_WIDTH                 1  /* DSP2RX_MUTERATE */
+#define WM8915_DSP2RX_UNMUTE_RAMP               0x0010  /* DSP2RX_UNMUTE_RAMP */
+#define WM8915_DSP2RX_UNMUTE_RAMP_MASK          0x0010  /* DSP2RX_UNMUTE_RAMP */
+#define WM8915_DSP2RX_UNMUTE_RAMP_SHIFT              4  /* DSP2RX_UNMUTE_RAMP */
+#define WM8915_DSP2RX_UNMUTE_RAMP_WIDTH              1  /* DSP2RX_UNMUTE_RAMP */
+
+/*
+ * R1313 (0x521) - DSP2 RX Filters (2)
+ */
+#define WM8915_DSP2RX_3D_GAIN_MASK              0x3E00  /* DSP2RX_3D_GAIN - [13:9] */
+#define WM8915_DSP2RX_3D_GAIN_SHIFT                  9  /* DSP2RX_3D_GAIN - [13:9] */
+#define WM8915_DSP2RX_3D_GAIN_WIDTH                  5  /* DSP2RX_3D_GAIN - [13:9] */
+#define WM8915_DSP2RX_3D_ENA                    0x0100  /* DSP2RX_3D_ENA */
+#define WM8915_DSP2RX_3D_ENA_MASK               0x0100  /* DSP2RX_3D_ENA */
+#define WM8915_DSP2RX_3D_ENA_SHIFT                   8  /* DSP2RX_3D_ENA */
+#define WM8915_DSP2RX_3D_ENA_WIDTH                   1  /* DSP2RX_3D_ENA */
+
+/*
+ * R1344 (0x540) - DSP2 DRC (1)
+ */
+#define WM8915_DSP2DRC_SIG_DET_RMS_MASK         0xF800  /* DSP2DRC_SIG_DET_RMS - [15:11] */
+#define WM8915_DSP2DRC_SIG_DET_RMS_SHIFT            11  /* DSP2DRC_SIG_DET_RMS - [15:11] */
+#define WM8915_DSP2DRC_SIG_DET_RMS_WIDTH             5  /* DSP2DRC_SIG_DET_RMS - [15:11] */
+#define WM8915_DSP2DRC_SIG_DET_PK_MASK          0x0600  /* DSP2DRC_SIG_DET_PK - [10:9] */
+#define WM8915_DSP2DRC_SIG_DET_PK_SHIFT              9  /* DSP2DRC_SIG_DET_PK - [10:9] */
+#define WM8915_DSP2DRC_SIG_DET_PK_WIDTH              2  /* DSP2DRC_SIG_DET_PK - [10:9] */
+#define WM8915_DSP2DRC_NG_ENA                   0x0100  /* DSP2DRC_NG_ENA */
+#define WM8915_DSP2DRC_NG_ENA_MASK              0x0100  /* DSP2DRC_NG_ENA */
+#define WM8915_DSP2DRC_NG_ENA_SHIFT                  8  /* DSP2DRC_NG_ENA */
+#define WM8915_DSP2DRC_NG_ENA_WIDTH                  1  /* DSP2DRC_NG_ENA */
+#define WM8915_DSP2DRC_SIG_DET_MODE             0x0080  /* DSP2DRC_SIG_DET_MODE */
+#define WM8915_DSP2DRC_SIG_DET_MODE_MASK        0x0080  /* DSP2DRC_SIG_DET_MODE */
+#define WM8915_DSP2DRC_SIG_DET_MODE_SHIFT            7  /* DSP2DRC_SIG_DET_MODE */
+#define WM8915_DSP2DRC_SIG_DET_MODE_WIDTH            1  /* DSP2DRC_SIG_DET_MODE */
+#define WM8915_DSP2DRC_SIG_DET                  0x0040  /* DSP2DRC_SIG_DET */
+#define WM8915_DSP2DRC_SIG_DET_MASK             0x0040  /* DSP2DRC_SIG_DET */
+#define WM8915_DSP2DRC_SIG_DET_SHIFT                 6  /* DSP2DRC_SIG_DET */
+#define WM8915_DSP2DRC_SIG_DET_WIDTH                 1  /* DSP2DRC_SIG_DET */
+#define WM8915_DSP2DRC_KNEE2_OP_ENA             0x0020  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8915_DSP2DRC_KNEE2_OP_ENA_MASK        0x0020  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8915_DSP2DRC_KNEE2_OP_ENA_SHIFT            5  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8915_DSP2DRC_KNEE2_OP_ENA_WIDTH            1  /* DSP2DRC_KNEE2_OP_ENA */
+#define WM8915_DSP2DRC_QR                       0x0010  /* DSP2DRC_QR */
+#define WM8915_DSP2DRC_QR_MASK                  0x0010  /* DSP2DRC_QR */
+#define WM8915_DSP2DRC_QR_SHIFT                      4  /* DSP2DRC_QR */
+#define WM8915_DSP2DRC_QR_WIDTH                      1  /* DSP2DRC_QR */
+#define WM8915_DSP2DRC_ANTICLIP                 0x0008  /* DSP2DRC_ANTICLIP */
+#define WM8915_DSP2DRC_ANTICLIP_MASK            0x0008  /* DSP2DRC_ANTICLIP */
+#define WM8915_DSP2DRC_ANTICLIP_SHIFT                3  /* DSP2DRC_ANTICLIP */
+#define WM8915_DSP2DRC_ANTICLIP_WIDTH                1  /* DSP2DRC_ANTICLIP */
+#define WM8915_DSP2RX_DRC_ENA                   0x0004  /* DSP2RX_DRC_ENA */
+#define WM8915_DSP2RX_DRC_ENA_MASK              0x0004  /* DSP2RX_DRC_ENA */
+#define WM8915_DSP2RX_DRC_ENA_SHIFT                  2  /* DSP2RX_DRC_ENA */
+#define WM8915_DSP2RX_DRC_ENA_WIDTH                  1  /* DSP2RX_DRC_ENA */
+#define WM8915_DSP2TXL_DRC_ENA                  0x0002  /* DSP2TXL_DRC_ENA */
+#define WM8915_DSP2TXL_DRC_ENA_MASK             0x0002  /* DSP2TXL_DRC_ENA */
+#define WM8915_DSP2TXL_DRC_ENA_SHIFT                 1  /* DSP2TXL_DRC_ENA */
+#define WM8915_DSP2TXL_DRC_ENA_WIDTH                 1  /* DSP2TXL_DRC_ENA */
+#define WM8915_DSP2TXR_DRC_ENA                  0x0001  /* DSP2TXR_DRC_ENA */
+#define WM8915_DSP2TXR_DRC_ENA_MASK             0x0001  /* DSP2TXR_DRC_ENA */
+#define WM8915_DSP2TXR_DRC_ENA_SHIFT                 0  /* DSP2TXR_DRC_ENA */
+#define WM8915_DSP2TXR_DRC_ENA_WIDTH                 1  /* DSP2TXR_DRC_ENA */
+
+/*
+ * R1345 (0x541) - DSP2 DRC (2)
+ */
+#define WM8915_DSP2DRC_ATK_MASK                 0x1E00  /* DSP2DRC_ATK - [12:9] */
+#define WM8915_DSP2DRC_ATK_SHIFT                     9  /* DSP2DRC_ATK - [12:9] */
+#define WM8915_DSP2DRC_ATK_WIDTH                     4  /* DSP2DRC_ATK - [12:9] */
+#define WM8915_DSP2DRC_DCY_MASK                 0x01E0  /* DSP2DRC_DCY - [8:5] */
+#define WM8915_DSP2DRC_DCY_SHIFT                     5  /* DSP2DRC_DCY - [8:5] */
+#define WM8915_DSP2DRC_DCY_WIDTH                     4  /* DSP2DRC_DCY - [8:5] */
+#define WM8915_DSP2DRC_MINGAIN_MASK             0x001C  /* DSP2DRC_MINGAIN - [4:2] */
+#define WM8915_DSP2DRC_MINGAIN_SHIFT                 2  /* DSP2DRC_MINGAIN - [4:2] */
+#define WM8915_DSP2DRC_MINGAIN_WIDTH                 3  /* DSP2DRC_MINGAIN - [4:2] */
+#define WM8915_DSP2DRC_MAXGAIN_MASK             0x0003  /* DSP2DRC_MAXGAIN - [1:0] */
+#define WM8915_DSP2DRC_MAXGAIN_SHIFT                 0  /* DSP2DRC_MAXGAIN - [1:0] */
+#define WM8915_DSP2DRC_MAXGAIN_WIDTH                 2  /* DSP2DRC_MAXGAIN - [1:0] */
+
+/*
+ * R1346 (0x542) - DSP2 DRC (3)
+ */
+#define WM8915_DSP2DRC_NG_MINGAIN_MASK          0xF000  /* DSP2DRC_NG_MINGAIN - [15:12] */
+#define WM8915_DSP2DRC_NG_MINGAIN_SHIFT             12  /* DSP2DRC_NG_MINGAIN - [15:12] */
+#define WM8915_DSP2DRC_NG_MINGAIN_WIDTH              4  /* DSP2DRC_NG_MINGAIN - [15:12] */
+#define WM8915_DSP2DRC_NG_EXP_MASK              0x0C00  /* DSP2DRC_NG_EXP - [11:10] */
+#define WM8915_DSP2DRC_NG_EXP_SHIFT                 10  /* DSP2DRC_NG_EXP - [11:10] */
+#define WM8915_DSP2DRC_NG_EXP_WIDTH                  2  /* DSP2DRC_NG_EXP - [11:10] */
+#define WM8915_DSP2DRC_QR_THR_MASK              0x0300  /* DSP2DRC_QR_THR - [9:8] */
+#define WM8915_DSP2DRC_QR_THR_SHIFT                  8  /* DSP2DRC_QR_THR - [9:8] */
+#define WM8915_DSP2DRC_QR_THR_WIDTH                  2  /* DSP2DRC_QR_THR - [9:8] */
+#define WM8915_DSP2DRC_QR_DCY_MASK              0x00C0  /* DSP2DRC_QR_DCY - [7:6] */
+#define WM8915_DSP2DRC_QR_DCY_SHIFT                  6  /* DSP2DRC_QR_DCY - [7:6] */
+#define WM8915_DSP2DRC_QR_DCY_WIDTH                  2  /* DSP2DRC_QR_DCY - [7:6] */
+#define WM8915_DSP2DRC_HI_COMP_MASK             0x0038  /* DSP2DRC_HI_COMP - [5:3] */
+#define WM8915_DSP2DRC_HI_COMP_SHIFT                 3  /* DSP2DRC_HI_COMP - [5:3] */
+#define WM8915_DSP2DRC_HI_COMP_WIDTH                 3  /* DSP2DRC_HI_COMP - [5:3] */
+#define WM8915_DSP2DRC_LO_COMP_MASK             0x0007  /* DSP2DRC_LO_COMP - [2:0] */
+#define WM8915_DSP2DRC_LO_COMP_SHIFT                 0  /* DSP2DRC_LO_COMP - [2:0] */
+#define WM8915_DSP2DRC_LO_COMP_WIDTH                 3  /* DSP2DRC_LO_COMP - [2:0] */
+
+/*
+ * R1347 (0x543) - DSP2 DRC (4)
+ */
+#define WM8915_DSP2DRC_KNEE_IP_MASK             0x07E0  /* DSP2DRC_KNEE_IP - [10:5] */
+#define WM8915_DSP2DRC_KNEE_IP_SHIFT                 5  /* DSP2DRC_KNEE_IP - [10:5] */
+#define WM8915_DSP2DRC_KNEE_IP_WIDTH                 6  /* DSP2DRC_KNEE_IP - [10:5] */
+#define WM8915_DSP2DRC_KNEE_OP_MASK             0x001F  /* DSP2DRC_KNEE_OP - [4:0] */
+#define WM8915_DSP2DRC_KNEE_OP_SHIFT                 0  /* DSP2DRC_KNEE_OP - [4:0] */
+#define WM8915_DSP2DRC_KNEE_OP_WIDTH                 5  /* DSP2DRC_KNEE_OP - [4:0] */
+
+/*
+ * R1348 (0x544) - DSP2 DRC (5)
+ */
+#define WM8915_DSP2DRC_KNEE2_IP_MASK            0x03E0  /* DSP2DRC_KNEE2_IP - [9:5] */
+#define WM8915_DSP2DRC_KNEE2_IP_SHIFT                5  /* DSP2DRC_KNEE2_IP - [9:5] */
+#define WM8915_DSP2DRC_KNEE2_IP_WIDTH                5  /* DSP2DRC_KNEE2_IP - [9:5] */
+#define WM8915_DSP2DRC_KNEE2_OP_MASK            0x001F  /* DSP2DRC_KNEE2_OP - [4:0] */
+#define WM8915_DSP2DRC_KNEE2_OP_SHIFT                0  /* DSP2DRC_KNEE2_OP - [4:0] */
+#define WM8915_DSP2DRC_KNEE2_OP_WIDTH                5  /* DSP2DRC_KNEE2_OP - [4:0] */
+
+/*
+ * R1408 (0x580) - DSP2 RX EQ Gains (1)
+ */
+#define WM8915_DSP2RX_EQ_B1_GAIN_MASK           0xF800  /* DSP2RX_EQ_B1_GAIN - [15:11] */
+#define WM8915_DSP2RX_EQ_B1_GAIN_SHIFT              11  /* DSP2RX_EQ_B1_GAIN - [15:11] */
+#define WM8915_DSP2RX_EQ_B1_GAIN_WIDTH               5  /* DSP2RX_EQ_B1_GAIN - [15:11] */
+#define WM8915_DSP2RX_EQ_B2_GAIN_MASK           0x07C0  /* DSP2RX_EQ_B2_GAIN - [10:6] */
+#define WM8915_DSP2RX_EQ_B2_GAIN_SHIFT               6  /* DSP2RX_EQ_B2_GAIN - [10:6] */
+#define WM8915_DSP2RX_EQ_B2_GAIN_WIDTH               5  /* DSP2RX_EQ_B2_GAIN - [10:6] */
+#define WM8915_DSP2RX_EQ_B3_GAIN_MASK           0x003E  /* DSP2RX_EQ_B3_GAIN - [5:1] */
+#define WM8915_DSP2RX_EQ_B3_GAIN_SHIFT               1  /* DSP2RX_EQ_B3_GAIN - [5:1] */
+#define WM8915_DSP2RX_EQ_B3_GAIN_WIDTH               5  /* DSP2RX_EQ_B3_GAIN - [5:1] */
+#define WM8915_DSP2RX_EQ_ENA                    0x0001  /* DSP2RX_EQ_ENA */
+#define WM8915_DSP2RX_EQ_ENA_MASK               0x0001  /* DSP2RX_EQ_ENA */
+#define WM8915_DSP2RX_EQ_ENA_SHIFT                   0  /* DSP2RX_EQ_ENA */
+#define WM8915_DSP2RX_EQ_ENA_WIDTH                   1  /* DSP2RX_EQ_ENA */
+
+/*
+ * R1409 (0x581) - DSP2 RX EQ Gains (2)
+ */
+#define WM8915_DSP2RX_EQ_B4_GAIN_MASK           0xF800  /* DSP2RX_EQ_B4_GAIN - [15:11] */
+#define WM8915_DSP2RX_EQ_B4_GAIN_SHIFT              11  /* DSP2RX_EQ_B4_GAIN - [15:11] */
+#define WM8915_DSP2RX_EQ_B4_GAIN_WIDTH               5  /* DSP2RX_EQ_B4_GAIN - [15:11] */
+#define WM8915_DSP2RX_EQ_B5_GAIN_MASK           0x07C0  /* DSP2RX_EQ_B5_GAIN - [10:6] */
+#define WM8915_DSP2RX_EQ_B5_GAIN_SHIFT               6  /* DSP2RX_EQ_B5_GAIN - [10:6] */
+#define WM8915_DSP2RX_EQ_B5_GAIN_WIDTH               5  /* DSP2RX_EQ_B5_GAIN - [10:6] */
+
+/*
+ * R1410 (0x582) - DSP2 RX EQ Band 1 A
+ */
+#define WM8915_DSP2RX_EQ_B1_A_MASK              0xFFFF  /* DSP2RX_EQ_B1_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B1_A_SHIFT                  0  /* DSP2RX_EQ_B1_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B1_A_WIDTH                 16  /* DSP2RX_EQ_B1_A - [15:0] */
+
+/*
+ * R1411 (0x583) - DSP2 RX EQ Band 1 B
+ */
+#define WM8915_DSP2RX_EQ_B1_B_MASK              0xFFFF  /* DSP2RX_EQ_B1_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B1_B_SHIFT                  0  /* DSP2RX_EQ_B1_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B1_B_WIDTH                 16  /* DSP2RX_EQ_B1_B - [15:0] */
+
+/*
+ * R1412 (0x584) - DSP2 RX EQ Band 1 PG
+ */
+#define WM8915_DSP2RX_EQ_B1_PG_MASK             0xFFFF  /* DSP2RX_EQ_B1_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B1_PG_SHIFT                 0  /* DSP2RX_EQ_B1_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B1_PG_WIDTH                16  /* DSP2RX_EQ_B1_PG - [15:0] */
+
+/*
+ * R1413 (0x585) - DSP2 RX EQ Band 2 A
+ */
+#define WM8915_DSP2RX_EQ_B2_A_MASK              0xFFFF  /* DSP2RX_EQ_B2_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_A_SHIFT                  0  /* DSP2RX_EQ_B2_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_A_WIDTH                 16  /* DSP2RX_EQ_B2_A - [15:0] */
+
+/*
+ * R1414 (0x586) - DSP2 RX EQ Band 2 B
+ */
+#define WM8915_DSP2RX_EQ_B2_B_MASK              0xFFFF  /* DSP2RX_EQ_B2_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_B_SHIFT                  0  /* DSP2RX_EQ_B2_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_B_WIDTH                 16  /* DSP2RX_EQ_B2_B - [15:0] */
+
+/*
+ * R1415 (0x587) - DSP2 RX EQ Band 2 C
+ */
+#define WM8915_DSP2RX_EQ_B2_C_MASK              0xFFFF  /* DSP2RX_EQ_B2_C - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_C_SHIFT                  0  /* DSP2RX_EQ_B2_C - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_C_WIDTH                 16  /* DSP2RX_EQ_B2_C - [15:0] */
+
+/*
+ * R1416 (0x588) - DSP2 RX EQ Band 2 PG
+ */
+#define WM8915_DSP2RX_EQ_B2_PG_MASK             0xFFFF  /* DSP2RX_EQ_B2_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_PG_SHIFT                 0  /* DSP2RX_EQ_B2_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B2_PG_WIDTH                16  /* DSP2RX_EQ_B2_PG - [15:0] */
+
+/*
+ * R1417 (0x589) - DSP2 RX EQ Band 3 A
+ */
+#define WM8915_DSP2RX_EQ_B3_A_MASK              0xFFFF  /* DSP2RX_EQ_B3_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_A_SHIFT                  0  /* DSP2RX_EQ_B3_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_A_WIDTH                 16  /* DSP2RX_EQ_B3_A - [15:0] */
+
+/*
+ * R1418 (0x58A) - DSP2 RX EQ Band 3 B
+ */
+#define WM8915_DSP2RX_EQ_B3_B_MASK              0xFFFF  /* DSP2RX_EQ_B3_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_B_SHIFT                  0  /* DSP2RX_EQ_B3_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_B_WIDTH                 16  /* DSP2RX_EQ_B3_B - [15:0] */
+
+/*
+ * R1419 (0x58B) - DSP2 RX EQ Band 3 C
+ */
+#define WM8915_DSP2RX_EQ_B3_C_MASK              0xFFFF  /* DSP2RX_EQ_B3_C - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_C_SHIFT                  0  /* DSP2RX_EQ_B3_C - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_C_WIDTH                 16  /* DSP2RX_EQ_B3_C - [15:0] */
+
+/*
+ * R1420 (0x58C) - DSP2 RX EQ Band 3 PG
+ */
+#define WM8915_DSP2RX_EQ_B3_PG_MASK             0xFFFF  /* DSP2RX_EQ_B3_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_PG_SHIFT                 0  /* DSP2RX_EQ_B3_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B3_PG_WIDTH                16  /* DSP2RX_EQ_B3_PG - [15:0] */
+
+/*
+ * R1421 (0x58D) - DSP2 RX EQ Band 4 A
+ */
+#define WM8915_DSP2RX_EQ_B4_A_MASK              0xFFFF  /* DSP2RX_EQ_B4_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_A_SHIFT                  0  /* DSP2RX_EQ_B4_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_A_WIDTH                 16  /* DSP2RX_EQ_B4_A - [15:0] */
+
+/*
+ * R1422 (0x58E) - DSP2 RX EQ Band 4 B
+ */
+#define WM8915_DSP2RX_EQ_B4_B_MASK              0xFFFF  /* DSP2RX_EQ_B4_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_B_SHIFT                  0  /* DSP2RX_EQ_B4_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_B_WIDTH                 16  /* DSP2RX_EQ_B4_B - [15:0] */
+
+/*
+ * R1423 (0x58F) - DSP2 RX EQ Band 4 C
+ */
+#define WM8915_DSP2RX_EQ_B4_C_MASK              0xFFFF  /* DSP2RX_EQ_B4_C - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_C_SHIFT                  0  /* DSP2RX_EQ_B4_C - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_C_WIDTH                 16  /* DSP2RX_EQ_B4_C - [15:0] */
+
+/*
+ * R1424 (0x590) - DSP2 RX EQ Band 4 PG
+ */
+#define WM8915_DSP2RX_EQ_B4_PG_MASK             0xFFFF  /* DSP2RX_EQ_B4_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_PG_SHIFT                 0  /* DSP2RX_EQ_B4_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B4_PG_WIDTH                16  /* DSP2RX_EQ_B4_PG - [15:0] */
+
+/*
+ * R1425 (0x591) - DSP2 RX EQ Band 5 A
+ */
+#define WM8915_DSP2RX_EQ_B5_A_MASK              0xFFFF  /* DSP2RX_EQ_B5_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B5_A_SHIFT                  0  /* DSP2RX_EQ_B5_A - [15:0] */
+#define WM8915_DSP2RX_EQ_B5_A_WIDTH                 16  /* DSP2RX_EQ_B5_A - [15:0] */
+
+/*
+ * R1426 (0x592) - DSP2 RX EQ Band 5 B
+ */
+#define WM8915_DSP2RX_EQ_B5_B_MASK              0xFFFF  /* DSP2RX_EQ_B5_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B5_B_SHIFT                  0  /* DSP2RX_EQ_B5_B - [15:0] */
+#define WM8915_DSP2RX_EQ_B5_B_WIDTH                 16  /* DSP2RX_EQ_B5_B - [15:0] */
+
+/*
+ * R1427 (0x593) - DSP2 RX EQ Band 5 PG
+ */
+#define WM8915_DSP2RX_EQ_B5_PG_MASK             0xFFFF  /* DSP2RX_EQ_B5_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B5_PG_SHIFT                 0  /* DSP2RX_EQ_B5_PG - [15:0] */
+#define WM8915_DSP2RX_EQ_B5_PG_WIDTH                16  /* DSP2RX_EQ_B5_PG - [15:0] */
+
+/*
+ * R1536 (0x600) - DAC1 Mixer Volumes
+ */
+#define WM8915_ADCR_DAC1_VOL_MASK               0x03E0  /* ADCR_DAC1_VOL - [9:5] */
+#define WM8915_ADCR_DAC1_VOL_SHIFT                   5  /* ADCR_DAC1_VOL - [9:5] */
+#define WM8915_ADCR_DAC1_VOL_WIDTH                   5  /* ADCR_DAC1_VOL - [9:5] */
+#define WM8915_ADCL_DAC1_VOL_MASK               0x001F  /* ADCL_DAC1_VOL - [4:0] */
+#define WM8915_ADCL_DAC1_VOL_SHIFT                   0  /* ADCL_DAC1_VOL - [4:0] */
+#define WM8915_ADCL_DAC1_VOL_WIDTH                   5  /* ADCL_DAC1_VOL - [4:0] */
+
+/*
+ * R1537 (0x601) - DAC1 Left Mixer Routing
+ */
+#define WM8915_ADCR_TO_DAC1L                    0x0020  /* ADCR_TO_DAC1L */
+#define WM8915_ADCR_TO_DAC1L_MASK               0x0020  /* ADCR_TO_DAC1L */
+#define WM8915_ADCR_TO_DAC1L_SHIFT                   5  /* ADCR_TO_DAC1L */
+#define WM8915_ADCR_TO_DAC1L_WIDTH                   1  /* ADCR_TO_DAC1L */
+#define WM8915_ADCL_TO_DAC1L                    0x0010  /* ADCL_TO_DAC1L */
+#define WM8915_ADCL_TO_DAC1L_MASK               0x0010  /* ADCL_TO_DAC1L */
+#define WM8915_ADCL_TO_DAC1L_SHIFT                   4  /* ADCL_TO_DAC1L */
+#define WM8915_ADCL_TO_DAC1L_WIDTH                   1  /* ADCL_TO_DAC1L */
+#define WM8915_DSP2RXL_TO_DAC1L                 0x0002  /* DSP2RXL_TO_DAC1L */
+#define WM8915_DSP2RXL_TO_DAC1L_MASK            0x0002  /* DSP2RXL_TO_DAC1L */
+#define WM8915_DSP2RXL_TO_DAC1L_SHIFT                1  /* DSP2RXL_TO_DAC1L */
+#define WM8915_DSP2RXL_TO_DAC1L_WIDTH                1  /* DSP2RXL_TO_DAC1L */
+#define WM8915_DSP1RXL_TO_DAC1L                 0x0001  /* DSP1RXL_TO_DAC1L */
+#define WM8915_DSP1RXL_TO_DAC1L_MASK            0x0001  /* DSP1RXL_TO_DAC1L */
+#define WM8915_DSP1RXL_TO_DAC1L_SHIFT                0  /* DSP1RXL_TO_DAC1L */
+#define WM8915_DSP1RXL_TO_DAC1L_WIDTH                1  /* DSP1RXL_TO_DAC1L */
+
+/*
+ * R1538 (0x602) - DAC1 Right Mixer Routing
+ */
+#define WM8915_ADCR_TO_DAC1R                    0x0020  /* ADCR_TO_DAC1R */
+#define WM8915_ADCR_TO_DAC1R_MASK               0x0020  /* ADCR_TO_DAC1R */
+#define WM8915_ADCR_TO_DAC1R_SHIFT                   5  /* ADCR_TO_DAC1R */
+#define WM8915_ADCR_TO_DAC1R_WIDTH                   1  /* ADCR_TO_DAC1R */
+#define WM8915_ADCL_TO_DAC1R                    0x0010  /* ADCL_TO_DAC1R */
+#define WM8915_ADCL_TO_DAC1R_MASK               0x0010  /* ADCL_TO_DAC1R */
+#define WM8915_ADCL_TO_DAC1R_SHIFT                   4  /* ADCL_TO_DAC1R */
+#define WM8915_ADCL_TO_DAC1R_WIDTH                   1  /* ADCL_TO_DAC1R */
+#define WM8915_DSP2RXR_TO_DAC1R                 0x0002  /* DSP2RXR_TO_DAC1R */
+#define WM8915_DSP2RXR_TO_DAC1R_MASK            0x0002  /* DSP2RXR_TO_DAC1R */
+#define WM8915_DSP2RXR_TO_DAC1R_SHIFT                1  /* DSP2RXR_TO_DAC1R */
+#define WM8915_DSP2RXR_TO_DAC1R_WIDTH                1  /* DSP2RXR_TO_DAC1R */
+#define WM8915_DSP1RXR_TO_DAC1R                 0x0001  /* DSP1RXR_TO_DAC1R */
+#define WM8915_DSP1RXR_TO_DAC1R_MASK            0x0001  /* DSP1RXR_TO_DAC1R */
+#define WM8915_DSP1RXR_TO_DAC1R_SHIFT                0  /* DSP1RXR_TO_DAC1R */
+#define WM8915_DSP1RXR_TO_DAC1R_WIDTH                1  /* DSP1RXR_TO_DAC1R */
+
+/*
+ * R1539 (0x603) - DAC2 Mixer Volumes
+ */
+#define WM8915_ADCR_DAC2_VOL_MASK               0x03E0  /* ADCR_DAC2_VOL - [9:5] */
+#define WM8915_ADCR_DAC2_VOL_SHIFT                   5  /* ADCR_DAC2_VOL - [9:5] */
+#define WM8915_ADCR_DAC2_VOL_WIDTH                   5  /* ADCR_DAC2_VOL - [9:5] */
+#define WM8915_ADCL_DAC2_VOL_MASK               0x001F  /* ADCL_DAC2_VOL - [4:0] */
+#define WM8915_ADCL_DAC2_VOL_SHIFT                   0  /* ADCL_DAC2_VOL - [4:0] */
+#define WM8915_ADCL_DAC2_VOL_WIDTH                   5  /* ADCL_DAC2_VOL - [4:0] */
+
+/*
+ * R1540 (0x604) - DAC2 Left Mixer Routing
+ */
+#define WM8915_ADCR_TO_DAC2L                    0x0020  /* ADCR_TO_DAC2L */
+#define WM8915_ADCR_TO_DAC2L_MASK               0x0020  /* ADCR_TO_DAC2L */
+#define WM8915_ADCR_TO_DAC2L_SHIFT                   5  /* ADCR_TO_DAC2L */
+#define WM8915_ADCR_TO_DAC2L_WIDTH                   1  /* ADCR_TO_DAC2L */
+#define WM8915_ADCL_TO_DAC2L                    0x0010  /* ADCL_TO_DAC2L */
+#define WM8915_ADCL_TO_DAC2L_MASK               0x0010  /* ADCL_TO_DAC2L */
+#define WM8915_ADCL_TO_DAC2L_SHIFT                   4  /* ADCL_TO_DAC2L */
+#define WM8915_ADCL_TO_DAC2L_WIDTH                   1  /* ADCL_TO_DAC2L */
+#define WM8915_DSP2RXL_TO_DAC2L                 0x0002  /* DSP2RXL_TO_DAC2L */
+#define WM8915_DSP2RXL_TO_DAC2L_MASK            0x0002  /* DSP2RXL_TO_DAC2L */
+#define WM8915_DSP2RXL_TO_DAC2L_SHIFT                1  /* DSP2RXL_TO_DAC2L */
+#define WM8915_DSP2RXL_TO_DAC2L_WIDTH                1  /* DSP2RXL_TO_DAC2L */
+#define WM8915_DSP1RXL_TO_DAC2L                 0x0001  /* DSP1RXL_TO_DAC2L */
+#define WM8915_DSP1RXL_TO_DAC2L_MASK            0x0001  /* DSP1RXL_TO_DAC2L */
+#define WM8915_DSP1RXL_TO_DAC2L_SHIFT                0  /* DSP1RXL_TO_DAC2L */
+#define WM8915_DSP1RXL_TO_DAC2L_WIDTH                1  /* DSP1RXL_TO_DAC2L */
+
+/*
+ * R1541 (0x605) - DAC2 Right Mixer Routing
+ */
+#define WM8915_ADCR_TO_DAC2R                    0x0020  /* ADCR_TO_DAC2R */
+#define WM8915_ADCR_TO_DAC2R_MASK               0x0020  /* ADCR_TO_DAC2R */
+#define WM8915_ADCR_TO_DAC2R_SHIFT                   5  /* ADCR_TO_DAC2R */
+#define WM8915_ADCR_TO_DAC2R_WIDTH                   1  /* ADCR_TO_DAC2R */
+#define WM8915_ADCL_TO_DAC2R                    0x0010  /* ADCL_TO_DAC2R */
+#define WM8915_ADCL_TO_DAC2R_MASK               0x0010  /* ADCL_TO_DAC2R */
+#define WM8915_ADCL_TO_DAC2R_SHIFT                   4  /* ADCL_TO_DAC2R */
+#define WM8915_ADCL_TO_DAC2R_WIDTH                   1  /* ADCL_TO_DAC2R */
+#define WM8915_DSP2RXR_TO_DAC2R                 0x0002  /* DSP2RXR_TO_DAC2R */
+#define WM8915_DSP2RXR_TO_DAC2R_MASK            0x0002  /* DSP2RXR_TO_DAC2R */
+#define WM8915_DSP2RXR_TO_DAC2R_SHIFT                1  /* DSP2RXR_TO_DAC2R */
+#define WM8915_DSP2RXR_TO_DAC2R_WIDTH                1  /* DSP2RXR_TO_DAC2R */
+#define WM8915_DSP1RXR_TO_DAC2R                 0x0001  /* DSP1RXR_TO_DAC2R */
+#define WM8915_DSP1RXR_TO_DAC2R_MASK            0x0001  /* DSP1RXR_TO_DAC2R */
+#define WM8915_DSP1RXR_TO_DAC2R_SHIFT                0  /* DSP1RXR_TO_DAC2R */
+#define WM8915_DSP1RXR_TO_DAC2R_WIDTH                1  /* DSP1RXR_TO_DAC2R */
+
+/*
+ * R1542 (0x606) - DSP1 TX Left Mixer Routing
+ */
+#define WM8915_ADC1L_TO_DSP1TXL                 0x0002  /* ADC1L_TO_DSP1TXL */
+#define WM8915_ADC1L_TO_DSP1TXL_MASK            0x0002  /* ADC1L_TO_DSP1TXL */
+#define WM8915_ADC1L_TO_DSP1TXL_SHIFT                1  /* ADC1L_TO_DSP1TXL */
+#define WM8915_ADC1L_TO_DSP1TXL_WIDTH                1  /* ADC1L_TO_DSP1TXL */
+#define WM8915_DACL_TO_DSP1TXL                  0x0001  /* DACL_TO_DSP1TXL */
+#define WM8915_DACL_TO_DSP1TXL_MASK             0x0001  /* DACL_TO_DSP1TXL */
+#define WM8915_DACL_TO_DSP1TXL_SHIFT                 0  /* DACL_TO_DSP1TXL */
+#define WM8915_DACL_TO_DSP1TXL_WIDTH                 1  /* DACL_TO_DSP1TXL */
+
+/*
+ * R1543 (0x607) - DSP1 TX Right Mixer Routing
+ */
+#define WM8915_ADC1R_TO_DSP1TXR                 0x0002  /* ADC1R_TO_DSP1TXR */
+#define WM8915_ADC1R_TO_DSP1TXR_MASK            0x0002  /* ADC1R_TO_DSP1TXR */
+#define WM8915_ADC1R_TO_DSP1TXR_SHIFT                1  /* ADC1R_TO_DSP1TXR */
+#define WM8915_ADC1R_TO_DSP1TXR_WIDTH                1  /* ADC1R_TO_DSP1TXR */
+#define WM8915_DACR_TO_DSP1TXR                  0x0001  /* DACR_TO_DSP1TXR */
+#define WM8915_DACR_TO_DSP1TXR_MASK             0x0001  /* DACR_TO_DSP1TXR */
+#define WM8915_DACR_TO_DSP1TXR_SHIFT                 0  /* DACR_TO_DSP1TXR */
+#define WM8915_DACR_TO_DSP1TXR_WIDTH                 1  /* DACR_TO_DSP1TXR */
+
+/*
+ * R1544 (0x608) - DSP2 TX Left Mixer Routing
+ */
+#define WM8915_ADC2L_TO_DSP2TXL                 0x0002  /* ADC2L_TO_DSP2TXL */
+#define WM8915_ADC2L_TO_DSP2TXL_MASK            0x0002  /* ADC2L_TO_DSP2TXL */
+#define WM8915_ADC2L_TO_DSP2TXL_SHIFT                1  /* ADC2L_TO_DSP2TXL */
+#define WM8915_ADC2L_TO_DSP2TXL_WIDTH                1  /* ADC2L_TO_DSP2TXL */
+#define WM8915_DACL_TO_DSP2TXL                  0x0001  /* DACL_TO_DSP2TXL */
+#define WM8915_DACL_TO_DSP2TXL_MASK             0x0001  /* DACL_TO_DSP2TXL */
+#define WM8915_DACL_TO_DSP2TXL_SHIFT                 0  /* DACL_TO_DSP2TXL */
+#define WM8915_DACL_TO_DSP2TXL_WIDTH                 1  /* DACL_TO_DSP2TXL */
+
+/*
+ * R1545 (0x609) - DSP2 TX Right Mixer Routing
+ */
+#define WM8915_ADC2R_TO_DSP2TXR                 0x0002  /* ADC2R_TO_DSP2TXR */
+#define WM8915_ADC2R_TO_DSP2TXR_MASK            0x0002  /* ADC2R_TO_DSP2TXR */
+#define WM8915_ADC2R_TO_DSP2TXR_SHIFT                1  /* ADC2R_TO_DSP2TXR */
+#define WM8915_ADC2R_TO_DSP2TXR_WIDTH                1  /* ADC2R_TO_DSP2TXR */
+#define WM8915_DACR_TO_DSP2TXR                  0x0001  /* DACR_TO_DSP2TXR */
+#define WM8915_DACR_TO_DSP2TXR_MASK             0x0001  /* DACR_TO_DSP2TXR */
+#define WM8915_DACR_TO_DSP2TXR_SHIFT                 0  /* DACR_TO_DSP2TXR */
+#define WM8915_DACR_TO_DSP2TXR_WIDTH                 1  /* DACR_TO_DSP2TXR */
+
+/*
+ * R1546 (0x60A) - DSP TX Mixer Select
+ */
+#define WM8915_DAC_TO_DSPTX_SRC                 0x0001  /* DAC_TO_DSPTX_SRC */
+#define WM8915_DAC_TO_DSPTX_SRC_MASK            0x0001  /* DAC_TO_DSPTX_SRC */
+#define WM8915_DAC_TO_DSPTX_SRC_SHIFT                0  /* DAC_TO_DSPTX_SRC */
+#define WM8915_DAC_TO_DSPTX_SRC_WIDTH                1  /* DAC_TO_DSPTX_SRC */
+
+/*
+ * R1552 (0x610) - DAC Softmute
+ */
+#define WM8915_DAC_SOFTMUTEMODE                 0x0002  /* DAC_SOFTMUTEMODE */
+#define WM8915_DAC_SOFTMUTEMODE_MASK            0x0002  /* DAC_SOFTMUTEMODE */
+#define WM8915_DAC_SOFTMUTEMODE_SHIFT                1  /* DAC_SOFTMUTEMODE */
+#define WM8915_DAC_SOFTMUTEMODE_WIDTH                1  /* DAC_SOFTMUTEMODE */
+#define WM8915_DAC_MUTERATE                     0x0001  /* DAC_MUTERATE */
+#define WM8915_DAC_MUTERATE_MASK                0x0001  /* DAC_MUTERATE */
+#define WM8915_DAC_MUTERATE_SHIFT                    0  /* DAC_MUTERATE */
+#define WM8915_DAC_MUTERATE_WIDTH                    1  /* DAC_MUTERATE */
+
+/*
+ * R1568 (0x620) - Oversampling
+ */
+#define WM8915_SPK_OSR128                       0x0008  /* SPK_OSR128 */
+#define WM8915_SPK_OSR128_MASK                  0x0008  /* SPK_OSR128 */
+#define WM8915_SPK_OSR128_SHIFT                      3  /* SPK_OSR128 */
+#define WM8915_SPK_OSR128_WIDTH                      1  /* SPK_OSR128 */
+#define WM8915_DMIC_OSR64                       0x0004  /* DMIC_OSR64 */
+#define WM8915_DMIC_OSR64_MASK                  0x0004  /* DMIC_OSR64 */
+#define WM8915_DMIC_OSR64_SHIFT                      2  /* DMIC_OSR64 */
+#define WM8915_DMIC_OSR64_WIDTH                      1  /* DMIC_OSR64 */
+#define WM8915_ADC_OSR128                       0x0002  /* ADC_OSR128 */
+#define WM8915_ADC_OSR128_MASK                  0x0002  /* ADC_OSR128 */
+#define WM8915_ADC_OSR128_SHIFT                      1  /* ADC_OSR128 */
+#define WM8915_ADC_OSR128_WIDTH                      1  /* ADC_OSR128 */
+#define WM8915_DAC_OSR128                       0x0001  /* DAC_OSR128 */
+#define WM8915_DAC_OSR128_MASK                  0x0001  /* DAC_OSR128 */
+#define WM8915_DAC_OSR128_SHIFT                      0  /* DAC_OSR128 */
+#define WM8915_DAC_OSR128_WIDTH                      1  /* DAC_OSR128 */
+
+/*
+ * R1569 (0x621) - Sidetone
+ */
+#define WM8915_ST_LPF                           0x1000  /* ST_LPF */
+#define WM8915_ST_LPF_MASK                      0x1000  /* ST_LPF */
+#define WM8915_ST_LPF_SHIFT                         12  /* ST_LPF */
+#define WM8915_ST_LPF_WIDTH                          1  /* ST_LPF */
+#define WM8915_ST_HPF_CUT_MASK                  0x0380  /* ST_HPF_CUT - [9:7] */
+#define WM8915_ST_HPF_CUT_SHIFT                      7  /* ST_HPF_CUT - [9:7] */
+#define WM8915_ST_HPF_CUT_WIDTH                      3  /* ST_HPF_CUT - [9:7] */
+#define WM8915_ST_HPF                           0x0040  /* ST_HPF */
+#define WM8915_ST_HPF_MASK                      0x0040  /* ST_HPF */
+#define WM8915_ST_HPF_SHIFT                          6  /* ST_HPF */
+#define WM8915_ST_HPF_WIDTH                          1  /* ST_HPF */
+#define WM8915_STR_SEL                          0x0002  /* STR_SEL */
+#define WM8915_STR_SEL_MASK                     0x0002  /* STR_SEL */
+#define WM8915_STR_SEL_SHIFT                         1  /* STR_SEL */
+#define WM8915_STR_SEL_WIDTH                         1  /* STR_SEL */
+#define WM8915_STL_SEL                          0x0001  /* STL_SEL */
+#define WM8915_STL_SEL_MASK                     0x0001  /* STL_SEL */
+#define WM8915_STL_SEL_SHIFT                         0  /* STL_SEL */
+#define WM8915_STL_SEL_WIDTH                         1  /* STL_SEL */
+
+/*
+ * R1792 (0x700) - GPIO 1
+ */
+#define WM8915_GP1_DIR                          0x8000  /* GP1_DIR */
+#define WM8915_GP1_DIR_MASK                     0x8000  /* GP1_DIR */
+#define WM8915_GP1_DIR_SHIFT                        15  /* GP1_DIR */
+#define WM8915_GP1_DIR_WIDTH                         1  /* GP1_DIR */
+#define WM8915_GP1_PU                           0x4000  /* GP1_PU */
+#define WM8915_GP1_PU_MASK                      0x4000  /* GP1_PU */
+#define WM8915_GP1_PU_SHIFT                         14  /* GP1_PU */
+#define WM8915_GP1_PU_WIDTH                          1  /* GP1_PU */
+#define WM8915_GP1_PD                           0x2000  /* GP1_PD */
+#define WM8915_GP1_PD_MASK                      0x2000  /* GP1_PD */
+#define WM8915_GP1_PD_SHIFT                         13  /* GP1_PD */
+#define WM8915_GP1_PD_WIDTH                          1  /* GP1_PD */
+#define WM8915_GP1_POL                          0x0400  /* GP1_POL */
+#define WM8915_GP1_POL_MASK                     0x0400  /* GP1_POL */
+#define WM8915_GP1_POL_SHIFT                        10  /* GP1_POL */
+#define WM8915_GP1_POL_WIDTH                         1  /* GP1_POL */
+#define WM8915_GP1_OP_CFG                       0x0200  /* GP1_OP_CFG */
+#define WM8915_GP1_OP_CFG_MASK                  0x0200  /* GP1_OP_CFG */
+#define WM8915_GP1_OP_CFG_SHIFT                      9  /* GP1_OP_CFG */
+#define WM8915_GP1_OP_CFG_WIDTH                      1  /* GP1_OP_CFG */
+#define WM8915_GP1_DB                           0x0100  /* GP1_DB */
+#define WM8915_GP1_DB_MASK                      0x0100  /* GP1_DB */
+#define WM8915_GP1_DB_SHIFT                          8  /* GP1_DB */
+#define WM8915_GP1_DB_WIDTH                          1  /* GP1_DB */
+#define WM8915_GP1_LVL                          0x0040  /* GP1_LVL */
+#define WM8915_GP1_LVL_MASK                     0x0040  /* GP1_LVL */
+#define WM8915_GP1_LVL_SHIFT                         6  /* GP1_LVL */
+#define WM8915_GP1_LVL_WIDTH                         1  /* GP1_LVL */
+#define WM8915_GP1_FN_MASK                      0x000F  /* GP1_FN - [3:0] */
+#define WM8915_GP1_FN_SHIFT                          0  /* GP1_FN - [3:0] */
+#define WM8915_GP1_FN_WIDTH                          4  /* GP1_FN - [3:0] */
+
+/*
+ * R1793 (0x701) - GPIO 2
+ */
+#define WM8915_GP2_DIR                          0x8000  /* GP2_DIR */
+#define WM8915_GP2_DIR_MASK                     0x8000  /* GP2_DIR */
+#define WM8915_GP2_DIR_SHIFT                        15  /* GP2_DIR */
+#define WM8915_GP2_DIR_WIDTH                         1  /* GP2_DIR */
+#define WM8915_GP2_PU                           0x4000  /* GP2_PU */
+#define WM8915_GP2_PU_MASK                      0x4000  /* GP2_PU */
+#define WM8915_GP2_PU_SHIFT                         14  /* GP2_PU */
+#define WM8915_GP2_PU_WIDTH                          1  /* GP2_PU */
+#define WM8915_GP2_PD                           0x2000  /* GP2_PD */
+#define WM8915_GP2_PD_MASK                      0x2000  /* GP2_PD */
+#define WM8915_GP2_PD_SHIFT                         13  /* GP2_PD */
+#define WM8915_GP2_PD_WIDTH                          1  /* GP2_PD */
+#define WM8915_GP2_POL                          0x0400  /* GP2_POL */
+#define WM8915_GP2_POL_MASK                     0x0400  /* GP2_POL */
+#define WM8915_GP2_POL_SHIFT                        10  /* GP2_POL */
+#define WM8915_GP2_POL_WIDTH                         1  /* GP2_POL */
+#define WM8915_GP2_OP_CFG                       0x0200  /* GP2_OP_CFG */
+#define WM8915_GP2_OP_CFG_MASK                  0x0200  /* GP2_OP_CFG */
+#define WM8915_GP2_OP_CFG_SHIFT                      9  /* GP2_OP_CFG */
+#define WM8915_GP2_OP_CFG_WIDTH                      1  /* GP2_OP_CFG */
+#define WM8915_GP2_DB                           0x0100  /* GP2_DB */
+#define WM8915_GP2_DB_MASK                      0x0100  /* GP2_DB */
+#define WM8915_GP2_DB_SHIFT                          8  /* GP2_DB */
+#define WM8915_GP2_DB_WIDTH                          1  /* GP2_DB */
+#define WM8915_GP2_LVL                          0x0040  /* GP2_LVL */
+#define WM8915_GP2_LVL_MASK                     0x0040  /* GP2_LVL */
+#define WM8915_GP2_LVL_SHIFT                         6  /* GP2_LVL */
+#define WM8915_GP2_LVL_WIDTH                         1  /* GP2_LVL */
+#define WM8915_GP2_FN_MASK                      0x000F  /* GP2_FN - [3:0] */
+#define WM8915_GP2_FN_SHIFT                          0  /* GP2_FN - [3:0] */
+#define WM8915_GP2_FN_WIDTH                          4  /* GP2_FN - [3:0] */
+
+/*
+ * R1794 (0x702) - GPIO 3
+ */
+#define WM8915_GP3_DIR                          0x8000  /* GP3_DIR */
+#define WM8915_GP3_DIR_MASK                     0x8000  /* GP3_DIR */
+#define WM8915_GP3_DIR_SHIFT                        15  /* GP3_DIR */
+#define WM8915_GP3_DIR_WIDTH                         1  /* GP3_DIR */
+#define WM8915_GP3_PU                           0x4000  /* GP3_PU */
+#define WM8915_GP3_PU_MASK                      0x4000  /* GP3_PU */
+#define WM8915_GP3_PU_SHIFT                         14  /* GP3_PU */
+#define WM8915_GP3_PU_WIDTH                          1  /* GP3_PU */
+#define WM8915_GP3_PD                           0x2000  /* GP3_PD */
+#define WM8915_GP3_PD_MASK                      0x2000  /* GP3_PD */
+#define WM8915_GP3_PD_SHIFT                         13  /* GP3_PD */
+#define WM8915_GP3_PD_WIDTH                          1  /* GP3_PD */
+#define WM8915_GP3_POL                          0x0400  /* GP3_POL */
+#define WM8915_GP3_POL_MASK                     0x0400  /* GP3_POL */
+#define WM8915_GP3_POL_SHIFT                        10  /* GP3_POL */
+#define WM8915_GP3_POL_WIDTH                         1  /* GP3_POL */
+#define WM8915_GP3_OP_CFG                       0x0200  /* GP3_OP_CFG */
+#define WM8915_GP3_OP_CFG_MASK                  0x0200  /* GP3_OP_CFG */
+#define WM8915_GP3_OP_CFG_SHIFT                      9  /* GP3_OP_CFG */
+#define WM8915_GP3_OP_CFG_WIDTH                      1  /* GP3_OP_CFG */
+#define WM8915_GP3_DB                           0x0100  /* GP3_DB */
+#define WM8915_GP3_DB_MASK                      0x0100  /* GP3_DB */
+#define WM8915_GP3_DB_SHIFT                          8  /* GP3_DB */
+#define WM8915_GP3_DB_WIDTH                          1  /* GP3_DB */
+#define WM8915_GP3_LVL                          0x0040  /* GP3_LVL */
+#define WM8915_GP3_LVL_MASK                     0x0040  /* GP3_LVL */
+#define WM8915_GP3_LVL_SHIFT                         6  /* GP3_LVL */
+#define WM8915_GP3_LVL_WIDTH                         1  /* GP3_LVL */
+#define WM8915_GP3_FN_MASK                      0x000F  /* GP3_FN - [3:0] */
+#define WM8915_GP3_FN_SHIFT                          0  /* GP3_FN - [3:0] */
+#define WM8915_GP3_FN_WIDTH                          4  /* GP3_FN - [3:0] */
+
+/*
+ * R1795 (0x703) - GPIO 4
+ */
+#define WM8915_GP4_DIR                          0x8000  /* GP4_DIR */
+#define WM8915_GP4_DIR_MASK                     0x8000  /* GP4_DIR */
+#define WM8915_GP4_DIR_SHIFT                        15  /* GP4_DIR */
+#define WM8915_GP4_DIR_WIDTH                         1  /* GP4_DIR */
+#define WM8915_GP4_PU                           0x4000  /* GP4_PU */
+#define WM8915_GP4_PU_MASK                      0x4000  /* GP4_PU */
+#define WM8915_GP4_PU_SHIFT                         14  /* GP4_PU */
+#define WM8915_GP4_PU_WIDTH                          1  /* GP4_PU */
+#define WM8915_GP4_PD                           0x2000  /* GP4_PD */
+#define WM8915_GP4_PD_MASK                      0x2000  /* GP4_PD */
+#define WM8915_GP4_PD_SHIFT                         13  /* GP4_PD */
+#define WM8915_GP4_PD_WIDTH                          1  /* GP4_PD */
+#define WM8915_GP4_POL                          0x0400  /* GP4_POL */
+#define WM8915_GP4_POL_MASK                     0x0400  /* GP4_POL */
+#define WM8915_GP4_POL_SHIFT                        10  /* GP4_POL */
+#define WM8915_GP4_POL_WIDTH                         1  /* GP4_POL */
+#define WM8915_GP4_OP_CFG                       0x0200  /* GP4_OP_CFG */
+#define WM8915_GP4_OP_CFG_MASK                  0x0200  /* GP4_OP_CFG */
+#define WM8915_GP4_OP_CFG_SHIFT                      9  /* GP4_OP_CFG */
+#define WM8915_GP4_OP_CFG_WIDTH                      1  /* GP4_OP_CFG */
+#define WM8915_GP4_DB                           0x0100  /* GP4_DB */
+#define WM8915_GP4_DB_MASK                      0x0100  /* GP4_DB */
+#define WM8915_GP4_DB_SHIFT                          8  /* GP4_DB */
+#define WM8915_GP4_DB_WIDTH                          1  /* GP4_DB */
+#define WM8915_GP4_LVL                          0x0040  /* GP4_LVL */
+#define WM8915_GP4_LVL_MASK                     0x0040  /* GP4_LVL */
+#define WM8915_GP4_LVL_SHIFT                         6  /* GP4_LVL */
+#define WM8915_GP4_LVL_WIDTH                         1  /* GP4_LVL */
+#define WM8915_GP4_FN_MASK                      0x000F  /* GP4_FN - [3:0] */
+#define WM8915_GP4_FN_SHIFT                          0  /* GP4_FN - [3:0] */
+#define WM8915_GP4_FN_WIDTH                          4  /* GP4_FN - [3:0] */
+
+/*
+ * R1796 (0x704) - GPIO 5
+ */
+#define WM8915_GP5_DIR                          0x8000  /* GP5_DIR */
+#define WM8915_GP5_DIR_MASK                     0x8000  /* GP5_DIR */
+#define WM8915_GP5_DIR_SHIFT                        15  /* GP5_DIR */
+#define WM8915_GP5_DIR_WIDTH                         1  /* GP5_DIR */
+#define WM8915_GP5_PU                           0x4000  /* GP5_PU */
+#define WM8915_GP5_PU_MASK                      0x4000  /* GP5_PU */
+#define WM8915_GP5_PU_SHIFT                         14  /* GP5_PU */
+#define WM8915_GP5_PU_WIDTH                          1  /* GP5_PU */
+#define WM8915_GP5_PD                           0x2000  /* GP5_PD */
+#define WM8915_GP5_PD_MASK                      0x2000  /* GP5_PD */
+#define WM8915_GP5_PD_SHIFT                         13  /* GP5_PD */
+#define WM8915_GP5_PD_WIDTH                          1  /* GP5_PD */
+#define WM8915_GP5_POL                          0x0400  /* GP5_POL */
+#define WM8915_GP5_POL_MASK                     0x0400  /* GP5_POL */
+#define WM8915_GP5_POL_SHIFT                        10  /* GP5_POL */
+#define WM8915_GP5_POL_WIDTH                         1  /* GP5_POL */
+#define WM8915_GP5_OP_CFG                       0x0200  /* GP5_OP_CFG */
+#define WM8915_GP5_OP_CFG_MASK                  0x0200  /* GP5_OP_CFG */
+#define WM8915_GP5_OP_CFG_SHIFT                      9  /* GP5_OP_CFG */
+#define WM8915_GP5_OP_CFG_WIDTH                      1  /* GP5_OP_CFG */
+#define WM8915_GP5_DB                           0x0100  /* GP5_DB */
+#define WM8915_GP5_DB_MASK                      0x0100  /* GP5_DB */
+#define WM8915_GP5_DB_SHIFT                          8  /* GP5_DB */
+#define WM8915_GP5_DB_WIDTH                          1  /* GP5_DB */
+#define WM8915_GP5_LVL                          0x0040  /* GP5_LVL */
+#define WM8915_GP5_LVL_MASK                     0x0040  /* GP5_LVL */
+#define WM8915_GP5_LVL_SHIFT                         6  /* GP5_LVL */
+#define WM8915_GP5_LVL_WIDTH                         1  /* GP5_LVL */
+#define WM8915_GP5_FN_MASK                      0x000F  /* GP5_FN - [3:0] */
+#define WM8915_GP5_FN_SHIFT                          0  /* GP5_FN - [3:0] */
+#define WM8915_GP5_FN_WIDTH                          4  /* GP5_FN - [3:0] */
+
+/*
+ * R1824 (0x720) - Pull Control (1)
+ */
+#define WM8915_DMICDAT2_PD                      0x1000  /* DMICDAT2_PD */
+#define WM8915_DMICDAT2_PD_MASK                 0x1000  /* DMICDAT2_PD */
+#define WM8915_DMICDAT2_PD_SHIFT                    12  /* DMICDAT2_PD */
+#define WM8915_DMICDAT2_PD_WIDTH                     1  /* DMICDAT2_PD */
+#define WM8915_DMICDAT1_PD                      0x0400  /* DMICDAT1_PD */
+#define WM8915_DMICDAT1_PD_MASK                 0x0400  /* DMICDAT1_PD */
+#define WM8915_DMICDAT1_PD_SHIFT                    10  /* DMICDAT1_PD */
+#define WM8915_DMICDAT1_PD_WIDTH                     1  /* DMICDAT1_PD */
+#define WM8915_MCLK2_PU                         0x0200  /* MCLK2_PU */
+#define WM8915_MCLK2_PU_MASK                    0x0200  /* MCLK2_PU */
+#define WM8915_MCLK2_PU_SHIFT                        9  /* MCLK2_PU */
+#define WM8915_MCLK2_PU_WIDTH                        1  /* MCLK2_PU */
+#define WM8915_MCLK2_PD                         0x0100  /* MCLK2_PD */
+#define WM8915_MCLK2_PD_MASK                    0x0100  /* MCLK2_PD */
+#define WM8915_MCLK2_PD_SHIFT                        8  /* MCLK2_PD */
+#define WM8915_MCLK2_PD_WIDTH                        1  /* MCLK2_PD */
+#define WM8915_MCLK1_PU                         0x0080  /* MCLK1_PU */
+#define WM8915_MCLK1_PU_MASK                    0x0080  /* MCLK1_PU */
+#define WM8915_MCLK1_PU_SHIFT                        7  /* MCLK1_PU */
+#define WM8915_MCLK1_PU_WIDTH                        1  /* MCLK1_PU */
+#define WM8915_MCLK1_PD                         0x0040  /* MCLK1_PD */
+#define WM8915_MCLK1_PD_MASK                    0x0040  /* MCLK1_PD */
+#define WM8915_MCLK1_PD_SHIFT                        6  /* MCLK1_PD */
+#define WM8915_MCLK1_PD_WIDTH                        1  /* MCLK1_PD */
+#define WM8915_DACDAT1_PU                       0x0020  /* DACDAT1_PU */
+#define WM8915_DACDAT1_PU_MASK                  0x0020  /* DACDAT1_PU */
+#define WM8915_DACDAT1_PU_SHIFT                      5  /* DACDAT1_PU */
+#define WM8915_DACDAT1_PU_WIDTH                      1  /* DACDAT1_PU */
+#define WM8915_DACDAT1_PD                       0x0010  /* DACDAT1_PD */
+#define WM8915_DACDAT1_PD_MASK                  0x0010  /* DACDAT1_PD */
+#define WM8915_DACDAT1_PD_SHIFT                      4  /* DACDAT1_PD */
+#define WM8915_DACDAT1_PD_WIDTH                      1  /* DACDAT1_PD */
+#define WM8915_DACLRCLK1_PU                     0x0008  /* DACLRCLK1_PU */
+#define WM8915_DACLRCLK1_PU_MASK                0x0008  /* DACLRCLK1_PU */
+#define WM8915_DACLRCLK1_PU_SHIFT                    3  /* DACLRCLK1_PU */
+#define WM8915_DACLRCLK1_PU_WIDTH                    1  /* DACLRCLK1_PU */
+#define WM8915_DACLRCLK1_PD                     0x0004  /* DACLRCLK1_PD */
+#define WM8915_DACLRCLK1_PD_MASK                0x0004  /* DACLRCLK1_PD */
+#define WM8915_DACLRCLK1_PD_SHIFT                    2  /* DACLRCLK1_PD */
+#define WM8915_DACLRCLK1_PD_WIDTH                    1  /* DACLRCLK1_PD */
+#define WM8915_BCLK1_PU                         0x0002  /* BCLK1_PU */
+#define WM8915_BCLK1_PU_MASK                    0x0002  /* BCLK1_PU */
+#define WM8915_BCLK1_PU_SHIFT                        1  /* BCLK1_PU */
+#define WM8915_BCLK1_PU_WIDTH                        1  /* BCLK1_PU */
+#define WM8915_BCLK1_PD                         0x0001  /* BCLK1_PD */
+#define WM8915_BCLK1_PD_MASK                    0x0001  /* BCLK1_PD */
+#define WM8915_BCLK1_PD_SHIFT                        0  /* BCLK1_PD */
+#define WM8915_BCLK1_PD_WIDTH                        1  /* BCLK1_PD */
+
+/*
+ * R1825 (0x721) - Pull Control (2)
+ */
+#define WM8915_LDO1ENA_PD                       0x0100  /* LDO1ENA_PD */
+#define WM8915_LDO1ENA_PD_MASK                  0x0100  /* LDO1ENA_PD */
+#define WM8915_LDO1ENA_PD_SHIFT                      8  /* LDO1ENA_PD */
+#define WM8915_LDO1ENA_PD_WIDTH                      1  /* LDO1ENA_PD */
+#define WM8915_ADDR_PD                          0x0040  /* ADDR_PD */
+#define WM8915_ADDR_PD_MASK                     0x0040  /* ADDR_PD */
+#define WM8915_ADDR_PD_SHIFT                         6  /* ADDR_PD */
+#define WM8915_ADDR_PD_WIDTH                         1  /* ADDR_PD */
+#define WM8915_DACDAT2_PU                       0x0020  /* DACDAT2_PU */
+#define WM8915_DACDAT2_PU_MASK                  0x0020  /* DACDAT2_PU */
+#define WM8915_DACDAT2_PU_SHIFT                      5  /* DACDAT2_PU */
+#define WM8915_DACDAT2_PU_WIDTH                      1  /* DACDAT2_PU */
+#define WM8915_DACDAT2_PD                       0x0010  /* DACDAT2_PD */
+#define WM8915_DACDAT2_PD_MASK                  0x0010  /* DACDAT2_PD */
+#define WM8915_DACDAT2_PD_SHIFT                      4  /* DACDAT2_PD */
+#define WM8915_DACDAT2_PD_WIDTH                      1  /* DACDAT2_PD */
+#define WM8915_DACLRCLK2_PU                     0x0008  /* DACLRCLK2_PU */
+#define WM8915_DACLRCLK2_PU_MASK                0x0008  /* DACLRCLK2_PU */
+#define WM8915_DACLRCLK2_PU_SHIFT                    3  /* DACLRCLK2_PU */
+#define WM8915_DACLRCLK2_PU_WIDTH                    1  /* DACLRCLK2_PU */
+#define WM8915_DACLRCLK2_PD                     0x0004  /* DACLRCLK2_PD */
+#define WM8915_DACLRCLK2_PD_MASK                0x0004  /* DACLRCLK2_PD */
+#define WM8915_DACLRCLK2_PD_SHIFT                    2  /* DACLRCLK2_PD */
+#define WM8915_DACLRCLK2_PD_WIDTH                    1  /* DACLRCLK2_PD */
+#define WM8915_BCLK2_PU                         0x0002  /* BCLK2_PU */
+#define WM8915_BCLK2_PU_MASK                    0x0002  /* BCLK2_PU */
+#define WM8915_BCLK2_PU_SHIFT                        1  /* BCLK2_PU */
+#define WM8915_BCLK2_PU_WIDTH                        1  /* BCLK2_PU */
+#define WM8915_BCLK2_PD                         0x0001  /* BCLK2_PD */
+#define WM8915_BCLK2_PD_MASK                    0x0001  /* BCLK2_PD */
+#define WM8915_BCLK2_PD_SHIFT                        0  /* BCLK2_PD */
+#define WM8915_BCLK2_PD_WIDTH                        1  /* BCLK2_PD */
+
+/*
+ * R1840 (0x730) - Interrupt Status 1
+ */
+#define WM8915_GP5_EINT                         0x0010  /* GP5_EINT */
+#define WM8915_GP5_EINT_MASK                    0x0010  /* GP5_EINT */
+#define WM8915_GP5_EINT_SHIFT                        4  /* GP5_EINT */
+#define WM8915_GP5_EINT_WIDTH                        1  /* GP5_EINT */
+#define WM8915_GP4_EINT                         0x0008  /* GP4_EINT */
+#define WM8915_GP4_EINT_MASK                    0x0008  /* GP4_EINT */
+#define WM8915_GP4_EINT_SHIFT                        3  /* GP4_EINT */
+#define WM8915_GP4_EINT_WIDTH                        1  /* GP4_EINT */
+#define WM8915_GP3_EINT                         0x0004  /* GP3_EINT */
+#define WM8915_GP3_EINT_MASK                    0x0004  /* GP3_EINT */
+#define WM8915_GP3_EINT_SHIFT                        2  /* GP3_EINT */
+#define WM8915_GP3_EINT_WIDTH                        1  /* GP3_EINT */
+#define WM8915_GP2_EINT                         0x0002  /* GP2_EINT */
+#define WM8915_GP2_EINT_MASK                    0x0002  /* GP2_EINT */
+#define WM8915_GP2_EINT_SHIFT                        1  /* GP2_EINT */
+#define WM8915_GP2_EINT_WIDTH                        1  /* GP2_EINT */
+#define WM8915_GP1_EINT                         0x0001  /* GP1_EINT */
+#define WM8915_GP1_EINT_MASK                    0x0001  /* GP1_EINT */
+#define WM8915_GP1_EINT_SHIFT                        0  /* GP1_EINT */
+#define WM8915_GP1_EINT_WIDTH                        1  /* GP1_EINT */
+
+/*
+ * R1841 (0x731) - Interrupt Status 2
+ */
+#define WM8915_DCS_DONE_23_EINT                 0x1000  /* DCS_DONE_23_EINT */
+#define WM8915_DCS_DONE_23_EINT_MASK            0x1000  /* DCS_DONE_23_EINT */
+#define WM8915_DCS_DONE_23_EINT_SHIFT               12  /* DCS_DONE_23_EINT */
+#define WM8915_DCS_DONE_23_EINT_WIDTH                1  /* DCS_DONE_23_EINT */
+#define WM8915_DCS_DONE_01_EINT                 0x0800  /* DCS_DONE_01_EINT */
+#define WM8915_DCS_DONE_01_EINT_MASK            0x0800  /* DCS_DONE_01_EINT */
+#define WM8915_DCS_DONE_01_EINT_SHIFT               11  /* DCS_DONE_01_EINT */
+#define WM8915_DCS_DONE_01_EINT_WIDTH                1  /* DCS_DONE_01_EINT */
+#define WM8915_WSEQ_DONE_EINT                   0x0400  /* WSEQ_DONE_EINT */
+#define WM8915_WSEQ_DONE_EINT_MASK              0x0400  /* WSEQ_DONE_EINT */
+#define WM8915_WSEQ_DONE_EINT_SHIFT                 10  /* WSEQ_DONE_EINT */
+#define WM8915_WSEQ_DONE_EINT_WIDTH                  1  /* WSEQ_DONE_EINT */
+#define WM8915_FIFOS_ERR_EINT                   0x0200  /* FIFOS_ERR_EINT */
+#define WM8915_FIFOS_ERR_EINT_MASK              0x0200  /* FIFOS_ERR_EINT */
+#define WM8915_FIFOS_ERR_EINT_SHIFT                  9  /* FIFOS_ERR_EINT */
+#define WM8915_FIFOS_ERR_EINT_WIDTH                  1  /* FIFOS_ERR_EINT */
+#define WM8915_DSP2DRC_SIG_DET_EINT             0x0080  /* DSP2DRC_SIG_DET_EINT */
+#define WM8915_DSP2DRC_SIG_DET_EINT_MASK        0x0080  /* DSP2DRC_SIG_DET_EINT */
+#define WM8915_DSP2DRC_SIG_DET_EINT_SHIFT            7  /* DSP2DRC_SIG_DET_EINT */
+#define WM8915_DSP2DRC_SIG_DET_EINT_WIDTH            1  /* DSP2DRC_SIG_DET_EINT */
+#define WM8915_DSP1DRC_SIG_DET_EINT             0x0040  /* DSP1DRC_SIG_DET_EINT */
+#define WM8915_DSP1DRC_SIG_DET_EINT_MASK        0x0040  /* DSP1DRC_SIG_DET_EINT */
+#define WM8915_DSP1DRC_SIG_DET_EINT_SHIFT            6  /* DSP1DRC_SIG_DET_EINT */
+#define WM8915_DSP1DRC_SIG_DET_EINT_WIDTH            1  /* DSP1DRC_SIG_DET_EINT */
+#define WM8915_FLL_SW_CLK_DONE_EINT             0x0008  /* FLL_SW_CLK_DONE_EINT */
+#define WM8915_FLL_SW_CLK_DONE_EINT_MASK        0x0008  /* FLL_SW_CLK_DONE_EINT */
+#define WM8915_FLL_SW_CLK_DONE_EINT_SHIFT            3  /* FLL_SW_CLK_DONE_EINT */
+#define WM8915_FLL_SW_CLK_DONE_EINT_WIDTH            1  /* FLL_SW_CLK_DONE_EINT */
+#define WM8915_FLL_LOCK_EINT                    0x0004  /* FLL_LOCK_EINT */
+#define WM8915_FLL_LOCK_EINT_MASK               0x0004  /* FLL_LOCK_EINT */
+#define WM8915_FLL_LOCK_EINT_SHIFT                   2  /* FLL_LOCK_EINT */
+#define WM8915_FLL_LOCK_EINT_WIDTH                   1  /* FLL_LOCK_EINT */
+#define WM8915_HP_DONE_EINT                     0x0002  /* HP_DONE_EINT */
+#define WM8915_HP_DONE_EINT_MASK                0x0002  /* HP_DONE_EINT */
+#define WM8915_HP_DONE_EINT_SHIFT                    1  /* HP_DONE_EINT */
+#define WM8915_HP_DONE_EINT_WIDTH                    1  /* HP_DONE_EINT */
+#define WM8915_MICD_EINT                        0x0001  /* MICD_EINT */
+#define WM8915_MICD_EINT_MASK                   0x0001  /* MICD_EINT */
+#define WM8915_MICD_EINT_SHIFT                       0  /* MICD_EINT */
+#define WM8915_MICD_EINT_WIDTH                       1  /* MICD_EINT */
+
+/*
+ * R1842 (0x732) - Interrupt Raw Status 2
+ */
+#define WM8915_DCS_DONE_23_STS                  0x1000  /* DCS_DONE_23_STS */
+#define WM8915_DCS_DONE_23_STS_MASK             0x1000  /* DCS_DONE_23_STS */
+#define WM8915_DCS_DONE_23_STS_SHIFT                12  /* DCS_DONE_23_STS */
+#define WM8915_DCS_DONE_23_STS_WIDTH                 1  /* DCS_DONE_23_STS */
+#define WM8915_DCS_DONE_01_STS                  0x0800  /* DCS_DONE_01_STS */
+#define WM8915_DCS_DONE_01_STS_MASK             0x0800  /* DCS_DONE_01_STS */
+#define WM8915_DCS_DONE_01_STS_SHIFT                11  /* DCS_DONE_01_STS */
+#define WM8915_DCS_DONE_01_STS_WIDTH                 1  /* DCS_DONE_01_STS */
+#define WM8915_WSEQ_DONE_STS                    0x0400  /* WSEQ_DONE_STS */
+#define WM8915_WSEQ_DONE_STS_MASK               0x0400  /* WSEQ_DONE_STS */
+#define WM8915_WSEQ_DONE_STS_SHIFT                  10  /* WSEQ_DONE_STS */
+#define WM8915_WSEQ_DONE_STS_WIDTH                   1  /* WSEQ_DONE_STS */
+#define WM8915_FIFOS_ERR_STS                    0x0200  /* FIFOS_ERR_STS */
+#define WM8915_FIFOS_ERR_STS_MASK               0x0200  /* FIFOS_ERR_STS */
+#define WM8915_FIFOS_ERR_STS_SHIFT                   9  /* FIFOS_ERR_STS */
+#define WM8915_FIFOS_ERR_STS_WIDTH                   1  /* FIFOS_ERR_STS */
+#define WM8915_DSP2DRC_SIG_DET_STS              0x0080  /* DSP2DRC_SIG_DET_STS */
+#define WM8915_DSP2DRC_SIG_DET_STS_MASK         0x0080  /* DSP2DRC_SIG_DET_STS */
+#define WM8915_DSP2DRC_SIG_DET_STS_SHIFT             7  /* DSP2DRC_SIG_DET_STS */
+#define WM8915_DSP2DRC_SIG_DET_STS_WIDTH             1  /* DSP2DRC_SIG_DET_STS */
+#define WM8915_DSP1DRC_SIG_DET_STS              0x0040  /* DSP1DRC_SIG_DET_STS */
+#define WM8915_DSP1DRC_SIG_DET_STS_MASK         0x0040  /* DSP1DRC_SIG_DET_STS */
+#define WM8915_DSP1DRC_SIG_DET_STS_SHIFT             6  /* DSP1DRC_SIG_DET_STS */
+#define WM8915_DSP1DRC_SIG_DET_STS_WIDTH             1  /* DSP1DRC_SIG_DET_STS */
+#define WM8915_FLL_LOCK_STS                     0x0004  /* FLL_LOCK_STS */
+#define WM8915_FLL_LOCK_STS_MASK                0x0004  /* FLL_LOCK_STS */
+#define WM8915_FLL_LOCK_STS_SHIFT                    2  /* FLL_LOCK_STS */
+#define WM8915_FLL_LOCK_STS_WIDTH                    1  /* FLL_LOCK_STS */
+
+/*
+ * R1848 (0x738) - Interrupt Status 1 Mask
+ */
+#define WM8915_IM_GP5_EINT                      0x0010  /* IM_GP5_EINT */
+#define WM8915_IM_GP5_EINT_MASK                 0x0010  /* IM_GP5_EINT */
+#define WM8915_IM_GP5_EINT_SHIFT                     4  /* IM_GP5_EINT */
+#define WM8915_IM_GP5_EINT_WIDTH                     1  /* IM_GP5_EINT */
+#define WM8915_IM_GP4_EINT                      0x0008  /* IM_GP4_EINT */
+#define WM8915_IM_GP4_EINT_MASK                 0x0008  /* IM_GP4_EINT */
+#define WM8915_IM_GP4_EINT_SHIFT                     3  /* IM_GP4_EINT */
+#define WM8915_IM_GP4_EINT_WIDTH                     1  /* IM_GP4_EINT */
+#define WM8915_IM_GP3_EINT                      0x0004  /* IM_GP3_EINT */
+#define WM8915_IM_GP3_EINT_MASK                 0x0004  /* IM_GP3_EINT */
+#define WM8915_IM_GP3_EINT_SHIFT                     2  /* IM_GP3_EINT */
+#define WM8915_IM_GP3_EINT_WIDTH                     1  /* IM_GP3_EINT */
+#define WM8915_IM_GP2_EINT                      0x0002  /* IM_GP2_EINT */
+#define WM8915_IM_GP2_EINT_MASK                 0x0002  /* IM_GP2_EINT */
+#define WM8915_IM_GP2_EINT_SHIFT                     1  /* IM_GP2_EINT */
+#define WM8915_IM_GP2_EINT_WIDTH                     1  /* IM_GP2_EINT */
+#define WM8915_IM_GP1_EINT                      0x0001  /* IM_GP1_EINT */
+#define WM8915_IM_GP1_EINT_MASK                 0x0001  /* IM_GP1_EINT */
+#define WM8915_IM_GP1_EINT_SHIFT                     0  /* IM_GP1_EINT */
+#define WM8915_IM_GP1_EINT_WIDTH                     1  /* IM_GP1_EINT */
+
+/*
+ * R1849 (0x739) - Interrupt Status 2 Mask
+ */
+#define WM8915_IM_DCS_DONE_23_EINT              0x1000  /* IM_DCS_DONE_23_EINT */
+#define WM8915_IM_DCS_DONE_23_EINT_MASK         0x1000  /* IM_DCS_DONE_23_EINT */
+#define WM8915_IM_DCS_DONE_23_EINT_SHIFT            12  /* IM_DCS_DONE_23_EINT */
+#define WM8915_IM_DCS_DONE_23_EINT_WIDTH             1  /* IM_DCS_DONE_23_EINT */
+#define WM8915_IM_DCS_DONE_01_EINT              0x0800  /* IM_DCS_DONE_01_EINT */
+#define WM8915_IM_DCS_DONE_01_EINT_MASK         0x0800  /* IM_DCS_DONE_01_EINT */
+#define WM8915_IM_DCS_DONE_01_EINT_SHIFT            11  /* IM_DCS_DONE_01_EINT */
+#define WM8915_IM_DCS_DONE_01_EINT_WIDTH             1  /* IM_DCS_DONE_01_EINT */
+#define WM8915_IM_WSEQ_DONE_EINT                0x0400  /* IM_WSEQ_DONE_EINT */
+#define WM8915_IM_WSEQ_DONE_EINT_MASK           0x0400  /* IM_WSEQ_DONE_EINT */
+#define WM8915_IM_WSEQ_DONE_EINT_SHIFT              10  /* IM_WSEQ_DONE_EINT */
+#define WM8915_IM_WSEQ_DONE_EINT_WIDTH               1  /* IM_WSEQ_DONE_EINT */
+#define WM8915_IM_FIFOS_ERR_EINT                0x0200  /* IM_FIFOS_ERR_EINT */
+#define WM8915_IM_FIFOS_ERR_EINT_MASK           0x0200  /* IM_FIFOS_ERR_EINT */
+#define WM8915_IM_FIFOS_ERR_EINT_SHIFT               9  /* IM_FIFOS_ERR_EINT */
+#define WM8915_IM_FIFOS_ERR_EINT_WIDTH               1  /* IM_FIFOS_ERR_EINT */
+#define WM8915_IM_DSP2DRC_SIG_DET_EINT          0x0080  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8915_IM_DSP2DRC_SIG_DET_EINT_MASK     0x0080  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8915_IM_DSP2DRC_SIG_DET_EINT_SHIFT         7  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8915_IM_DSP2DRC_SIG_DET_EINT_WIDTH         1  /* IM_DSP2DRC_SIG_DET_EINT */
+#define WM8915_IM_DSP1DRC_SIG_DET_EINT          0x0040  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8915_IM_DSP1DRC_SIG_DET_EINT_MASK     0x0040  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8915_IM_DSP1DRC_SIG_DET_EINT_SHIFT         6  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8915_IM_DSP1DRC_SIG_DET_EINT_WIDTH         1  /* IM_DSP1DRC_SIG_DET_EINT */
+#define WM8915_IM_FLL_SW_CLK_DONE_EINT          0x0008  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8915_IM_FLL_SW_CLK_DONE_EINT_MASK     0x0008  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8915_IM_FLL_SW_CLK_DONE_EINT_SHIFT         3  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8915_IM_FLL_SW_CLK_DONE_EINT_WIDTH         1  /* IM_FLL_SW_CLK_DONE_EINT */
+#define WM8915_IM_FLL_LOCK_EINT                 0x0004  /* IM_FLL_LOCK_EINT */
+#define WM8915_IM_FLL_LOCK_EINT_MASK            0x0004  /* IM_FLL_LOCK_EINT */
+#define WM8915_IM_FLL_LOCK_EINT_SHIFT                2  /* IM_FLL_LOCK_EINT */
+#define WM8915_IM_FLL_LOCK_EINT_WIDTH                1  /* IM_FLL_LOCK_EINT */
+#define WM8915_IM_HP_DONE_EINT                  0x0002  /* IM_HP_DONE_EINT */
+#define WM8915_IM_HP_DONE_EINT_MASK             0x0002  /* IM_HP_DONE_EINT */
+#define WM8915_IM_HP_DONE_EINT_SHIFT                 1  /* IM_HP_DONE_EINT */
+#define WM8915_IM_HP_DONE_EINT_WIDTH                 1  /* IM_HP_DONE_EINT */
+#define WM8915_IM_MICD_EINT                     0x0001  /* IM_MICD_EINT */
+#define WM8915_IM_MICD_EINT_MASK                0x0001  /* IM_MICD_EINT */
+#define WM8915_IM_MICD_EINT_SHIFT                    0  /* IM_MICD_EINT */
+#define WM8915_IM_MICD_EINT_WIDTH                    1  /* IM_MICD_EINT */
+
+/*
+ * R1856 (0x740) - Interrupt Control
+ */
+#define WM8915_IM_IRQ                           0x0001  /* IM_IRQ */
+#define WM8915_IM_IRQ_MASK                      0x0001  /* IM_IRQ */
+#define WM8915_IM_IRQ_SHIFT                          0  /* IM_IRQ */
+#define WM8915_IM_IRQ_WIDTH                          1  /* IM_IRQ */
+
+/*
+ * R2048 (0x800) - Left PDM Speaker
+ */
+#define WM8915_SPKL_ENA                         0x0010  /* SPKL_ENA */
+#define WM8915_SPKL_ENA_MASK                    0x0010  /* SPKL_ENA */
+#define WM8915_SPKL_ENA_SHIFT                        4  /* SPKL_ENA */
+#define WM8915_SPKL_ENA_WIDTH                        1  /* SPKL_ENA */
+#define WM8915_SPKL_MUTE                        0x0008  /* SPKL_MUTE */
+#define WM8915_SPKL_MUTE_MASK                   0x0008  /* SPKL_MUTE */
+#define WM8915_SPKL_MUTE_SHIFT                       3  /* SPKL_MUTE */
+#define WM8915_SPKL_MUTE_WIDTH                       1  /* SPKL_MUTE */
+#define WM8915_SPKL_MUTE_ZC                     0x0004  /* SPKL_MUTE_ZC */
+#define WM8915_SPKL_MUTE_ZC_MASK                0x0004  /* SPKL_MUTE_ZC */
+#define WM8915_SPKL_MUTE_ZC_SHIFT                    2  /* SPKL_MUTE_ZC */
+#define WM8915_SPKL_MUTE_ZC_WIDTH                    1  /* SPKL_MUTE_ZC */
+#define WM8915_SPKL_SRC_MASK                    0x0003  /* SPKL_SRC - [1:0] */
+#define WM8915_SPKL_SRC_SHIFT                        0  /* SPKL_SRC - [1:0] */
+#define WM8915_SPKL_SRC_WIDTH                        2  /* SPKL_SRC - [1:0] */
+
+/*
+ * R2049 (0x801) - Right PDM Speaker
+ */
+#define WM8915_SPKR_ENA                         0x0010  /* SPKR_ENA */
+#define WM8915_SPKR_ENA_MASK                    0x0010  /* SPKR_ENA */
+#define WM8915_SPKR_ENA_SHIFT                        4  /* SPKR_ENA */
+#define WM8915_SPKR_ENA_WIDTH                        1  /* SPKR_ENA */
+#define WM8915_SPKR_MUTE                        0x0008  /* SPKR_MUTE */
+#define WM8915_SPKR_MUTE_MASK                   0x0008  /* SPKR_MUTE */
+#define WM8915_SPKR_MUTE_SHIFT                       3  /* SPKR_MUTE */
+#define WM8915_SPKR_MUTE_WIDTH                       1  /* SPKR_MUTE */
+#define WM8915_SPKR_MUTE_ZC                     0x0004  /* SPKR_MUTE_ZC */
+#define WM8915_SPKR_MUTE_ZC_MASK                0x0004  /* SPKR_MUTE_ZC */
+#define WM8915_SPKR_MUTE_ZC_SHIFT                    2  /* SPKR_MUTE_ZC */
+#define WM8915_SPKR_MUTE_ZC_WIDTH                    1  /* SPKR_MUTE_ZC */
+#define WM8915_SPKR_SRC_MASK                    0x0003  /* SPKR_SRC - [1:0] */
+#define WM8915_SPKR_SRC_SHIFT                        0  /* SPKR_SRC - [1:0] */
+#define WM8915_SPKR_SRC_WIDTH                        2  /* SPKR_SRC - [1:0] */
+
+/*
+ * R2050 (0x802) - PDM Speaker Mute Sequence
+ */
+#define WM8915_SPK_MUTE_ENDIAN                  0x0100  /* SPK_MUTE_ENDIAN */
+#define WM8915_SPK_MUTE_ENDIAN_MASK             0x0100  /* SPK_MUTE_ENDIAN */
+#define WM8915_SPK_MUTE_ENDIAN_SHIFT                 8  /* SPK_MUTE_ENDIAN */
+#define WM8915_SPK_MUTE_ENDIAN_WIDTH                 1  /* SPK_MUTE_ENDIAN */
+#define WM8915_SPK_MUTE_SEQ1_MASK               0x00FF  /* SPK_MUTE_SEQ1 - [7:0] */
+#define WM8915_SPK_MUTE_SEQ1_SHIFT                   0  /* SPK_MUTE_SEQ1 - [7:0] */
+#define WM8915_SPK_MUTE_SEQ1_WIDTH                   8  /* SPK_MUTE_SEQ1 - [7:0] */
+
+/*
+ * R2051 (0x803) - PDM Speaker Volume
+ */
+#define WM8915_SPKR_VOL_MASK                    0x00F0  /* SPKR_VOL - [7:4] */
+#define WM8915_SPKR_VOL_SHIFT                        4  /* SPKR_VOL - [7:4] */
+#define WM8915_SPKR_VOL_WIDTH                        4  /* SPKR_VOL - [7:4] */
+#define WM8915_SPKL_VOL_MASK                    0x000F  /* SPKL_VOL - [3:0] */
+#define WM8915_SPKL_VOL_SHIFT                        0  /* SPKL_VOL - [3:0] */
+#define WM8915_SPKL_VOL_WIDTH                        4  /* SPKL_VOL - [3:0] */
+
+#endif

+ 1051 - 0
sound/soc/codecs/wm8958-dsp2.c

@@ -0,0 +1,1051 @@
+/*
+ * wm8958-dsp2.c  --  WM8958 DSP2 support
+ *
+ * Copyright 2011 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/slab.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <trace/events/asoc.h>
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+#include <linux/mfd/wm8994/pdata.h>
+#include <linux/mfd/wm8994/gpio.h>
+
+#include "wm8994.h"
+
+#define WM_FW_BLOCK_INFO 0xff
+#define WM_FW_BLOCK_PM   0x00
+#define WM_FW_BLOCK_X    0x01
+#define WM_FW_BLOCK_Y    0x02
+#define WM_FW_BLOCK_Z    0x03
+#define WM_FW_BLOCK_I    0x06
+#define WM_FW_BLOCK_A    0x08
+#define WM_FW_BLOCK_C    0x0c
+
+static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name,
+			  const struct firmware *fw, bool check)
+{
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	u64 data64;
+	u32 data32;
+	const u8 *data;
+	char *str;
+	size_t block_len, len;
+	int ret = 0;
+
+	/* Suppress unneeded downloads */
+	if (wm8994->cur_fw == fw)
+		return 0;
+
+	if (fw->size < 32) {
+		dev_err(codec->dev, "%s: firmware too short\n", name);
+		goto err;
+	}
+
+	if (memcmp(fw->data, "WMFW", 4) != 0) {
+		dev_err(codec->dev, "%s: firmware has bad file magic %08x\n",
+			name, data32);
+		goto err;
+	}
+
+	memcpy(&data32, fw->data + 4, sizeof(data32));
+	len = be32_to_cpu(data32);
+
+	memcpy(&data32, fw->data + 8, sizeof(data32));
+	data32 = be32_to_cpu(data32);
+	if ((data32 >> 24) & 0xff) {
+		dev_err(codec->dev, "%s: unsupported firmware version %d\n",
+			name, (data32 >> 24) & 0xff);
+		goto err;
+	}
+	if ((data32 & 0xffff) != 8958) {
+		dev_err(codec->dev, "%s: unsupported target device %d\n",
+			name, data32 & 0xffff);
+		goto err;
+	}
+	if (((data32 >> 16) & 0xff) != 0xc) {
+		dev_err(codec->dev, "%s: unsupported target core %d\n",
+			name, (data32 >> 16) & 0xff);
+		goto err;
+	}
+
+	if (check) {
+		memcpy(&data64, fw->data + 24, sizeof(u64));
+		dev_info(codec->dev, "%s timestamp %llx\n",
+			 name, be64_to_cpu(data64));
+	} else {
+		snd_soc_write(codec, 0x102, 0x2);
+		snd_soc_write(codec, 0x900, 0x2);
+	}
+
+	data = fw->data + len;
+	len = fw->size - len;
+	while (len) {
+		if (len < 12) {
+			dev_err(codec->dev, "%s short data block of %zd\n",
+				name, len);
+			goto err;
+		}
+
+		memcpy(&data32, data + 4, sizeof(data32));
+		block_len = be32_to_cpu(data32);
+		if (block_len + 8 > len) {
+			dev_err(codec->dev, "%zd byte block longer than file\n",
+				block_len);
+			goto err;
+		}
+		if (block_len == 0) {
+			dev_err(codec->dev, "Zero length block\n");
+			goto err;
+		}
+
+		memcpy(&data32, data, sizeof(data32));
+		data32 = be32_to_cpu(data32);
+
+		switch ((data32 >> 24) & 0xff) {
+		case WM_FW_BLOCK_INFO:
+			/* Informational text */
+			if (!check)
+				break;
+
+			str = kzalloc(block_len + 1, GFP_KERNEL);
+			if (str) {
+				memcpy(str, data + 8, block_len);
+				dev_info(codec->dev, "%s: %s\n", name, str);
+				kfree(str);
+			} else {
+				dev_err(codec->dev, "Out of memory\n");
+			}
+			break;
+		case WM_FW_BLOCK_PM:
+		case WM_FW_BLOCK_X:
+		case WM_FW_BLOCK_Y:
+		case WM_FW_BLOCK_Z:
+		case WM_FW_BLOCK_I:
+		case WM_FW_BLOCK_A:
+		case WM_FW_BLOCK_C:
+			dev_dbg(codec->dev, "%s: %zd bytes of %x@%x\n", name,
+				block_len, (data32 >> 24) & 0xff,
+				data32 & 0xffffff);
+
+			if (check)
+				break;
+
+			data32 &= 0xffffff;
+
+			wm8994_bulk_write(codec->control_data,
+					  data32 & 0xffffff,
+					  block_len / 2,
+					  (void *)(data + 8));
+
+			break;
+		default:
+			dev_warn(codec->dev, "%s: unknown block type %d\n",
+				 name, (data32 >> 24) & 0xff);
+			break;
+		}
+
+		/* Round up to the next 32 bit word */
+		block_len += block_len % 4;
+
+		data += block_len + 8;
+		len -= block_len + 8;
+	}
+
+	if (!check) {
+		dev_dbg(codec->dev, "%s: download done\n", name);
+		wm8994->cur_fw = fw;
+	} else {
+		dev_info(codec->dev, "%s: got firmware\n", name);
+	}
+
+	goto ok;
+
+err:
+	ret = -EINVAL;
+ok:
+	if (!check) {
+		snd_soc_write(codec, 0x900, 0x0);
+		snd_soc_write(codec, 0x102, 0x0);
+	}
+
+	return ret;
+}
+
+static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path)
+{
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_pdata *pdata = wm8994->pdata;
+	int i;
+
+	/* If the DSP is already running then noop */
+	if (snd_soc_read(codec, WM8958_DSP2_PROGRAM) & WM8958_DSP2_ENA)
+		return;
+
+	/* If we have MBC firmware download it */
+	if (wm8994->mbc)
+		wm8958_dsp2_fw(codec, "MBC", wm8994->mbc, false);
+
+	snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+			    WM8958_DSP2_ENA, WM8958_DSP2_ENA);
+
+	/* If we've got user supplied MBC settings use them */
+	if (pdata && pdata->num_mbc_cfgs) {
+		struct wm8958_mbc_cfg *cfg
+			= &pdata->mbc_cfgs[wm8994->mbc_cfg];
+
+		for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++)
+			snd_soc_write(codec, i + WM8958_MBC_BAND_1_K_1,
+				      cfg->coeff_regs[i]);
+
+		for (i = 0; i < ARRAY_SIZE(cfg->cutoff_regs); i++)
+			snd_soc_write(codec,
+				      i + WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1,
+				      cfg->cutoff_regs[i]);
+	}
+
+	/* Run the DSP */
+	snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
+		      WM8958_DSP2_RUNR);
+
+	/* And we're off! */
+	snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+			    WM8958_MBC_ENA |
+			    WM8958_MBC_SEL_MASK,
+			    path << WM8958_MBC_SEL_SHIFT |
+			    WM8958_MBC_ENA);
+}
+
+static void wm8958_dsp_start_vss(struct snd_soc_codec *codec, int path)
+{
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_pdata *pdata = wm8994->pdata;
+	int i, ena;
+
+	if (wm8994->mbc_vss)
+		wm8958_dsp2_fw(codec, "MBC+VSS", wm8994->mbc_vss, false);
+
+	snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+			    WM8958_DSP2_ENA, WM8958_DSP2_ENA);
+
+	/* If we've got user supplied settings use them */
+	if (pdata && pdata->num_mbc_cfgs) {
+		struct wm8958_mbc_cfg *cfg
+			= &pdata->mbc_cfgs[wm8994->mbc_cfg];
+
+		for (i = 0; i < ARRAY_SIZE(cfg->combined_regs); i++)
+			snd_soc_write(codec, i + 0x2800,
+				      cfg->combined_regs[i]);
+	}
+
+	if (pdata && pdata->num_vss_cfgs) {
+		struct wm8958_vss_cfg *cfg
+			= &pdata->vss_cfgs[wm8994->vss_cfg];
+
+		for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
+			snd_soc_write(codec, i + 0x2600, cfg->regs[i]);
+	}
+
+	if (pdata && pdata->num_vss_hpf_cfgs) {
+		struct wm8958_vss_hpf_cfg *cfg
+			= &pdata->vss_hpf_cfgs[wm8994->vss_hpf_cfg];
+
+		for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
+			snd_soc_write(codec, i + 0x2400, cfg->regs[i]);
+	}
+
+	/* Run the DSP */
+	snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
+		      WM8958_DSP2_RUNR);
+
+	/* Enable the algorithms we've selected */
+	ena = 0;
+	if (wm8994->mbc_ena[path])
+		ena |= 0x8;
+	if (wm8994->hpf2_ena[path])
+		ena |= 0x4;
+	if (wm8994->hpf1_ena[path])
+		ena |= 0x2;
+	if (wm8994->vss_ena[path])
+		ena |= 0x1;
+
+	snd_soc_write(codec, 0x2201, ena);
+
+	/* Switch the DSP into the data path */
+	snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+			    WM8958_MBC_SEL_MASK | WM8958_MBC_ENA,
+			    path << WM8958_MBC_SEL_SHIFT | WM8958_MBC_ENA);
+}
+
+static void wm8958_dsp_start_enh_eq(struct snd_soc_codec *codec, int path)
+{
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_pdata *pdata = wm8994->pdata;
+	int i;
+
+	wm8958_dsp2_fw(codec, "ENH_EQ", wm8994->enh_eq, false);
+
+	snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+			    WM8958_DSP2_ENA, WM8958_DSP2_ENA);
+
+	/* If we've got user supplied settings use them */
+	if (pdata && pdata->num_enh_eq_cfgs) {
+		struct wm8958_enh_eq_cfg *cfg
+			= &pdata->enh_eq_cfgs[wm8994->enh_eq_cfg];
+
+		for (i = 0; i < ARRAY_SIZE(cfg->regs); i++)
+			snd_soc_write(codec, i + 0x2200,
+				      cfg->regs[i]);
+	}
+
+	/* Run the DSP */
+	snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
+		      WM8958_DSP2_RUNR);
+
+	/* Switch the DSP into the data path */
+	snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+			    WM8958_MBC_SEL_MASK | WM8958_MBC_ENA,
+			    path << WM8958_MBC_SEL_SHIFT | WM8958_MBC_ENA);
+}
+
+static void wm8958_dsp_apply(struct snd_soc_codec *codec, int path, int start)
+{
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	int pwr_reg = snd_soc_read(codec, WM8994_POWER_MANAGEMENT_5);
+	int ena, reg, aif;
+
+	switch (path) {
+	case 0:
+		pwr_reg &= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA);
+		aif = 0;
+		break;
+	case 1:
+		pwr_reg &= (WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA);
+		aif = 0;
+		break;
+	case 2:
+		pwr_reg &= (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA);
+		aif = 1;
+		break;
+	default:
+		BUG();
+		return;
+	}
+
+	/* Do we have both an active AIF and an active algorithm? */
+	ena = wm8994->mbc_ena[path] || wm8994->vss_ena[path] ||
+		wm8994->hpf1_ena[path] || wm8994->hpf2_ena[path] ||
+		wm8994->enh_eq_ena[path];
+	if (!pwr_reg)
+		ena = 0;
+
+	reg = snd_soc_read(codec, WM8958_DSP2_PROGRAM);
+
+	dev_dbg(codec->dev, "DSP path %d %d startup: %d, power: %x, DSP: %x\n",
+		path, wm8994->dsp_active, start, pwr_reg, reg);
+
+	if (start && ena) {
+		/* If the DSP is already running then noop */
+		if (reg & WM8958_DSP2_ENA)
+			return;
+
+		/* If either AIFnCLK is not yet enabled postpone */
+		if (!(snd_soc_read(codec, WM8994_AIF1_CLOCKING_1)
+		      & WM8994_AIF1CLK_ENA_MASK) &&
+		    !(snd_soc_read(codec, WM8994_AIF2_CLOCKING_1)
+		      & WM8994_AIF2CLK_ENA_MASK))
+			return;
+
+		/* Switch the clock over to the appropriate AIF */
+		snd_soc_update_bits(codec, WM8994_CLOCKING_1,
+				    WM8958_DSP2CLK_SRC | WM8958_DSP2CLK_ENA,
+				    aif << WM8958_DSP2CLK_SRC_SHIFT |
+				    WM8958_DSP2CLK_ENA);
+
+		if (wm8994->enh_eq_ena[path])
+			wm8958_dsp_start_enh_eq(codec, path);
+		else if (wm8994->vss_ena[path] || wm8994->hpf1_ena[path] ||
+		    wm8994->hpf2_ena[path])
+			wm8958_dsp_start_vss(codec, path);
+		else if (wm8994->mbc_ena[path])
+			wm8958_dsp_start_mbc(codec, path);
+
+		wm8994->dsp_active = path;
+
+		dev_dbg(codec->dev, "DSP running in path %d\n", path);
+	}
+
+	if (!start && wm8994->dsp_active == path) {
+		/* If the DSP is already stopped then noop */
+		if (!(reg & WM8958_DSP2_ENA))
+			return;
+
+		snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
+				    WM8958_MBC_ENA, 0);	
+		snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
+			      WM8958_DSP2_STOP);
+		snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
+				    WM8958_DSP2_ENA, 0);
+		snd_soc_update_bits(codec, WM8994_CLOCKING_1,
+				    WM8958_DSP2CLK_ENA, 0);
+
+		wm8994->dsp_active = -1;
+
+		dev_dbg(codec->dev, "DSP stopped\n");
+	}
+}
+
+int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
+		  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	int i;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+	case SND_SOC_DAPM_PRE_PMU:
+		for (i = 0; i < 3; i++)
+			wm8958_dsp_apply(codec, i, 1);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+	case SND_SOC_DAPM_PRE_PMD:
+		for (i = 0; i < 3; i++)
+			wm8958_dsp_apply(codec, i, 0);
+		break;
+	}
+
+	return 0;
+}
+
+/* Check if DSP2 is in use on another AIF */
+static int wm8958_dsp2_busy(struct wm8994_priv *wm8994, int aif)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(wm8994->mbc_ena); i++) {
+		if (i == aif)
+			continue;
+		if (wm8994->mbc_ena[i] || wm8994->vss_ena[i] ||
+		    wm8994->hpf1_ena[i] || wm8994->hpf2_ena[i])
+			return 1;
+	}
+
+	return 0;
+}
+
+static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_pdata *pdata = wm8994->pdata;
+	int value = ucontrol->value.integer.value[0];
+	int reg;
+
+	/* Don't allow on the fly reconfiguration */
+	reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
+		return -EBUSY;
+
+	if (value >= pdata->num_mbc_cfgs)
+		return -EINVAL;
+
+	wm8994->mbc_cfg = value;
+
+	return 0;
+}
+
+static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg;
+
+	return 0;
+}
+
+static int wm8958_mbc_info(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int wm8958_mbc_get(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int mbc = kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc];
+
+	return 0;
+}
+
+static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int mbc = kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	if (wm8994->mbc_ena[mbc] == ucontrol->value.integer.value[0])
+		return 0;
+
+	if (ucontrol->value.integer.value[0] > 1)
+		return -EINVAL;
+
+	if (wm8958_dsp2_busy(wm8994, mbc)) {
+		dev_dbg(codec->dev, "DSP2 active on %d already\n", mbc);
+		return -EBUSY;
+	}
+
+	if (wm8994->enh_eq_ena[mbc])
+		return -EBUSY;
+
+	wm8994->mbc_ena[mbc] = ucontrol->value.integer.value[0];
+
+	wm8958_dsp_apply(codec, mbc, wm8994->mbc_ena[mbc]);
+
+	return 0;
+}
+
+#define WM8958_MBC_SWITCH(xname, xval) {\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+	.info = wm8958_mbc_info, \
+	.get = wm8958_mbc_get, .put = wm8958_mbc_put, \
+	.private_value = xval }
+
+static int wm8958_put_vss_enum(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_pdata *pdata = wm8994->pdata;
+	int value = ucontrol->value.integer.value[0];
+	int reg;
+
+	/* Don't allow on the fly reconfiguration */
+	reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
+		return -EBUSY;
+
+	if (value >= pdata->num_vss_cfgs)
+		return -EINVAL;
+
+	wm8994->vss_cfg = value;
+
+	return 0;
+}
+
+static int wm8958_get_vss_enum(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.enumerated.item[0] = wm8994->vss_cfg;
+
+	return 0;
+}
+
+static int wm8958_put_vss_hpf_enum(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_pdata *pdata = wm8994->pdata;
+	int value = ucontrol->value.integer.value[0];
+	int reg;
+
+	/* Don't allow on the fly reconfiguration */
+	reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
+		return -EBUSY;
+
+	if (value >= pdata->num_vss_hpf_cfgs)
+		return -EINVAL;
+
+	wm8994->vss_hpf_cfg = value;
+
+	return 0;
+}
+
+static int wm8958_get_vss_hpf_enum(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.enumerated.item[0] = wm8994->vss_hpf_cfg;
+
+	return 0;
+}
+
+static int wm8958_vss_info(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int wm8958_vss_get(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int vss = kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = wm8994->vss_ena[vss];
+
+	return 0;
+}
+
+static int wm8958_vss_put(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int vss = kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	if (wm8994->vss_ena[vss] == ucontrol->value.integer.value[0])
+		return 0;
+
+	if (ucontrol->value.integer.value[0] > 1)
+		return -EINVAL;
+
+	if (!wm8994->mbc_vss)
+		return -ENODEV;
+
+	if (wm8958_dsp2_busy(wm8994, vss)) {
+		dev_dbg(codec->dev, "DSP2 active on %d already\n", vss);
+		return -EBUSY;
+	}
+
+	if (wm8994->enh_eq_ena[vss])
+		return -EBUSY;
+
+	wm8994->vss_ena[vss] = ucontrol->value.integer.value[0];
+
+	wm8958_dsp_apply(codec, vss, wm8994->vss_ena[vss]);
+
+	return 0;
+}
+
+
+#define WM8958_VSS_SWITCH(xname, xval) {\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+	.info = wm8958_vss_info, \
+	.get = wm8958_vss_get, .put = wm8958_vss_put, \
+	.private_value = xval }
+
+static int wm8958_hpf_info(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int wm8958_hpf_get(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int hpf = kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	if (hpf < 3)
+		ucontrol->value.integer.value[0] = wm8994->hpf1_ena[hpf % 3];
+	else
+		ucontrol->value.integer.value[0] = wm8994->hpf2_ena[hpf % 3];
+
+	return 0;
+}
+
+static int wm8958_hpf_put(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int hpf = kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	if (hpf < 3) {
+		if (wm8994->hpf1_ena[hpf % 3] ==
+		    ucontrol->value.integer.value[0])
+			return 0;
+	} else {
+		if (wm8994->hpf2_ena[hpf % 3] ==
+		    ucontrol->value.integer.value[0])
+			return 0;
+	}
+
+	if (ucontrol->value.integer.value[0] > 1)
+		return -EINVAL;
+
+	if (!wm8994->mbc_vss)
+		return -ENODEV;
+
+	if (wm8958_dsp2_busy(wm8994, hpf % 3)) {
+		dev_dbg(codec->dev, "DSP2 active on %d already\n", hpf);
+		return -EBUSY;
+	}
+
+	if (wm8994->enh_eq_ena[hpf % 3])
+		return -EBUSY;
+
+	if (hpf < 3)
+		wm8994->hpf1_ena[hpf % 3] = ucontrol->value.integer.value[0];
+	else
+		wm8994->hpf2_ena[hpf % 3] = ucontrol->value.integer.value[0];
+
+	wm8958_dsp_apply(codec, hpf % 3, ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+#define WM8958_HPF_SWITCH(xname, xval) {\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+	.info = wm8958_hpf_info, \
+	.get = wm8958_hpf_get, .put = wm8958_hpf_put, \
+	.private_value = xval }
+
+static int wm8958_put_enh_eq_enum(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_pdata *pdata = wm8994->pdata;
+	int value = ucontrol->value.integer.value[0];
+	int reg;
+
+	/* Don't allow on the fly reconfiguration */
+	reg = snd_soc_read(codec, WM8994_CLOCKING_1);
+	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
+		return -EBUSY;
+
+	if (value >= pdata->num_enh_eq_cfgs)
+		return -EINVAL;
+
+	wm8994->enh_eq_cfg = value;
+
+	return 0;
+}
+
+static int wm8958_get_enh_eq_enum(struct snd_kcontrol *kcontrol,
+				  struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.enumerated.item[0] = wm8994->enh_eq_cfg;
+
+	return 0;
+}
+
+static int wm8958_enh_eq_info(struct snd_kcontrol *kcontrol,
+			   struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 1;
+	return 0;
+}
+
+static int wm8958_enh_eq_get(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int eq = kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	ucontrol->value.integer.value[0] = wm8994->enh_eq_ena[eq];
+
+	return 0;
+}
+
+static int wm8958_enh_eq_put(struct snd_kcontrol *kcontrol,
+			  struct snd_ctl_elem_value *ucontrol)
+{
+	int eq = kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	if (wm8994->enh_eq_ena[eq] == ucontrol->value.integer.value[0])
+		return 0;
+
+	if (ucontrol->value.integer.value[0] > 1)
+		return -EINVAL;
+
+	if (!wm8994->enh_eq)
+		return -ENODEV;
+
+	if (wm8958_dsp2_busy(wm8994, eq)) {
+		dev_dbg(codec->dev, "DSP2 active on %d already\n", eq);
+		return -EBUSY;
+	}
+
+	if (wm8994->mbc_ena[eq] || wm8994->vss_ena[eq] ||
+	    wm8994->hpf1_ena[eq] || wm8994->hpf2_ena[eq])
+		return -EBUSY;
+
+	wm8994->enh_eq_ena[eq] = ucontrol->value.integer.value[0];
+
+	wm8958_dsp_apply(codec, eq, ucontrol->value.integer.value[0]);
+
+	return 0;
+}
+
+#define WM8958_ENH_EQ_SWITCH(xname, xval) {\
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+	.info = wm8958_enh_eq_info, \
+	.get = wm8958_enh_eq_get, .put = wm8958_enh_eq_put, \
+	.private_value = xval }
+
+static const struct snd_kcontrol_new wm8958_mbc_snd_controls[] = {
+WM8958_MBC_SWITCH("AIF1DAC1 MBC Switch", 0),
+WM8958_MBC_SWITCH("AIF1DAC2 MBC Switch", 1),
+WM8958_MBC_SWITCH("AIF2DAC MBC Switch", 2),
+};
+
+static const struct snd_kcontrol_new wm8958_vss_snd_controls[] = {
+WM8958_VSS_SWITCH("AIF1DAC1 VSS Switch", 0),
+WM8958_VSS_SWITCH("AIF1DAC2 VSS Switch", 1),
+WM8958_VSS_SWITCH("AIF2DAC VSS Switch", 2),
+WM8958_HPF_SWITCH("AIF1DAC1 HPF1 Switch", 0),
+WM8958_HPF_SWITCH("AIF1DAC2 HPF1 Switch", 1),
+WM8958_HPF_SWITCH("AIF2DAC HPF1 Switch", 2),
+WM8958_HPF_SWITCH("AIF1DAC1 HPF2 Switch", 3),
+WM8958_HPF_SWITCH("AIF1DAC2 HPF2 Switch", 4),
+WM8958_HPF_SWITCH("AIF2DAC HPF2 Switch", 5),
+};
+
+static const struct snd_kcontrol_new wm8958_enh_eq_snd_controls[] = {
+WM8958_ENH_EQ_SWITCH("AIF1DAC1 Enhanced EQ Switch", 0),
+WM8958_ENH_EQ_SWITCH("AIF1DAC2 Enhanced EQ Switch", 1),
+WM8958_ENH_EQ_SWITCH("AIF2DAC Enhanced EQ Switch", 2),
+};
+
+static void wm8958_enh_eq_loaded(const struct firmware *fw, void *context)
+{
+	struct snd_soc_codec *codec = context;
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	if (fw && (wm8958_dsp2_fw(codec, "ENH_EQ", fw, true) == 0)) {
+		mutex_lock(&codec->mutex);
+		wm8994->enh_eq = fw;
+		mutex_unlock(&codec->mutex);
+	}
+}
+
+static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context)
+{
+	struct snd_soc_codec *codec = context;
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	if (fw && (wm8958_dsp2_fw(codec, "MBC+VSS", fw, true) == 0)) {
+		mutex_lock(&codec->mutex);
+		wm8994->mbc_vss = fw;
+		mutex_unlock(&codec->mutex);
+	}
+
+	/* We can't have more than one request outstanding at once so
+	 * we daisy chain.
+	 */
+	request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+				"wm8958_enh_eq.wfw", codec->dev, GFP_KERNEL,
+				codec, wm8958_enh_eq_loaded);
+}
+
+static void wm8958_mbc_loaded(const struct firmware *fw, void *context)
+{
+	struct snd_soc_codec *codec = context;
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+
+	if (wm8958_dsp2_fw(codec, "MBC", fw, true) != 0)
+		return;
+
+	mutex_lock(&codec->mutex);
+	wm8994->mbc = fw;
+	mutex_unlock(&codec->mutex);
+
+	/* We can't have more than one request outstanding at once so
+	 * we daisy chain.
+	 */
+	request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+				"wm8958_mbc_vss.wfw", codec->dev, GFP_KERNEL,
+				codec, wm8958_mbc_vss_loaded);
+}
+
+void wm8958_dsp2_init(struct snd_soc_codec *codec)
+{
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994_pdata *pdata = wm8994->pdata;
+	int ret, i;
+
+	wm8994->dsp_active = -1;
+
+	snd_soc_add_controls(codec, wm8958_mbc_snd_controls,
+			     ARRAY_SIZE(wm8958_mbc_snd_controls));
+	snd_soc_add_controls(codec, wm8958_vss_snd_controls,
+			     ARRAY_SIZE(wm8958_vss_snd_controls));
+	snd_soc_add_controls(codec, wm8958_enh_eq_snd_controls,
+			     ARRAY_SIZE(wm8958_enh_eq_snd_controls));
+
+
+	/* We don't *require* firmware and don't want to delay boot */
+	request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
+				"wm8958_mbc.wfw", codec->dev, GFP_KERNEL,
+				codec, wm8958_mbc_loaded);
+
+	if (!pdata)
+		return;
+
+	if (pdata->num_mbc_cfgs) {
+		struct snd_kcontrol_new control[] = {
+			SOC_ENUM_EXT("MBC Mode", wm8994->mbc_enum,
+				     wm8958_get_mbc_enum, wm8958_put_mbc_enum),
+		};
+
+		/* We need an array of texts for the enum API */
+		wm8994->mbc_texts = kmalloc(sizeof(char *)
+					    * pdata->num_mbc_cfgs, GFP_KERNEL);
+		if (!wm8994->mbc_texts) {
+			dev_err(wm8994->codec->dev,
+				"Failed to allocate %d MBC config texts\n",
+				pdata->num_mbc_cfgs);
+			return;
+		}
+
+		for (i = 0; i < pdata->num_mbc_cfgs; i++)
+			wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name;
+
+		wm8994->mbc_enum.max = pdata->num_mbc_cfgs;
+		wm8994->mbc_enum.texts = wm8994->mbc_texts;
+
+		ret = snd_soc_add_controls(wm8994->codec, control, 1);
+		if (ret != 0)
+			dev_err(wm8994->codec->dev,
+				"Failed to add MBC mode controls: %d\n", ret);
+	}
+
+	if (pdata->num_vss_cfgs) {
+		struct snd_kcontrol_new control[] = {
+			SOC_ENUM_EXT("VSS Mode", wm8994->vss_enum,
+				     wm8958_get_vss_enum, wm8958_put_vss_enum),
+		};
+
+		/* We need an array of texts for the enum API */
+		wm8994->vss_texts = kmalloc(sizeof(char *)
+					    * pdata->num_vss_cfgs, GFP_KERNEL);
+		if (!wm8994->vss_texts) {
+			dev_err(wm8994->codec->dev,
+				"Failed to allocate %d VSS config texts\n",
+				pdata->num_vss_cfgs);
+			return;
+		}
+
+		for (i = 0; i < pdata->num_vss_cfgs; i++)
+			wm8994->vss_texts[i] = pdata->vss_cfgs[i].name;
+
+		wm8994->vss_enum.max = pdata->num_vss_cfgs;
+		wm8994->vss_enum.texts = wm8994->vss_texts;
+
+		ret = snd_soc_add_controls(wm8994->codec, control, 1);
+		if (ret != 0)
+			dev_err(wm8994->codec->dev,
+				"Failed to add VSS mode controls: %d\n", ret);
+	}
+
+	if (pdata->num_vss_hpf_cfgs) {
+		struct snd_kcontrol_new control[] = {
+			SOC_ENUM_EXT("VSS HPF Mode", wm8994->vss_hpf_enum,
+				     wm8958_get_vss_hpf_enum,
+				     wm8958_put_vss_hpf_enum),
+		};
+
+		/* We need an array of texts for the enum API */
+		wm8994->vss_hpf_texts = kmalloc(sizeof(char *)
+						* pdata->num_vss_hpf_cfgs, GFP_KERNEL);
+		if (!wm8994->vss_hpf_texts) {
+			dev_err(wm8994->codec->dev,
+				"Failed to allocate %d VSS HPF config texts\n",
+				pdata->num_vss_hpf_cfgs);
+			return;
+		}
+
+		for (i = 0; i < pdata->num_vss_hpf_cfgs; i++)
+			wm8994->vss_hpf_texts[i] = pdata->vss_hpf_cfgs[i].name;
+
+		wm8994->vss_hpf_enum.max = pdata->num_vss_hpf_cfgs;
+		wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts;
+
+		ret = snd_soc_add_controls(wm8994->codec, control, 1);
+		if (ret != 0)
+			dev_err(wm8994->codec->dev,
+				"Failed to add VSS HPFmode controls: %d\n",
+				ret);
+	}
+
+	if (pdata->num_enh_eq_cfgs) {
+		struct snd_kcontrol_new control[] = {
+			SOC_ENUM_EXT("Enhanced EQ Mode", wm8994->enh_eq_enum,
+				     wm8958_get_enh_eq_enum,
+				     wm8958_put_enh_eq_enum),
+		};
+
+		/* We need an array of texts for the enum API */
+		wm8994->enh_eq_texts = kmalloc(sizeof(char *)
+						* pdata->num_enh_eq_cfgs, GFP_KERNEL);
+		if (!wm8994->enh_eq_texts) {
+			dev_err(wm8994->codec->dev,
+				"Failed to allocate %d enhanced EQ config texts\n",
+				pdata->num_enh_eq_cfgs);
+			return;
+		}
+
+		for (i = 0; i < pdata->num_enh_eq_cfgs; i++)
+			wm8994->enh_eq_texts[i] = pdata->enh_eq_cfgs[i].name;
+
+		wm8994->enh_eq_enum.max = pdata->num_enh_eq_cfgs;
+		wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts;
+
+		ret = snd_soc_add_controls(wm8994->codec, control, 1);
+		if (ret != 0)
+			dev_err(wm8994->codec->dev,
+				"Failed to add enhanced EQ controls: %d\n",
+				ret);
+	}
+}

+ 58 - 5
sound/soc/codecs/wm8962.c

@@ -58,6 +58,7 @@ struct wm8962_priv {
 	int bclk;  /* Desired BCLK */
 	int bclk;  /* Desired BCLK */
 	int lrclk;
 	int lrclk;
 
 
+	struct completion fll_lock;
 	int fll_src;
 	int fll_src;
 	int fll_fref;
 	int fll_fref;
 	int fll_fout;
 	int fll_fout;
@@ -2038,6 +2039,13 @@ static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol,
 	return 0;
 	return 0;
 }
 }
 
 
+static const char *cap_hpf_mode_text[] = {
+	"Hi-fi", "Application"
+};
+
+static const struct soc_enum cap_hpf_mode =
+	SOC_ENUM_SINGLE(WM8962_ADC_DAC_CONTROL_2, 10, 2, cap_hpf_mode_text);
+
 static const struct snd_kcontrol_new wm8962_snd_controls[] = {
 static const struct snd_kcontrol_new wm8962_snd_controls[] = {
 SOC_DOUBLE("Input Mixer Switch", WM8962_INPUT_MIXER_CONTROL_1, 3, 2, 1, 1),
 SOC_DOUBLE("Input Mixer Switch", WM8962_INPUT_MIXER_CONTROL_1, 3, 2, 1, 1),
 
 
@@ -2063,6 +2071,9 @@ SOC_DOUBLE_R("Capture Switch", WM8962_LEFT_INPUT_VOLUME,
 	     WM8962_RIGHT_INPUT_VOLUME, 7, 1, 1),
 	     WM8962_RIGHT_INPUT_VOLUME, 7, 1, 1),
 SOC_DOUBLE_R("Capture ZC Switch", WM8962_LEFT_INPUT_VOLUME,
 SOC_DOUBLE_R("Capture ZC Switch", WM8962_LEFT_INPUT_VOLUME,
 	     WM8962_RIGHT_INPUT_VOLUME, 6, 1, 1),
 	     WM8962_RIGHT_INPUT_VOLUME, 6, 1, 1),
+SOC_SINGLE("Capture HPF Switch", WM8962_ADC_DAC_CONTROL_1, 0, 1, 1),
+SOC_ENUM("Capture HPF Mode", cap_hpf_mode),
+SOC_SINGLE("Capture HPF Cutoff", WM8962_ADC_DAC_CONTROL_2, 7, 7, 0),
 
 
 SOC_DOUBLE_R_TLV("Sidetone Volume", WM8962_DAC_DSP_MIXING_1,
 SOC_DOUBLE_R_TLV("Sidetone Volume", WM8962_DAC_DSP_MIXING_1,
 		 WM8962_DAC_DSP_MIXING_2, 4, 12, 0, st_tlv),
 		 WM8962_DAC_DSP_MIXING_2, 4, 12, 0, st_tlv),
@@ -2467,6 +2478,7 @@ SND_SOC_DAPM_INPUT("IN3R"),
 SND_SOC_DAPM_INPUT("IN4L"),
 SND_SOC_DAPM_INPUT("IN4L"),
 SND_SOC_DAPM_INPUT("IN4R"),
 SND_SOC_DAPM_INPUT("IN4R"),
 SND_SOC_DAPM_INPUT("Beep"),
 SND_SOC_DAPM_INPUT("Beep"),
+SND_SOC_DAPM_INPUT("DMICDAT"),
 
 
 SND_SOC_DAPM_MICBIAS("MICBIAS", WM8962_PWR_MGMT_1, 1, 0),
 SND_SOC_DAPM_MICBIAS("MICBIAS", WM8962_PWR_MGMT_1, 1, 0),
 
 
@@ -2486,6 +2498,8 @@ SND_SOC_DAPM_MIXER("MIXINL", WM8962_PWR_MGMT_1, 5, 0,
 SND_SOC_DAPM_MIXER("MIXINR", WM8962_PWR_MGMT_1, 4, 0,
 SND_SOC_DAPM_MIXER("MIXINR", WM8962_PWR_MGMT_1, 4, 0,
 		   mixinr, ARRAY_SIZE(mixinr)),
 		   mixinr, ARRAY_SIZE(mixinr)),
 
 
+SND_SOC_DAPM_AIF_IN("DMIC", NULL, 0, WM8962_PWR_MGMT_1, 10, 0),
+
 SND_SOC_DAPM_ADC("ADCL", "Capture", WM8962_PWR_MGMT_1, 3, 0),
 SND_SOC_DAPM_ADC("ADCL", "Capture", WM8962_PWR_MGMT_1, 3, 0),
 SND_SOC_DAPM_ADC("ADCR", "Capture", WM8962_PWR_MGMT_1, 2, 0),
 SND_SOC_DAPM_ADC("ADCR", "Capture", WM8962_PWR_MGMT_1, 2, 0),
 
 
@@ -2563,13 +2577,17 @@ static const struct snd_soc_dapm_route wm8962_intercon[] = {
 
 
 	{ "MICBIAS", NULL, "SYSCLK" },
 	{ "MICBIAS", NULL, "SYSCLK" },
 
 
+	{ "DMIC", NULL, "DMICDAT" },
+
 	{ "ADCL", NULL, "SYSCLK" },
 	{ "ADCL", NULL, "SYSCLK" },
 	{ "ADCL", NULL, "TOCLK" },
 	{ "ADCL", NULL, "TOCLK" },
 	{ "ADCL", NULL, "MIXINL" },
 	{ "ADCL", NULL, "MIXINL" },
+	{ "ADCL", NULL, "DMIC" },
 
 
 	{ "ADCR", NULL, "SYSCLK" },
 	{ "ADCR", NULL, "SYSCLK" },
 	{ "ADCR", NULL, "TOCLK" },
 	{ "ADCR", NULL, "TOCLK" },
 	{ "ADCR", NULL, "MIXINR" },
 	{ "ADCR", NULL, "MIXINR" },
+	{ "ADCR", NULL, "DMIC" },
 
 
 	{ "STL", "Left", "ADCL" },
 	{ "STL", "Left", "ADCL" },
 	{ "STL", "Right", "ADCR" },
 	{ "STL", "Right", "ADCR" },
@@ -2990,7 +3008,6 @@ static int wm8962_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
 	case WM8962_SYSCLK_FLL:
 	case WM8962_SYSCLK_FLL:
 		wm8962->sysclk = WM8962_SYSCLK_FLL;
 		wm8962->sysclk = WM8962_SYSCLK_FLL;
 		src = 1 << WM8962_SYSCLK_SRC_SHIFT;
 		src = 1 << WM8962_SYSCLK_SRC_SHIFT;
-		WARN_ON(freq != wm8962->fll_fout);
 		break;
 		break;
 	default:
 	default:
 		return -EINVAL;
 		return -EINVAL;
@@ -3172,12 +3189,12 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
 	return 0;
 	return 0;
 }
 }
 
 
-static int wm8962_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
+static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
 			  unsigned int Fref, unsigned int Fout)
 			  unsigned int Fref, unsigned int Fout)
 {
 {
-	struct snd_soc_codec *codec = dai->codec;
 	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
 	struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
 	struct _fll_div fll_div;
 	struct _fll_div fll_div;
+	unsigned long timeout;
 	int ret;
 	int ret;
 	int fll1 = snd_soc_read(codec, WM8962_FLL_CONTROL_1) & WM8962_FLL_ENA;
 	int fll1 = snd_soc_read(codec, WM8962_FLL_CONTROL_1) & WM8962_FLL_ENA;
 
 
@@ -3244,6 +3261,11 @@ static int wm8962_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
 
 
 	dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
 	dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout);
 
 
+	/* This should be a massive overestimate */
+	timeout = msecs_to_jiffies(1);
+
+	wait_for_completion_timeout(&wm8962->fll_lock, timeout);
+
 	wm8962->fll_fref = Fref;
 	wm8962->fll_fref = Fref;
 	wm8962->fll_fout = Fout;
 	wm8962->fll_fout = Fout;
 	wm8962->fll_src = source;
 	wm8962->fll_src = source;
@@ -3274,7 +3296,6 @@ static struct snd_soc_dai_ops wm8962_dai_ops = {
 	.hw_params = wm8962_hw_params,
 	.hw_params = wm8962_hw_params,
 	.set_sysclk = wm8962_set_dai_sysclk,
 	.set_sysclk = wm8962_set_dai_sysclk,
 	.set_fmt = wm8962_set_dai_fmt,
 	.set_fmt = wm8962_set_dai_fmt,
-	.set_pll = wm8962_set_fll,
 	.digital_mute = wm8962_mute,
 	.digital_mute = wm8962_mute,
 };
 };
 
 
@@ -3340,6 +3361,11 @@ static irqreturn_t wm8962_irq(int irq, void *data)
 	active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2);
 	active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2);
 	active &= ~mask;
 	active &= ~mask;
 
 
+	if (active & WM8962_FLL_LOCK_EINT) {
+		dev_dbg(codec->dev, "FLL locked\n");
+		complete(&wm8962->fll_lock);
+	}
+
 	if (active & WM8962_FIFOS_ERR_EINT)
 	if (active & WM8962_FIFOS_ERR_EINT)
 		dev_err(codec->dev, "FIFO error\n");
 		dev_err(codec->dev, "FIFO error\n");
 
 
@@ -3709,9 +3735,11 @@ static int wm8962_probe(struct snd_soc_codec *codec)
 					      dev);
 					      dev);
 	u16 *reg_cache = codec->reg_cache;
 	u16 *reg_cache = codec->reg_cache;
 	int i, trigger, irq_pol;
 	int i, trigger, irq_pol;
+	bool dmicclk, dmicdat;
 
 
 	wm8962->codec = codec;
 	wm8962->codec = codec;
 	INIT_DELAYED_WORK(&wm8962->mic_work, wm8962_mic_work);
 	INIT_DELAYED_WORK(&wm8962->mic_work, wm8962_mic_work);
+	init_completion(&wm8962->fll_lock);
 
 
 	codec->cache_sync = 1;
 	codec->cache_sync = 1;
 	codec->dapm.idle_bias_off = 1;
 	codec->dapm.idle_bias_off = 1;
@@ -3845,6 +3873,29 @@ static int wm8962_probe(struct snd_soc_codec *codec)
 
 
 	wm8962_add_widgets(codec);
 	wm8962_add_widgets(codec);
 
 
+	/* Save boards having to disable DMIC when not in use */
+	dmicclk = false;
+	dmicdat = false;
+	for (i = 0; i < WM8962_MAX_GPIO; i++) {
+		switch (snd_soc_read(codec, WM8962_GPIO_BASE + i)
+			& WM8962_GP2_FN_MASK) {
+		case WM8962_GPIO_FN_DMICCLK:
+			dmicclk = true;
+			break;
+		case WM8962_GPIO_FN_DMICDAT:
+			dmicdat = true;
+			break;
+		default:
+			break;
+		}
+	}
+	if (!dmicclk || !dmicdat) {
+		dev_dbg(codec->dev, "DMIC not in use, disabling\n");
+		snd_soc_dapm_nc_pin(&codec->dapm, "DMICDAT");
+	}
+	if (dmicclk != dmicdat)
+		dev_warn(codec->dev, "DMIC GPIOs partially configured\n");
+
 	wm8962_init_beep(codec);
 	wm8962_init_beep(codec);
 	wm8962_init_gpio(codec);
 	wm8962_init_gpio(codec);
 
 
@@ -3868,9 +3919,10 @@ static int wm8962_probe(struct snd_soc_codec *codec)
 				i2c->irq, ret);
 				i2c->irq, ret);
 			/* Non-fatal */
 			/* Non-fatal */
 		} else {
 		} else {
-			/* Enable error reporting IRQs by default */
+			/* Enable some IRQs by default */
 			snd_soc_update_bits(codec,
 			snd_soc_update_bits(codec,
 					    WM8962_INTERRUPT_STATUS_2_MASK,
 					    WM8962_INTERRUPT_STATUS_2_MASK,
+					    WM8962_FLL_LOCK_EINT |
 					    WM8962_TEMP_SHUT_EINT |
 					    WM8962_TEMP_SHUT_EINT |
 					    WM8962_FIFOS_ERR_EINT, 0);
 					    WM8962_FIFOS_ERR_EINT, 0);
 		}
 		}
@@ -3918,6 +3970,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8962 = {
 	.reg_cache_default = wm8962_reg,
 	.reg_cache_default = wm8962_reg,
 	.volatile_register = wm8962_volatile_register,
 	.volatile_register = wm8962_volatile_register,
 	.readable_register = wm8962_readable_register,
 	.readable_register = wm8962_readable_register,
+	.set_pll = wm8962_set_fll,
 };
 };
 
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)

+ 2 - 1
sound/soc/codecs/wm8993.c

@@ -718,7 +718,8 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w,
 static int class_w_put(struct snd_kcontrol *kcontrol,
 static int class_w_put(struct snd_kcontrol *kcontrol,
 		       struct snd_ctl_elem_value *ucontrol)
 		       struct snd_ctl_elem_value *ucontrol)
 {
 {
-	struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *widget = wlist->widgets[0];
 	struct snd_soc_codec *codec = widget->codec;
 	struct snd_soc_codec *codec = widget->codec;
 	struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
 	struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
 	int ret;
 	int ret;

+ 81 - 314
sound/soc/codecs/wm8994.c

@@ -38,12 +38,6 @@
 #include "wm8994.h"
 #include "wm8994.h"
 #include "wm_hubs.h"
 #include "wm_hubs.h"
 
 
-struct fll_config {
-	int src;
-	int in;
-	int out;
-};
-
 #define WM8994_NUM_DRC 3
 #define WM8994_NUM_DRC 3
 #define WM8994_NUM_EQ  3
 #define WM8994_NUM_EQ  3
 
 
@@ -59,63 +53,11 @@ static int wm8994_retune_mobile_base[] = {
 	WM8994_AIF2_EQ_GAINS_1,
 	WM8994_AIF2_EQ_GAINS_1,
 };
 };
 
 
-struct wm8994_micdet {
-	struct snd_soc_jack *jack;
-	int det;
-	int shrt;
-};
-
-/* codec private data */
-struct wm8994_priv {
-	struct wm_hubs_data hubs;
-	enum snd_soc_control_type control_type;
-	void *control_data;
-	struct snd_soc_codec *codec;
-	int sysclk[2];
-	int sysclk_rate[2];
-	int mclk[2];
-	int aifclk[2];
-	struct fll_config fll[2], fll_suspend[2];
-
-	int dac_rates[2];
-	int lrclk_shared[2];
-
-	int mbc_ena[3];
-
-	/* Platform dependent DRC configuration */
-	const char **drc_texts;
-	int drc_cfg[WM8994_NUM_DRC];
-	struct soc_enum drc_enum;
-
-	/* Platform dependent ReTune mobile configuration */
-	int num_retune_mobile_texts;
-	const char **retune_mobile_texts;
-	int retune_mobile_cfg[WM8994_NUM_EQ];
-	struct soc_enum retune_mobile_enum;
-
-	/* Platform dependent MBC configuration */
-	int mbc_cfg;
-	const char **mbc_texts;
-	struct soc_enum mbc_enum;
-
-	struct wm8994_micdet micdet[2];
-
-	wm8958_micdet_cb jack_cb;
-	void *jack_cb_data;
-	int micdet_irq;
-
-	int revision;
-	struct wm8994_pdata *pdata;
-
-	unsigned int aif1clk_enable:1;
-	unsigned int aif2clk_enable:1;
-
-	unsigned int aif1clk_disable:1;
-	unsigned int aif2clk_disable:1;
-};
-
 static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg)
 static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg)
 {
 {
+	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994 *control = wm8994->control_data;
+
 	switch (reg) {
 	switch (reg) {
 	case WM8994_GPIO_1:
 	case WM8994_GPIO_1:
 	case WM8994_GPIO_2:
 	case WM8994_GPIO_2:
@@ -132,6 +74,15 @@ static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg)
 	case WM8994_INTERRUPT_STATUS_2:
 	case WM8994_INTERRUPT_STATUS_2:
 	case WM8994_INTERRUPT_RAW_STATUS_2:
 	case WM8994_INTERRUPT_RAW_STATUS_2:
 		return 1;
 		return 1;
+
+	case WM8958_DSP2_PROGRAM:
+	case WM8958_DSP2_CONFIG:
+	case WM8958_DSP2_EXECCONTROL:
+		if (control->type == WM8958)
+			return 1;
+		else
+			return 0;
+
 	default:
 	default:
 		break;
 		break;
 	}
 	}
@@ -574,215 +525,6 @@ static const struct soc_enum dac_osr =
 static const struct soc_enum adc_osr =
 static const struct soc_enum adc_osr =
 	SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 1, 2, osr_text);
 	SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 1, 2, osr_text);
 
 
-static void wm8958_mbc_apply(struct snd_soc_codec *codec, int mbc, int start)
-{
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-	struct wm8994_pdata *pdata = wm8994->pdata;
-	int pwr_reg = snd_soc_read(codec, WM8994_POWER_MANAGEMENT_5);
-	int ena, reg, aif, i;
-
-	switch (mbc) {
-	case 0:
-		pwr_reg &= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA);
-		aif = 0;
-		break;
-	case 1:
-		pwr_reg &= (WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA);
-		aif = 0;
-		break;
-	case 2:
-		pwr_reg &= (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA);
-		aif = 1;
-		break;
-	default:
-		BUG();
-		return;
-	}
-
-	/* We can only enable the MBC if the AIF is enabled and we
-	 * want it to be enabled. */
-	ena = pwr_reg && wm8994->mbc_ena[mbc];
-
-	reg = snd_soc_read(codec, WM8958_DSP2_PROGRAM);
-
-	dev_dbg(codec->dev, "MBC %d startup: %d, power: %x, DSP: %x\n",
-		mbc, start, pwr_reg, reg);
-
-	if (start && ena) {
-		/* If the DSP is already running then noop */
-		if (reg & WM8958_DSP2_ENA)
-			return;
-
-		/* Switch the clock over to the appropriate AIF */
-		snd_soc_update_bits(codec, WM8994_CLOCKING_1,
-				    WM8958_DSP2CLK_SRC | WM8958_DSP2CLK_ENA,
-				    aif << WM8958_DSP2CLK_SRC_SHIFT |
-				    WM8958_DSP2CLK_ENA);
-
-		snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
-				    WM8958_DSP2_ENA, WM8958_DSP2_ENA);
-
-		/* If we've got user supplied MBC settings use them */
-		if (pdata && pdata->num_mbc_cfgs) {
-			struct wm8958_mbc_cfg *cfg
-				= &pdata->mbc_cfgs[wm8994->mbc_cfg];
-
-			for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++)
-				snd_soc_write(codec, i + WM8958_MBC_BAND_1_K_1,
-					      cfg->coeff_regs[i]);
-
-			for (i = 0; i < ARRAY_SIZE(cfg->cutoff_regs); i++)
-				snd_soc_write(codec,
-					      i + WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1,
-					      cfg->cutoff_regs[i]);
-		}
-
-		/* Run the DSP */
-		snd_soc_write(codec, WM8958_DSP2_EXECCONTROL,
-			      WM8958_DSP2_RUNR);
-
-		/* And we're off! */
-		snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
-				    WM8958_MBC_ENA | WM8958_MBC_SEL_MASK,
-				    mbc << WM8958_MBC_SEL_SHIFT |
-				    WM8958_MBC_ENA);
-	} else {
-		/* If the DSP is already stopped then noop */
-		if (!(reg & WM8958_DSP2_ENA))
-			return;
-
-		snd_soc_update_bits(codec, WM8958_DSP2_CONFIG,
-				    WM8958_MBC_ENA, 0);	
-		snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM,
-				    WM8958_DSP2_ENA, 0);
-		snd_soc_update_bits(codec, WM8994_CLOCKING_1,
-				    WM8958_DSP2CLK_ENA, 0);
-	}
-}
-
-static int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
-		    struct snd_kcontrol *kcontrol, int event)
-{
-	struct snd_soc_codec *codec = w->codec;
-	int mbc;
-
-	switch (w->shift) {
-	case 13:
-	case 12:
-		mbc = 2;
-		break;
-	case 11:
-	case 10:
-		mbc = 1;
-		break;
-	case 9:
-	case 8:
-		mbc = 0;
-		break;
-	default:
-		BUG();
-		return -EINVAL;
-	}
-
-	switch (event) {
-	case SND_SOC_DAPM_POST_PMU:
-		wm8958_mbc_apply(codec, mbc, 1);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		wm8958_mbc_apply(codec, mbc, 0);
-		break;
-	}
-
-	return 0;
-}
-
-static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol,
-			       struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-	struct wm8994_pdata *pdata = wm8994->pdata;
-	int value = ucontrol->value.integer.value[0];
-	int reg;
-
-	/* Don't allow on the fly reconfiguration */
-	reg = snd_soc_read(codec, WM8994_CLOCKING_1);
-	if (reg < 0 || reg & WM8958_DSP2CLK_ENA)
-		return -EBUSY;
-
-	if (value >= pdata->num_mbc_cfgs)
-		return -EINVAL;
-
-	wm8994->mbc_cfg = value;
-
-	return 0;
-}
-
-static int wm8958_get_mbc_enum(struct snd_kcontrol *kcontrol,
-			       struct snd_ctl_elem_value *ucontrol)
-{
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-
-	ucontrol->value.enumerated.item[0] = wm8994->mbc_cfg;
-
-	return 0;
-}
-
-static int wm8958_mbc_info(struct snd_kcontrol *kcontrol,
-			   struct snd_ctl_elem_info *uinfo)
-{
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-	uinfo->count = 1;
-	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = 1;
-	return 0;
-}
-
-static int wm8958_mbc_get(struct snd_kcontrol *kcontrol,
-			  struct snd_ctl_elem_value *ucontrol)
-{
-	int mbc = kcontrol->private_value;
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-
-	ucontrol->value.integer.value[0] = wm8994->mbc_ena[mbc];
-
-	return 0;
-}
-
-static int wm8958_mbc_put(struct snd_kcontrol *kcontrol,
-			  struct snd_ctl_elem_value *ucontrol)
-{
-	int mbc = kcontrol->private_value;
-	int i;
-	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
-
-	if (ucontrol->value.integer.value[0] > 1)
-		return -EINVAL;
-
-	for (i = 0; i < ARRAY_SIZE(wm8994->mbc_ena); i++) {
-		if (mbc != i && wm8994->mbc_ena[i]) {
-			dev_dbg(codec->dev, "MBC %d active already\n", mbc);
-			return -EBUSY;
-		}
-	}
-
-	wm8994->mbc_ena[mbc] = ucontrol->value.integer.value[0];
-
-	wm8958_mbc_apply(codec, mbc, wm8994->mbc_ena[mbc]);
-
-	return 0;
-}
-
-#define WM8958_MBC_SWITCH(xname, xval) {\
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
-	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,\
-	.info = wm8958_mbc_info, \
-	.get = wm8958_mbc_get, .put = wm8958_mbc_put, \
-	.private_value = xval }
-
 static const struct snd_kcontrol_new wm8994_snd_controls[] = {
 static const struct snd_kcontrol_new wm8994_snd_controls[] = {
 SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME,
 SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME,
 		 WM8994_AIF1_ADC1_RIGHT_VOLUME,
 		 WM8994_AIF1_ADC1_RIGHT_VOLUME,
@@ -924,9 +666,6 @@ SOC_SINGLE_TLV("AIF2 EQ5 Volume", WM8994_AIF2_EQ_GAINS_2, 6, 31, 0,
 
 
 static const struct snd_kcontrol_new wm8958_snd_controls[] = {
 static const struct snd_kcontrol_new wm8958_snd_controls[] = {
 SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv),
 SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv),
-WM8958_MBC_SWITCH("AIF1DAC1 MBC Switch", 0),
-WM8958_MBC_SWITCH("AIF1DAC2 MBC Switch", 1),
-WM8958_MBC_SWITCH("AIF2DAC MBC Switch", 2),
 };
 };
 
 
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
@@ -1032,6 +771,9 @@ static int late_enable_ev(struct snd_soc_dapm_widget *w,
 		break;
 		break;
 	}
 	}
 
 
+	/* We may also have postponed startup of DSP, handle that. */
+	wm8958_aif_ev(w, kcontrol, event);
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1135,7 +877,8 @@ static const char *hp_mux_text[] = {
 static int wm8994_put_hp_enum(struct snd_kcontrol *kcontrol,
 static int wm8994_put_hp_enum(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 			      struct snd_ctl_elem_value *ucontrol)
 {
 {
-	struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *w = wlist->widgets[0];
 	struct snd_soc_codec *codec = w->codec;
 	struct snd_soc_codec *codec = w->codec;
 	int ret;
 	int ret;
 
 
@@ -1262,7 +1005,8 @@ SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
 static int wm8994_put_class_w(struct snd_kcontrol *kcontrol,
 static int wm8994_put_class_w(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 			      struct snd_ctl_elem_value *ucontrol)
 {
 {
-	struct snd_soc_dapm_widget *w = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *w = wlist->widgets[0];
 	struct snd_soc_codec *codec = w->codec;
 	struct snd_soc_codec *codec = w->codec;
 	int ret;
 	int ret;
 
 
@@ -2180,6 +1924,8 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
 					    WM8994_VMID_BUF_ENA |
 					    WM8994_VMID_BUF_ENA |
 					    WM8994_VMID_RAMP_MASK, 0);
 					    WM8994_VMID_RAMP_MASK, 0);
 
 
+			wm8994->cur_fw = NULL;
+
 			pm_runtime_put(codec->dev);
 			pm_runtime_put(codec->dev);
 		}
 		}
 		break;
 		break;
@@ -2672,11 +2418,22 @@ static struct snd_soc_dai_driver wm8994_dai[] = {
 static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state)
 static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
 {
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994 *control = codec->control_data;
 	int i, ret;
 	int i, ret;
 
 
+	switch (control->type) {
+	case WM8994:
+		snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, 0);
+		break;
+	case WM8958:
+		snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+				    WM8958_MICD_ENA, 0);
+		break;
+	}
+
 	for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
 	for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
 		memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i],
 		memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i],
-		       sizeof(struct fll_config));
+		       sizeof(struct wm8994_fll_config));
 		ret = _wm8994_set_fll(codec, i + 1, 0, 0, 0);
 		ret = _wm8994_set_fll(codec, i + 1, 0, 0, 0);
 		if (ret < 0)
 		if (ret < 0)
 			dev_warn(codec->dev, "Failed to stop FLL%d: %d\n",
 			dev_warn(codec->dev, "Failed to stop FLL%d: %d\n",
@@ -2691,6 +2448,7 @@ static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state)
 static int wm8994_resume(struct snd_soc_codec *codec)
 static int wm8994_resume(struct snd_soc_codec *codec)
 {
 {
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 	struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+	struct wm8994 *control = codec->control_data;
 	int i, ret;
 	int i, ret;
 	unsigned int val, mask;
 	unsigned int val, mask;
 
 
@@ -2729,6 +2487,19 @@ static int wm8994_resume(struct snd_soc_codec *codec)
 				 i + 1, ret);
 				 i + 1, ret);
 	}
 	}
 
 
+	switch (control->type) {
+	case WM8994:
+		if (wm8994->micdet[0].jack || wm8994->micdet[1].jack)
+			snd_soc_update_bits(codec, WM8994_MICBIAS,
+					    WM8994_MICD_ENA, WM8994_MICD_ENA);
+		break;
+	case WM8958:
+		if (wm8994->jack_cb)
+			snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
+					    WM8958_MICD_ENA, WM8958_MICD_ENA);
+		break;
+	}
+
 	return 0;
 	return 0;
 }
 }
 #else
 #else
@@ -2862,34 +2633,6 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
 	dev_dbg(codec->dev, "%d ReTune Mobile configurations\n",
 	dev_dbg(codec->dev, "%d ReTune Mobile configurations\n",
 		pdata->num_retune_mobile_cfgs);
 		pdata->num_retune_mobile_cfgs);
 
 
-	if (pdata->num_mbc_cfgs) {
-		struct snd_kcontrol_new control[] = {
-			SOC_ENUM_EXT("MBC Mode", wm8994->mbc_enum,
-				     wm8958_get_mbc_enum, wm8958_put_mbc_enum),
-		};
-
-		/* We need an array of texts for the enum API */
-		wm8994->mbc_texts = kmalloc(sizeof(char *)
-					    * pdata->num_mbc_cfgs, GFP_KERNEL);
-		if (!wm8994->mbc_texts) {
-			dev_err(wm8994->codec->dev,
-				"Failed to allocate %d MBC config texts\n",
-				pdata->num_mbc_cfgs);
-			return;
-		}
-
-		for (i = 0; i < pdata->num_mbc_cfgs; i++)
-			wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name;
-
-		wm8994->mbc_enum.max = pdata->num_mbc_cfgs;
-		wm8994->mbc_enum.texts = wm8994->mbc_texts;
-
-		ret = snd_soc_add_controls(wm8994->codec, control, 1);
-		if (ret != 0)
-			dev_err(wm8994->codec->dev,
-				"Failed to add MBC mode controls: %d\n", ret);
-	}
-
 	if (pdata->num_retune_mobile_cfgs)
 	if (pdata->num_retune_mobile_cfgs)
 		wm8994_handle_retune_mobile_pdata(wm8994);
 		wm8994_handle_retune_mobile_pdata(wm8994);
 	else
 	else
@@ -3343,14 +3086,23 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 	case WM8958:
 	case WM8958:
 		snd_soc_add_controls(codec, wm8958_snd_controls,
 		snd_soc_add_controls(codec, wm8958_snd_controls,
 				     ARRAY_SIZE(wm8958_snd_controls));
 				     ARRAY_SIZE(wm8958_snd_controls));
-		snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets,
-					  ARRAY_SIZE(wm8994_lateclk_widgets));
-		snd_soc_dapm_new_controls(dapm, wm8994_adc_widgets,
-					  ARRAY_SIZE(wm8994_adc_widgets));
-		snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets,
-					  ARRAY_SIZE(wm8994_dac_widgets));
 		snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
 		snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
 					  ARRAY_SIZE(wm8958_dapm_widgets));
 					  ARRAY_SIZE(wm8958_dapm_widgets));
+		if (wm8994->revision < 1) {
+			snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets,
+						  ARRAY_SIZE(wm8994_lateclk_revd_widgets));
+			snd_soc_dapm_new_controls(dapm, wm8994_adc_revd_widgets,
+						  ARRAY_SIZE(wm8994_adc_revd_widgets));
+			snd_soc_dapm_new_controls(dapm, wm8994_dac_revd_widgets,
+						  ARRAY_SIZE(wm8994_dac_revd_widgets));
+		} else {
+			snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets,
+						  ARRAY_SIZE(wm8994_lateclk_widgets));
+			snd_soc_dapm_new_controls(dapm, wm8994_adc_widgets,
+						  ARRAY_SIZE(wm8994_adc_widgets));
+			snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets,
+						  ARRAY_SIZE(wm8994_dac_widgets));
+		}
 		break;
 		break;
 	}
 	}
 		
 		
@@ -3374,10 +3126,19 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 		}
 		}
 		break;
 		break;
 	case WM8958:
 	case WM8958:
-		snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon,
-					ARRAY_SIZE(wm8994_lateclk_intercon));
-		snd_soc_dapm_add_routes(dapm, wm8958_intercon,
-					ARRAY_SIZE(wm8958_intercon));
+		if (wm8994->revision < 1) {
+			snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon,
+						ARRAY_SIZE(wm8994_revd_intercon));
+			snd_soc_dapm_add_routes(dapm, wm8994_lateclk_revd_intercon,
+						ARRAY_SIZE(wm8994_lateclk_revd_intercon));
+		} else {
+			snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon,
+						ARRAY_SIZE(wm8994_lateclk_intercon));
+			snd_soc_dapm_add_routes(dapm, wm8958_intercon,
+						ARRAY_SIZE(wm8958_intercon));
+		}
+
+		wm8958_dsp2_init(codec);
 		break;
 		break;
 	}
 	}
 
 
@@ -3420,6 +3181,12 @@ static int  wm8994_codec_remove(struct snd_soc_codec *codec)
 			free_irq(wm8994->micdet_irq, wm8994);
 			free_irq(wm8994->micdet_irq, wm8994);
 		break;
 		break;
 	}
 	}
+	if (wm8994->mbc)
+		release_firmware(wm8994->mbc);
+	if (wm8994->mbc_vss)
+		release_firmware(wm8994->mbc_vss);
+	if (wm8994->enh_eq)
+		release_firmware(wm8994->enh_eq);
 	kfree(wm8994->retune_mobile_texts);
 	kfree(wm8994->retune_mobile_texts);
 	kfree(wm8994->drc_texts);
 	kfree(wm8994->drc_texts);
 	kfree(wm8994);
 	kfree(wm8994);

+ 97 - 0
sound/soc/codecs/wm8994.h

@@ -10,6 +10,9 @@
 #define _WM8994_H
 #define _WM8994_H
 
 
 #include <sound/soc.h>
 #include <sound/soc.h>
+#include <linux/firmware.h>
+
+#include "wm_hubs.h"
 
 
 /* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */
 /* Sources for AIF1/2 SYSCLK - use with set_dai_sysclk() */
 #define WM8994_SYSCLK_MCLK1 1
 #define WM8994_SYSCLK_MCLK1 1
@@ -45,4 +48,98 @@ struct wm8994_access_mask {
 extern const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE];
 extern const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE];
 extern const u16 wm8994_reg_defaults[WM8994_CACHE_SIZE];
 extern const u16 wm8994_reg_defaults[WM8994_CACHE_SIZE];
 
 
+int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
+		  struct snd_kcontrol *kcontrol, int event);
+
+void wm8958_dsp2_init(struct snd_soc_codec *codec);
+
+struct wm8994_micdet {
+	struct snd_soc_jack *jack;
+	int det;
+	int shrt;
+};
+
+/* codec private data */
+struct wm8994_fll_config {
+	int src;
+	int in;
+	int out;
+};
+
+#define WM8994_NUM_DRC 3
+#define WM8994_NUM_EQ  3
+
+struct wm8994_priv {
+	struct wm_hubs_data hubs;
+	enum snd_soc_control_type control_type;
+	void *control_data;
+	struct snd_soc_codec *codec;
+	int sysclk[2];
+	int sysclk_rate[2];
+	int mclk[2];
+	int aifclk[2];
+	struct wm8994_fll_config fll[2], fll_suspend[2];
+
+	int dac_rates[2];
+	int lrclk_shared[2];
+
+	int mbc_ena[3];
+	int hpf1_ena[3];
+	int hpf2_ena[3];
+	int vss_ena[3];
+	int enh_eq_ena[3];
+
+	/* Platform dependant DRC configuration */
+	const char **drc_texts;
+	int drc_cfg[WM8994_NUM_DRC];
+	struct soc_enum drc_enum;
+
+	/* Platform dependant ReTune mobile configuration */
+	int num_retune_mobile_texts;
+	const char **retune_mobile_texts;
+	int retune_mobile_cfg[WM8994_NUM_EQ];
+	struct soc_enum retune_mobile_enum;
+
+	/* Platform dependant MBC configuration */
+	int mbc_cfg;
+	const char **mbc_texts;
+	struct soc_enum mbc_enum;
+
+	/* Platform dependant VSS configuration */
+	int vss_cfg;
+	const char **vss_texts;
+	struct soc_enum vss_enum;
+
+	/* Platform dependant VSS HPF configuration */
+	int vss_hpf_cfg;
+	const char **vss_hpf_texts;
+	struct soc_enum vss_hpf_enum;
+
+	/* Platform dependant enhanced EQ configuration */
+	int enh_eq_cfg;
+	const char **enh_eq_texts;
+	struct soc_enum enh_eq_enum;
+
+	struct wm8994_micdet micdet[2];
+
+	wm8958_micdet_cb jack_cb;
+	void *jack_cb_data;
+	int micdet_irq;
+
+	int revision;
+	struct wm8994_pdata *pdata;
+
+	unsigned int aif1clk_enable:1;
+	unsigned int aif2clk_enable:1;
+
+	unsigned int aif1clk_disable:1;
+	unsigned int aif2clk_disable:1;
+
+	int dsp_active;
+	const struct firmware *cur_fw;
+	const struct firmware *mbc;
+	const struct firmware *mbc_vss;
+	const struct firmware *enh_eq;
+};
+
 #endif
 #endif

+ 2 - 2
sound/soc/codecs/wm8995.c

@@ -305,11 +305,11 @@ static int check_clk_sys(struct snd_soc_dapm_widget *source,
 static int wm8995_put_class_w(struct snd_kcontrol *kcontrol,
 static int wm8995_put_class_w(struct snd_kcontrol *kcontrol,
 			      struct snd_ctl_elem_value *ucontrol)
 			      struct snd_ctl_elem_value *ucontrol)
 {
 {
-	struct snd_soc_dapm_widget *w;
+	struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+	struct snd_soc_dapm_widget *w = wlist->widgets[0];
 	struct snd_soc_codec *codec;
 	struct snd_soc_codec *codec;
 	int ret;
 	int ret;
 
 
-	w = snd_kcontrol_chip(kcontrol);
 	codec = w->codec;
 	codec = w->codec;
 	ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
 	ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
 	wm8995_update_class_w(codec);
 	wm8995_update_class_w(codec);

+ 5 - 13
sound/soc/codecs/wm9705.c

@@ -142,7 +142,7 @@ static const struct snd_soc_dapm_widget wm9705_dapm_widgets[] = {
  * constantly enabled, we use the mutes on those inputs to simulate such
  * constantly enabled, we use the mutes on those inputs to simulate such
  * controls.
  * controls.
  */
  */
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm9705_audio_map[] = {
 	/* HP mixer */
 	/* HP mixer */
 	{"HP Mixer", "PCBeep Playback Switch", "PCBEEP PGA"},
 	{"HP Mixer", "PCBeep Playback Switch", "PCBEEP PGA"},
 	{"HP Mixer", "CD Playback Switch", "CD PGA"},
 	{"HP Mixer", "CD Playback Switch", "CD PGA"},
@@ -200,17 +200,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	{"Right ADC", NULL, "ADC PGA"},
 	{"Right ADC", NULL, "ADC PGA"},
 };
 };
 
 
-static int wm9705_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, wm9705_dapm_widgets,
-					ARRAY_SIZE(wm9705_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-	return 0;
-}
-
 /* We use a register cache to enhance read performance. */
 /* We use a register cache to enhance read performance. */
 static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg)
 static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg)
 {
 {
@@ -364,7 +353,6 @@ static int wm9705_soc_probe(struct snd_soc_codec *codec)
 
 
 	snd_soc_add_controls(codec, wm9705_snd_ac97_controls,
 	snd_soc_add_controls(codec, wm9705_snd_ac97_controls,
 				ARRAY_SIZE(wm9705_snd_ac97_controls));
 				ARRAY_SIZE(wm9705_snd_ac97_controls));
-	wm9705_add_widgets(codec);
 
 
 	return 0;
 	return 0;
 
 
@@ -390,6 +378,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9705 = {
 	.reg_word_size = sizeof(u16),
 	.reg_word_size = sizeof(u16),
 	.reg_cache_step = 2,
 	.reg_cache_step = 2,
 	.reg_cache_default = wm9705_reg,
 	.reg_cache_default = wm9705_reg,
+	.dapm_widgets = wm9705_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm9705_dapm_widgets),
+	.dapm_routes = wm9705_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(wm9705_audio_map),
 };
 };
 
 
 static __devinit int wm9705_probe(struct platform_device *pdev)
 static __devinit int wm9705_probe(struct platform_device *pdev)

+ 5 - 13
sound/soc/codecs/wm9712.c

@@ -332,7 +332,7 @@ SND_SOC_DAPM_INPUT("MIC1"),
 SND_SOC_DAPM_INPUT("MIC2"),
 SND_SOC_DAPM_INPUT("MIC2"),
 };
 };
 
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm9712_audio_map[] = {
 	/* virtual mixer - mixes left & right channels for spk and mono */
 	/* virtual mixer - mixes left & right channels for spk and mono */
 	{"AC97 Mixer", NULL, "Left DAC"},
 	{"AC97 Mixer", NULL, "Left DAC"},
 	{"AC97 Mixer", NULL, "Right DAC"},
 	{"AC97 Mixer", NULL, "Right DAC"},
@@ -429,17 +429,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	{"ROUT2", NULL, "Speaker PGA"},
 	{"ROUT2", NULL, "Speaker PGA"},
 };
 };
 
 
-static int wm9712_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, wm9712_dapm_widgets,
-				  ARRAY_SIZE(wm9712_dapm_widgets));
-	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-	return 0;
-}
-
 static unsigned int ac97_read(struct snd_soc_codec *codec,
 static unsigned int ac97_read(struct snd_soc_codec *codec,
 	unsigned int reg)
 	unsigned int reg)
 {
 {
@@ -651,7 +640,6 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec)
 	wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	snd_soc_add_controls(codec, wm9712_snd_ac97_controls,
 	snd_soc_add_controls(codec, wm9712_snd_ac97_controls,
 				ARRAY_SIZE(wm9712_snd_ac97_controls));
 				ARRAY_SIZE(wm9712_snd_ac97_controls));
-	wm9712_add_widgets(codec);
 
 
 	return 0;
 	return 0;
 
 
@@ -678,6 +666,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9712 = {
 	.reg_word_size = sizeof(u16),
 	.reg_word_size = sizeof(u16),
 	.reg_cache_step = 2,
 	.reg_cache_step = 2,
 	.reg_cache_default = wm9712_reg,
 	.reg_cache_default = wm9712_reg,
+	.dapm_widgets = wm9712_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm9712_dapm_widgets),
+	.dapm_routes = wm9712_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(wm9712_audio_map),
 };
 };
 
 
 static __devinit int wm9712_probe(struct platform_device *pdev)
 static __devinit int wm9712_probe(struct platform_device *pdev)

+ 5 - 14
sound/soc/codecs/wm9713.c

@@ -487,7 +487,7 @@ SND_SOC_DAPM_INPUT("MIC2B"),
 SND_SOC_DAPM_VMID("VMID"),
 SND_SOC_DAPM_VMID("VMID"),
 };
 };
 
 
-static const struct snd_soc_dapm_route audio_map[] = {
+static const struct snd_soc_dapm_route wm9713_audio_map[] = {
 	/* left HP mixer */
 	/* left HP mixer */
 	{"Left HP Mixer", "Beep Playback Switch",    "PCBEEP"},
 	{"Left HP Mixer", "Beep Playback Switch",    "PCBEEP"},
 	{"Left HP Mixer", "Voice Playback Switch",   "Voice DAC"},
 	{"Left HP Mixer", "Voice Playback Switch",   "Voice DAC"},
@@ -644,18 +644,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	{"Capture Mono Mux", "Right", "Right Capture Source"},
 	{"Capture Mono Mux", "Right", "Right Capture Source"},
 };
 };
 
 
-static int wm9713_add_widgets(struct snd_soc_codec *codec)
-{
-	struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-	snd_soc_dapm_new_controls(dapm, wm9713_dapm_widgets,
-				  ARRAY_SIZE(wm9713_dapm_widgets));
-
-	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
-
-	return 0;
-}
-
 static unsigned int ac97_read(struct snd_soc_codec *codec,
 static unsigned int ac97_read(struct snd_soc_codec *codec,
 	unsigned int reg)
 	unsigned int reg)
 {
 {
@@ -1231,7 +1219,6 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec)
 
 
 	snd_soc_add_controls(codec, wm9713_snd_ac97_controls,
 	snd_soc_add_controls(codec, wm9713_snd_ac97_controls,
 				ARRAY_SIZE(wm9713_snd_ac97_controls));
 				ARRAY_SIZE(wm9713_snd_ac97_controls));
-	wm9713_add_widgets(codec);
 
 
 	return 0;
 	return 0;
 
 
@@ -1262,6 +1249,10 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9713 = {
 	.reg_word_size = sizeof(u16),
 	.reg_word_size = sizeof(u16),
 	.reg_cache_step = 2,
 	.reg_cache_step = 2,
 	.reg_cache_default = wm9713_reg,
 	.reg_cache_default = wm9713_reg,
+	.dapm_widgets = wm9713_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm9713_dapm_widgets),
+	.dapm_routes = wm9713_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(wm9713_audio_map),
 };
 };
 
 
 static __devinit int wm9713_probe(struct platform_device *pdev)
 static __devinit int wm9713_probe(struct platform_device *pdev)

+ 14 - 10
sound/soc/codecs/wm_hubs.c

@@ -787,17 +787,17 @@ static const struct snd_soc_dapm_route analogue_routes[] = {
 static const struct snd_soc_dapm_route lineout1_diff_routes[] = {
 static const struct snd_soc_dapm_route lineout1_diff_routes[] = {
 	{ "LINEOUT1 Mixer", "IN1L Switch", "IN1L PGA" },
 	{ "LINEOUT1 Mixer", "IN1L Switch", "IN1L PGA" },
 	{ "LINEOUT1 Mixer", "IN1R Switch", "IN1R PGA" },
 	{ "LINEOUT1 Mixer", "IN1R Switch", "IN1R PGA" },
-	{ "LINEOUT1 Mixer", "Output Switch", "Left Output Mixer" },
+	{ "LINEOUT1 Mixer", "Output Switch", "Left Output PGA" },
 
 
 	{ "LINEOUT1N Driver", NULL, "LINEOUT1 Mixer" },
 	{ "LINEOUT1N Driver", NULL, "LINEOUT1 Mixer" },
 	{ "LINEOUT1P Driver", NULL, "LINEOUT1 Mixer" },
 	{ "LINEOUT1P Driver", NULL, "LINEOUT1 Mixer" },
 };
 };
 
 
 static const struct snd_soc_dapm_route lineout1_se_routes[] = {
 static const struct snd_soc_dapm_route lineout1_se_routes[] = {
-	{ "LINEOUT1N Mixer", "Left Output Switch", "Left Output Mixer" },
-	{ "LINEOUT1N Mixer", "Right Output Switch", "Left Output Mixer" },
+	{ "LINEOUT1N Mixer", "Left Output Switch", "Left Output PGA" },
+	{ "LINEOUT1N Mixer", "Right Output Switch", "Right Output PGA" },
 
 
-	{ "LINEOUT1P Mixer", "Left Output Switch", "Left Output Mixer" },
+	{ "LINEOUT1P Mixer", "Left Output Switch", "Left Output PGA" },
 
 
 	{ "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" },
 	{ "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" },
 	{ "LINEOUT1P Driver", NULL, "LINEOUT1P Mixer" },
 	{ "LINEOUT1P Driver", NULL, "LINEOUT1P Mixer" },
@@ -806,17 +806,17 @@ static const struct snd_soc_dapm_route lineout1_se_routes[] = {
 static const struct snd_soc_dapm_route lineout2_diff_routes[] = {
 static const struct snd_soc_dapm_route lineout2_diff_routes[] = {
 	{ "LINEOUT2 Mixer", "IN2L Switch", "IN2L PGA" },
 	{ "LINEOUT2 Mixer", "IN2L Switch", "IN2L PGA" },
 	{ "LINEOUT2 Mixer", "IN2R Switch", "IN2R PGA" },
 	{ "LINEOUT2 Mixer", "IN2R Switch", "IN2R PGA" },
-	{ "LINEOUT2 Mixer", "Output Switch", "Right Output Mixer" },
+	{ "LINEOUT2 Mixer", "Output Switch", "Right Output PGA" },
 
 
 	{ "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" },
 	{ "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" },
 	{ "LINEOUT2P Driver", NULL, "LINEOUT2 Mixer" },
 	{ "LINEOUT2P Driver", NULL, "LINEOUT2 Mixer" },
 };
 };
 
 
 static const struct snd_soc_dapm_route lineout2_se_routes[] = {
 static const struct snd_soc_dapm_route lineout2_se_routes[] = {
-	{ "LINEOUT2N Mixer", "Left Output Switch", "Left Output Mixer" },
-	{ "LINEOUT2N Mixer", "Right Output Switch", "Left Output Mixer" },
+	{ "LINEOUT2N Mixer", "Left Output Switch", "Left Output PGA" },
+	{ "LINEOUT2N Mixer", "Right Output Switch", "Right Output PGA" },
 
 
-	{ "LINEOUT2P Mixer", "Right Output Switch", "Right Output Mixer" },
+	{ "LINEOUT2P Mixer", "Right Output Switch", "Right Output PGA" },
 
 
 	{ "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" },
 	{ "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" },
 	{ "LINEOUT2P Driver", NULL, "LINEOUT2P Mixer" },
 	{ "LINEOUT2P Driver", NULL, "LINEOUT2P Mixer" },
@@ -836,17 +836,21 @@ int wm_hubs_add_analogue_controls(struct snd_soc_codec *codec)
 	snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_3_4_VOLUME,
 	snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_3_4_VOLUME,
 			    WM8993_IN2_VU, WM8993_IN2_VU);
 			    WM8993_IN2_VU, WM8993_IN2_VU);
 
 
+	snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_LEFT,
+			    WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);
 	snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_RIGHT,
 	snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_RIGHT,
 			    WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);
 			    WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);
 
 
 	snd_soc_update_bits(codec, WM8993_LEFT_OUTPUT_VOLUME,
 	snd_soc_update_bits(codec, WM8993_LEFT_OUTPUT_VOLUME,
-			    WM8993_HPOUT1L_ZC, WM8993_HPOUT1L_ZC);
+			    WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC,
+			    WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC);
 	snd_soc_update_bits(codec, WM8993_RIGHT_OUTPUT_VOLUME,
 	snd_soc_update_bits(codec, WM8993_RIGHT_OUTPUT_VOLUME,
 			    WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC,
 			    WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC,
 			    WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC);
 			    WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC);
 
 
 	snd_soc_update_bits(codec, WM8993_LEFT_OPGA_VOLUME,
 	snd_soc_update_bits(codec, WM8993_LEFT_OPGA_VOLUME,
-			    WM8993_MIXOUTL_ZC, WM8993_MIXOUTL_ZC);
+			    WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU,
+			    WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU);
 	snd_soc_update_bits(codec, WM8993_RIGHT_OPGA_VOLUME,
 	snd_soc_update_bits(codec, WM8993_RIGHT_OPGA_VOLUME,
 			    WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU,
 			    WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU,
 			    WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU);
 			    WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU);

+ 2 - 0
sound/soc/davinci/davinci-mcasp.c

@@ -909,6 +909,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 	dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
 	dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
 	dma_data->asp_chan_q = pdata->asp_chan_q;
 	dma_data->asp_chan_q = pdata->asp_chan_q;
 	dma_data->ram_chan_q = pdata->ram_chan_q;
 	dma_data->ram_chan_q = pdata->ram_chan_q;
+	dma_data->sram_size = pdata->sram_size_playback;
 	dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset +
 	dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset +
 							mem->start);
 							mem->start);
 
 
@@ -925,6 +926,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 	dma_data = &dev->dma_params[SNDRV_PCM_STREAM_CAPTURE];
 	dma_data = &dev->dma_params[SNDRV_PCM_STREAM_CAPTURE];
 	dma_data->asp_chan_q = pdata->asp_chan_q;
 	dma_data->asp_chan_q = pdata->asp_chan_q;
 	dma_data->ram_chan_q = pdata->ram_chan_q;
 	dma_data->ram_chan_q = pdata->ram_chan_q;
+	dma_data->sram_size = pdata->sram_size_capture;
 	dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset +
 	dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset +
 							mem->start);
 							mem->start);
 
 

+ 0 - 6
sound/soc/imx/imx-ssi.c

@@ -667,12 +667,6 @@ static int imx_ssi_probe(struct platform_device *pdev)
 	if (res)
 	if (res)
 		ssi->dma_params_rx.dma = res->start;
 		ssi->dma_params_rx.dma = res->start;
 
 
-	if ((cpu_is_mx27() || cpu_is_mx21()) &&
-			!(ssi->flags & IMX_SSI_USE_AC97) &&
-			(ssi->flags & IMX_SSI_DMA)) {
-		ssi->flags |= IMX_SSI_DMA;
-	}
-
 	platform_set_drvdata(pdev, ssi);
 	platform_set_drvdata(pdev, ssi);
 
 
 	ret = snd_soc_register_dai(&pdev->dev, dai);
 	ret = snd_soc_register_dai(&pdev->dev, dai);

+ 1 - 1
sound/soc/jz4740/jz4740-i2s.c

@@ -133,7 +133,7 @@ static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream,
 	struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 	struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai);
 	uint32_t conf;
 	uint32_t conf;
 
 
-	if (!dai->active)
+	if (dai->active)
 		return;
 		return;
 
 
 	conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);
 	conf = jz4740_i2s_read(i2s, JZ_REG_AIC_CONF);

+ 16 - 30
sound/soc/jz4740/qi_lb60.c

@@ -27,11 +27,7 @@
 static int qi_lb60_spk_event(struct snd_soc_dapm_widget *widget,
 static int qi_lb60_spk_event(struct snd_soc_dapm_widget *widget,
 			     struct snd_kcontrol *ctrl, int event)
 			     struct snd_kcontrol *ctrl, int event)
 {
 {
-	int on = 0;
-	if (event & SND_SOC_DAPM_POST_PMU)
-		on = 1;
-	else if (event & SND_SOC_DAPM_PRE_PMD)
-		on = 0;
+	int on = !SND_SOC_DAPM_EVENT_OFF(event);
 
 
 	gpio_set_value(QI_LB60_SND_GPIO, on);
 	gpio_set_value(QI_LB60_SND_GPIO, on);
 	gpio_set_value(QI_LB60_AMP_GPIO, on);
 	gpio_set_value(QI_LB60_AMP_GPIO, on);
@@ -70,12 +66,6 @@ static int qi_lb60_codec_init(struct snd_soc_pcm_runtime *rtd)
 		return ret;
 		return ret;
 	}
 	}
 
 
-	snd_soc_dapm_new_controls(dapm, qi_lb60_widgets,
-				  ARRAY_SIZE(qi_lb60_widgets));
-	snd_soc_dapm_add_routes(dapm, qi_lb60_routes,
-				ARRAY_SIZE(qi_lb60_routes));
-	snd_soc_dapm_sync(dapm);
-
 	return 0;
 	return 0;
 }
 }
 
 
@@ -93,10 +83,20 @@ static struct snd_soc_card qi_lb60 = {
 	.name = "QI LB60",
 	.name = "QI LB60",
 	.dai_link = &qi_lb60_dai,
 	.dai_link = &qi_lb60_dai,
 	.num_links = 1,
 	.num_links = 1,
+
+	.dapm_widgets = qi_lb60_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(qi_lb60_widgets),
+	.dapm_routes = qi_lb60_routes,
+	.num_dapm_routes = ARRAY_SIZE(qi_lb60_routes),
 };
 };
 
 
 static struct platform_device *qi_lb60_snd_device;
 static struct platform_device *qi_lb60_snd_device;
 
 
+static const struct gpio qi_lb60_gpios[] = {
+	{ QI_LB60_SND_GPIO, GPIOF_OUT_INIT_LOW, "SND" },
+	{ QI_LB60_AMP_GPIO, GPIOF_OUT_INIT_LOW, "AMP" },
+};
+
 static int __init qi_lb60_init(void)
 static int __init qi_lb60_init(void)
 {
 {
 	int ret;
 	int ret;
@@ -106,23 +106,12 @@ static int __init qi_lb60_init(void)
 	if (!qi_lb60_snd_device)
 	if (!qi_lb60_snd_device)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	ret = gpio_request(QI_LB60_SND_GPIO, "SND");
+	ret = gpio_request_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
 	if (ret) {
 	if (ret) {
-		pr_err("qi_lb60 snd: Failed to request SND GPIO(%d): %d\n",
-				QI_LB60_SND_GPIO, ret);
+		pr_err("qi_lb60 snd: Failed to request gpios: %d\n", ret);
 		goto err_device_put;
 		goto err_device_put;
 	}
 	}
 
 
-	ret = gpio_request(QI_LB60_AMP_GPIO, "AMP");
-	if (ret) {
-		pr_err("qi_lb60 snd: Failed to request AMP GPIO(%d): %d\n",
-				QI_LB60_AMP_GPIO, ret);
-		goto err_gpio_free_snd;
-	}
-
-	gpio_direction_output(QI_LB60_SND_GPIO, 0);
-	gpio_direction_output(QI_LB60_AMP_GPIO, 0);
-
 	platform_set_drvdata(qi_lb60_snd_device, &qi_lb60);
 	platform_set_drvdata(qi_lb60_snd_device, &qi_lb60);
 
 
 	ret = platform_device_add(qi_lb60_snd_device);
 	ret = platform_device_add(qi_lb60_snd_device);
@@ -135,10 +124,8 @@ static int __init qi_lb60_init(void)
 
 
 err_unset_pdata:
 err_unset_pdata:
 	platform_set_drvdata(qi_lb60_snd_device, NULL);
 	platform_set_drvdata(qi_lb60_snd_device, NULL);
-/*err_gpio_free_amp:*/
-	gpio_free(QI_LB60_AMP_GPIO);
-err_gpio_free_snd:
-	gpio_free(QI_LB60_SND_GPIO);
+/*err_gpio_free_array:*/
+	gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
 err_device_put:
 err_device_put:
 	platform_device_put(qi_lb60_snd_device);
 	platform_device_put(qi_lb60_snd_device);
 
 
@@ -148,9 +135,8 @@ module_init(qi_lb60_init);
 
 
 static void __exit qi_lb60_exit(void)
 static void __exit qi_lb60_exit(void)
 {
 {
-	gpio_free(QI_LB60_AMP_GPIO);
-	gpio_free(QI_LB60_SND_GPIO);
 	platform_device_unregister(qi_lb60_snd_device);
 	platform_device_unregister(qi_lb60_snd_device);
+	gpio_free_array(qi_lb60_gpios, ARRAY_SIZE(qi_lb60_gpios));
 }
 }
 module_exit(qi_lb60_exit);
 module_exit(qi_lb60_exit);
 
 

+ 10 - 0
sound/soc/mid-x86/sst_platform.c

@@ -249,10 +249,13 @@ static int sst_platform_open(struct snd_pcm_substream *substream)
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
 	stream->sstdrv_ops->vendor_id = MSIC_VENDOR_ID;
 	stream->sstdrv_ops->vendor_id = MSIC_VENDOR_ID;
+	stream->sstdrv_ops->module_name = SST_CARD_NAMES;
 	/* registering with SST driver to get access to SST APIs to use */
 	/* registering with SST driver to get access to SST APIs to use */
 	ret_val = register_sst_card(stream->sstdrv_ops);
 	ret_val = register_sst_card(stream->sstdrv_ops);
 	if (ret_val) {
 	if (ret_val) {
 		pr_err("sst: sst card registration failed\n");
 		pr_err("sst: sst card registration failed\n");
+		kfree(stream->sstdrv_ops);
+		kfree(stream);
 		return ret_val;
 		return ret_val;
 	}
 	}
 	runtime->private_data = stream;
 	runtime->private_data = stream;
@@ -270,6 +273,7 @@ static int sst_platform_close(struct snd_pcm_substream *substream)
 	str_id = stream->stream_info.str_id;
 	str_id = stream->stream_info.str_id;
 	if (str_id)
 	if (str_id)
 		ret_val = stream->sstdrv_ops->pcm_control->close(str_id);
 		ret_val = stream->sstdrv_ops->pcm_control->close(str_id);
+	unregister_sst_card(stream->sstdrv_ops);
 	kfree(stream->sstdrv_ops);
 	kfree(stream->sstdrv_ops);
 	kfree(stream);
 	kfree(stream);
 	return ret_val;
 	return ret_val;
@@ -376,6 +380,11 @@ static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 	return 0;
 }
 }
 
 
+static int sst_platform_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
 static struct snd_pcm_ops sst_platform_ops = {
 static struct snd_pcm_ops sst_platform_ops = {
 	.open = sst_platform_open,
 	.open = sst_platform_open,
 	.close = sst_platform_close,
 	.close = sst_platform_close,
@@ -384,6 +393,7 @@ static struct snd_pcm_ops sst_platform_ops = {
 	.trigger = sst_platform_pcm_trigger,
 	.trigger = sst_platform_pcm_trigger,
 	.pointer = sst_platform_pcm_pointer,
 	.pointer = sst_platform_pcm_pointer,
 	.hw_params = sst_platform_pcm_hw_params,
 	.hw_params = sst_platform_pcm_hw_params,
+	.hw_free = sst_platform_pcm_hw_free,
 };
 };
 
 
 static void sst_pcm_free(struct snd_pcm *pcm)
 static void sst_pcm_free(struct snd_pcm *pcm)

+ 3 - 3
sound/soc/omap/omap-mcbsp.c

@@ -4,7 +4,7 @@
  * Copyright (C) 2008 Nokia Corporation
  * Copyright (C) 2008 Nokia Corporation
  *
  *
  * Contact: Jarkko Nikula <jhnikula@gmail.com>
  * Contact: Jarkko Nikula <jhnikula@gmail.com>
- *          Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *          Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  *
  * This program is free software; you can redistribute it and/or
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * modify it under the terms of the GNU General Public License
@@ -146,7 +146,7 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
 	 * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words)
 	 * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words)
 	 * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words)
 	 * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words)
 	 */
 	 */
-	if (cpu_is_omap343x() || cpu_is_omap44xx()) {
+	if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
 		/*
 		/*
 		* Rule for the buffer size. We should not allow
 		* Rule for the buffer size. We should not allow
 		* smaller buffer than the FIFO size to avoid underruns
 		* smaller buffer than the FIFO size to avoid underruns
@@ -258,7 +258,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
 	default:
 	default:
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
-	if (cpu_is_omap343x()) {
+	if (cpu_is_omap34xx()) {
 		dma_data->set_threshold = omap_mcbsp_set_threshold;
 		dma_data->set_threshold = omap_mcbsp_set_threshold;
 		/* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
 		/* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
 		if (omap_mcbsp_get_dma_op_mode(bus_id) ==
 		if (omap_mcbsp_get_dma_op_mode(bus_id) ==

+ 1 - 1
sound/soc/omap/omap-mcbsp.h

@@ -4,7 +4,7 @@
  * Copyright (C) 2008 Nokia Corporation
  * Copyright (C) 2008 Nokia Corporation
  *
  *
  * Contact: Jarkko Nikula <jhnikula@gmail.com>
  * Contact: Jarkko Nikula <jhnikula@gmail.com>
- *          Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *          Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  *
  * This program is free software; you can redistribute it and/or
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * modify it under the terms of the GNU General Public License

+ 4 - 3
sound/soc/omap/omap-pcm.c

@@ -4,7 +4,7 @@
  * Copyright (C) 2008 Nokia Corporation
  * Copyright (C) 2008 Nokia Corporation
  *
  *
  * Contact: Jarkko Nikula <jhnikula@gmail.com>
  * Contact: Jarkko Nikula <jhnikula@gmail.com>
- *          Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *          Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  *
  * This program is free software; you can redistribute it and/or
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * modify it under the terms of the GNU General Public License
@@ -37,7 +37,8 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {
 				  SNDRV_PCM_INFO_MMAP_VALID |
 				  SNDRV_PCM_INFO_MMAP_VALID |
 				  SNDRV_PCM_INFO_INTERLEAVED |
 				  SNDRV_PCM_INFO_INTERLEAVED |
 				  SNDRV_PCM_INFO_PAUSE |
 				  SNDRV_PCM_INFO_PAUSE |
-				  SNDRV_PCM_INFO_RESUME,
+				  SNDRV_PCM_INFO_RESUME |
+				  SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
 	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
 	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
 				  SNDRV_PCM_FMTBIT_S32_LE,
 				  SNDRV_PCM_FMTBIT_S32_LE,
 	.period_bytes_min	= 32,
 	.period_bytes_min	= 32,
@@ -195,7 +196,7 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream)
 	if ((cpu_is_omap1510()))
 	if ((cpu_is_omap1510()))
 		omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ |
 		omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ |
 			      OMAP_DMA_LAST_IRQ | OMAP_DMA_BLOCK_IRQ);
 			      OMAP_DMA_LAST_IRQ | OMAP_DMA_BLOCK_IRQ);
-	else
+	else if (!substream->runtime->no_period_wakeup)
 		omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ);
 		omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ);
 
 
 	if (!(cpu_class_is_omap1())) {
 	if (!(cpu_class_is_omap1())) {

+ 1 - 1
sound/soc/omap/omap-pcm.h

@@ -4,7 +4,7 @@
  * Copyright (C) 2008 Nokia Corporation
  * Copyright (C) 2008 Nokia Corporation
  *
  *
  * Contact: Jarkko Nikula <jhnikula@gmail.com>
  * Contact: Jarkko Nikula <jhnikula@gmail.com>
- *          Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *          Peter Ujfalusi <peter.ujfalusi@ti.com>
  *
  *
  * This program is free software; you can redistribute it and/or
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * modify it under the terms of the GNU General Public License

+ 1 - 1
sound/soc/omap/rx51.c

@@ -3,7 +3,7 @@
  *
  *
  * Copyright (C) 2008 - 2009 Nokia Corporation
  * Copyright (C) 2008 - 2009 Nokia Corporation
  *
  *
- * Contact: Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Contact: Peter Ujfalusi <peter.ujfalusi@ti.com>
  *          Eduardo Valentin <eduardo.valentin@nokia.com>
  *          Eduardo Valentin <eduardo.valentin@nokia.com>
  *          Jarkko Nikula <jhnikula@gmail.com>
  *          Jarkko Nikula <jhnikula@gmail.com>
  *
  *

+ 9 - 0
sound/soc/pxa/Kconfig

@@ -155,6 +155,15 @@ config SND_SOC_RAUMFELD
 	help
 	help
 	  Say Y if you want to add support for SoC audio on Raumfeld devices
 	  Say Y if you want to add support for SoC audio on Raumfeld devices
 
 
+config SND_PXA2XX_SOC_HX4700
+	tristate "SoC Audio support for HP iPAQ hx4700"
+	depends on SND_PXA2XX_SOC && MACH_H4700
+	select SND_PXA2XX_SOC_I2S
+	select SND_SOC_AK4641
+	help
+	  Say Y if you want to add support for SoC audio on the
+	  HP iPAQ hx4700.
+
 config SND_PXA2XX_SOC_MAGICIAN
 config SND_PXA2XX_SOC_MAGICIAN
 	tristate "SoC Audio support for HTC Magician"
 	tristate "SoC Audio support for HTC Magician"
 	depends on SND_PXA2XX_SOC && MACH_MAGICIAN
 	depends on SND_PXA2XX_SOC && MACH_MAGICIAN

+ 2 - 0
sound/soc/pxa/Makefile

@@ -22,6 +22,7 @@ snd-soc-palm27x-objs := palm27x.o
 snd-soc-saarb-objs := saarb.o
 snd-soc-saarb-objs := saarb.o
 snd-soc-tavorevb3-objs := tavorevb3.o
 snd-soc-tavorevb3-objs := tavorevb3.o
 snd-soc-zylonite-objs := zylonite.o
 snd-soc-zylonite-objs := zylonite.o
+snd-soc-hx4700-objs := hx4700.o
 snd-soc-magician-objs := magician.o
 snd-soc-magician-objs := magician.o
 snd-soc-mioa701-objs := mioa701_wm9713.o
 snd-soc-mioa701-objs := mioa701_wm9713.o
 snd-soc-z2-objs := z2.o
 snd-soc-z2-objs := z2.o
@@ -37,6 +38,7 @@ obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o
 obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o
 obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o
 obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o
 obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o
 obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o
 obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o
+obj-$(CONFIG_SND_PXA2XX_SOC_HX4700) += snd-soc-hx4700.o
 obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o
 obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o
 obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
 obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
 obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o
 obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o

+ 1 - 1
sound/soc/pxa/corgi.c

@@ -310,7 +310,7 @@ static struct snd_soc_dai_link corgi_dai = {
 	.cpu_dai_name = "pxa2xx-i2s",
 	.cpu_dai_name = "pxa2xx-i2s",
 	.codec_dai_name = "wm8731-hifi",
 	.codec_dai_name = "wm8731-hifi",
 	.platform_name = "pxa-pcm-audio",
 	.platform_name = "pxa-pcm-audio",
-	.codec_name = "wm8731-codec.0-001b",
+	.codec_name = "wm8731.0-001b",
 	.init = corgi_wm8731_init,
 	.init = corgi_wm8731_init,
 	.ops = &corgi_ops,
 	.ops = &corgi_ops,
 };
 };

+ 255 - 0
sound/soc/pxa/hx4700.c

@@ -0,0 +1,255 @@
+/*
+ * SoC audio for HP iPAQ hx4700
+ *
+ * Copyright (c) 2009 Philipp Zabel
+ *
+ *  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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <mach/hx4700.h>
+#include <asm/mach-types.h>
+#include "pxa2xx-i2s.h"
+
+#include "../codecs/ak4641.h"
+
+static struct snd_soc_jack hs_jack;
+
+/* Headphones jack detection DAPM pin */
+static struct snd_soc_jack_pin hs_jack_pin[] = {
+	{
+		.pin	= "Headphone Jack",
+		.mask	= SND_JACK_HEADPHONE,
+	},
+	{
+		.pin	= "Speaker",
+		/* disable speaker when hp jack is inserted */
+		.mask   = SND_JACK_HEADPHONE,
+		.invert	= 1,
+	},
+};
+
+/* Headphones jack detection GPIO */
+static struct snd_soc_jack_gpio hs_jack_gpio = {
+	.gpio		= GPIO75_HX4700_EARPHONE_nDET,
+	.invert		= true,
+	.name		= "hp-gpio",
+	.report		= SND_JACK_HEADPHONE,
+	.debounce_time	= 200,
+};
+
+/*
+ * iPAQ hx4700 uses I2S for capture and playback.
+ */
+static int hx4700_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+
+	/* set codec DAI configuration */
+	ret = snd_soc_dai_set_fmt(codec_dai,
+			SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = snd_soc_dai_set_fmt(cpu_dai,
+			SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set the I2S system clock as output */
+	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+			SND_SOC_CLOCK_OUT);
+	if (ret < 0)
+		return ret;
+
+	/* inform codec driver about clock freq *
+	 * (PXA I2S always uses divider 256)    */
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, 256 * params_rate(params),
+			SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops hx4700_ops = {
+	.hw_params = hx4700_hw_params,
+};
+
+static int hx4700_spk_power(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *k, int event)
+{
+	gpio_set_value(GPIO107_HX4700_SPK_nSD, !!SND_SOC_DAPM_EVENT_ON(event));
+	return 0;
+}
+
+static int hx4700_hp_power(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *k, int event)
+{
+	gpio_set_value(GPIO92_HX4700_HP_DRIVER, !!SND_SOC_DAPM_EVENT_ON(event));
+	return 0;
+}
+
+/* hx4700 machine dapm widgets */
+static const struct snd_soc_dapm_widget hx4700_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", hx4700_hp_power),
+	SND_SOC_DAPM_SPK("Speaker", hx4700_spk_power),
+	SND_SOC_DAPM_MIC("Built-in Microphone", NULL),
+};
+
+/* hx4700 machine audio_map */
+static const struct snd_soc_dapm_route hx4700_audio_map[] = {
+
+	/* Headphone connected to LOUT, ROUT */
+	{"Headphone Jack", NULL, "LOUT"},
+	{"Headphone Jack", NULL, "ROUT"},
+
+	/* Speaker connected to MOUT2 */
+	{"Speaker", NULL, "MOUT2"},
+
+	/* Microphone connected to MICIN */
+	{"MICIN", NULL, "Built-in Microphone"},
+	{"AIN", NULL, "MICOUT"},
+};
+
+/*
+ * Logic for a ak4641 as connected on a HP iPAQ hx4700
+ */
+static int hx4700_ak4641_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	int err;
+
+	/* NC codec pins */
+	/* FIXME: is anything connected here? */
+	snd_soc_dapm_nc_pin(dapm, "MOUT1");
+	snd_soc_dapm_nc_pin(dapm, "MICEXT");
+	snd_soc_dapm_nc_pin(dapm, "AUX");
+
+	/* Jack detection API stuff */
+	err = snd_soc_jack_new(codec, "Headphone Jack",
+				SND_JACK_HEADPHONE, &hs_jack);
+	if (err)
+		return err;
+
+	err = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pin),
+					hs_jack_pin);
+	if (err)
+		return err;
+
+	err = snd_soc_jack_add_gpios(&hs_jack, 1, &hs_jack_gpio);
+
+	return err;
+}
+
+/* hx4700 digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link hx4700_dai = {
+	.name = "ak4641",
+	.stream_name = "AK4641",
+	.cpu_dai_name = "pxa2xx-i2s",
+	.codec_dai_name = "ak4641-hifi",
+	.platform_name = "pxa-pcm-audio",
+	.codec_name = "ak4641.0-0012",
+	.init = hx4700_ak4641_init,
+	.ops = &hx4700_ops,
+};
+
+/* hx4700 audio machine driver */
+static struct snd_soc_card snd_soc_card_hx4700 = {
+	.name			= "iPAQ hx4700",
+	.dai_link		= &hx4700_dai,
+	.num_links		= 1,
+	.dapm_widgets		= hx4700_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(hx4700_dapm_widgets),
+	.dapm_routes		= hx4700_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(hx4700_audio_map),
+};
+
+static struct gpio hx4700_audio_gpios[] = {
+	{ GPIO107_HX4700_SPK_nSD, GPIOF_OUT_INIT_HIGH, "SPK_POWER" },
+	{ GPIO92_HX4700_HP_DRIVER, GPIOF_OUT_INIT_LOW, "EP_POWER" },
+};
+
+static int __devinit hx4700_audio_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	if (!machine_is_h4700())
+		return -ENODEV;
+
+	ret = gpio_request_array(hx4700_audio_gpios,
+				ARRAY_SIZE(hx4700_audio_gpios));
+	if (ret)
+		return ret;
+
+	snd_soc_card_hx4700.dev = &pdev->dev;
+	ret = snd_soc_register_card(&snd_soc_card_hx4700);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int __devexit hx4700_audio_remove(struct platform_device *pdev)
+{
+	snd_soc_jack_free_gpios(&hs_jack, 1, &hs_jack_gpio);
+	snd_soc_unregister_card(&snd_soc_card_hx4700);
+
+	gpio_set_value(GPIO92_HX4700_HP_DRIVER, 0);
+	gpio_set_value(GPIO107_HX4700_SPK_nSD, 0);
+
+	gpio_free_array(hx4700_audio_gpios, ARRAY_SIZE(hx4700_audio_gpios));
+	return 0;
+}
+
+static struct platform_driver hx4700_audio_driver = {
+	.driver	= {
+		.name = "hx4700-audio",
+		.owner = THIS_MODULE,
+		.pm = &snd_soc_pm_ops,
+	},
+	.probe	= hx4700_audio_probe,
+	.remove	= __devexit_p(hx4700_audio_remove),
+};
+
+static int __init hx4700_modinit(void)
+{
+	return platform_driver_register(&hx4700_audio_driver);
+}
+module_init(hx4700_modinit);
+
+static void __exit hx4700_modexit(void)
+{
+	platform_driver_unregister(&hx4700_audio_driver);
+}
+
+module_exit(hx4700_modexit);
+
+MODULE_AUTHOR("Philipp Zabel");
+MODULE_DESCRIPTION("ALSA SoC iPAQ hx4700");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:hx4700-audio");

+ 1 - 1
sound/soc/pxa/poodle.c

@@ -276,7 +276,7 @@ static struct snd_soc_dai_link poodle_dai = {
 	.cpu_dai_name = "pxa2xx-i2s",
 	.cpu_dai_name = "pxa2xx-i2s",
 	.codec_dai_name = "wm8731-hifi",
 	.codec_dai_name = "wm8731-hifi",
 	.platform_name = "pxa-pcm-audio",
 	.platform_name = "pxa-pcm-audio",
-	.codec_name = "wm8731-codec.0-001b",
+	.codec_name = "wm8731.0-001b",
 	.init = poodle_wm8731_init,
 	.init = poodle_wm8731_init,
 	.ops = &poodle_ops,
 	.ops = &poodle_ops,
 };
 };

+ 29 - 12
sound/soc/pxa/spitz.c

@@ -42,6 +42,7 @@
 
 
 static int spitz_jack_func;
 static int spitz_jack_func;
 static int spitz_spk_func;
 static int spitz_spk_func;
+static int spitz_mic_gpio;
 
 
 static void spitz_ext_control(struct snd_soc_codec *codec)
 static void spitz_ext_control(struct snd_soc_codec *codec)
 {
 {
@@ -217,14 +218,7 @@ static int spitz_set_spk(struct snd_kcontrol *kcontrol,
 static int spitz_mic_bias(struct snd_soc_dapm_widget *w,
 static int spitz_mic_bias(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *k, int event)
 	struct snd_kcontrol *k, int event)
 {
 {
-	if (machine_is_borzoi() || machine_is_spitz())
-		gpio_set_value(SPITZ_GPIO_MIC_BIAS,
-				SND_SOC_DAPM_EVENT_ON(event));
-
-	if (machine_is_akita())
-		gpio_set_value(AKITA_GPIO_MIC_BIAS,
-				SND_SOC_DAPM_EVENT_ON(event));
-
+	gpio_set_value_cansleep(spitz_mic_gpio, SND_SOC_DAPM_EVENT_ON(event));
 	return 0;
 	return 0;
 }
 }
 
 
@@ -339,22 +333,45 @@ static int __init spitz_init(void)
 	if (!(machine_is_spitz() || machine_is_borzoi() || machine_is_akita()))
 	if (!(machine_is_spitz() || machine_is_borzoi() || machine_is_akita()))
 		return -ENODEV;
 		return -ENODEV;
 
 
+	if (machine_is_borzoi() || machine_is_spitz())
+		spitz_mic_gpio = SPITZ_GPIO_MIC_BIAS;
+	else
+		spitz_mic_gpio = AKITA_GPIO_MIC_BIAS;
+
+	ret = gpio_request(spitz_mic_gpio, "MIC GPIO");
+	if (ret)
+		goto err1;
+
+	ret = gpio_direction_output(spitz_mic_gpio, 0);
+	if (ret)
+		goto err2;
+
 	spitz_snd_device = platform_device_alloc("soc-audio", -1);
 	spitz_snd_device = platform_device_alloc("soc-audio", -1);
-	if (!spitz_snd_device)
-		return -ENOMEM;
+	if (!spitz_snd_device) {
+		ret = -ENOMEM;
+		goto err2;
+	}
 
 
 	platform_set_drvdata(spitz_snd_device, &snd_soc_spitz);
 	platform_set_drvdata(spitz_snd_device, &snd_soc_spitz);
-	ret = platform_device_add(spitz_snd_device);
 
 
+	ret = platform_device_add(spitz_snd_device);
 	if (ret)
 	if (ret)
-		platform_device_put(spitz_snd_device);
+		goto err3;
+
+	return 0;
 
 
+err3:
+	platform_device_put(spitz_snd_device);
+err2:
+	gpio_free(spitz_mic_gpio);
+err1:
 	return ret;
 	return ret;
 }
 }
 
 
 static void __exit spitz_exit(void)
 static void __exit spitz_exit(void)
 {
 {
 	platform_device_unregister(spitz_snd_device);
 	platform_device_unregister(spitz_snd_device);
+	gpio_free(spitz_mic_gpio);
 }
 }
 
 
 module_init(spitz_init);
 module_init(spitz_init);

+ 15 - 0
sound/soc/samsung/Kconfig

@@ -162,3 +162,18 @@ config SND_SOC_SAMSUNG_SMDK_SPDIF
 	select SND_SAMSUNG_SPDIF
 	select SND_SAMSUNG_SPDIF
 	help
 	help
 	  Say Y if you want to add support for SoC S/PDIF audio on the SMDK.
 	  Say Y if you want to add support for SoC S/PDIF audio on the SMDK.
+
+config SND_SOC_SMDK_WM8580_PCM
+	tristate "SoC PCM Audio support for WM8580 on SMDK"
+	depends on SND_SOC_SAMSUNG && (MACH_SMDK6450 || MACH_SMDKV210 || MACH_SMDKC110)
+	select SND_SOC_WM8580
+	select SND_SAMSUNG_PCM
+	help
+	  Say Y if you want to add support for SoC audio on the SMDK.
+
+config SND_SOC_SPEYSIDE
+	tristate "Audio support for Wolfson Speyside"
+	depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
+	select SND_SAMSUNG_I2S
+	select SND_SOC_WM8915
+	select SND_SOC_WM9081

+ 4 - 0
sound/soc/samsung/Makefile

@@ -34,6 +34,8 @@ snd-soc-smdk-wm9713-objs := smdk_wm9713.o
 snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
 snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o
 snd-soc-goni-wm8994-objs := goni_wm8994.o
 snd-soc-goni-wm8994-objs := goni_wm8994.o
 snd-soc-smdk-spdif-objs := smdk_spdif.o
 snd-soc-smdk-spdif-objs := smdk_spdif.o
+snd-soc-smdk-wm8580pcm-objs := smdk_wm8580pcm.o
+snd-soc-speyside-objs := speyside.o
 
 
 obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
@@ -51,3 +53,5 @@ obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM9713) += snd-soc-smdk-wm9713.o
 obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
 obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o
 obj-$(CONFIG_SND_SOC_GONI_AQUILA_WM8994) += snd-soc-goni-wm8994.o
 obj-$(CONFIG_SND_SOC_GONI_AQUILA_WM8994) += snd-soc-goni-wm8994.o
+obj-$(CONFIG_SND_SOC_SMDK_WM8580_PCM) += snd-soc-smdk-wm8580pcm.o
+obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o

+ 0 - 1
sound/soc/samsung/goni_wm8994.c

@@ -246,7 +246,6 @@ static struct snd_soc_dai_link goni_dai[] = {
 	.stream_name = "Voice",
 	.stream_name = "Voice",
 	.cpu_dai_name = "goni-voice-dai",
 	.cpu_dai_name = "goni-voice-dai",
 	.codec_dai_name = "wm8994-aif2",
 	.codec_dai_name = "wm8994-aif2",
-	.platform_name = "samsung-audio",
 	.codec_name = "wm8994-codec.0-001a",
 	.codec_name = "wm8994-codec.0-001a",
 	.ops = &goni_voice_ops,
 	.ops = &goni_voice_ops,
 },
 },

+ 0 - 1
sound/soc/samsung/neo1973_wm8753.c

@@ -432,7 +432,6 @@ static struct snd_soc_dai_link neo1973_dai[] = {
 { /* Voice via BT */
 { /* Voice via BT */
 	.name = "Bluetooth",
 	.name = "Bluetooth",
 	.stream_name = "Voice",
 	.stream_name = "Voice",
-	.platform_name = "samsung-audio",
 	.cpu_dai_name = "dfbmcs320-pcm",
 	.cpu_dai_name = "dfbmcs320-pcm",
 	.codec_dai_name = "wm8753-voice",
 	.codec_dai_name = "wm8753-voice",
 	.codec_name = "wm8753-codec.0-001a",
 	.codec_name = "wm8753-codec.0-001a",

+ 206 - 0
sound/soc/samsung/smdk_wm8580pcm.c

@@ -0,0 +1,206 @@
+/*
+ *  sound/soc/samsung/smdk_wm8580pcm.c
+ *
+ *  Copyright (c) 2011 Samsung Electronics Co. Ltd
+ *
+ *  This program is free software; you can redistribute  it and/or  modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ */
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include <sound/pcm.h>
+
+#include <asm/mach-types.h>
+
+#include "../codecs/wm8580.h"
+#include "dma.h"
+#include "pcm.h"
+
+/*
+ * Board Settings:
+ *  o '1' means 'ON'
+ *  o '0' means 'OFF'
+ *  o 'X' means 'Don't care'
+ *
+ * SMDK6410, SMDK6440, SMDK6450 Base B/D: CFG1-0000, CFG2-1111
+ * SMDKC110, SMDKV210: CFGB11-100100, CFGB12-0000
+ */
+
+#define SMDK_WM8580_EXT_OSC 12000000
+#define SMDK_WM8580_EXT_MCLK 4096000
+#define SMDK_WM8580_EXT_VOICE 2048000
+
+static unsigned long mclk_freq;
+static unsigned long xtal_freq;
+
+/*
+ * If MCLK clock directly gets from XTAL, we don't have to use PLL
+ * to make MCLK, but if XTAL clock source connects with other codec
+ * pin (like XTI), we should have to set codec's PLL to make MCLK.
+ * Because Samsung SoC does not support pcmcdclk output like I2S.
+ */
+
+static int smdk_wm8580_pcm_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int rfs, ret;
+
+	switch (params_rate(params)) {
+	case 8000:
+		break;
+	default:
+		printk(KERN_ERR "%s:%d Sampling Rate %u not supported!\n",
+		__func__, __LINE__, params_rate(params));
+		return -EINVAL;
+	}
+
+	rfs = mclk_freq / params_rate(params) / 2;
+
+	/* Set the codec DAI configuration */
+	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B
+				| SND_SOC_DAIFMT_IB_NF
+				| SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* Set the cpu DAI configuration */
+	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_B
+				| SND_SOC_DAIFMT_IB_NF
+				| SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	if (mclk_freq == xtal_freq) {
+		ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_MCLK,
+						mclk_freq, SND_SOC_CLOCK_IN);
+		if (ret < 0)
+			return ret;
+
+		ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
+						WM8580_CLKSRC_MCLK);
+		if (ret < 0)
+			return ret;
+	} else {
+		ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA,
+						mclk_freq, SND_SOC_CLOCK_IN);
+		if (ret < 0)
+			return ret;
+
+		ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
+						WM8580_CLKSRC_PLLA);
+		if (ret < 0)
+			return ret;
+
+		ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0,
+						xtal_freq, mclk_freq);
+		if (ret < 0)
+			return ret;
+	}
+
+	/* Set PCM source clock on CPU */
+	ret = snd_soc_dai_set_sysclk(cpu_dai, S3C_PCM_CLKSRC_MUX,
+					mclk_freq, SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* Set SCLK_DIV for making bclk */
+	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_PCM_SCLK_PER_FS, rfs);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops smdk_wm8580_pcm_ops = {
+	.hw_params = smdk_wm8580_pcm_hw_params,
+};
+
+static struct snd_soc_dai_link smdk_dai[] = {
+	{
+		.name = "WM8580 PAIF PCM RX",
+		.stream_name = "Playback",
+		.cpu_dai_name = "samsung-pcm.0",
+		.codec_dai_name = "wm8580-hifi-playback",
+		.platform_name = "samsung-audio",
+		.codec_name = "wm8580-codec.0-001b",
+		.ops = &smdk_wm8580_pcm_ops,
+	}, {
+		.name = "WM8580 PAIF PCM TX",
+		.stream_name = "Capture",
+		.cpu_dai_name = "samsung-pcm.0",
+		.codec_dai_name = "wm8580-hifi-capture",
+		.platform_name = "samsung-audio",
+		.codec_name = "wm8580-codec.0-001b",
+		.ops = &smdk_wm8580_pcm_ops,
+	},
+};
+
+static struct snd_soc_card smdk_pcm = {
+	.name = "SMDK-PCM",
+	.dai_link = smdk_dai,
+	.num_links = 2,
+};
+
+/*
+ * After SMDKC110 Base Board's Rev is '0.1', 12MHz External OSC(X1)
+ * is absent (or not connected), so we connect EXT_VOICE_CLK(OSC4),
+ * 2.0484Mhz, directly with MCLK both Codec and SoC.
+ */
+static int __devinit snd_smdk_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+
+	xtal_freq = SMDK_WM8580_EXT_OSC;
+	mclk_freq = SMDK_WM8580_EXT_MCLK;
+
+	if (machine_is_smdkc110() || machine_is_smdkv210())
+		xtal_freq = mclk_freq = SMDK_WM8580_EXT_VOICE;
+
+	smdk_pcm.dev = &pdev->dev;
+	ret = snd_soc_register_card(&smdk_pcm);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __devexit snd_smdk_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_card(&smdk_pcm);
+	platform_set_drvdata(pdev, NULL);
+	return 0;
+}
+
+static struct platform_driver snd_smdk_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "samsung-smdk-pcm",
+	},
+	.probe = snd_smdk_probe,
+	.remove = __devexit_p(snd_smdk_remove),
+};
+
+static int __init smdk_audio_init(void)
+{
+	return platform_driver_register(&snd_smdk_driver);
+}
+
+module_init(smdk_audio_init);
+
+static void __exit smdk_audio_exit(void)
+{
+	platform_driver_unregister(&snd_smdk_driver);
+}
+
+module_exit(smdk_audio_exit);
+
+MODULE_AUTHOR("Sangbeom Kim, <sbkim73@samsung.com>");
+MODULE_DESCRIPTION("ALSA SoC SMDK WM8580 for PCM");
+MODULE_LICENSE("GPL");

+ 332 - 0
sound/soc/samsung/speyside.c

@@ -0,0 +1,332 @@
+/*
+ * Speyside audio support
+ *
+ * Copyright 2011 Wolfson Microelectronics
+ *
+ * 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.
+ */
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <linux/gpio.h>
+
+#include "../codecs/wm8915.h"
+#include "../codecs/wm9081.h"
+
+#define WM8915_HPSEL_GPIO 214
+
+static int speyside_set_bias_level(struct snd_soc_card *card,
+				   enum snd_soc_bias_level level)
+{
+	struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+	int ret;
+
+	switch (level) {
+	case SND_SOC_BIAS_STANDBY:
+		ret = snd_soc_dai_set_sysclk(codec_dai, WM8915_SYSCLK_MCLK1,
+					     32768, SND_SOC_CLOCK_IN);
+		if (ret < 0)
+			return ret;
+
+		ret = snd_soc_dai_set_pll(codec_dai, WM8915_FLL_MCLK1,
+					  0, 0, 0);
+		if (ret < 0) {
+			pr_err("Failed to stop FLL\n");
+			return ret;
+		}
+
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int speyside_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	int ret;
+
+	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
+					 | SND_SOC_DAIFMT_NB_NF
+					 | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
+					 | SND_SOC_DAIFMT_NB_NF
+					 | SND_SOC_DAIFMT_CBM_CFM);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_pll(codec_dai, 0, WM8915_FLL_MCLK1,
+				  32768, 256 * 48000);
+	if (ret < 0)
+		return ret;
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, WM8915_SYSCLK_FLL,
+				     256 * 48000, SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_ops speyside_ops = {
+	.hw_params = speyside_hw_params,
+};
+
+static struct snd_soc_jack speyside_headset;
+
+/* Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin speyside_headset_pins[] = {
+	{
+		.pin = "Headset Mic",
+		.mask = SND_JACK_MICROPHONE,
+	},
+	{
+		.pin = "Headphone",
+		.mask = SND_JACK_HEADPHONE,
+	},
+};
+
+/* Default the headphone selection to active high */
+static int speyside_jack_polarity;
+
+static int speyside_get_micbias(struct snd_soc_dapm_widget *source,
+				struct snd_soc_dapm_widget *sink)
+{
+	if (speyside_jack_polarity && (strcmp(source->name, "MICB1") == 0))
+		return 1;
+	if (!speyside_jack_polarity && (strcmp(source->name, "MICB2") == 0))
+		return 1;
+
+	return 0;
+}
+
+static void speyside_set_polarity(struct snd_soc_codec *codec,
+				  int polarity)
+{
+	speyside_jack_polarity = !polarity;
+	gpio_direction_output(WM8915_HPSEL_GPIO, speyside_jack_polarity);
+
+	/* Re-run DAPM to make sure we're using the correct mic bias */
+	snd_soc_dapm_sync(&codec->dapm);
+}
+
+static int speyside_wm8915_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_dai *dai = rtd->codec_dai;
+	struct snd_soc_codec *codec = rtd->codec;
+	int ret;
+
+	ret = snd_soc_dai_set_sysclk(dai, WM8915_SYSCLK_MCLK1, 32768, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = gpio_request(WM8915_HPSEL_GPIO, "HP_SEL");
+	if (ret != 0)
+		pr_err("Failed to request HP_SEL GPIO: %d\n", ret);
+	gpio_direction_output(WM8915_HPSEL_GPIO, speyside_jack_polarity);
+
+	ret = snd_soc_jack_new(codec, "Headset",
+			       SND_JACK_HEADSET | SND_JACK_BTN_0,
+			       &speyside_headset);
+	if (ret)
+		return ret;
+
+	ret = snd_soc_jack_add_pins(&speyside_headset,
+				    ARRAY_SIZE(speyside_headset_pins),
+				    speyside_headset_pins);
+	if (ret)
+		return ret;
+
+	wm8915_detect(codec, &speyside_headset, speyside_set_polarity);
+
+	return 0;
+}
+
+static int speyside_late_probe(struct snd_soc_card *card)
+{
+	snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
+	snd_soc_dapm_ignore_suspend(&card->dapm, "Headset Mic");
+	snd_soc_dapm_ignore_suspend(&card->dapm, "Main AMIC");
+	snd_soc_dapm_ignore_suspend(&card->dapm, "Main DMIC");
+	snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
+	snd_soc_dapm_ignore_suspend(&card->dapm, "WM1250 Output");
+	snd_soc_dapm_ignore_suspend(&card->dapm, "WM1250 Input");
+
+	return 0;
+}
+
+static struct snd_soc_dai_link speyside_dai[] = {
+	{
+		.name = "CPU",
+		.stream_name = "CPU",
+		.cpu_dai_name = "samsung-i2s.0",
+		.codec_dai_name = "wm8915-aif1",
+		.platform_name = "samsung-audio",
+		.codec_name = "wm8915.1-001a",
+		.init = speyside_wm8915_init,
+		.ops = &speyside_ops,
+	},
+	{
+		.name = "Baseband",
+		.stream_name = "Baseband",
+		.cpu_dai_name = "wm8915-aif2",
+		.codec_dai_name = "wm1250-ev1",
+		.codec_name = "wm1250-ev1.1-0027",
+		.ops = &speyside_ops,
+		.ignore_suspend = 1,
+	},
+};
+
+static int speyside_wm9081_init(struct snd_soc_dapm_context *dapm)
+{
+	snd_soc_dapm_nc_pin(dapm, "LINEOUT");
+
+	/* At any time the WM9081 is active it will have this clock */
+	return snd_soc_codec_set_sysclk(dapm->codec, WM9081_SYSCLK_MCLK,
+					48000 * 256, 0);
+}
+
+static struct snd_soc_aux_dev speyside_aux_dev[] = {
+	{
+		.name = "wm9081",
+		.codec_name = "wm9081.1-006c",
+		.init = speyside_wm9081_init,
+	},
+};
+
+static struct snd_soc_codec_conf speyside_codec_conf[] = {
+	{
+		.dev_name = "wm9081.1-006c",
+		.name_prefix = "Sub",
+	},
+};
+
+static const struct snd_kcontrol_new controls[] = {
+	SOC_DAPM_PIN_SWITCH("Main Speaker"),
+	SOC_DAPM_PIN_SWITCH("Main DMIC"),
+	SOC_DAPM_PIN_SWITCH("Main AMIC"),
+	SOC_DAPM_PIN_SWITCH("WM1250 Input"),
+	SOC_DAPM_PIN_SWITCH("WM1250 Output"),
+};
+
+static struct snd_soc_dapm_widget widgets[] = {
+	SND_SOC_DAPM_HP("Headphone", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+
+	SND_SOC_DAPM_SPK("Main Speaker", NULL),
+
+	SND_SOC_DAPM_MIC("Main AMIC", NULL),
+	SND_SOC_DAPM_MIC("Main DMIC", NULL),
+};
+
+static struct snd_soc_dapm_route audio_paths[] = {
+	{ "IN1RN", NULL, "MICB1" },
+	{ "IN1RP", NULL, "MICB1" },
+	{ "IN1RN", NULL, "MICB2" },
+	{ "IN1RP", NULL, "MICB2" },
+	{ "MICB1", NULL, "Headset Mic", speyside_get_micbias },
+	{ "MICB2", NULL, "Headset Mic", speyside_get_micbias },
+
+	{ "IN1LP", NULL, "MICB2" },
+	{ "IN1RN", NULL, "MICB1" },
+	{ "MICB2", NULL, "Main AMIC" },
+
+	{ "DMIC1DAT", NULL, "MICB1" },
+	{ "DMIC2DAT", NULL, "MICB1" },
+	{ "MICB1", NULL, "Main DMIC" },
+
+	{ "Headphone", NULL, "HPOUT1L" },
+	{ "Headphone", NULL, "HPOUT1R" },
+
+	{ "Sub IN1", NULL, "HPOUT2L" },
+	{ "Sub IN2", NULL, "HPOUT2R" },
+
+	{ "Main Speaker", NULL, "Sub SPKN" },
+	{ "Main Speaker", NULL, "Sub SPKP" },
+	{ "Main Speaker", NULL, "SPKDAT" },
+};
+
+static struct snd_soc_card speyside = {
+	.name = "Speyside",
+	.dai_link = speyside_dai,
+	.num_links = ARRAY_SIZE(speyside_dai),
+	.aux_dev = speyside_aux_dev,
+	.num_aux_devs = ARRAY_SIZE(speyside_aux_dev),
+	.codec_conf = speyside_codec_conf,
+	.num_configs = ARRAY_SIZE(speyside_codec_conf),
+
+	.set_bias_level = speyside_set_bias_level,
+
+	.controls = controls,
+	.num_controls = ARRAY_SIZE(controls),
+	.dapm_widgets = widgets,
+	.num_dapm_widgets = ARRAY_SIZE(widgets),
+	.dapm_routes = audio_paths,
+	.num_dapm_routes = ARRAY_SIZE(audio_paths),
+
+	.late_probe = speyside_late_probe,
+};
+
+static __devinit int speyside_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &speyside;
+	int ret;
+
+	card->dev = &pdev->dev;
+
+	ret = snd_soc_register_card(card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+			ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __devexit speyside_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+	snd_soc_unregister_card(card);
+
+	return 0;
+}
+
+static struct platform_driver speyside_driver = {
+	.driver = {
+		.name = "speyside",
+		.owner = THIS_MODULE,
+		.pm = &snd_soc_pm_ops,
+	},
+	.probe = speyside_probe,
+	.remove = __devexit_p(speyside_remove),
+};
+
+static int __init speyside_audio_init(void)
+{
+	return platform_driver_register(&speyside_driver);
+}
+module_init(speyside_audio_init);
+
+static void __exit speyside_audio_exit(void)
+{
+	platform_driver_unregister(&speyside_driver);
+}
+module_exit(speyside_audio_exit);
+
+MODULE_DESCRIPTION("Speyside audio support");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:speyside");

+ 155 - 33
sound/soc/sh/fsi.c

@@ -86,8 +86,8 @@
 #define SE	(1 << 0)	/* Fix the master clock */
 #define SE	(1 << 0)	/* Fix the master clock */
 
 
 /* CLK_RST */
 /* CLK_RST */
-#define B_CLK		0x00000010
-#define A_CLK		0x00000001
+#define CRB	(1 << 4)
+#define CRA	(1 << 0)
 
 
 /* IO SHIFT / MACRO */
 /* IO SHIFT / MACRO */
 #define BI_SHIFT	12
 #define BI_SHIFT	12
@@ -146,11 +146,20 @@ struct fsi_priv {
 	void __iomem *base;
 	void __iomem *base;
 	struct fsi_master *master;
 	struct fsi_master *master;
 
 
-	int chan_num;
 	struct fsi_stream playback;
 	struct fsi_stream playback;
 	struct fsi_stream capture;
 	struct fsi_stream capture;
 
 
+	int chan_num:16;
+	int clk_master:1;
+
 	long rate;
 	long rate;
+
+	/* for suspend/resume */
+	u32 saved_do_fmt;
+	u32 saved_di_fmt;
+	u32 saved_ckg1;
+	u32 saved_ckg2;
+	u32 saved_out_sel;
 };
 };
 
 
 struct fsi_core {
 struct fsi_core {
@@ -171,6 +180,14 @@ struct fsi_master {
 	struct fsi_core *core;
 	struct fsi_core *core;
 	struct sh_fsi_platform_info *info;
 	struct sh_fsi_platform_info *info;
 	spinlock_t lock;
 	spinlock_t lock;
+
+	/* for suspend/resume */
+	u32 saved_a_mclk;
+	u32 saved_b_mclk;
+	u32 saved_iemsk;
+	u32 saved_imsk;
+	u32 saved_clk_rst;
+	u32 saved_soft_rst;
 };
 };
 
 
 /*
 /*
@@ -244,6 +261,11 @@ static struct fsi_master *fsi_get_master(struct fsi_priv *fsi)
 	return fsi->master;
 	return fsi->master;
 }
 }
 
 
+static int fsi_is_clk_master(struct fsi_priv *fsi)
+{
+	return fsi->clk_master;
+}
+
 static int fsi_is_port_a(struct fsi_priv *fsi)
 static int fsi_is_port_a(struct fsi_priv *fsi)
 {
 {
 	return fsi->master->base == fsi->base;
 	return fsi->master->base == fsi->base;
@@ -535,20 +557,45 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
 }
 }
 
 
 /*
 /*
- *		ctrl function
+ *		clock function
  */
  */
+#define fsi_module_init(m, d)	__fsi_module_clk_ctrl(m, d, 1)
+#define fsi_module_kill(m, d)	__fsi_module_clk_ctrl(m, d, 0)
+static void __fsi_module_clk_ctrl(struct fsi_master *master,
+				  struct device *dev,
+				  int enable)
+{
+	pm_runtime_get_sync(dev);
+
+	if (enable) {
+		/* enable only SR */
+		fsi_master_mask_set(master, SOFT_RST, FSISR, FSISR);
+		fsi_master_mask_set(master, SOFT_RST, PASR | PBSR, 0);
+	} else {
+		/* clear all registers */
+		fsi_master_mask_set(master, SOFT_RST, FSISR, 0);
+	}
 
 
-static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable)
+	pm_runtime_put_sync(dev);
+}
+
+#define fsi_port_start(f)	__fsi_port_clk_ctrl(f, 1)
+#define fsi_port_stop(f)	__fsi_port_clk_ctrl(f, 0)
+static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int enable)
 {
 {
-	u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4);
 	struct fsi_master *master = fsi_get_master(fsi);
 	struct fsi_master *master = fsi_get_master(fsi);
+	u32 soft = fsi_is_port_a(fsi) ? PASR : PBSR;
+	u32 clk  = fsi_is_port_a(fsi) ? CRA  : CRB;
+	int is_master = fsi_is_clk_master(fsi);
 
 
-	if (enable)
-		fsi_master_mask_set(master, CLK_RST, val, val);
-	else
-		fsi_master_mask_set(master, CLK_RST, val, 0);
+	fsi_master_mask_set(master, SOFT_RST, soft, (enable) ? soft : 0);
+	if (is_master)
+		fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
 }
 }
 
 
+/*
+ *		ctrl function
+ */
 static void fsi_fifo_init(struct fsi_priv *fsi,
 static void fsi_fifo_init(struct fsi_priv *fsi,
 			  int is_play,
 			  int is_play,
 			  struct snd_soc_dai *dai)
 			  struct snd_soc_dai *dai)
@@ -601,18 +648,6 @@ static void fsi_fifo_init(struct fsi_priv *fsi,
 	}
 	}
 }
 }
 
 
-static void fsi_soft_all_reset(struct fsi_master *master)
-{
-	/* port AB reset */
-	fsi_master_mask_set(master, SOFT_RST, PASR | PBSR, 0);
-	mdelay(10);
-
-	/* soft reset */
-	fsi_master_mask_set(master, SOFT_RST, FSISR, 0);
-	fsi_master_mask_set(master, SOFT_RST, FSISR, FSISR);
-	mdelay(10);
-}
-
 static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream)
 static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream)
 {
 {
 	struct snd_pcm_runtime *runtime;
 	struct snd_pcm_runtime *runtime;
@@ -793,14 +828,13 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
 	struct fsi_priv *fsi = fsi_get_priv(substream);
 	struct fsi_priv *fsi = fsi_get_priv(substream);
 	int is_play = fsi_is_play(substream);
 	int is_play = fsi_is_play(substream);
 	struct fsi_master *master = fsi_get_master(fsi);
 	struct fsi_master *master = fsi_get_master(fsi);
-	set_rate_func set_rate;
+	set_rate_func set_rate = fsi_get_info_set_rate(master);
 
 
 	fsi_irq_disable(fsi, is_play);
 	fsi_irq_disable(fsi, is_play);
-	fsi_clk_ctrl(fsi, 0);
 
 
-	set_rate = fsi_get_info_set_rate(master);
-	if (set_rate && fsi->rate)
+	if (fsi_is_clk_master(fsi))
 		set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0);
 		set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0);
+
 	fsi->rate = 0;
 	fsi->rate = 0;
 
 
 	pm_runtime_put_sync(dai->dev);
 	pm_runtime_put_sync(dai->dev);
@@ -821,8 +855,10 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
 				frames_to_bytes(runtime, runtime->period_size));
 				frames_to_bytes(runtime, runtime->period_size));
 		ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi);
 		ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi);
 		fsi_irq_enable(fsi, is_play);
 		fsi_irq_enable(fsi, is_play);
+		fsi_port_start(fsi);
 		break;
 		break;
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_STOP:
+		fsi_port_stop(fsi);
 		fsi_irq_disable(fsi, is_play);
 		fsi_irq_disable(fsi, is_play);
 		fsi_stream_pop(fsi, is_play);
 		fsi_stream_pop(fsi, is_play);
 		break;
 		break;
@@ -876,6 +912,8 @@ static int fsi_set_fmt_spdif(struct fsi_priv *fsi)
 static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 {
 	struct fsi_priv *fsi = fsi_get_priv_frm_dai(dai);
 	struct fsi_priv *fsi = fsi_get_priv_frm_dai(dai);
+	struct fsi_master *master = fsi_get_master(fsi);
+	set_rate_func set_rate = fsi_get_info_set_rate(master);
 	u32 flags = fsi_get_info_flags(fsi);
 	u32 flags = fsi_get_info_flags(fsi);
 	u32 data = 0;
 	u32 data = 0;
 	int ret;
 	int ret;
@@ -886,6 +924,7 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBM_CFM:
 	case SND_SOC_DAIFMT_CBM_CFM:
 		data = DIMD | DOMD;
 		data = DIMD | DOMD;
+		fsi->clk_master = 1;
 		break;
 		break;
 	case SND_SOC_DAIFMT_CBS_CFS:
 	case SND_SOC_DAIFMT_CBS_CFS:
 		break;
 		break;
@@ -893,6 +932,13 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 		ret = -EINVAL;
 		ret = -EINVAL;
 		goto set_fmt_exit;
 		goto set_fmt_exit;
 	}
 	}
+
+	if (fsi_is_clk_master(fsi) && !set_rate) {
+		dev_err(dai->dev, "platform doesn't have set_rate\n");
+		ret = -EINVAL;
+		goto set_fmt_exit;
+	}
+
 	fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data);
 	fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data);
 
 
 	/* set format */
 	/* set format */
@@ -919,13 +965,12 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
 {
 {
 	struct fsi_priv *fsi = fsi_get_priv(substream);
 	struct fsi_priv *fsi = fsi_get_priv(substream);
 	struct fsi_master *master = fsi_get_master(fsi);
 	struct fsi_master *master = fsi_get_master(fsi);
-	set_rate_func set_rate;
+	set_rate_func set_rate = fsi_get_info_set_rate(master);
 	int fsi_ver = master->core->ver;
 	int fsi_ver = master->core->ver;
 	long rate = params_rate(params);
 	long rate = params_rate(params);
 	int ret;
 	int ret;
 
 
-	set_rate = fsi_get_info_set_rate(master);
-	if (!set_rate)
+	if (!fsi_is_clk_master(fsi))
 		return 0;
 		return 0;
 
 
 	ret = set_rate(dai->dev, fsi_is_port_a(fsi), rate, 1);
 	ret = set_rate(dai->dev, fsi_is_port_a(fsi), rate, 1);
@@ -987,7 +1032,6 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
 
 
 		fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data);
 		fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data);
 		udelay(10);
 		udelay(10);
-		fsi_clk_ctrl(fsi, 1);
 		ret = 0;
 		ret = 0;
 	}
 	}
 
 
@@ -1202,9 +1246,7 @@ static int fsi_probe(struct platform_device *pdev)
 	pm_runtime_enable(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
 	dev_set_drvdata(&pdev->dev, master);
 	dev_set_drvdata(&pdev->dev, master);
 
 
-	pm_runtime_get_sync(&pdev->dev);
-	fsi_soft_all_reset(master);
-	pm_runtime_put_sync(&pdev->dev);
+	fsi_module_init(master, &pdev->dev);
 
 
 	ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED,
 	ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED,
 			  id_entry->name, master);
 			  id_entry->name, master);
@@ -1248,6 +1290,8 @@ static int fsi_remove(struct platform_device *pdev)
 
 
 	master = dev_get_drvdata(&pdev->dev);
 	master = dev_get_drvdata(&pdev->dev);
 
 
+	fsi_module_kill(master, &pdev->dev);
+
 	free_irq(master->irq, master);
 	free_irq(master->irq, master);
 	pm_runtime_disable(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 
 
@@ -1260,6 +1304,82 @@ static int fsi_remove(struct platform_device *pdev)
 	return 0;
 	return 0;
 }
 }
 
 
+static void __fsi_suspend(struct fsi_priv *fsi,
+			  struct device *dev,
+			  set_rate_func set_rate)
+{
+	fsi->saved_do_fmt	= fsi_reg_read(fsi, DO_FMT);
+	fsi->saved_di_fmt	= fsi_reg_read(fsi, DI_FMT);
+	fsi->saved_ckg1		= fsi_reg_read(fsi, CKG1);
+	fsi->saved_ckg2		= fsi_reg_read(fsi, CKG2);
+	fsi->saved_out_sel	= fsi_reg_read(fsi, OUT_SEL);
+
+	if (fsi_is_clk_master(fsi))
+		set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 0);
+}
+
+static void __fsi_resume(struct fsi_priv *fsi,
+			 struct device *dev,
+			 set_rate_func set_rate)
+{
+	fsi_reg_write(fsi, DO_FMT,	fsi->saved_do_fmt);
+	fsi_reg_write(fsi, DI_FMT,	fsi->saved_di_fmt);
+	fsi_reg_write(fsi, CKG1,	fsi->saved_ckg1);
+	fsi_reg_write(fsi, CKG2,	fsi->saved_ckg2);
+	fsi_reg_write(fsi, OUT_SEL,	fsi->saved_out_sel);
+
+	if (fsi_is_clk_master(fsi))
+		set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 1);
+}
+
+static int fsi_suspend(struct device *dev)
+{
+	struct fsi_master *master = dev_get_drvdata(dev);
+	set_rate_func set_rate = fsi_get_info_set_rate(master);
+
+	pm_runtime_get_sync(dev);
+
+	__fsi_suspend(&master->fsia, dev, set_rate);
+	__fsi_suspend(&master->fsib, dev, set_rate);
+
+	master->saved_a_mclk	= fsi_core_read(master, a_mclk);
+	master->saved_b_mclk	= fsi_core_read(master, b_mclk);
+	master->saved_iemsk	= fsi_core_read(master, iemsk);
+	master->saved_imsk	= fsi_core_read(master, imsk);
+	master->saved_clk_rst	= fsi_master_read(master, CLK_RST);
+	master->saved_soft_rst	= fsi_master_read(master, SOFT_RST);
+
+	fsi_module_kill(master, dev);
+
+	pm_runtime_put_sync(dev);
+
+	return 0;
+}
+
+static int fsi_resume(struct device *dev)
+{
+	struct fsi_master *master = dev_get_drvdata(dev);
+	set_rate_func set_rate = fsi_get_info_set_rate(master);
+
+	pm_runtime_get_sync(dev);
+
+	fsi_module_init(master, dev);
+
+	fsi_master_mask_set(master, SOFT_RST, 0xffff, master->saved_soft_rst);
+	fsi_master_mask_set(master, CLK_RST, 0xffff, master->saved_clk_rst);
+	fsi_core_mask_set(master, a_mclk, 0xffff, master->saved_a_mclk);
+	fsi_core_mask_set(master, b_mclk, 0xffff, master->saved_b_mclk);
+	fsi_core_mask_set(master, iemsk, 0xffff, master->saved_iemsk);
+	fsi_core_mask_set(master, imsk, 0xffff, master->saved_imsk);
+
+	__fsi_resume(&master->fsia, dev, set_rate);
+	__fsi_resume(&master->fsib, dev, set_rate);
+
+	pm_runtime_put_sync(dev);
+
+	return 0;
+}
+
 static int fsi_runtime_nop(struct device *dev)
 static int fsi_runtime_nop(struct device *dev)
 {
 {
 	/* Runtime PM callback shared between ->runtime_suspend()
 	/* Runtime PM callback shared between ->runtime_suspend()
@@ -1273,6 +1393,8 @@ static int fsi_runtime_nop(struct device *dev)
 }
 }
 
 
 static struct dev_pm_ops fsi_pm_ops = {
 static struct dev_pm_ops fsi_pm_ops = {
+	.suspend		= fsi_suspend,
+	.resume			= fsi_resume,
 	.runtime_suspend	= fsi_runtime_nop,
 	.runtime_suspend	= fsi_runtime_nop,
 	.runtime_resume		= fsi_runtime_nop,
 	.runtime_resume		= fsi_runtime_nop,
 };
 };

+ 148 - 464
sound/soc/soc-cache.c

@@ -20,40 +20,28 @@
 
 
 #include <trace/events/asoc.h>
 #include <trace/events/asoc.h>
 
 
-static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
-				     unsigned int reg)
+#ifdef CONFIG_SPI_MASTER
+static int do_spi_write(void *control, const char *data, int len)
 {
 {
+	struct spi_device *spi = control;
 	int ret;
 	int ret;
-	unsigned int val;
-
-	if (reg >= codec->driver->reg_cache_size ||
-		snd_soc_codec_volatile_register(codec, reg) ||
-		codec->cache_bypass) {
-			if (codec->cache_only)
-				return -1;
-
-			BUG_ON(!codec->hw_read);
-			return codec->hw_read(codec, reg);
-	}
 
 
-	ret = snd_soc_cache_read(codec, reg, &val);
+	ret = spi_write(spi, data, len);
 	if (ret < 0)
 	if (ret < 0)
-		return -1;
-	return val;
+		return ret;
+
+	return len;
 }
 }
+#endif
 
 
-static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
-			     unsigned int value)
+static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg,
+		       unsigned int value, const void *data, int len)
 {
 {
-	u8 data[2];
 	int ret;
 	int ret;
 
 
-	data[0] = (reg << 4) | ((value >> 8) & 0x000f);
-	data[1] = value & 0x00ff;
-
 	if (!snd_soc_codec_volatile_register(codec, reg) &&
 	if (!snd_soc_codec_volatile_register(codec, reg) &&
-		reg < codec->driver->reg_cache_size &&
-		!codec->cache_bypass) {
+	    reg < codec->driver->reg_cache_size &&
+	    !codec->cache_bypass) {
 		ret = snd_soc_cache_write(codec, reg, value);
 		ret = snd_soc_cache_write(codec, reg, value);
 		if (ret < 0)
 		if (ret < 0)
 			return -1;
 			return -1;
@@ -64,8 +52,8 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
 		return 0;
 		return 0;
 	}
 	}
 
 
-	ret = codec->hw_write(codec->control_data, data, 2);
-	if (ret == 2)
+	ret = codec->hw_write(codec->control_data, data, len);
+	if (ret == len)
 		return 0;
 		return 0;
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
@@ -73,50 +61,19 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
 		return -EIO;
 		return -EIO;
 }
 }
 
 
-#if defined(CONFIG_SPI_MASTER)
-static int snd_soc_4_12_spi_write(void *control_data, const char *data,
-				 int len)
-{
-	struct spi_device *spi = control_data;
-	struct spi_transfer t;
-	struct spi_message m;
-	u8 msg[2];
-
-	if (len <= 0)
-		return 0;
-
-	msg[0] = data[1];
-	msg[1] = data[0];
-
-	spi_message_init(&m);
-	memset(&t, 0, sizeof t);
-
-	t.tx_buf = &msg[0];
-	t.len = len;
-
-	spi_message_add_tail(&t, &m);
-	spi_sync(spi, &m);
-
-	return len;
-}
-#else
-#define snd_soc_4_12_spi_write NULL
-#endif
-
-static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
-				     unsigned int reg)
+static unsigned int do_hw_read(struct snd_soc_codec *codec, unsigned int reg)
 {
 {
 	int ret;
 	int ret;
 	unsigned int val;
 	unsigned int val;
 
 
 	if (reg >= codec->driver->reg_cache_size ||
 	if (reg >= codec->driver->reg_cache_size ||
-		snd_soc_codec_volatile_register(codec, reg) ||
-		codec->cache_bypass) {
-			if (codec->cache_only)
-				return -1;
+	    snd_soc_codec_volatile_register(codec, reg) ||
+	    codec->cache_bypass) {
+		if (codec->cache_only)
+			return -1;
 
 
-			BUG_ON(!codec->hw_read);
-			return codec->hw_read(codec, reg);
+		BUG_ON(!codec->hw_read);
+		return codec->hw_read(codec, reg);
 	}
 	}
 
 
 	ret = snd_soc_cache_read(codec, reg, &val);
 	ret = snd_soc_cache_read(codec, reg, &val);
@@ -125,259 +82,117 @@ static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
 	return val;
 	return val;
 }
 }
 
 
-static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
-			     unsigned int value)
+static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec,
+				      unsigned int reg)
 {
 {
-	u8 data[2];
-	int ret;
-
-	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
-	data[1] = value & 0x00ff;
-
-	if (!snd_soc_codec_volatile_register(codec, reg) &&
-		reg < codec->driver->reg_cache_size &&
-		!codec->cache_bypass) {
-		ret = snd_soc_cache_write(codec, reg, value);
-		if (ret < 0)
-			return -1;
-	}
-
-	if (codec->cache_only) {
-		codec->cache_sync = 1;
-		return 0;
-	}
-
-	ret = codec->hw_write(codec->control_data, data, 2);
-	if (ret == 2)
-		return 0;
-	if (ret < 0)
-		return ret;
-	else
-		return -EIO;
+	return do_hw_read(codec, reg);
 }
 }
 
 
-#if defined(CONFIG_SPI_MASTER)
-static int snd_soc_7_9_spi_write(void *control_data, const char *data,
-				 int len)
+static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg,
+			      unsigned int value)
 {
 {
-	struct spi_device *spi = control_data;
-	struct spi_transfer t;
-	struct spi_message m;
-	u8 msg[2];
+	u16 data;
 
 
-	if (len <= 0)
-		return 0;
+	data = cpu_to_be16((reg << 12) | (value & 0xffffff));
 
 
-	msg[0] = data[0];
-	msg[1] = data[1];
+	return do_hw_write(codec, reg, value, &data, 2);
+}
 
 
-	spi_message_init(&m);
-	memset(&t, 0, sizeof t);
+static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
+				     unsigned int reg)
+{
+	return do_hw_read(codec, reg);
+}
 
 
-	t.tx_buf = &msg[0];
-	t.len = len;
+static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
+			     unsigned int value)
+{
+	u8 data[2];
 
 
-	spi_message_add_tail(&t, &m);
-	spi_sync(spi, &m);
+	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+	data[1] = value & 0x00ff;
 
 
-	return len;
+	return do_hw_write(codec, reg, value, data, 2);
 }
 }
-#else
-#define snd_soc_7_9_spi_write NULL
-#endif
 
 
 static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
 static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
 			     unsigned int value)
 			     unsigned int value)
 {
 {
 	u8 data[2];
 	u8 data[2];
-	int ret;
 
 
 	reg &= 0xff;
 	reg &= 0xff;
 	data[0] = reg;
 	data[0] = reg;
 	data[1] = value & 0xff;
 	data[1] = value & 0xff;
 
 
-	if (!snd_soc_codec_volatile_register(codec, reg) &&
-		reg < codec->driver->reg_cache_size &&
-		!codec->cache_bypass) {
-		ret = snd_soc_cache_write(codec, reg, value);
-		if (ret < 0)
-			return -1;
-	}
-
-	if (codec->cache_only) {
-		codec->cache_sync = 1;
-		return 0;
-	}
-
-	if (codec->hw_write(codec->control_data, data, 2) == 2)
-		return 0;
-	else
-		return -EIO;
+	return do_hw_write(codec, reg, value, data, 2);
 }
 }
 
 
 static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
 static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec,
 				     unsigned int reg)
 				     unsigned int reg)
 {
 {
-	int ret;
-	unsigned int val;
-
-	reg &= 0xff;
-	if (reg >= codec->driver->reg_cache_size ||
-		snd_soc_codec_volatile_register(codec, reg) ||
-		codec->cache_bypass) {
-			if (codec->cache_only)
-				return -1;
-
-			BUG_ON(!codec->hw_read);
-			return codec->hw_read(codec, reg);
-	}
-
-	ret = snd_soc_cache_read(codec, reg, &val);
-	if (ret < 0)
-		return -1;
-	return val;
-}
-
-#if defined(CONFIG_SPI_MASTER)
-static int snd_soc_8_8_spi_write(void *control_data, const char *data,
-				 int len)
-{
-	struct spi_device *spi = control_data;
-	struct spi_transfer t;
-	struct spi_message m;
-	u8 msg[2];
-
-	if (len <= 0)
-		return 0;
-
-	msg[0] = data[0];
-	msg[1] = data[1];
-
-	spi_message_init(&m);
-	memset(&t, 0, sizeof t);
-
-	t.tx_buf = &msg[0];
-	t.len = len;
-
-	spi_message_add_tail(&t, &m);
-	spi_sync(spi, &m);
-
-	return len;
+	return do_hw_read(codec, reg);
 }
 }
-#else
-#define snd_soc_8_8_spi_write NULL
-#endif
 
 
 static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
 static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
 			      unsigned int value)
 			      unsigned int value)
 {
 {
 	u8 data[3];
 	u8 data[3];
-	int ret;
 
 
 	data[0] = reg;
 	data[0] = reg;
 	data[1] = (value >> 8) & 0xff;
 	data[1] = (value >> 8) & 0xff;
 	data[2] = value & 0xff;
 	data[2] = value & 0xff;
 
 
-	if (!snd_soc_codec_volatile_register(codec, reg) &&
-		reg < codec->driver->reg_cache_size &&
-		!codec->cache_bypass) {
-		ret = snd_soc_cache_write(codec, reg, value);
-		if (ret < 0)
-			return -1;
-	}
-
-	if (codec->cache_only) {
-		codec->cache_sync = 1;
-		return 0;
-	}
-
-	if (codec->hw_write(codec->control_data, data, 3) == 3)
-		return 0;
-	else
-		return -EIO;
+	return do_hw_write(codec, reg, value, data, 3);
 }
 }
 
 
 static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
 static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec,
 				      unsigned int reg)
 				      unsigned int reg)
 {
 {
-	int ret;
-	unsigned int val;
-
-	if (reg >= codec->driver->reg_cache_size ||
-	    snd_soc_codec_volatile_register(codec, reg) ||
-	    codec->cache_bypass) {
-		if (codec->cache_only)
-			return -1;
-
-		BUG_ON(!codec->hw_read);
-		return codec->hw_read(codec, reg);
-	}
-
-	ret = snd_soc_cache_read(codec, reg, &val);
-	if (ret < 0)
-		return -1;
-	return val;
-}
-
-#if defined(CONFIG_SPI_MASTER)
-static int snd_soc_8_16_spi_write(void *control_data, const char *data,
-				 int len)
-{
-	struct spi_device *spi = control_data;
-	struct spi_transfer t;
-	struct spi_message m;
-	u8 msg[3];
-
-	if (len <= 0)
-		return 0;
-
-	msg[0] = data[0];
-	msg[1] = data[1];
-	msg[2] = data[2];
-
-	spi_message_init(&m);
-	memset(&t, 0, sizeof t);
-
-	t.tx_buf = &msg[0];
-	t.len = len;
-
-	spi_message_add_tail(&t, &m);
-	spi_sync(spi, &m);
-
-	return len;
+	return do_hw_read(codec, reg);
 }
 }
-#else
-#define snd_soc_8_16_spi_write NULL
-#endif
 
 
 #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
 #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
-static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
-					  unsigned int r)
+static unsigned int do_i2c_read(struct snd_soc_codec *codec,
+				void *reg, int reglen,
+				void *data, int datalen)
 {
 {
 	struct i2c_msg xfer[2];
 	struct i2c_msg xfer[2];
-	u8 reg = r;
-	u8 data;
 	int ret;
 	int ret;
 	struct i2c_client *client = codec->control_data;
 	struct i2c_client *client = codec->control_data;
 
 
 	/* Write register */
 	/* Write register */
 	xfer[0].addr = client->addr;
 	xfer[0].addr = client->addr;
 	xfer[0].flags = 0;
 	xfer[0].flags = 0;
-	xfer[0].len = 1;
-	xfer[0].buf = &reg;
+	xfer[0].len = reglen;
+	xfer[0].buf = reg;
 
 
 	/* Read data */
 	/* Read data */
 	xfer[1].addr = client->addr;
 	xfer[1].addr = client->addr;
 	xfer[1].flags = I2C_M_RD;
 	xfer[1].flags = I2C_M_RD;
-	xfer[1].len = 1;
-	xfer[1].buf = &data;
+	xfer[1].len = datalen;
+	xfer[1].buf = data;
 
 
 	ret = i2c_transfer(client->adapter, xfer, 2);
 	ret = i2c_transfer(client->adapter, xfer, 2);
-	if (ret != 2) {
-		dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+	if (ret == 2)
 		return 0;
 		return 0;
-	}
+	else if (ret < 0)
+		return ret;
+	else
+		return -EIO;
+}
+#endif
 
 
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
+					 unsigned int r)
+{
+	u8 reg = r;
+	u8 data;
+	int ret;
+
+	ret = do_i2c_read(codec, &reg, 1, &data, 1);
+	if (ret < 0)
+		return 0;
 	return data;
 	return data;
 }
 }
 #else
 #else
@@ -388,30 +203,13 @@ static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec,
 static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
 static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
 					  unsigned int r)
 					  unsigned int r)
 {
 {
-	struct i2c_msg xfer[2];
 	u8 reg = r;
 	u8 reg = r;
 	u16 data;
 	u16 data;
 	int ret;
 	int ret;
-	struct i2c_client *client = codec->control_data;
 
 
-	/* Write register */
-	xfer[0].addr = client->addr;
-	xfer[0].flags = 0;
-	xfer[0].len = 1;
-	xfer[0].buf = &reg;
-
-	/* Read data */
-	xfer[1].addr = client->addr;
-	xfer[1].flags = I2C_M_RD;
-	xfer[1].len = 2;
-	xfer[1].buf = (u8 *)&data;
-
-	ret = i2c_transfer(client->adapter, xfer, 2);
-	if (ret != 2) {
-		dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+	ret = do_i2c_read(codec, &reg, 1, &data, 2);
+	if (ret < 0)
 		return 0;
 		return 0;
-	}
-
 	return (data >> 8) | ((data & 0xff) << 8);
 	return (data >> 8) | ((data & 0xff) << 8);
 }
 }
 #else
 #else
@@ -422,30 +220,13 @@ static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec,
 static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
 static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
 					  unsigned int r)
 					  unsigned int r)
 {
 {
-	struct i2c_msg xfer[2];
 	u16 reg = r;
 	u16 reg = r;
 	u8 data;
 	u8 data;
 	int ret;
 	int ret;
-	struct i2c_client *client = codec->control_data;
-
-	/* Write register */
-	xfer[0].addr = client->addr;
-	xfer[0].flags = 0;
-	xfer[0].len = 2;
-	xfer[0].buf = (u8 *)&reg;
-
-	/* Read data */
-	xfer[1].addr = client->addr;
-	xfer[1].flags = I2C_M_RD;
-	xfer[1].len = 1;
-	xfer[1].buf = &data;
 
 
-	ret = i2c_transfer(client->adapter, xfer, 2);
-	if (ret != 2) {
-		dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+	ret = do_i2c_read(codec, &reg, 2, &data, 1);
+	if (ret < 0)
 		return 0;
 		return 0;
-	}
-
 	return data;
 	return data;
 }
 }
 #else
 #else
@@ -453,120 +234,34 @@ static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec,
 #endif
 #endif
 
 
 static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
 static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec,
-				     unsigned int reg)
+				      unsigned int reg)
 {
 {
-	int ret;
-	unsigned int val;
-
-	reg &= 0xff;
-	if (reg >= codec->driver->reg_cache_size ||
-		snd_soc_codec_volatile_register(codec, reg) ||
-		codec->cache_bypass) {
-			if (codec->cache_only)
-				return -1;
-
-			BUG_ON(!codec->hw_read);
-			return codec->hw_read(codec, reg);
-	}
-
-	ret = snd_soc_cache_read(codec, reg, &val);
-	if (ret < 0)
-		return -1;
-	return val;
+	return do_hw_read(codec, reg);
 }
 }
 
 
 static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
 static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
-			     unsigned int value)
+			      unsigned int value)
 {
 {
 	u8 data[3];
 	u8 data[3];
-	int ret;
 
 
 	data[0] = (reg >> 8) & 0xff;
 	data[0] = (reg >> 8) & 0xff;
 	data[1] = reg & 0xff;
 	data[1] = reg & 0xff;
 	data[2] = value;
 	data[2] = value;
 
 
-	reg &= 0xff;
-	if (!snd_soc_codec_volatile_register(codec, reg) &&
-		reg < codec->driver->reg_cache_size &&
-		!codec->cache_bypass) {
-		ret = snd_soc_cache_write(codec, reg, value);
-		if (ret < 0)
-			return -1;
-	}
-
-	if (codec->cache_only) {
-		codec->cache_sync = 1;
-		return 0;
-	}
-
-	ret = codec->hw_write(codec->control_data, data, 3);
-	if (ret == 3)
-		return 0;
-	if (ret < 0)
-		return ret;
-	else
-		return -EIO;
-}
-
-#if defined(CONFIG_SPI_MASTER)
-static int snd_soc_16_8_spi_write(void *control_data, const char *data,
-				 int len)
-{
-	struct spi_device *spi = control_data;
-	struct spi_transfer t;
-	struct spi_message m;
-	u8 msg[3];
-
-	if (len <= 0)
-		return 0;
-
-	msg[0] = data[0];
-	msg[1] = data[1];
-	msg[2] = data[2];
-
-	spi_message_init(&m);
-	memset(&t, 0, sizeof t);
-
-	t.tx_buf = &msg[0];
-	t.len = len;
-
-	spi_message_add_tail(&t, &m);
-	spi_sync(spi, &m);
-
-	return len;
+	return do_hw_write(codec, reg, value, data, 3);
 }
 }
-#else
-#define snd_soc_16_8_spi_write NULL
-#endif
 
 
 #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
 #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
 static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
 static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
 					   unsigned int r)
 					   unsigned int r)
 {
 {
-	struct i2c_msg xfer[2];
 	u16 reg = cpu_to_be16(r);
 	u16 reg = cpu_to_be16(r);
 	u16 data;
 	u16 data;
 	int ret;
 	int ret;
-	struct i2c_client *client = codec->control_data;
-
-	/* Write register */
-	xfer[0].addr = client->addr;
-	xfer[0].flags = 0;
-	xfer[0].len = 2;
-	xfer[0].buf = (u8 *)&reg;
 
 
-	/* Read data */
-	xfer[1].addr = client->addr;
-	xfer[1].flags = I2C_M_RD;
-	xfer[1].len = 2;
-	xfer[1].buf = (u8 *)&data;
-
-	ret = i2c_transfer(client->adapter, xfer, 2);
-	if (ret != 2) {
-		dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
+	ret = do_i2c_read(codec, &reg, 2, &data, 2);
+	if (ret < 0)
 		return 0;
 		return 0;
-	}
-
 	return be16_to_cpu(data);
 	return be16_to_cpu(data);
 }
 }
 #else
 #else
@@ -576,52 +271,59 @@ static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec,
 static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
 static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
 				       unsigned int reg)
 				       unsigned int reg)
 {
 {
-	int ret;
-	unsigned int val;
-
-	if (reg >= codec->driver->reg_cache_size ||
-	    snd_soc_codec_volatile_register(codec, reg) ||
-	    codec->cache_bypass) {
-		if (codec->cache_only)
-			return -1;
-
-		BUG_ON(!codec->hw_read);
-		return codec->hw_read(codec, reg);
-	}
-
-	ret = snd_soc_cache_read(codec, reg, &val);
-	if (ret < 0)
-		return -1;
-
-	return val;
+	return do_hw_read(codec, reg);
 }
 }
 
 
 static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
 static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
 			       unsigned int value)
 			       unsigned int value)
 {
 {
 	u8 data[4];
 	u8 data[4];
-	int ret;
 
 
 	data[0] = (reg >> 8) & 0xff;
 	data[0] = (reg >> 8) & 0xff;
 	data[1] = reg & 0xff;
 	data[1] = reg & 0xff;
 	data[2] = (value >> 8) & 0xff;
 	data[2] = (value >> 8) & 0xff;
 	data[3] = value & 0xff;
 	data[3] = value & 0xff;
 
 
-	if (!snd_soc_codec_volatile_register(codec, reg) &&
-		reg < codec->driver->reg_cache_size &&
-		!codec->cache_bypass) {
-		ret = snd_soc_cache_write(codec, reg, value);
-		if (ret < 0)
-			return -1;
-	}
+	return do_hw_write(codec, reg, value, data, 4);
+}
 
 
-	if (codec->cache_only) {
-		codec->cache_sync = 1;
-		return 0;
+/* Primitive bulk write support for soc-cache.  The data pointed to by
+ * `data' needs to already be in the form the hardware expects
+ * including any leading register specific data.  Any data written
+ * through this function will not go through the cache as it only
+ * handles writing to volatile or out of bounds registers.
+ */
+static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg,
+				     const void *data, size_t len)
+{
+	int ret;
+
+	/* To ensure that we don't get out of sync with the cache, check
+	 * whether the base register is volatile or if we've directly asked
+	 * to bypass the cache.  Out of bounds registers are considered
+	 * volatile.
+	 */
+	if (!codec->cache_bypass
+	    && !snd_soc_codec_volatile_register(codec, reg)
+	    && reg < codec->driver->reg_cache_size)
+		return -EINVAL;
+
+	switch (codec->control_type) {
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+	case SND_SOC_I2C:
+		ret = i2c_master_send(codec->control_data, data, len);
+		break;
+#endif
+#if defined(CONFIG_SPI_MASTER)
+	case SND_SOC_SPI:
+		ret = spi_write(codec->control_data, data, len);
+		break;
+#endif
+	default:
+		BUG();
 	}
 	}
 
 
-	ret = codec->hw_write(codec->control_data, data, 4);
-	if (ret == 4)
+	if (ret == len)
 		return 0;
 		return 0;
 	if (ret < 0)
 	if (ret < 0)
 		return ret;
 		return ret;
@@ -629,79 +331,40 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
 		return -EIO;
 		return -EIO;
 }
 }
 
 
-#if defined(CONFIG_SPI_MASTER)
-static int snd_soc_16_16_spi_write(void *control_data, const char *data,
-				 int len)
-{
-	struct spi_device *spi = control_data;
-	struct spi_transfer t;
-	struct spi_message m;
-	u8 msg[4];
-
-	if (len <= 0)
-		return 0;
-
-	msg[0] = data[0];
-	msg[1] = data[1];
-	msg[2] = data[2];
-	msg[3] = data[3];
-
-	spi_message_init(&m);
-	memset(&t, 0, sizeof t);
-
-	t.tx_buf = &msg[0];
-	t.len = len;
-
-	spi_message_add_tail(&t, &m);
-	spi_sync(spi, &m);
-
-	return len;
-}
-#else
-#define snd_soc_16_16_spi_write NULL
-#endif
-
 static struct {
 static struct {
 	int addr_bits;
 	int addr_bits;
 	int data_bits;
 	int data_bits;
 	int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
 	int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
-	int (*spi_write)(void *, const char *, int);
 	unsigned int (*read)(struct snd_soc_codec *, unsigned int);
 	unsigned int (*read)(struct snd_soc_codec *, unsigned int);
 	unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
 	unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
 } io_types[] = {
 } io_types[] = {
 	{
 	{
 		.addr_bits = 4, .data_bits = 12,
 		.addr_bits = 4, .data_bits = 12,
 		.write = snd_soc_4_12_write, .read = snd_soc_4_12_read,
 		.write = snd_soc_4_12_write, .read = snd_soc_4_12_read,
-		.spi_write = snd_soc_4_12_spi_write,
 	},
 	},
 	{
 	{
 		.addr_bits = 7, .data_bits = 9,
 		.addr_bits = 7, .data_bits = 9,
 		.write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
 		.write = snd_soc_7_9_write, .read = snd_soc_7_9_read,
-		.spi_write = snd_soc_7_9_spi_write,
 	},
 	},
 	{
 	{
 		.addr_bits = 8, .data_bits = 8,
 		.addr_bits = 8, .data_bits = 8,
 		.write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
 		.write = snd_soc_8_8_write, .read = snd_soc_8_8_read,
 		.i2c_read = snd_soc_8_8_read_i2c,
 		.i2c_read = snd_soc_8_8_read_i2c,
-		.spi_write = snd_soc_8_8_spi_write,
 	},
 	},
 	{
 	{
 		.addr_bits = 8, .data_bits = 16,
 		.addr_bits = 8, .data_bits = 16,
 		.write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
 		.write = snd_soc_8_16_write, .read = snd_soc_8_16_read,
 		.i2c_read = snd_soc_8_16_read_i2c,
 		.i2c_read = snd_soc_8_16_read_i2c,
-		.spi_write = snd_soc_8_16_spi_write,
 	},
 	},
 	{
 	{
 		.addr_bits = 16, .data_bits = 8,
 		.addr_bits = 16, .data_bits = 8,
 		.write = snd_soc_16_8_write, .read = snd_soc_16_8_read,
 		.write = snd_soc_16_8_write, .read = snd_soc_16_8_read,
 		.i2c_read = snd_soc_16_8_read_i2c,
 		.i2c_read = snd_soc_16_8_read_i2c,
-		.spi_write = snd_soc_16_8_spi_write,
 	},
 	},
 	{
 	{
 		.addr_bits = 16, .data_bits = 16,
 		.addr_bits = 16, .data_bits = 16,
 		.write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
 		.write = snd_soc_16_16_write, .read = snd_soc_16_16_read,
 		.i2c_read = snd_soc_16_16_read_i2c,
 		.i2c_read = snd_soc_16_16_read_i2c,
-		.spi_write = snd_soc_16_16_spi_write,
 	},
 	},
 };
 };
 
 
@@ -709,7 +372,6 @@ static struct {
  * snd_soc_codec_set_cache_io: Set up standard I/O functions.
  * snd_soc_codec_set_cache_io: Set up standard I/O functions.
  *
  *
  * @codec: CODEC to configure.
  * @codec: CODEC to configure.
- * @type: Type of cache.
  * @addr_bits: Number of bits of register address data.
  * @addr_bits: Number of bits of register address data.
  * @data_bits: Number of bits of data per register.
  * @data_bits: Number of bits of data per register.
  * @control: Control bus used.
  * @control: Control bus used.
@@ -744,6 +406,7 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
 
 
 	codec->write = io_types[i].write;
 	codec->write = io_types[i].write;
 	codec->read = io_types[i].read;
 	codec->read = io_types[i].read;
+	codec->bulk_write_raw = snd_soc_hw_bulk_write_raw;
 
 
 	switch (control) {
 	switch (control) {
 	case SND_SOC_CUSTOM:
 	case SND_SOC_CUSTOM:
@@ -762,8 +425,9 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
 		break;
 		break;
 
 
 	case SND_SOC_SPI:
 	case SND_SOC_SPI:
-		if (io_types[i].spi_write)
-			codec->hw_write = io_types[i].spi_write;
+#ifdef CONFIG_SPI_MASTER
+		codec->hw_write = do_spi_write;
+#endif
 
 
 		codec->control_data = container_of(codec->dev,
 		codec->control_data = container_of(codec->dev,
 						   struct spi_device,
 						   struct spi_device,
@@ -889,6 +553,8 @@ static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
 		rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
 		rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
 		if (rbnode->value == rbnode->defval)
 		if (rbnode->value == rbnode->defval)
 			continue;
 			continue;
+		WARN_ON(codec->writable_register &&
+			codec->writable_register(codec, rbnode->reg));
 		ret = snd_soc_cache_read(codec, rbnode->reg, &val);
 		ret = snd_soc_cache_read(codec, rbnode->reg, &val);
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
@@ -1149,6 +815,8 @@ static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec)
 
 
 	lzo_blocks = codec->reg_cache;
 	lzo_blocks = codec->reg_cache;
 	for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
 	for_each_set_bit(i, lzo_blocks[0]->sync_bmp, lzo_blocks[0]->sync_bmp_nbits) {
+		WARN_ON(codec->writable_register &&
+			codec->writable_register(codec, i));
 		ret = snd_soc_cache_read(codec, i, &val);
 		ret = snd_soc_cache_read(codec, i, &val);
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
@@ -1407,6 +1075,8 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
 
 
 	codec_drv = codec->driver;
 	codec_drv = codec->driver;
 	for (i = 0; i < codec_drv->reg_cache_size; ++i) {
 	for (i = 0; i < codec_drv->reg_cache_size; ++i) {
+		WARN_ON(codec->writable_register &&
+			codec->writable_register(codec, i));
 		ret = snd_soc_cache_read(codec, i, &val);
 		ret = snd_soc_cache_read(codec, i, &val);
 		if (ret)
 		if (ret)
 			return ret;
 			return ret;
@@ -1523,7 +1193,7 @@ int snd_soc_cache_init(struct snd_soc_codec *codec)
 				codec->cache_ops->name, codec->name);
 				codec->cache_ops->name, codec->name);
 		return codec->cache_ops->init(codec);
 		return codec->cache_ops->init(codec);
 	}
 	}
-	return -EINVAL;
+	return -ENOSYS;
 }
 }
 
 
 /*
 /*
@@ -1538,7 +1208,7 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec)
 				codec->cache_ops->name, codec->name);
 				codec->cache_ops->name, codec->name);
 		return codec->cache_ops->exit(codec);
 		return codec->cache_ops->exit(codec);
 	}
 	}
-	return -EINVAL;
+	return -ENOSYS;
 }
 }
 
 
 /**
 /**
@@ -1562,7 +1232,7 @@ int snd_soc_cache_read(struct snd_soc_codec *codec,
 	}
 	}
 
 
 	mutex_unlock(&codec->cache_rw_mutex);
 	mutex_unlock(&codec->cache_rw_mutex);
-	return -EINVAL;
+	return -ENOSYS;
 }
 }
 EXPORT_SYMBOL_GPL(snd_soc_cache_read);
 EXPORT_SYMBOL_GPL(snd_soc_cache_read);
 
 
@@ -1587,7 +1257,7 @@ int snd_soc_cache_write(struct snd_soc_codec *codec,
 	}
 	}
 
 
 	mutex_unlock(&codec->cache_rw_mutex);
 	mutex_unlock(&codec->cache_rw_mutex);
-	return -EINVAL;
+	return -ENOSYS;
 }
 }
 EXPORT_SYMBOL_GPL(snd_soc_cache_write);
 EXPORT_SYMBOL_GPL(snd_soc_cache_write);
 
 
@@ -1610,7 +1280,7 @@ int snd_soc_cache_sync(struct snd_soc_codec *codec)
 	}
 	}
 
 
 	if (!codec->cache_ops || !codec->cache_ops->sync)
 	if (!codec->cache_ops || !codec->cache_ops->sync)
-		return -EINVAL;
+		return -ENOSYS;
 
 
 	if (codec->cache_ops->name)
 	if (codec->cache_ops->name)
 		name = codec->cache_ops->name;
 		name = codec->cache_ops->name;
@@ -1677,3 +1347,17 @@ int snd_soc_default_readable_register(struct snd_soc_codec *codec,
 	return codec->driver->reg_access_default[index].read;
 	return codec->driver->reg_access_default[index].read;
 }
 }
 EXPORT_SYMBOL_GPL(snd_soc_default_readable_register);
 EXPORT_SYMBOL_GPL(snd_soc_default_readable_register);
+
+int snd_soc_default_writable_register(struct snd_soc_codec *codec,
+				      unsigned int reg)
+{
+	int index;
+
+	if (reg >= codec->driver->reg_cache_size)
+		return 1;
+	index = snd_soc_get_reg_access_index(codec, reg);
+	if (index < 0)
+		return 0;
+	return codec->driver->reg_access_default[index].write;
+}
+EXPORT_SYMBOL_GPL(snd_soc_default_writable_register);

Some files were not shown because too many files changed in this diff