Browse Source

Merge tag 'asoc-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-next

ASoC: Additional updates for v3.7

A couple more updates for 3.7, enhancements to the ux500 and wm2000
drivers, a new driver for DA9055 and the support for regulator bypass
mode.  With the exception of the DA9055 this has all had a chance to
soak in -next (the driver was added on Friday so should be in -next
today).
Takashi Iwai 12 years ago
parent
commit
0fd0ba5f9e
40 changed files with 2307 additions and 174 deletions
  1. 21 0
      Documentation/ABI/testing/sysfs-class-regulator
  2. 36 0
      Documentation/devicetree/bindings/sound/cs4271.txt
  3. 39 0
      Documentation/devicetree/bindings/sound/ux500-mop500.txt
  4. 43 0
      Documentation/devicetree/bindings/sound/ux500-msp.txt
  5. 1 0
      arch/arm/mach-imx/eukrea_mbimx27-baseboard.c
  6. 1 0
      arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c
  7. 1 0
      arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c
  8. 1 0
      arch/arm/mach-imx/eukrea_mbimxsd51-baseboard.c
  9. 1 78
      arch/arm/mach-ux500/board-mop500-msp.c
  10. 0 2
      arch/arm/mach-ux500/include/mach/msp.h
  11. 5 0
      drivers/extcon/extcon-arizona.c
  12. 4 0
      drivers/regulator/arizona-ldo1.c
  13. 5 0
      drivers/regulator/arizona-micsupp.c
  14. 126 0
      drivers/regulator/core.c
  15. 8 0
      drivers/regulator/wm831x-ldo.c
  16. 4 2
      include/linux/mfd/abx500/ab8500-codec.h
  17. 8 0
      include/linux/regulator/consumer.h
  18. 14 0
      include/linux/regulator/driver.h
  19. 2 0
      include/linux/regulator/machine.h
  20. 33 0
      include/sound/da9055.h
  21. 3 0
      include/sound/soc-dapm.h
  22. 4 0
      sound/soc/codecs/Kconfig
  23. 2 0
      sound/soc/codecs/Makefile
  24. 81 0
      sound/soc/codecs/ab8500-codec.c
  25. 42 0
      sound/soc/codecs/arizona.c
  26. 1 1
      sound/soc/codecs/arizona.h
  27. 2 2
      sound/soc/codecs/cs4270.c
  28. 21 3
      sound/soc/codecs/cs4271.c
  29. 1510 0
      sound/soc/codecs/da9055.c
  30. 7 11
      sound/soc/codecs/wm0010.c
  31. 48 12
      sound/soc/codecs/wm2000.c
  32. 1 1
      sound/soc/codecs/wm5102.c
  33. 63 16
      sound/soc/codecs/wm5110.c
  34. 5 0
      sound/soc/codecs/wm_hubs.c
  35. 19 18
      sound/soc/fsl/eukrea-tlv320.c
  36. 21 2
      sound/soc/soc-dapm.c
  37. 42 5
      sound/soc/ux500/mop500.c
  38. 6 0
      sound/soc/ux500/ux500_msp_dai.c
  39. 70 19
      sound/soc/ux500/ux500_msp_i2s.c
  40. 6 2
      sound/soc/ux500/ux500_msp_i2s.h

+ 21 - 0
Documentation/ABI/testing/sysfs-class-regulator

@@ -349,3 +349,24 @@ Description:
 
 		This will be one of the same strings reported by
 		the "state" attribute.
+
+What:		/sys/class/regulator/.../bypass
+Date:		September 2012
+KernelVersion:	3.7
+Contact:	Mark Brown <broonie@opensource.wolfsonmicro.com>
+Description:
+		Some regulator directories will contain a field called
+		bypass.  This indicates if the device is in bypass mode.
+
+		This will be one of the following strings:
+
+		'enabled'
+		'disabled'
+		'unknown'
+
+		'enabled' means the regulator is in bypass mode.
+
+		'disabled' means that the regulator is regulating.
+
+		'unknown' means software cannot determine the state, or
+		the reported state is invalid.

+ 36 - 0
Documentation/devicetree/bindings/sound/cs4271.txt

@@ -0,0 +1,36 @@
+Cirrus Logic CS4271 DT bindings
+
+This driver supports both the I2C and the SPI bus.
+
+Required properties:
+
+ - compatible: "cirrus,cs4271"
+
+For required properties on SPI, please consult
+Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Required properties on I2C:
+
+ - reg: the i2c address
+
+
+Optional properties:
+
+ - reset-gpio: 	a GPIO spec to define which pin is connected to the chip's
+		!RESET pin
+
+Examples:
+
+	codec_i2c: cs4271@10 {
+		compatible = "cirrus,cs4271";
+		reg = <0x10>;
+		reset-gpio = <&gpio 23 0>;
+	};
+
+	codec_spi: cs4271@0 {
+		compatible = "cirrus,cs4271";
+		reg = <0x0>;
+		reset-gpio = <&gpio 23 0>;
+		spi-max-frequency = <6000000>;
+	};
+

+ 39 - 0
Documentation/devicetree/bindings/sound/ux500-mop500.txt

@@ -0,0 +1,39 @@
+* MOP500 Audio Machine Driver
+
+This node is responsible for linking together all ux500 Audio Driver components.
+
+Required properties:
+ - compatible              : "stericsson,snd-soc-mop500"
+
+Non-standard properties:
+ - stericsson,cpu-dai      : Phandle to the CPU-side DAI
+ - stericsson,audio-codec  : Phandle to the Audio CODEC
+ - stericsson,card-name    : Over-ride default card name
+
+Example:
+
+	sound {
+		compatible = "stericsson,snd-soc-mop500";
+
+		stericsson,cpu-dai = <&msp1 &msp3>;
+		stericsson,audio-codec = <&codec>;
+	};
+
+	msp1: msp@80124000 {
+		compatible = "stericsson,ux500-msp-i2s";
+		reg = <0x80124000 0x1000>;
+		interrupts = <0 62 0x4>;
+		v-ape-supply = <&db8500_vape_reg>;
+	};
+
+	msp3: msp@80125000 {
+		compatible = "stericsson,ux500-msp-i2s";
+		reg = <0x80125000 0x1000>;
+		interrupts = <0 62 0x4>;
+		v-ape-supply = <&db8500_vape_reg>;
+	};
+
+	codec: ab8500-codec {
+		compatible = "stericsson,ab8500-codec";
+		stericsson,earpeice-cmv = <950>; /* Units in mV. */
+	};

+ 43 - 0
Documentation/devicetree/bindings/sound/ux500-msp.txt

@@ -0,0 +1,43 @@
+* ux500 MSP (CPU-side Digital Audio Interface)
+
+Required properties:
+ - compatible       :"stericsson,ux500-msp-i2s"
+ - reg              : Physical base address and length of the device's registers.
+
+Optional properties:
+ - interrupts       : The interrupt output from the device.
+ - interrupt-parent : The parent interrupt controller.
+ - <name>-supply    : Phandle to the regulator <name> supply
+
+Example:
+
+	sound {
+		compatible = "stericsson,snd-soc-mop500";
+
+		stericsson,platform-pcm-dma = <&pcm>;
+		stericsson,cpu-dai = <&msp1 &msp3>;
+		stericsson,audio-codec = <&codec>;
+	};
+
+	pcm: ux500-pcm {
+		compatible = "stericsson,ux500-pcm";
+	};
+
+	msp1: msp@80124000 {
+		compatible = "stericsson,ux500-msp-i2s";
+		reg = <0x80124000 0x1000>;
+		interrupts = <0 62 0x4>;
+		v-ape-supply = <&db8500_vape_reg>;
+	};
+
+	msp3: msp@80125000 {
+		compatible = "stericsson,ux500-msp-i2s";
+		reg = <0x80125000 0x1000>;
+		interrupts = <0 62 0x4>;
+		v-ape-supply = <&db8500_vape_reg>;
+	};
+
+	codec: ab8500-codec {
+		compatible = "stericsson,ab8500-codec";
+		stericsson,earpeice-cmv = <950>; /* Units in mV. */
+	};

+ 1 - 0
arch/arm/mach-imx/eukrea_mbimx27-baseboard.c

@@ -348,4 +348,5 @@ void __init eukrea_mbimx27_baseboard_init(void)
 	imx27_add_imx_keypad(&eukrea_mbimx27_keymap_data);
 
 	gpio_led_register_device(-1, &eukrea_mbimx27_gpio_led_info);
+	imx_add_platform_device("eukrea_tlv320", 0, NULL, 0, NULL, 0);
 }

+ 1 - 0
arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c

@@ -306,4 +306,5 @@ void __init eukrea_mbimxsd25_baseboard_init(void)
 	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 	gpio_led_register_device(-1, &eukrea_mbimxsd_led_info);
 	imx_add_gpio_keys(&eukrea_mbimxsd_button_data);
+	imx_add_platform_device("eukrea_tlv320", 0, NULL, 0, NULL, 0);
 }

+ 1 - 0
arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c

@@ -315,4 +315,5 @@ void __init eukrea_mbimxsd35_baseboard_init(void)
 	platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 	gpio_led_register_device(-1, &eukrea_mbimxsd_led_info);
 	imx_add_gpio_keys(&eukrea_mbimxsd_button_data);
+	imx_add_platform_device("eukrea_tlv320", 0, NULL, 0, NULL, 0);
 }

+ 1 - 0
arch/arm/mach-imx/eukrea_mbimxsd51-baseboard.c

@@ -228,4 +228,5 @@ void __init eukrea_mbimxsd51_baseboard_init(void)
 
 	gpio_led_register_device(-1, &eukrea_mbimxsd51_led_info);
 	imx_add_gpio_keys(&eukrea_mbimxsd51_button_data);
+	imx_add_platform_device("eukrea_tlv320", 0, NULL, 0, NULL, 0);
 }

+ 1 - 78
arch/arm/mach-ux500/board-mop500-msp.c

@@ -7,7 +7,6 @@
 #include <linux/platform_device.h>
 #include <linux/init.h>
 #include <linux/gpio.h>
-#include <linux/pinctrl/consumer.h>
 
 #include <plat/gpio-nomadik.h>
 #include <plat/pincfg.h>
@@ -23,53 +22,6 @@
 #include "devices-db8500.h"
 #include "pins-db8500.h"
 
-/* MSP1/3 Tx/Rx usage protection */
-static DEFINE_SPINLOCK(msp_rxtx_lock);
-
-/* Reference Count */
-static int msp_rxtx_ref;
-
-/* Pin modes */
-struct pinctrl *msp1_p;
-struct pinctrl_state *msp1_def;
-struct pinctrl_state *msp1_sleep;
-
-int msp13_i2s_init(void)
-{
-	int retval = 0;
-	unsigned long flags;
-
-	spin_lock_irqsave(&msp_rxtx_lock, flags);
-	if (msp_rxtx_ref == 0 && !(IS_ERR(msp1_p) || IS_ERR(msp1_def))) {
-		retval = pinctrl_select_state(msp1_p, msp1_def);
-		if (retval)
-			pr_err("could not set MSP1 defstate\n");
-	}
-	if (!retval)
-		msp_rxtx_ref++;
-	spin_unlock_irqrestore(&msp_rxtx_lock, flags);
-
-	return retval;
-}
-
-int msp13_i2s_exit(void)
-{
-	int retval = 0;
-	unsigned long flags;
-
-	spin_lock_irqsave(&msp_rxtx_lock, flags);
-	WARN_ON(!msp_rxtx_ref);
-	msp_rxtx_ref--;
-	if (msp_rxtx_ref == 0 && !(IS_ERR(msp1_p) || IS_ERR(msp1_sleep))) {
-		retval = pinctrl_select_state(msp1_p, msp1_sleep);
-		if (retval)
-			pr_err("could not set MSP1 sleepstate\n");
-	}
-	spin_unlock_irqrestore(&msp_rxtx_lock, flags);
-
-	return retval;
-}
-
 static struct stedma40_chan_cfg msp0_dma_rx = {
 	.high_priority = true,
 	.dir = STEDMA40_PERIPH_TO_MEM,
@@ -132,8 +84,6 @@ static struct msp_i2s_platform_data msp1_platform_data = {
 	.id = MSP_I2S_1,
 	.msp_i2s_dma_rx = NULL,
 	.msp_i2s_dma_tx = &msp1_dma_tx,
-	.msp_i2s_init = msp13_i2s_init,
-	.msp_i2s_exit = msp13_i2s_exit,
 };
 
 static struct stedma40_chan_cfg msp2_dma_rx = {
@@ -219,49 +169,22 @@ static struct msp_i2s_platform_data msp3_platform_data = {
 	.id		= MSP_I2S_3,
 	.msp_i2s_dma_rx	= &msp1_dma_rx,
 	.msp_i2s_dma_tx	= NULL,
-	.msp_i2s_init = msp13_i2s_init,
-	.msp_i2s_exit = msp13_i2s_exit,
 };
 
 int mop500_msp_init(struct device *parent)
 {
-	struct platform_device *msp1;
-
 	pr_info("%s: Register platform-device 'snd-soc-mop500'.\n", __func__);
 	platform_device_register(&snd_soc_mop500);
 
 	pr_info("Initialize MSP I2S-devices.\n");
 	db8500_add_msp_i2s(parent, 0, U8500_MSP0_BASE, IRQ_DB8500_MSP0,
 			   &msp0_platform_data);
-	msp1 = db8500_add_msp_i2s(parent, 1, U8500_MSP1_BASE, IRQ_DB8500_MSP1,
+	db8500_add_msp_i2s(parent, 1, U8500_MSP1_BASE, IRQ_DB8500_MSP1,
 			   &msp1_platform_data);
 	db8500_add_msp_i2s(parent, 2, U8500_MSP2_BASE, IRQ_DB8500_MSP2,
 			   &msp2_platform_data);
 	db8500_add_msp_i2s(parent, 3, U8500_MSP3_BASE, IRQ_DB8500_MSP1,
 			   &msp3_platform_data);
 
-	/* Get the pinctrl handle for MSP1 */
-	if (msp1) {
-		msp1_p = pinctrl_get(&msp1->dev);
-		if (IS_ERR(msp1_p))
-			dev_err(&msp1->dev, "could not get MSP1 pinctrl\n");
-		else {
-			msp1_def = pinctrl_lookup_state(msp1_p,
-							PINCTRL_STATE_DEFAULT);
-			if (IS_ERR(msp1_def)) {
-				dev_err(&msp1->dev,
-					"could not get MSP1 defstate\n");
-			}
-			msp1_sleep = pinctrl_lookup_state(msp1_p,
-							  PINCTRL_STATE_SLEEP);
-			if (IS_ERR(msp1_sleep))
-				dev_err(&msp1->dev,
-					"could not get MSP1 idlestate\n");
-		}
-	}
-
-	pr_info("%s: Register platform-device 'ux500-pcm'\n", __func__);
-	platform_device_register(&ux500_pcm);
-
 	return 0;
 }

+ 0 - 2
arch/arm/mach-ux500/include/mach/msp.h

@@ -22,8 +22,6 @@ struct msp_i2s_platform_data {
 	enum msp_i2s_id id;
 	struct stedma40_chan_cfg *msp_i2s_dma_rx;
 	struct stedma40_chan_cfg *msp_i2s_dma_tx;
-	int (*msp_i2s_init) (void);
-	int (*msp_i2s_exit) (void);
 };
 
 #endif

+ 5 - 0
drivers/extcon/extcon-arizona.c

@@ -434,6 +434,11 @@ static int __devinit arizona_extcon_probe(struct platform_device *pdev)
 	regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
 			   ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
 
+	ret = regulator_allow_bypass(info->micvdd, true);
+	if (ret != 0)
+		dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
+			 ret);
+
 	pm_runtime_put(&pdev->dev);
 
 	return 0;

+ 4 - 0
drivers/regulator/arizona-ldo1.c

@@ -39,6 +39,8 @@ static struct regulator_ops arizona_ldo1_ops = {
 	.map_voltage = regulator_map_voltage_linear,
 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+	.get_bypass = regulator_get_bypass_regmap,
+	.set_bypass = regulator_set_bypass_regmap,
 };
 
 static const struct regulator_desc arizona_ldo1 = {
@@ -49,6 +51,8 @@ static const struct regulator_desc arizona_ldo1 = {
 
 	.vsel_reg = ARIZONA_LDO1_CONTROL_1,
 	.vsel_mask = ARIZONA_LDO1_VSEL_MASK,
+	.bypass_reg = ARIZONA_LDO1_CONTROL_1,
+	.bypass_mask = ARIZONA_LDO1_BYPASS,
 	.min_uV = 900000,
 	.uV_step = 50000,
 	.n_voltages = 7,

+ 5 - 0
drivers/regulator/arizona-micsupp.c

@@ -82,6 +82,9 @@ static struct regulator_ops arizona_micsupp_ops = {
 
 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
+
+	.get_bypass = regulator_get_bypass_regmap,
+	.set_bypass = regulator_set_bypass_regmap,
 };
 
 static const struct regulator_desc arizona_micsupp = {
@@ -95,6 +98,8 @@ static const struct regulator_desc arizona_micsupp = {
 	.vsel_mask = ARIZONA_LDO2_VSEL_MASK,
 	.enable_reg = ARIZONA_MIC_CHARGE_PUMP_1,
 	.enable_mask = ARIZONA_CPMIC_ENA,
+	.bypass_reg = ARIZONA_MIC_CHARGE_PUMP_1,
+	.bypass_mask = ARIZONA_CPMIC_BYPASS,
 
 	.owner = THIS_MODULE,
 };

+ 126 - 0
drivers/regulator/core.c

@@ -77,6 +77,7 @@ struct regulator {
 	struct device *dev;
 	struct list_head list;
 	unsigned int always_on:1;
+	unsigned int bypass:1;
 	int uA_load;
 	int min_uV;
 	int max_uV;
@@ -394,6 +395,9 @@ static ssize_t regulator_status_show(struct device *dev,
 	case REGULATOR_STATUS_STANDBY:
 		label = "standby";
 		break;
+	case REGULATOR_STATUS_BYPASS:
+		label = "bypass";
+		break;
 	case REGULATOR_STATUS_UNDEFINED:
 		label = "undefined";
 		break;
@@ -585,6 +589,27 @@ static ssize_t regulator_suspend_standby_state_show(struct device *dev,
 static DEVICE_ATTR(suspend_standby_state, 0444,
 		regulator_suspend_standby_state_show, NULL);
 
+static ssize_t regulator_bypass_show(struct device *dev,
+				     struct device_attribute *attr, char *buf)
+{
+	struct regulator_dev *rdev = dev_get_drvdata(dev);
+	const char *report;
+	bool bypass;
+	int ret;
+
+	ret = rdev->desc->ops->get_bypass(rdev, &bypass);
+
+	if (ret != 0)
+		report = "unknown";
+	else if (bypass)
+		report = "enabled";
+	else
+		report = "disabled";
+
+	return sprintf(buf, "%s\n", report);
+}
+static DEVICE_ATTR(bypass, 0444,
+		   regulator_bypass_show, NULL);
 
 /*
  * These are the only attributes are present for all regulators.
@@ -2673,6 +2698,100 @@ out:
 }
 EXPORT_SYMBOL_GPL(regulator_set_optimum_mode);
 
+/**
+ * regulator_set_bypass_regmap - Default set_bypass() using regmap
+ *
+ * @rdev: device to operate on.
+ * @enable: state to set.
+ */
+int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable)
+{
+	unsigned int val;
+
+	if (enable)
+		val = rdev->desc->bypass_mask;
+	else
+		val = 0;
+
+	return regmap_update_bits(rdev->regmap, rdev->desc->bypass_reg,
+				  rdev->desc->bypass_mask, val);
+}
+EXPORT_SYMBOL_GPL(regulator_set_bypass_regmap);
+
+/**
+ * regulator_get_bypass_regmap - Default get_bypass() using regmap
+ *
+ * @rdev: device to operate on.
+ * @enable: current state.
+ */
+int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable)
+{
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(rdev->regmap, rdev->desc->bypass_reg, &val);
+	if (ret != 0)
+		return ret;
+
+	*enable = val & rdev->desc->bypass_mask;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(regulator_get_bypass_regmap);
+
+/**
+ * regulator_allow_bypass - allow the regulator to go into bypass mode
+ *
+ * @regulator: Regulator to configure
+ * @allow: enable or disable bypass mode
+ *
+ * Allow the regulator to go into bypass mode if all other consumers
+ * for the regulator also enable bypass mode and the machine
+ * constraints allow this.  Bypass mode means that the regulator is
+ * simply passing the input directly to the output with no regulation.
+ */
+int regulator_allow_bypass(struct regulator *regulator, bool enable)
+{
+	struct regulator_dev *rdev = regulator->rdev;
+	int ret = 0;
+
+	if (!rdev->desc->ops->set_bypass)
+		return 0;
+
+	if (rdev->constraints &&
+	    !(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_BYPASS))
+		return 0;
+
+	mutex_lock(&rdev->mutex);
+
+	if (enable && !regulator->bypass) {
+		rdev->bypass_count++;
+
+		if (rdev->bypass_count == rdev->open_count) {
+			ret = rdev->desc->ops->set_bypass(rdev, enable);
+			if (ret != 0)
+				rdev->bypass_count--;
+		}
+
+	} else if (!enable && regulator->bypass) {
+		rdev->bypass_count--;
+
+		if (rdev->bypass_count != rdev->open_count) {
+			ret = rdev->desc->ops->set_bypass(rdev, enable);
+			if (ret != 0)
+				rdev->bypass_count++;
+		}
+	}
+
+	if (ret == 0)
+		regulator->bypass = enable;
+
+	mutex_unlock(&rdev->mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(regulator_allow_bypass);
+
 /**
  * regulator_register_notifier - register regulator event notifier
  * @regulator: regulator source
@@ -3036,6 +3155,11 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
 		if (status < 0)
 			return status;
 	}
+	if (ops->get_bypass) {
+		status = device_create_file(dev, &dev_attr_bypass);
+		if (status < 0)
+			return status;
+	}
 
 	/* some attributes are type-specific */
 	if (rdev->desc->type == REGULATOR_CURRENT) {
@@ -3124,6 +3248,8 @@ static void rdev_init_debugfs(struct regulator_dev *rdev)
 			   &rdev->use_count);
 	debugfs_create_u32("open_count", 0444, rdev->debugfs,
 			   &rdev->open_count);
+	debugfs_create_u32("bypass_count", 0444, rdev->debugfs,
+			   &rdev->bypass_count);
 }
 
 /**

+ 8 - 0
drivers/regulator/wm831x-ldo.c

@@ -237,6 +237,8 @@ static struct regulator_ops wm831x_gp_ldo_ops = {
 	.set_mode = wm831x_gp_ldo_set_mode,
 	.get_status = wm831x_gp_ldo_get_status,
 	.get_optimum_mode = wm831x_gp_ldo_get_optimum_mode,
+	.get_bypass = regulator_get_bypass_regmap,
+	.set_bypass = regulator_set_bypass_regmap,
 
 	.is_enabled = regulator_is_enabled_regmap,
 	.enable = regulator_enable_regmap,
@@ -293,6 +295,8 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev)
 	ldo->desc.vsel_mask = WM831X_LDO1_ON_VSEL_MASK;
 	ldo->desc.enable_reg = WM831X_LDO_ENABLE;
 	ldo->desc.enable_mask = 1 << id;
+	ldo->desc.bypass_reg = ldo->base;
+	ldo->desc.bypass_mask = WM831X_LDO1_SWI;
 
 	config.dev = pdev->dev.parent;
 	if (pdata)
@@ -488,6 +492,8 @@ static struct regulator_ops wm831x_aldo_ops = {
 	.get_mode = wm831x_aldo_get_mode,
 	.set_mode = wm831x_aldo_set_mode,
 	.get_status = wm831x_aldo_get_status,
+	.set_bypass = regulator_set_bypass_regmap,
+	.get_bypass = regulator_get_bypass_regmap,
 
 	.is_enabled = regulator_is_enabled_regmap,
 	.enable = regulator_enable_regmap,
@@ -544,6 +550,8 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev)
 	ldo->desc.vsel_mask = WM831X_LDO7_ON_VSEL_MASK;
 	ldo->desc.enable_reg = WM831X_LDO_ENABLE;
 	ldo->desc.enable_mask = 1 << id;
+	ldo->desc.bypass_reg = ldo->base;
+	ldo->desc.bypass_mask = WM831X_LDO7_SWI;
 
 	config.dev = pdev->dev.parent;
 	if (pdata)

+ 4 - 2
include/linux/mfd/abx500/ab8500-codec.h

@@ -23,7 +23,8 @@ enum amic_type {
 /* Mic-biases */
 enum amic_micbias {
 	AMIC_MICBIAS_VAMIC1,
-	AMIC_MICBIAS_VAMIC2
+	AMIC_MICBIAS_VAMIC2,
+	AMIC_MICBIAS_UNKNOWN
 };
 
 /* Bias-voltage */
@@ -31,7 +32,8 @@ enum ear_cm_voltage {
 	EAR_CMV_0_95V,
 	EAR_CMV_1_10V,
 	EAR_CMV_1_27V,
-	EAR_CMV_1_58V
+	EAR_CMV_1_58V,
+	EAR_CMV_UNKNOWN
 };
 
 /* Analog microphone settings */

+ 8 - 0
include/linux/regulator/consumer.h

@@ -177,6 +177,8 @@ int regulator_set_mode(struct regulator *regulator, unsigned int mode);
 unsigned int regulator_get_mode(struct regulator *regulator);
 int regulator_set_optimum_mode(struct regulator *regulator, int load_uA);
 
+int regulator_allow_bypass(struct regulator *regulator, bool allow);
+
 /* regulator notifier block */
 int regulator_register_notifier(struct regulator *regulator,
 			      struct notifier_block *nb);
@@ -328,6 +330,12 @@ static inline int regulator_set_optimum_mode(struct regulator *regulator,
 	return REGULATOR_MODE_NORMAL;
 }
 
+static inline int regulator_allow_bypass(struct regulator *regulator,
+					 bool allow)
+{
+	return 0;
+}
+
 static inline int regulator_register_notifier(struct regulator *regulator,
 			      struct notifier_block *nb)
 {

+ 14 - 0
include/linux/regulator/driver.h

@@ -32,6 +32,8 @@ enum regulator_status {
 	REGULATOR_STATUS_NORMAL,
 	REGULATOR_STATUS_IDLE,
 	REGULATOR_STATUS_STANDBY,
+	/* The regulator is enabled but not regulating */
+	REGULATOR_STATUS_BYPASS,
 	/* in case that any other status doesn't apply */
 	REGULATOR_STATUS_UNDEFINED,
 };
@@ -67,6 +69,9 @@ enum regulator_status {
  * @get_optimum_mode: Get the most efficient operating mode for the regulator
  *                    when running with the specified parameters.
  *
+ * @set_bypass: Set the regulator in bypass mode.
+ * @get_bypass: Get the regulator bypass mode state.
+ *
  * @enable_time: Time taken for the regulator voltage output voltage to
  *               stabilise after being enabled, in microseconds.
  * @set_ramp_delay: Set the ramp delay for the regulator. The driver should
@@ -133,6 +138,10 @@ struct regulator_ops {
 	unsigned int (*get_optimum_mode) (struct regulator_dev *, int input_uV,
 					  int output_uV, int load_uA);
 
+	/* control and report on bypass mode */
+	int (*set_bypass)(struct regulator_dev *dev, bool enable);
+	int (*get_bypass)(struct regulator_dev *dev, bool *enable);
+
 	/* the operations below are for configuration of regulator state when
 	 * its parent PMIC enters a global STANDBY/HIBERNATE state */
 
@@ -205,6 +214,8 @@ struct regulator_desc {
 	unsigned int vsel_mask;
 	unsigned int enable_reg;
 	unsigned int enable_mask;
+	unsigned int bypass_reg;
+	unsigned int bypass_mask;
 
 	unsigned int enable_time;
 };
@@ -253,6 +264,7 @@ struct regulator_dev {
 	int exclusive;
 	u32 use_count;
 	u32 open_count;
+	u32 bypass_count;
 
 	/* lists we belong to */
 	struct list_head list; /* list of all regulators */
@@ -310,6 +322,8 @@ int regulator_disable_regmap(struct regulator_dev *rdev);
 int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
 				   unsigned int old_selector,
 				   unsigned int new_selector);
+int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable);
+int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable);
 
 void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
 

+ 2 - 0
include/linux/regulator/machine.h

@@ -32,6 +32,7 @@ struct regulator;
  *           board/machine.
  * STATUS:   Regulator can be enabled and disabled.
  * DRMS:     Dynamic Regulator Mode Switching is enabled for this regulator.
+ * BYPASS:   Regulator can be put into bypass mode
  */
 
 #define REGULATOR_CHANGE_VOLTAGE	0x1
@@ -39,6 +40,7 @@ struct regulator;
 #define REGULATOR_CHANGE_MODE		0x4
 #define REGULATOR_CHANGE_STATUS		0x8
 #define REGULATOR_CHANGE_DRMS		0x10
+#define REGULATOR_CHANGE_BYPASS		0x20
 
 /**
  * struct regulator_state - regulator state during low power system states

+ 33 - 0
include/sound/da9055.h

@@ -0,0 +1,33 @@
+/*
+ * DA9055 ALSA Soc codec driver
+ *
+ * Copyright (c) 2012 Dialog Semiconductor
+ *
+ * Tested on (Samsung SMDK6410 board + DA9055 EVB) using I2S and I2C
+ * Written by David Chen <david.chen@diasemi.com> and
+ * Ashish Chavan <ashish.chavan@kpitcummins.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 __SOUND_DA9055_H__
+#define __SOUND_DA9055_H__
+
+enum da9055_micbias_voltage {
+	DA9055_MICBIAS_1_6V = 0,
+	DA9055_MICBIAS_1_8V = 1,
+	DA9055_MICBIAS_2_1V = 2,
+	DA9055_MICBIAS_2_2V = 3,
+};
+
+struct da9055_platform_data {
+	/* Selects which of the two MicBias pins acts as the bias source */
+	bool micbias_source;
+	/* Selects the micbias voltage */
+	enum da9055_micbias_voltage micbias;
+};
+
+#endif

+ 3 - 0
include/sound/soc-dapm.h

@@ -320,6 +320,9 @@ struct device;
 #define SND_SOC_DAPM_EVENT_OFF(e)	\
 	(e & (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD))
 
+/* regulator widget flags */
+#define SND_SOC_DAPM_REGULATOR_BYPASS     0x1     /* bypass when disabled */
+
 struct snd_soc_dapm_widget;
 enum snd_soc_dapm_type;
 struct snd_soc_dapm_path;

+ 4 - 0
sound/soc/codecs/Kconfig

@@ -37,6 +37,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_CX20442
 	select SND_SOC_DA7210 if I2C
 	select SND_SOC_DA732X if I2C
+	select SND_SOC_DA9055 if I2C
 	select SND_SOC_DFBMCS320
 	select SND_SOC_ISABELLE if I2C
 	select SND_SOC_JZ4740_CODEC
@@ -239,6 +240,9 @@ config SND_SOC_DA7210
 config SND_SOC_DA732X
         tristate
 
+config SND_SOC_DA9055
+	tristate
+
 config SND_SOC_DFBMCS320
 	tristate
 

+ 2 - 0
sound/soc/codecs/Makefile

@@ -24,6 +24,7 @@ snd-soc-cs4271-objs := cs4271.o
 snd-soc-cx20442-objs := cx20442.o
 snd-soc-da7210-objs := da7210.o
 snd-soc-da732x-objs := da732x.o
+snd-soc-da9055-objs := da9055.o
 snd-soc-dfbmcs320-objs := dfbmcs320.o
 snd-soc-dmic-objs := dmic.o
 snd-soc-isabelle-objs := isabelle.o
@@ -144,6 +145,7 @@ obj-$(CONFIG_SND_SOC_CS4271)	+= snd-soc-cs4271.o
 obj-$(CONFIG_SND_SOC_CX20442)	+= snd-soc-cx20442.o
 obj-$(CONFIG_SND_SOC_DA7210)	+= snd-soc-da7210.o
 obj-$(CONFIG_SND_SOC_DA732X)	+= snd-soc-da732x.o
+obj-$(CONFIG_SND_SOC_DA9055)	+= snd-soc-da9055.o
 obj-$(CONFIG_SND_SOC_DFBMCS320)	+= snd-soc-dfbmcs320.o
 obj-$(CONFIG_SND_SOC_DMIC)	+= snd-soc-dmic.o
 obj-$(CONFIG_SND_SOC_ISABELLE)	+= snd-soc-isabelle.o

+ 81 - 0
sound/soc/codecs/ab8500-codec.c

@@ -34,6 +34,7 @@
 #include <linux/mfd/abx500/ab8500-sysctrl.h>
 #include <linux/mfd/abx500/ab8500-codec.h>
 #include <linux/regulator/consumer.h>
+#include <linux/of.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -2394,9 +2395,65 @@ struct snd_soc_dai_driver ab8500_codec_dai[] = {
 	}
 };
 
+static void ab8500_codec_of_probe(struct device *dev, struct device_node *np,
+				struct ab8500_codec_platform_data *codec)
+{
+	u32 value;
+
+	if (of_get_property(np, "stericsson,amic1-type-single-ended", NULL))
+		codec->amics.mic1_type = AMIC_TYPE_SINGLE_ENDED;
+	else
+		codec->amics.mic1_type = AMIC_TYPE_DIFFERENTIAL;
+
+	if (of_get_property(np, "stericsson,amic2-type-single-ended", NULL))
+		codec->amics.mic2_type = AMIC_TYPE_SINGLE_ENDED;
+	else
+		codec->amics.mic2_type = AMIC_TYPE_DIFFERENTIAL;
+
+	/* Has a non-standard Vamic been requested? */
+	if (of_get_property(np, "stericsson,amic1a-bias-vamic2", NULL))
+		codec->amics.mic1a_micbias = AMIC_MICBIAS_VAMIC2;
+	else
+		codec->amics.mic1a_micbias = AMIC_MICBIAS_VAMIC1;
+
+	if (of_get_property(np, "stericsson,amic1b-bias-vamic2", NULL))
+		codec->amics.mic1b_micbias = AMIC_MICBIAS_VAMIC2;
+	else
+		codec->amics.mic1b_micbias = AMIC_MICBIAS_VAMIC1;
+
+	if (of_get_property(np, "stericsson,amic2-bias-vamic1", NULL))
+		codec->amics.mic2_micbias = AMIC_MICBIAS_VAMIC1;
+	else
+		codec->amics.mic2_micbias = AMIC_MICBIAS_VAMIC2;
+
+	if (!of_property_read_u32(np, "stericsson,earpeice-cmv", &value)) {
+		switch (value) {
+		case 950 :
+			codec->ear_cmv = EAR_CMV_0_95V;
+			break;
+		case 1100 :
+			codec->ear_cmv = EAR_CMV_1_10V;
+			break;
+		case 1270 :
+			codec->ear_cmv = EAR_CMV_1_27V;
+			break;
+		case 1580 :
+			codec->ear_cmv = EAR_CMV_1_58V;
+			break;
+		default :
+			codec->ear_cmv = EAR_CMV_UNKNOWN;
+			dev_err(dev, "Unsuitable earpiece voltage found in DT\n");
+		}
+	} else {
+		dev_warn(dev, "No earpiece voltage found in DT - using default\n");
+		codec->ear_cmv = EAR_CMV_0_95V;
+	}
+}
+
 static int ab8500_codec_probe(struct snd_soc_codec *codec)
 {
 	struct device *dev = codec->dev;
+	struct device_node *np = dev->of_node;
 	struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev);
 	struct ab8500_platform_data *pdata;
 	struct filter_control *fc;
@@ -2407,6 +2464,30 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
 	/* Setup AB8500 according to board-settings */
 	pdata = dev_get_platdata(dev->parent);
 
+	if (np) {
+		if (!pdata)
+			pdata = devm_kzalloc(dev,
+					sizeof(struct ab8500_platform_data),
+					GFP_KERNEL);
+
+		if (pdata && !pdata->codec)
+			pdata->codec
+				= devm_kzalloc(dev,
+					sizeof(struct ab8500_codec_platform_data),
+					GFP_KERNEL);
+
+		if (!(pdata && pdata->codec))
+			return -ENOMEM;
+
+		ab8500_codec_of_probe(dev, np, pdata->codec);
+
+	} else {
+		if (!(pdata && pdata->codec)) {
+			dev_err(dev, "No codec platform data or DT found\n");
+			return -EINVAL;
+		}
+	}
+
 	status = ab8500_audio_setup_mics(codec, &pdata->codec->amics);
 	if (status < 0) {
 		pr_err("%s: Failed to setup mics (%d)!\n", __func__, status);

+ 42 - 0
sound/soc/codecs/arizona.c

@@ -119,6 +119,24 @@ const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
 	"DSP1.4",
 	"DSP1.5",
 	"DSP1.6",
+	"DSP2.1",
+	"DSP2.2",
+	"DSP2.3",
+	"DSP2.4",
+	"DSP2.5",
+	"DSP2.6",
+	"DSP3.1",
+	"DSP3.2",
+	"DSP3.3",
+	"DSP3.4",
+	"DSP3.5",
+	"DSP3.6",
+	"DSP4.1",
+	"DSP4.2",
+	"DSP4.3",
+	"DSP4.4",
+	"DSP4.5",
+	"DSP4.6",
 	"ASRC1L",
 	"ASRC1R",
 	"ASRC2L",
@@ -180,6 +198,24 @@ int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
 	0x6b,
 	0x6c,
 	0x6d,
+	0x70,  /* DSP2.1 */
+	0x71,
+	0x72,
+	0x73,
+	0x74,
+	0x75,
+	0x78,  /* DSP3.1 */
+	0x79,
+	0x7a,
+	0x7b,
+	0x7c,
+	0x7d,
+	0x80,  /* DSP4.1 */
+	0x81,
+	0x82,
+	0x83,
+	0x84,
+	0x85,
 	0x90,  /* ASRC1L */
 	0x91,
 	0x92,
@@ -234,6 +270,9 @@ static unsigned int arizona_sysclk_48k_rates[] = {
 	12288000,
 	22579200,
 	49152000,
+	73728000,
+	98304000,
+	147456000,
 };
 
 static unsigned int arizona_sysclk_44k1_rates[] = {
@@ -241,6 +280,9 @@ static unsigned int arizona_sysclk_44k1_rates[] = {
 	11289600,
 	24576000,
 	45158400,
+	67737600,
+	90316800,
+	135475200,
 };
 
 static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,

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

@@ -61,7 +61,7 @@ struct arizona_priv {
 	struct arizona_dai_priv dai[ARIZONA_MAX_DAI];
 };
 
-#define ARIZONA_NUM_MIXER_INPUTS 57
+#define ARIZONA_NUM_MIXER_INPUTS 75
 
 extern const unsigned int arizona_mixer_tlv[];
 extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS];

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

@@ -459,7 +459,7 @@ static struct snd_soc_dai_driver cs4270_dai = {
 	.name = "cs4270-hifi",
 	.playback = {
 		.stream_name = "Playback",
-		.channels_min = 1,
+		.channels_min = 2,
 		.channels_max = 2,
 		.rates = SNDRV_PCM_RATE_CONTINUOUS,
 		.rate_min = 4000,
@@ -468,7 +468,7 @@ static struct snd_soc_dai_driver cs4270_dai = {
 	},
 	.capture = {
 		.stream_name = "Capture",
-		.channels_min = 1,
+		.channels_min = 2,
 		.channels_max = 2,
 		.rates = SNDRV_PCM_RATE_CONTINUOUS,
 		.rate_min = 4000,

+ 21 - 3
sound/soc/codecs/cs4271.c

@@ -22,12 +22,14 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <sound/tlv.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
 #include <linux/spi/spi.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
 #include <sound/cs4271.h>
 
 #define CS4271_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
@@ -458,6 +460,14 @@ static int cs4271_soc_resume(struct snd_soc_codec *codec)
 #define cs4271_soc_resume	NULL
 #endif /* CONFIG_PM */
 
+#ifdef CONFIG_OF
+static const struct of_device_id cs4271_dt_ids[] = {
+	{ .compatible = "cirrus,cs4271", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, cs4271_dt_ids);
+#endif
+
 static int cs4271_probe(struct snd_soc_codec *codec)
 {
 	struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
@@ -465,6 +475,12 @@ static int cs4271_probe(struct snd_soc_codec *codec)
 	int ret;
 	int gpio_nreset = -EINVAL;
 
+#ifdef CONFIG_OF
+	if (of_match_device(cs4271_dt_ids, codec->dev))
+		gpio_nreset = of_get_named_gpio(codec->dev->of_node,
+						"reset-gpio", 0);
+#endif
+
 	if (cs4271plat && gpio_is_valid(cs4271plat->gpio_nreset))
 		gpio_nreset = cs4271plat->gpio_nreset;
 
@@ -569,6 +585,7 @@ static struct spi_driver cs4271_spi_driver = {
 	.driver = {
 		.name	= "cs4271",
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(cs4271_dt_ids),
 	},
 	.probe		= cs4271_spi_probe,
 	.remove		= __devexit_p(cs4271_spi_remove),
@@ -608,6 +625,7 @@ static struct i2c_driver cs4271_i2c_driver = {
 	.driver = {
 		.name	= "cs4271",
 		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(cs4271_dt_ids),
 	},
 	.id_table	= cs4271_i2c_id,
 	.probe		= cs4271_i2c_probe,

+ 1510 - 0
sound/soc/codecs/da9055.c

@@ -0,0 +1,1510 @@
+/*
+ * DA9055 ALSA Soc codec driver
+ *
+ * Copyright (c) 2012 Dialog Semiconductor
+ *
+ * Tested on (Samsung SMDK6410 board + DA9055 EVB) using I2S and I2C
+ * Written by David Chen <david.chen@diasemi.com> and
+ * Ashish Chavan <ashish.chavan@kpitcummins.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/delay.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/da9055.h>
+
+/* DA9055 register space */
+
+/* Status Registers */
+#define DA9055_STATUS1			0x02
+#define DA9055_PLL_STATUS		0x03
+#define DA9055_AUX_L_GAIN_STATUS	0x04
+#define DA9055_AUX_R_GAIN_STATUS	0x05
+#define DA9055_MIC_L_GAIN_STATUS	0x06
+#define DA9055_MIC_R_GAIN_STATUS	0x07
+#define DA9055_MIXIN_L_GAIN_STATUS	0x08
+#define DA9055_MIXIN_R_GAIN_STATUS	0x09
+#define DA9055_ADC_L_GAIN_STATUS	0x0A
+#define DA9055_ADC_R_GAIN_STATUS	0x0B
+#define DA9055_DAC_L_GAIN_STATUS	0x0C
+#define DA9055_DAC_R_GAIN_STATUS	0x0D
+#define DA9055_HP_L_GAIN_STATUS		0x0E
+#define DA9055_HP_R_GAIN_STATUS		0x0F
+#define DA9055_LINE_GAIN_STATUS		0x10
+
+/* System Initialisation Registers */
+#define DA9055_CIF_CTRL			0x20
+#define DA9055_DIG_ROUTING_AIF		0X21
+#define DA9055_SR			0x22
+#define DA9055_REFERENCES		0x23
+#define DA9055_PLL_FRAC_TOP		0x24
+#define DA9055_PLL_FRAC_BOT		0x25
+#define DA9055_PLL_INTEGER		0x26
+#define DA9055_PLL_CTRL			0x27
+#define DA9055_AIF_CLK_MODE		0x28
+#define DA9055_AIF_CTRL			0x29
+#define DA9055_DIG_ROUTING_DAC		0x2A
+#define DA9055_ALC_CTRL1		0x2B
+
+/* Input - Gain, Select and Filter Registers */
+#define DA9055_AUX_L_GAIN		0x30
+#define DA9055_AUX_R_GAIN		0x31
+#define DA9055_MIXIN_L_SELECT		0x32
+#define DA9055_MIXIN_R_SELECT		0x33
+#define DA9055_MIXIN_L_GAIN		0x34
+#define DA9055_MIXIN_R_GAIN		0x35
+#define DA9055_ADC_L_GAIN		0x36
+#define DA9055_ADC_R_GAIN		0x37
+#define DA9055_ADC_FILTERS1		0x38
+#define DA9055_MIC_L_GAIN		0x39
+#define DA9055_MIC_R_GAIN		0x3A
+
+/* Output - Gain, Select and Filter Registers */
+#define DA9055_DAC_FILTERS5		0x40
+#define DA9055_DAC_FILTERS2		0x41
+#define DA9055_DAC_FILTERS3		0x42
+#define DA9055_DAC_FILTERS4		0x43
+#define DA9055_DAC_FILTERS1		0x44
+#define DA9055_DAC_L_GAIN		0x45
+#define DA9055_DAC_R_GAIN		0x46
+#define DA9055_CP_CTRL			0x47
+#define DA9055_HP_L_GAIN		0x48
+#define DA9055_HP_R_GAIN		0x49
+#define DA9055_LINE_GAIN		0x4A
+#define DA9055_MIXOUT_L_SELECT		0x4B
+#define DA9055_MIXOUT_R_SELECT		0x4C
+
+/* System Controller Registers */
+#define DA9055_SYSTEM_MODES_INPUT	0x50
+#define DA9055_SYSTEM_MODES_OUTPUT	0x51
+
+/* Control Registers */
+#define DA9055_AUX_L_CTRL		0x60
+#define DA9055_AUX_R_CTRL		0x61
+#define DA9055_MIC_BIAS_CTRL		0x62
+#define DA9055_MIC_L_CTRL		0x63
+#define DA9055_MIC_R_CTRL		0x64
+#define DA9055_MIXIN_L_CTRL		0x65
+#define DA9055_MIXIN_R_CTRL		0x66
+#define DA9055_ADC_L_CTRL		0x67
+#define DA9055_ADC_R_CTRL		0x68
+#define DA9055_DAC_L_CTRL		0x69
+#define DA9055_DAC_R_CTRL		0x6A
+#define DA9055_HP_L_CTRL		0x6B
+#define DA9055_HP_R_CTRL		0x6C
+#define DA9055_LINE_CTRL		0x6D
+#define DA9055_MIXOUT_L_CTRL		0x6E
+#define DA9055_MIXOUT_R_CTRL		0x6F
+
+/* Configuration Registers */
+#define DA9055_LDO_CTRL			0x90
+#define DA9055_IO_CTRL			0x91
+#define DA9055_GAIN_RAMP_CTRL		0x92
+#define DA9055_MIC_CONFIG		0x93
+#define DA9055_PC_COUNT			0x94
+#define DA9055_CP_VOL_THRESHOLD1	0x95
+#define DA9055_CP_DELAY			0x96
+#define DA9055_CP_DETECTOR		0x97
+#define DA9055_AIF_OFFSET		0x98
+#define DA9055_DIG_CTRL			0x99
+#define DA9055_ALC_CTRL2		0x9A
+#define DA9055_ALC_CTRL3		0x9B
+#define DA9055_ALC_NOISE		0x9C
+#define DA9055_ALC_TARGET_MIN		0x9D
+#define DA9055_ALC_TARGET_MAX		0x9E
+#define DA9055_ALC_GAIN_LIMITS		0x9F
+#define DA9055_ALC_ANA_GAIN_LIMITS	0xA0
+#define DA9055_ALC_ANTICLIP_CTRL	0xA1
+#define DA9055_ALC_ANTICLIP_LEVEL	0xA2
+#define DA9055_ALC_OFFSET_OP2M_L	0xA6
+#define DA9055_ALC_OFFSET_OP2U_L	0xA7
+#define DA9055_ALC_OFFSET_OP2M_R	0xAB
+#define DA9055_ALC_OFFSET_OP2U_R	0xAC
+#define DA9055_ALC_CIC_OP_LVL_CTRL	0xAD
+#define DA9055_ALC_CIC_OP_LVL_DATA	0xAE
+#define DA9055_DAC_NG_SETUP_TIME	0xAF
+#define DA9055_DAC_NG_OFF_THRESHOLD	0xB0
+#define DA9055_DAC_NG_ON_THRESHOLD	0xB1
+#define DA9055_DAC_NG_CTRL		0xB2
+
+/* SR bit fields */
+#define DA9055_SR_8000			(0x1 << 0)
+#define DA9055_SR_11025			(0x2 << 0)
+#define DA9055_SR_12000			(0x3 << 0)
+#define DA9055_SR_16000			(0x5 << 0)
+#define DA9055_SR_22050			(0x6 << 0)
+#define DA9055_SR_24000			(0x7 << 0)
+#define DA9055_SR_32000			(0x9 << 0)
+#define DA9055_SR_44100			(0xA << 0)
+#define DA9055_SR_48000			(0xB << 0)
+#define DA9055_SR_88200			(0xE << 0)
+#define DA9055_SR_96000			(0xF << 0)
+
+/* REFERENCES bit fields */
+#define DA9055_BIAS_EN			(1 << 3)
+#define DA9055_VMID_EN			(1 << 7)
+
+/* PLL_CTRL bit fields */
+#define DA9055_PLL_INDIV_10_20_MHZ	(1 << 2)
+#define DA9055_PLL_SRM_EN		(1 << 6)
+#define DA9055_PLL_EN			(1 << 7)
+
+/* AIF_CLK_MODE bit fields */
+#define DA9055_AIF_BCLKS_PER_WCLK_32	(0 << 0)
+#define DA9055_AIF_BCLKS_PER_WCLK_64	(1 << 0)
+#define DA9055_AIF_BCLKS_PER_WCLK_128	(2 << 0)
+#define DA9055_AIF_BCLKS_PER_WCLK_256	(3 << 0)
+#define DA9055_AIF_CLK_EN_SLAVE_MODE	(0 << 7)
+#define DA9055_AIF_CLK_EN_MASTER_MODE	(1 << 7)
+
+/* AIF_CTRL bit fields */
+#define DA9055_AIF_FORMAT_I2S_MODE	(0 << 0)
+#define DA9055_AIF_FORMAT_LEFT_J	(1 << 0)
+#define DA9055_AIF_FORMAT_RIGHT_J	(2 << 0)
+#define DA9055_AIF_WORD_S16_LE		(0 << 2)
+#define DA9055_AIF_WORD_S20_3LE		(1 << 2)
+#define DA9055_AIF_WORD_S24_LE		(2 << 2)
+#define DA9055_AIF_WORD_S32_LE		(3 << 2)
+
+/* MIXIN_L_CTRL bit fields */
+#define DA9055_MIXIN_L_MIX_EN		(1 << 3)
+
+/* MIXIN_R_CTRL bit fields */
+#define DA9055_MIXIN_R_MIX_EN		(1 << 3)
+
+/* ADC_L_CTRL bit fields */
+#define DA9055_ADC_L_EN			(1 << 7)
+
+/* ADC_R_CTRL bit fields */
+#define DA9055_ADC_R_EN			(1 << 7)
+
+/* DAC_L_CTRL bit fields */
+#define DA9055_DAC_L_MUTE_EN		(1 << 6)
+
+/* DAC_R_CTRL bit fields */
+#define DA9055_DAC_R_MUTE_EN		(1 << 6)
+
+/* HP_L_CTRL bit fields */
+#define DA9055_HP_L_AMP_OE		(1 << 3)
+
+/* HP_R_CTRL bit fields */
+#define DA9055_HP_R_AMP_OE		(1 << 3)
+
+/* LINE_CTRL bit fields */
+#define DA9055_LINE_AMP_OE		(1 << 3)
+
+/* MIXOUT_L_CTRL bit fields */
+#define DA9055_MIXOUT_L_MIX_EN		(1 << 3)
+
+/* MIXOUT_R_CTRL bit fields */
+#define DA9055_MIXOUT_R_MIX_EN		(1 << 3)
+
+/* MIC bias select bit fields */
+#define DA9055_MICBIAS2_EN		(1 << 6)
+
+/* ALC_CIC_OP_LEVEL_CTRL bit fields */
+#define DA9055_ALC_DATA_MIDDLE		(2 << 0)
+#define DA9055_ALC_DATA_TOP		(3 << 0)
+#define DA9055_ALC_CIC_OP_CHANNEL_LEFT	(0 << 7)
+#define DA9055_ALC_CIC_OP_CHANNEL_RIGHT	(1 << 7)
+
+#define DA9055_AIF_BCLK_MASK		(3 << 0)
+#define DA9055_AIF_CLK_MODE_MASK	(1 << 7)
+#define DA9055_AIF_FORMAT_MASK		(3 << 0)
+#define DA9055_AIF_WORD_LENGTH_MASK	(3 << 2)
+#define DA9055_GAIN_RAMPING_EN		(1 << 5)
+#define DA9055_MICBIAS_LEVEL_MASK	(3 << 4)
+
+#define DA9055_ALC_OFFSET_15_8		0x00FF00
+#define DA9055_ALC_OFFSET_17_16		0x030000
+#define DA9055_ALC_AVG_ITERATIONS	5
+
+struct pll_div {
+	int fref;
+	int fout;
+	u8 frac_top;
+	u8 frac_bot;
+	u8 integer;
+	u8 mode;	/* 0 = slave, 1 = master */
+};
+
+/* PLL divisor table */
+static const struct pll_div da9055_pll_div[] = {
+	/* for MASTER mode, fs = 44.1Khz and its harmonics */
+	{11289600, 2822400, 0x00, 0x00, 0x20, 1},	/* MCLK=11.2896Mhz */
+	{12000000, 2822400, 0x03, 0x61, 0x1E, 1},	/* MCLK=12Mhz */
+	{12288000, 2822400, 0x0C, 0xCC, 0x1D, 1},	/* MCLK=12.288Mhz */
+	{13000000, 2822400, 0x19, 0x45, 0x1B, 1},	/* MCLK=13Mhz */
+	{13500000, 2822400, 0x18, 0x56, 0x1A, 1},	/* MCLK=13.5Mhz */
+	{14400000, 2822400, 0x02, 0xD0, 0x19, 1},	/* MCLK=14.4Mhz */
+	{19200000, 2822400, 0x1A, 0x1C, 0x12, 1},	/* MCLK=19.2Mhz */
+	{19680000, 2822400, 0x0B, 0x6D, 0x12, 1},	/* MCLK=19.68Mhz */
+	{19800000, 2822400, 0x07, 0xDD, 0x12, 1},	/* MCLK=19.8Mhz */
+	/* for MASTER mode, fs = 48Khz and its harmonics */
+	{11289600, 3072000, 0x1A, 0x8E, 0x22, 1},	/* MCLK=11.2896Mhz */
+	{12000000, 3072000, 0x18, 0x93, 0x20, 1},	/* MCLK=12Mhz */
+	{12288000, 3072000, 0x00, 0x00, 0x20, 1},	/* MCLK=12.288Mhz */
+	{13000000, 3072000, 0x07, 0xEA, 0x1E, 1},	/* MCLK=13Mhz */
+	{13500000, 3072000, 0x04, 0x11, 0x1D, 1},	/* MCLK=13.5Mhz */
+	{14400000, 3072000, 0x09, 0xD0, 0x1B, 1},	/* MCLK=14.4Mhz */
+	{19200000, 3072000, 0x0F, 0x5C, 0x14, 1},	/* MCLK=19.2Mhz */
+	{19680000, 3072000, 0x1F, 0x60, 0x13, 1},	/* MCLK=19.68Mhz */
+	{19800000, 3072000, 0x1B, 0x80, 0x13, 1},	/* MCLK=19.8Mhz */
+	/* for SLAVE mode with SRM */
+	{11289600, 2822400, 0x0D, 0x47, 0x21, 0},	/* MCLK=11.2896Mhz */
+	{12000000, 2822400, 0x0D, 0xFA, 0x1F, 0},	/* MCLK=12Mhz */
+	{12288000, 2822400, 0x16, 0x66, 0x1E, 0},	/* MCLK=12.288Mhz */
+	{13000000, 2822400, 0x00, 0x98, 0x1D, 0},	/* MCLK=13Mhz */
+	{13500000, 2822400, 0x1E, 0x33, 0x1B, 0},	/* MCLK=13.5Mhz */
+	{14400000, 2822400, 0x06, 0x50, 0x1A, 0},	/* MCLK=14.4Mhz */
+	{19200000, 2822400, 0x14, 0xBC, 0x13, 0},	/* MCLK=19.2Mhz */
+	{19680000, 2822400, 0x05, 0x66, 0x13, 0},	/* MCLK=19.68Mhz */
+	{19800000, 2822400, 0x01, 0xAE, 0x13, 0},	/* MCLK=19.8Mhz  */
+};
+
+enum clk_src {
+	DA9055_CLKSRC_MCLK
+};
+
+/* Gain and Volume */
+
+static const unsigned int aux_vol_tlv[] = {
+	TLV_DB_RANGE_HEAD(2),
+	0x0, 0x10, TLV_DB_SCALE_ITEM(-5400, 0, 0),
+	/* -54dB to 15dB */
+	0x11, 0x3f, TLV_DB_SCALE_ITEM(-5400, 150, 0)
+};
+
+static const unsigned int digital_gain_tlv[] = {
+	TLV_DB_RANGE_HEAD(2),
+	0x0, 0x07, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
+	/* -78dB to 12dB */
+	0x08, 0x7f, TLV_DB_SCALE_ITEM(-7800, 75, 0)
+};
+
+static const unsigned int alc_analog_gain_tlv[] = {
+	TLV_DB_RANGE_HEAD(2),
+	0x0, 0x0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
+	/* 0dB to 36dB */
+	0x01, 0x07, TLV_DB_SCALE_ITEM(0, 600, 0)
+};
+
+static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(mixin_gain_tlv, -450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(eq_gain_tlv, -1050, 150, 0);
+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -5700, 100, 0);
+static const DECLARE_TLV_DB_SCALE(lineout_vol_tlv, -4800, 100, 0);
+static const DECLARE_TLV_DB_SCALE(alc_threshold_tlv, -9450, 150, 0);
+static const DECLARE_TLV_DB_SCALE(alc_gain_tlv, 0, 600, 0);
+
+/* ADC and DAC high pass filter cutoff value */
+static const char * const da9055_hpf_cutoff_txt[] = {
+	"Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000"
+};
+
+static const struct soc_enum da9055_dac_hpf_cutoff =
+	SOC_ENUM_SINGLE(DA9055_DAC_FILTERS1, 4, 4, da9055_hpf_cutoff_txt);
+
+static const struct soc_enum da9055_adc_hpf_cutoff =
+	SOC_ENUM_SINGLE(DA9055_ADC_FILTERS1, 4, 4, da9055_hpf_cutoff_txt);
+
+/* ADC and DAC voice mode (8kHz) high pass cutoff value */
+static const char * const da9055_vf_cutoff_txt[] = {
+	"2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
+};
+
+static const struct soc_enum da9055_dac_vf_cutoff =
+	SOC_ENUM_SINGLE(DA9055_DAC_FILTERS1, 0, 8, da9055_vf_cutoff_txt);
+
+static const struct soc_enum da9055_adc_vf_cutoff =
+	SOC_ENUM_SINGLE(DA9055_ADC_FILTERS1, 0, 8, da9055_vf_cutoff_txt);
+
+/* Gain ramping rate value */
+static const char * const da9055_gain_ramping_txt[] = {
+	"nominal rate", "nominal rate * 4", "nominal rate * 8",
+	"nominal rate / 8"
+};
+
+static const struct soc_enum da9055_gain_ramping_rate =
+	SOC_ENUM_SINGLE(DA9055_GAIN_RAMP_CTRL, 0, 4, da9055_gain_ramping_txt);
+
+/* DAC noise gate setup time value */
+static const char * const da9055_dac_ng_setup_time_txt[] = {
+	"256 samples", "512 samples", "1024 samples", "2048 samples"
+};
+
+static const struct soc_enum da9055_dac_ng_setup_time =
+	SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 0, 4,
+			da9055_dac_ng_setup_time_txt);
+
+/* DAC noise gate rampup rate value */
+static const char * const da9055_dac_ng_rampup_txt[] = {
+	"0.02 ms/dB", "0.16 ms/dB"
+};
+
+static const struct soc_enum da9055_dac_ng_rampup_rate =
+	SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 2, 2,
+			da9055_dac_ng_rampup_txt);
+
+/* DAC noise gate rampdown rate value */
+static const char * const da9055_dac_ng_rampdown_txt[] = {
+	"0.64 ms/dB", "20.48 ms/dB"
+};
+
+static const struct soc_enum da9055_dac_ng_rampdown_rate =
+	SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 3, 2,
+			da9055_dac_ng_rampdown_txt);
+
+/* DAC soft mute rate value */
+static const char * const da9055_dac_soft_mute_rate_txt[] = {
+	"1", "2", "4", "8", "16", "32", "64"
+};
+
+static const struct soc_enum da9055_dac_soft_mute_rate =
+	SOC_ENUM_SINGLE(DA9055_DAC_FILTERS5, 4, 7,
+			da9055_dac_soft_mute_rate_txt);
+
+/* DAC routing select */
+static const char * const da9055_dac_src_txt[] = {
+	"ADC output left", "ADC output right", "AIF input left",
+	"AIF input right"
+};
+
+static const struct soc_enum da9055_dac_l_src =
+	SOC_ENUM_SINGLE(DA9055_DIG_ROUTING_DAC, 0, 4, da9055_dac_src_txt);
+
+static const struct soc_enum da9055_dac_r_src =
+	SOC_ENUM_SINGLE(DA9055_DIG_ROUTING_DAC, 4, 4, da9055_dac_src_txt);
+
+/* MIC PGA Left source select */
+static const char * const da9055_mic_l_src_txt[] = {
+	"MIC1_P_N", "MIC1_P", "MIC1_N", "MIC2_L"
+};
+
+static const struct soc_enum da9055_mic_l_src =
+	SOC_ENUM_SINGLE(DA9055_MIXIN_L_SELECT, 4, 4, da9055_mic_l_src_txt);
+
+/* MIC PGA Right source select */
+static const char * const da9055_mic_r_src_txt[] = {
+	"MIC2_R_L", "MIC2_R", "MIC2_L"
+};
+
+static const struct soc_enum da9055_mic_r_src =
+	SOC_ENUM_SINGLE(DA9055_MIXIN_R_SELECT, 4, 3, da9055_mic_r_src_txt);
+
+/* ALC Input Signal Tracking rate select */
+static const char * const da9055_signal_tracking_rate_txt[] = {
+	"1/4", "1/16", "1/256", "1/65536"
+};
+
+static const struct soc_enum da9055_integ_attack_rate =
+	SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 4, 4,
+			da9055_signal_tracking_rate_txt);
+
+static const struct soc_enum da9055_integ_release_rate =
+	SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 6, 4,
+			da9055_signal_tracking_rate_txt);
+
+/* ALC Attack Rate select */
+static const char * const da9055_attack_rate_txt[] = {
+	"44/fs", "88/fs", "176/fs", "352/fs", "704/fs", "1408/fs", "2816/fs",
+	"5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs"
+};
+
+static const struct soc_enum da9055_attack_rate =
+	SOC_ENUM_SINGLE(DA9055_ALC_CTRL2, 0, 13, da9055_attack_rate_txt);
+
+/* ALC Release Rate select */
+static const char * const da9055_release_rate_txt[] = {
+	"176/fs", "352/fs", "704/fs", "1408/fs", "2816/fs", "5632/fs",
+	"11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs"
+};
+
+static const struct soc_enum da9055_release_rate =
+	SOC_ENUM_SINGLE(DA9055_ALC_CTRL2, 4, 11, da9055_release_rate_txt);
+
+/* ALC Hold Time select */
+static const char * const da9055_hold_time_txt[] = {
+	"62/fs", "124/fs", "248/fs", "496/fs", "992/fs", "1984/fs", "3968/fs",
+	"7936/fs", "15872/fs", "31744/fs", "63488/fs", "126976/fs",
+	"253952/fs", "507904/fs", "1015808/fs", "2031616/fs"
+};
+
+static const struct soc_enum da9055_hold_time =
+	SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 0, 16, da9055_hold_time_txt);
+
+static int da9055_get_alc_data(struct snd_soc_codec *codec, u8 reg_val)
+{
+	int mid_data, top_data;
+	int sum = 0;
+	u8 iteration;
+
+	for (iteration = 0; iteration < DA9055_ALC_AVG_ITERATIONS;
+	     iteration++) {
+		/* Select the left or right channel and capture data */
+		snd_soc_write(codec, DA9055_ALC_CIC_OP_LVL_CTRL, reg_val);
+
+		/* Select middle 8 bits for read back from data register */
+		snd_soc_write(codec, DA9055_ALC_CIC_OP_LVL_CTRL,
+			      reg_val | DA9055_ALC_DATA_MIDDLE);
+		mid_data = snd_soc_read(codec, DA9055_ALC_CIC_OP_LVL_DATA);
+
+		/* Select top 8 bits for read back from data register */
+		snd_soc_write(codec, DA9055_ALC_CIC_OP_LVL_CTRL,
+			      reg_val | DA9055_ALC_DATA_TOP);
+		top_data = snd_soc_read(codec, DA9055_ALC_CIC_OP_LVL_DATA);
+
+		sum += ((mid_data << 8) | (top_data << 16));
+	}
+
+	return sum / DA9055_ALC_AVG_ITERATIONS;
+}
+
+static int da9055_put_alc_sw(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	u8 reg_val, adc_left, adc_right;
+	int avg_left_data, avg_right_data, offset_l, offset_r;
+
+	if (ucontrol->value.integer.value[0]) {
+		/*
+		 * While enabling ALC (or ALC sync mode), calibration of the DC
+		 * offsets must be done first
+		 */
+
+		/* Save current values from ADC control registers */
+		adc_left = snd_soc_read(codec, DA9055_ADC_L_CTRL);
+		adc_right = snd_soc_read(codec, DA9055_ADC_R_CTRL);
+
+		/* Enable ADC Left and Right */
+		snd_soc_update_bits(codec, DA9055_ADC_L_CTRL,
+				    DA9055_ADC_L_EN, DA9055_ADC_L_EN);
+		snd_soc_update_bits(codec, DA9055_ADC_R_CTRL,
+				    DA9055_ADC_R_EN, DA9055_ADC_R_EN);
+
+		/* Calculate average for Left and Right data */
+		/* Left Data */
+		avg_left_data = da9055_get_alc_data(codec,
+				DA9055_ALC_CIC_OP_CHANNEL_LEFT);
+		/* Right Data */
+		avg_right_data = da9055_get_alc_data(codec,
+				 DA9055_ALC_CIC_OP_CHANNEL_RIGHT);
+
+		/* Calculate DC offset */
+		offset_l = -avg_left_data;
+		offset_r = -avg_right_data;
+
+		reg_val = (offset_l & DA9055_ALC_OFFSET_15_8) >> 8;
+		snd_soc_write(codec, DA9055_ALC_OFFSET_OP2M_L, reg_val);
+		reg_val = (offset_l & DA9055_ALC_OFFSET_17_16) >> 16;
+		snd_soc_write(codec, DA9055_ALC_OFFSET_OP2U_L, reg_val);
+
+		reg_val = (offset_r & DA9055_ALC_OFFSET_15_8) >> 8;
+		snd_soc_write(codec, DA9055_ALC_OFFSET_OP2M_R, reg_val);
+		reg_val = (offset_r & DA9055_ALC_OFFSET_17_16) >> 16;
+		snd_soc_write(codec, DA9055_ALC_OFFSET_OP2U_R, reg_val);
+
+		/* Restore original values of ADC control registers */
+		snd_soc_write(codec, DA9055_ADC_L_CTRL, adc_left);
+		snd_soc_write(codec, DA9055_ADC_R_CTRL, adc_right);
+	}
+
+	return snd_soc_put_volsw(kcontrol, ucontrol);
+}
+
+static const struct snd_kcontrol_new da9055_snd_controls[] = {
+
+	/* Volume controls */
+	SOC_DOUBLE_R_TLV("Mic Volume",
+			 DA9055_MIC_L_GAIN, DA9055_MIC_R_GAIN,
+			 0, 0x7, 0, mic_vol_tlv),
+	SOC_DOUBLE_R_TLV("Aux Volume",
+			 DA9055_AUX_L_GAIN, DA9055_AUX_R_GAIN,
+			 0, 0x3f, 0, aux_vol_tlv),
+	SOC_DOUBLE_R_TLV("Mixin PGA Volume",
+			 DA9055_MIXIN_L_GAIN, DA9055_MIXIN_R_GAIN,
+			 0, 0xf, 0, mixin_gain_tlv),
+	SOC_DOUBLE_R_TLV("ADC Volume",
+			 DA9055_ADC_L_GAIN, DA9055_ADC_R_GAIN,
+			 0, 0x7f, 0, digital_gain_tlv),
+
+	SOC_DOUBLE_R_TLV("DAC Volume",
+			 DA9055_DAC_L_GAIN, DA9055_DAC_R_GAIN,
+			 0, 0x7f, 0, digital_gain_tlv),
+	SOC_DOUBLE_R_TLV("Headphone Volume",
+			 DA9055_HP_L_GAIN, DA9055_HP_R_GAIN,
+			 0, 0x3f, 0, hp_vol_tlv),
+	SOC_SINGLE_TLV("Lineout Volume", DA9055_LINE_GAIN, 0, 0x3f, 0,
+		       lineout_vol_tlv),
+
+	/* DAC Equalizer controls */
+	SOC_SINGLE("DAC EQ Switch", DA9055_DAC_FILTERS4, 7, 1, 0),
+	SOC_SINGLE_TLV("DAC EQ1 Volume", DA9055_DAC_FILTERS2, 0, 0xf, 0,
+		       eq_gain_tlv),
+	SOC_SINGLE_TLV("DAC EQ2 Volume", DA9055_DAC_FILTERS2, 4, 0xf, 0,
+		       eq_gain_tlv),
+	SOC_SINGLE_TLV("DAC EQ3 Volume", DA9055_DAC_FILTERS3, 0, 0xf, 0,
+		       eq_gain_tlv),
+	SOC_SINGLE_TLV("DAC EQ4 Volume", DA9055_DAC_FILTERS3, 4, 0xf, 0,
+		       eq_gain_tlv),
+	SOC_SINGLE_TLV("DAC EQ5 Volume", DA9055_DAC_FILTERS4, 0, 0xf, 0,
+		       eq_gain_tlv),
+
+	/* High Pass Filter and Voice Mode controls */
+	SOC_SINGLE("ADC HPF Switch", DA9055_ADC_FILTERS1, 7, 1, 0),
+	SOC_ENUM("ADC HPF Cutoff", da9055_adc_hpf_cutoff),
+	SOC_SINGLE("ADC Voice Mode Switch", DA9055_ADC_FILTERS1, 3, 1, 0),
+	SOC_ENUM("ADC Voice Cutoff", da9055_adc_vf_cutoff),
+
+	SOC_SINGLE("DAC HPF Switch", DA9055_DAC_FILTERS1, 7, 1, 0),
+	SOC_ENUM("DAC HPF Cutoff", da9055_dac_hpf_cutoff),
+	SOC_SINGLE("DAC Voice Mode Switch", DA9055_DAC_FILTERS1, 3, 1, 0),
+	SOC_ENUM("DAC Voice Cutoff", da9055_dac_vf_cutoff),
+
+	/* Mute controls */
+	SOC_DOUBLE_R("Mic Switch", DA9055_MIC_L_CTRL,
+		     DA9055_MIC_R_CTRL, 6, 1, 0),
+	SOC_DOUBLE_R("Aux Switch", DA9055_AUX_L_CTRL,
+		     DA9055_AUX_R_CTRL, 6, 1, 0),
+	SOC_DOUBLE_R("Mixin PGA Switch", DA9055_MIXIN_L_CTRL,
+		     DA9055_MIXIN_R_CTRL, 6, 1, 0),
+	SOC_DOUBLE_R("ADC Switch", DA9055_ADC_L_CTRL,
+		     DA9055_ADC_R_CTRL, 6, 1, 0),
+	SOC_DOUBLE_R("Headphone Switch", DA9055_HP_L_CTRL,
+		     DA9055_HP_R_CTRL, 6, 1, 0),
+	SOC_SINGLE("Lineout Switch", DA9055_LINE_CTRL, 6, 1, 0),
+	SOC_SINGLE("DAC Soft Mute Switch", DA9055_DAC_FILTERS5, 7, 1, 0),
+	SOC_ENUM("DAC Soft Mute Rate", da9055_dac_soft_mute_rate),
+
+	/* Zero Cross controls */
+	SOC_DOUBLE_R("Aux ZC Switch", DA9055_AUX_L_CTRL,
+		     DA9055_AUX_R_CTRL, 4, 1, 0),
+	SOC_DOUBLE_R("Mixin PGA ZC Switch", DA9055_MIXIN_L_CTRL,
+		     DA9055_MIXIN_R_CTRL, 4, 1, 0),
+	SOC_DOUBLE_R("Headphone ZC Switch", DA9055_HP_L_CTRL,
+		     DA9055_HP_R_CTRL, 4, 1, 0),
+	SOC_SINGLE("Lineout ZC Switch", DA9055_LINE_CTRL, 4, 1, 0),
+
+	/* Gain Ramping controls */
+	SOC_DOUBLE_R("Aux Gain Ramping Switch", DA9055_AUX_L_CTRL,
+		     DA9055_AUX_R_CTRL, 5, 1, 0),
+	SOC_DOUBLE_R("Mixin Gain Ramping Switch", DA9055_MIXIN_L_CTRL,
+		     DA9055_MIXIN_R_CTRL, 5, 1, 0),
+	SOC_DOUBLE_R("ADC Gain Ramping Switch", DA9055_ADC_L_CTRL,
+		     DA9055_ADC_R_CTRL, 5, 1, 0),
+	SOC_DOUBLE_R("DAC Gain Ramping Switch", DA9055_DAC_L_CTRL,
+		     DA9055_DAC_R_CTRL, 5, 1, 0),
+	SOC_DOUBLE_R("Headphone Gain Ramping Switch", DA9055_HP_L_CTRL,
+		     DA9055_HP_R_CTRL, 5, 1, 0),
+	SOC_SINGLE("Lineout Gain Ramping Switch", DA9055_LINE_CTRL, 5, 1, 0),
+	SOC_ENUM("Gain Ramping Rate", da9055_gain_ramping_rate),
+
+	/* DAC Noise Gate controls */
+	SOC_SINGLE("DAC NG Switch", DA9055_DAC_NG_CTRL, 7, 1, 0),
+	SOC_SINGLE("DAC NG ON Threshold", DA9055_DAC_NG_ON_THRESHOLD,
+		   0, 0x7, 0),
+	SOC_SINGLE("DAC NG OFF Threshold", DA9055_DAC_NG_OFF_THRESHOLD,
+		   0, 0x7, 0),
+	SOC_ENUM("DAC NG Setup Time", da9055_dac_ng_setup_time),
+	SOC_ENUM("DAC NG Rampup Rate", da9055_dac_ng_rampup_rate),
+	SOC_ENUM("DAC NG Rampdown Rate", da9055_dac_ng_rampdown_rate),
+
+	/* DAC Invertion control */
+	SOC_SINGLE("DAC Left Invert", DA9055_DIG_CTRL, 3, 1, 0),
+	SOC_SINGLE("DAC Right Invert", DA9055_DIG_CTRL, 7, 1, 0),
+
+	/* DMIC controls */
+	SOC_DOUBLE_R("DMIC Switch", DA9055_MIXIN_L_SELECT,
+		     DA9055_MIXIN_R_SELECT, 7, 1, 0),
+
+	/* ALC Controls */
+	SOC_DOUBLE_EXT("ALC Switch", DA9055_ALC_CTRL1, 3, 7, 1, 0,
+		       snd_soc_get_volsw, da9055_put_alc_sw),
+	SOC_SINGLE_EXT("ALC Sync Mode Switch", DA9055_ALC_CTRL1, 1, 1, 0,
+		       snd_soc_get_volsw, da9055_put_alc_sw),
+	SOC_SINGLE("ALC Offset Switch", DA9055_ALC_CTRL1, 0, 1, 0),
+	SOC_SINGLE("ALC Anticlip Mode Switch", DA9055_ALC_ANTICLIP_CTRL,
+		   7, 1, 0),
+	SOC_SINGLE("ALC Anticlip Level", DA9055_ALC_ANTICLIP_LEVEL,
+		   0, 0x7f, 0),
+	SOC_SINGLE_TLV("ALC Min Threshold Volume", DA9055_ALC_TARGET_MIN,
+		       0, 0x3f, 1, alc_threshold_tlv),
+	SOC_SINGLE_TLV("ALC Max Threshold Volume", DA9055_ALC_TARGET_MAX,
+		       0, 0x3f, 1, alc_threshold_tlv),
+	SOC_SINGLE_TLV("ALC Noise Threshold Volume", DA9055_ALC_NOISE,
+		       0, 0x3f, 1, alc_threshold_tlv),
+	SOC_SINGLE_TLV("ALC Max Gain Volume", DA9055_ALC_GAIN_LIMITS,
+		       4, 0xf, 0, alc_gain_tlv),
+	SOC_SINGLE_TLV("ALC Max Attenuation Volume", DA9055_ALC_GAIN_LIMITS,
+		       0, 0xf, 0, alc_gain_tlv),
+	SOC_SINGLE_TLV("ALC Min Analog Gain Volume",
+		       DA9055_ALC_ANA_GAIN_LIMITS,
+		       0, 0x7, 0, alc_analog_gain_tlv),
+	SOC_SINGLE_TLV("ALC Max Analog Gain Volume",
+		       DA9055_ALC_ANA_GAIN_LIMITS,
+		       4, 0x7, 0, alc_analog_gain_tlv),
+	SOC_ENUM("ALC Attack Rate", da9055_attack_rate),
+	SOC_ENUM("ALC Release Rate", da9055_release_rate),
+	SOC_ENUM("ALC Hold Time", da9055_hold_time),
+	/*
+	 * Rate at which input signal envelope is tracked as the signal gets
+	 * larger
+	 */
+	SOC_ENUM("ALC Integ Attack Rate", da9055_integ_attack_rate),
+	/*
+	 * Rate at which input signal envelope is tracked as the signal gets
+	 * smaller
+	 */
+	SOC_ENUM("ALC Integ Release Rate", da9055_integ_release_rate),
+};
+
+/* DAPM Controls */
+
+/* Mic PGA Left Source */
+static const struct snd_kcontrol_new da9055_mic_l_mux_controls =
+SOC_DAPM_ENUM("Route", da9055_mic_l_src);
+
+/* Mic PGA Right Source */
+static const struct snd_kcontrol_new da9055_mic_r_mux_controls =
+SOC_DAPM_ENUM("Route", da9055_mic_r_src);
+
+/* In Mixer Left */
+static const struct snd_kcontrol_new da9055_dapm_mixinl_controls[] = {
+	SOC_DAPM_SINGLE("Aux Left Switch", DA9055_MIXIN_L_SELECT, 0, 1, 0),
+	SOC_DAPM_SINGLE("Mic Left Switch", DA9055_MIXIN_L_SELECT, 1, 1, 0),
+	SOC_DAPM_SINGLE("Mic Right Switch", DA9055_MIXIN_L_SELECT, 2, 1, 0),
+};
+
+/* In Mixer Right */
+static const struct snd_kcontrol_new da9055_dapm_mixinr_controls[] = {
+	SOC_DAPM_SINGLE("Aux Right Switch", DA9055_MIXIN_R_SELECT, 0, 1, 0),
+	SOC_DAPM_SINGLE("Mic Right Switch", DA9055_MIXIN_R_SELECT, 1, 1, 0),
+	SOC_DAPM_SINGLE("Mic Left Switch", DA9055_MIXIN_R_SELECT, 2, 1, 0),
+	SOC_DAPM_SINGLE("Mixin Left Switch", DA9055_MIXIN_R_SELECT, 3, 1, 0),
+};
+
+/* DAC Left Source */
+static const struct snd_kcontrol_new da9055_dac_l_mux_controls =
+SOC_DAPM_ENUM("Route", da9055_dac_l_src);
+
+/* DAC Right Source */
+static const struct snd_kcontrol_new da9055_dac_r_mux_controls =
+SOC_DAPM_ENUM("Route", da9055_dac_r_src);
+
+/* Out Mixer Left */
+static const struct snd_kcontrol_new da9055_dapm_mixoutl_controls[] = {
+	SOC_DAPM_SINGLE("Aux Left Switch", DA9055_MIXOUT_L_SELECT, 0, 1, 0),
+	SOC_DAPM_SINGLE("Mixin Left Switch", DA9055_MIXOUT_L_SELECT, 1, 1, 0),
+	SOC_DAPM_SINGLE("Mixin Right Switch", DA9055_MIXOUT_L_SELECT, 2, 1, 0),
+	SOC_DAPM_SINGLE("DAC Left Switch", DA9055_MIXOUT_L_SELECT, 3, 1, 0),
+	SOC_DAPM_SINGLE("Aux Left Invert Switch", DA9055_MIXOUT_L_SELECT,
+			4, 1, 0),
+	SOC_DAPM_SINGLE("Mixin Left Invert Switch", DA9055_MIXOUT_L_SELECT,
+			5, 1, 0),
+	SOC_DAPM_SINGLE("Mixin Right Invert Switch", DA9055_MIXOUT_L_SELECT,
+			6, 1, 0),
+};
+
+/* Out Mixer Right */
+static const struct snd_kcontrol_new da9055_dapm_mixoutr_controls[] = {
+	SOC_DAPM_SINGLE("Aux Right Switch", DA9055_MIXOUT_R_SELECT, 0, 1, 0),
+	SOC_DAPM_SINGLE("Mixin Right Switch", DA9055_MIXOUT_R_SELECT, 1, 1, 0),
+	SOC_DAPM_SINGLE("Mixin Left Switch", DA9055_MIXOUT_R_SELECT, 2, 1, 0),
+	SOC_DAPM_SINGLE("DAC Right Switch", DA9055_MIXOUT_R_SELECT, 3, 1, 0),
+	SOC_DAPM_SINGLE("Aux Right Invert Switch", DA9055_MIXOUT_R_SELECT,
+			4, 1, 0),
+	SOC_DAPM_SINGLE("Mixin Right Invert Switch", DA9055_MIXOUT_R_SELECT,
+			5, 1, 0),
+	SOC_DAPM_SINGLE("Mixin Left Invert Switch", DA9055_MIXOUT_R_SELECT,
+			6, 1, 0),
+};
+
+/* DAPM widgets */
+static const struct snd_soc_dapm_widget da9055_dapm_widgets[] = {
+	/* Input Side */
+
+	/* Input Lines */
+	SND_SOC_DAPM_INPUT("MIC1"),
+	SND_SOC_DAPM_INPUT("MIC2"),
+	SND_SOC_DAPM_INPUT("AUXL"),
+	SND_SOC_DAPM_INPUT("AUXR"),
+
+	/* MUXs for Mic PGA source selection */
+	SND_SOC_DAPM_MUX("Mic Left Source", SND_SOC_NOPM, 0, 0,
+			 &da9055_mic_l_mux_controls),
+	SND_SOC_DAPM_MUX("Mic Right Source", SND_SOC_NOPM, 0, 0,
+			 &da9055_mic_r_mux_controls),
+
+	/* Input PGAs */
+	SND_SOC_DAPM_PGA("Mic Left", DA9055_MIC_L_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Mic Right", DA9055_MIC_R_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Aux Left", DA9055_AUX_L_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Aux Right", DA9055_AUX_R_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("MIXIN Left", DA9055_MIXIN_L_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("MIXIN Right", DA9055_MIXIN_R_CTRL, 7, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("Mic Bias", DA9055_MIC_BIAS_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("AIF", DA9055_AIF_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_SUPPLY("Charge Pump", DA9055_CP_CTRL, 7, 0, NULL, 0),
+
+	/* Input Mixers */
+	SND_SOC_DAPM_MIXER("In Mixer Left", SND_SOC_NOPM, 0, 0,
+			   &da9055_dapm_mixinl_controls[0],
+			   ARRAY_SIZE(da9055_dapm_mixinl_controls)),
+	SND_SOC_DAPM_MIXER("In Mixer Right", SND_SOC_NOPM, 0, 0,
+			   &da9055_dapm_mixinr_controls[0],
+			   ARRAY_SIZE(da9055_dapm_mixinr_controls)),
+
+	/* ADCs */
+	SND_SOC_DAPM_ADC("ADC Left", "Capture", DA9055_ADC_L_CTRL, 7, 0),
+	SND_SOC_DAPM_ADC("ADC Right", "Capture", DA9055_ADC_R_CTRL, 7, 0),
+
+	/* Output Side */
+
+	/* MUXs for DAC source selection */
+	SND_SOC_DAPM_MUX("DAC Left Source", SND_SOC_NOPM, 0, 0,
+			 &da9055_dac_l_mux_controls),
+	SND_SOC_DAPM_MUX("DAC Right Source", SND_SOC_NOPM, 0, 0,
+			 &da9055_dac_r_mux_controls),
+
+	/* AIF input */
+	SND_SOC_DAPM_AIF_IN("AIFIN Left", "Playback", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_IN("AIFIN Right", "Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	/* DACs */
+	SND_SOC_DAPM_DAC("DAC Left", "Playback", DA9055_DAC_L_CTRL, 7, 0),
+	SND_SOC_DAPM_DAC("DAC Right", "Playback", DA9055_DAC_R_CTRL, 7, 0),
+
+	/* Output Mixers */
+	SND_SOC_DAPM_MIXER("Out Mixer Left", SND_SOC_NOPM, 0, 0,
+			   &da9055_dapm_mixoutl_controls[0],
+			   ARRAY_SIZE(da9055_dapm_mixoutl_controls)),
+	SND_SOC_DAPM_MIXER("Out Mixer Right", SND_SOC_NOPM, 0, 0,
+			   &da9055_dapm_mixoutr_controls[0],
+			   ARRAY_SIZE(da9055_dapm_mixoutr_controls)),
+
+	/* Output PGAs */
+	SND_SOC_DAPM_PGA("MIXOUT Left", DA9055_MIXOUT_L_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("MIXOUT Right", DA9055_MIXOUT_R_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Lineout", DA9055_LINE_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Headphone Left", DA9055_HP_L_CTRL, 7, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Headphone Right", DA9055_HP_R_CTRL, 7, 0, NULL, 0),
+
+	/* Output Lines */
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+	SND_SOC_DAPM_OUTPUT("LINE"),
+};
+
+/* DAPM audio route definition */
+static const struct snd_soc_dapm_route da9055_audio_map[] = {
+	/* Dest       Connecting Widget    source */
+
+	/* Input path */
+	{"Mic Left Source", "MIC1_P_N", "MIC1"},
+	{"Mic Left Source", "MIC1_P", "MIC1"},
+	{"Mic Left Source", "MIC1_N", "MIC1"},
+	{"Mic Left Source", "MIC2_L", "MIC2"},
+
+	{"Mic Right Source", "MIC2_R_L", "MIC2"},
+	{"Mic Right Source", "MIC2_R", "MIC2"},
+	{"Mic Right Source", "MIC2_L", "MIC2"},
+
+	{"Mic Left", NULL, "Mic Left Source"},
+	{"Mic Right", NULL, "Mic Right Source"},
+
+	{"Aux Left", NULL, "AUXL"},
+	{"Aux Right", NULL, "AUXR"},
+
+	{"In Mixer Left", "Mic Left Switch", "Mic Left"},
+	{"In Mixer Left", "Mic Right Switch", "Mic Right"},
+	{"In Mixer Left", "Aux Left Switch", "Aux Left"},
+
+	{"In Mixer Right", "Mic Right Switch", "Mic Right"},
+	{"In Mixer Right", "Mic Left Switch", "Mic Left"},
+	{"In Mixer Right", "Aux Right Switch", "Aux Right"},
+	{"In Mixer Right", "Mixin Left Switch", "MIXIN Left"},
+
+	{"MIXIN Left", NULL, "In Mixer Left"},
+	{"ADC Left", NULL, "MIXIN Left"},
+
+	{"MIXIN Right", NULL, "In Mixer Right"},
+	{"ADC Right", NULL, "MIXIN Right"},
+
+	{"ADC Left", NULL, "AIF"},
+	{"ADC Right", NULL, "AIF"},
+
+	/* Output path */
+	{"AIFIN Left", NULL, "AIF"},
+	{"AIFIN Right", NULL, "AIF"},
+
+	{"DAC Left Source", "ADC output left", "ADC Left"},
+	{"DAC Left Source", "ADC output right", "ADC Right"},
+	{"DAC Left Source", "AIF input left", "AIFIN Left"},
+	{"DAC Left Source", "AIF input right", "AIFIN Right"},
+
+	{"DAC Right Source", "ADC output left", "ADC Left"},
+	{"DAC Right Source", "ADC output right", "ADC Right"},
+	{"DAC Right Source", "AIF input left", "AIFIN Left"},
+	{"DAC Right Source", "AIF input right", "AIFIN Right"},
+
+	{"DAC Left", NULL, "DAC Left Source"},
+	{"DAC Right", NULL, "DAC Right Source"},
+
+	{"Out Mixer Left", "Aux Left Switch", "Aux Left"},
+	{"Out Mixer Left", "Mixin Left Switch", "MIXIN Left"},
+	{"Out Mixer Left", "Mixin Right Switch", "MIXIN Right"},
+	{"Out Mixer Left", "Aux Left Invert Switch", "Aux Left"},
+	{"Out Mixer Left", "Mixin Left Invert Switch", "MIXIN Left"},
+	{"Out Mixer Left", "Mixin Right Invert Switch", "MIXIN Right"},
+	{"Out Mixer Left", "DAC Left Switch", "DAC Left"},
+
+	{"Out Mixer Right", "Aux Right Switch", "Aux Right"},
+	{"Out Mixer Right", "Mixin Right Switch", "MIXIN Right"},
+	{"Out Mixer Right", "Mixin Left Switch", "MIXIN Left"},
+	{"Out Mixer Right", "Aux Right Invert Switch", "Aux Right"},
+	{"Out Mixer Right", "Mixin Right Invert Switch", "MIXIN Right"},
+	{"Out Mixer Right", "Mixin Left Invert Switch", "MIXIN Left"},
+	{"Out Mixer Right", "DAC Right Switch", "DAC Right"},
+
+	{"MIXOUT Left", NULL, "Out Mixer Left"},
+	{"Headphone Left", NULL, "MIXOUT Left"},
+	{"Headphone Left", NULL, "Charge Pump"},
+	{"HPL", NULL, "Headphone Left"},
+
+	{"MIXOUT Right", NULL, "Out Mixer Right"},
+	{"Headphone Right", NULL, "MIXOUT Right"},
+	{"Headphone Right", NULL, "Charge Pump"},
+	{"HPR", NULL, "Headphone Right"},
+
+	{"MIXOUT Right", NULL, "Out Mixer Right"},
+	{"Lineout", NULL, "MIXOUT Right"},
+	{"LINE", NULL, "Lineout"},
+};
+
+/* Codec private data */
+struct da9055_priv {
+	struct regmap *regmap;
+	unsigned int mclk_rate;
+	int master;
+	struct da9055_platform_data *pdata;
+};
+
+static struct reg_default da9055_reg_defaults[] = {
+	{ 0x21, 0x10 },
+	{ 0x22, 0x0A },
+	{ 0x23, 0x00 },
+	{ 0x24, 0x00 },
+	{ 0x25, 0x00 },
+	{ 0x26, 0x00 },
+	{ 0x27, 0x0C },
+	{ 0x28, 0x01 },
+	{ 0x29, 0x08 },
+	{ 0x2A, 0x32 },
+	{ 0x2B, 0x00 },
+	{ 0x30, 0x35 },
+	{ 0x31, 0x35 },
+	{ 0x32, 0x00 },
+	{ 0x33, 0x00 },
+	{ 0x34, 0x03 },
+	{ 0x35, 0x03 },
+	{ 0x36, 0x6F },
+	{ 0x37, 0x6F },
+	{ 0x38, 0x80 },
+	{ 0x39, 0x01 },
+	{ 0x3A, 0x01 },
+	{ 0x40, 0x00 },
+	{ 0x41, 0x88 },
+	{ 0x42, 0x88 },
+	{ 0x43, 0x08 },
+	{ 0x44, 0x80 },
+	{ 0x45, 0x6F },
+	{ 0x46, 0x6F },
+	{ 0x47, 0x61 },
+	{ 0x48, 0x35 },
+	{ 0x49, 0x35 },
+	{ 0x4A, 0x35 },
+	{ 0x4B, 0x00 },
+	{ 0x4C, 0x00 },
+	{ 0x60, 0x44 },
+	{ 0x61, 0x44 },
+	{ 0x62, 0x00 },
+	{ 0x63, 0x40 },
+	{ 0x64, 0x40 },
+	{ 0x65, 0x40 },
+	{ 0x66, 0x40 },
+	{ 0x67, 0x40 },
+	{ 0x68, 0x40 },
+	{ 0x69, 0x48 },
+	{ 0x6A, 0x40 },
+	{ 0x6B, 0x41 },
+	{ 0x6C, 0x40 },
+	{ 0x6D, 0x40 },
+	{ 0x6E, 0x10 },
+	{ 0x6F, 0x10 },
+	{ 0x90, 0x80 },
+	{ 0x92, 0x02 },
+	{ 0x93, 0x00 },
+	{ 0x99, 0x00 },
+	{ 0x9A, 0x00 },
+	{ 0x9B, 0x00 },
+	{ 0x9C, 0x3F },
+	{ 0x9D, 0x00 },
+	{ 0x9E, 0x3F },
+	{ 0x9F, 0xFF },
+	{ 0xA0, 0x71 },
+	{ 0xA1, 0x00 },
+	{ 0xA2, 0x00 },
+	{ 0xA6, 0x00 },
+	{ 0xA7, 0x00 },
+	{ 0xAB, 0x00 },
+	{ 0xAC, 0x00 },
+	{ 0xAD, 0x00 },
+	{ 0xAF, 0x08 },
+	{ 0xB0, 0x00 },
+	{ 0xB1, 0x00 },
+	{ 0xB2, 0x00 },
+};
+
+static bool da9055_volatile_register(struct device *dev,
+				     unsigned int reg)
+{
+	switch (reg) {
+	case DA9055_STATUS1:
+	case DA9055_PLL_STATUS:
+	case DA9055_AUX_L_GAIN_STATUS:
+	case DA9055_AUX_R_GAIN_STATUS:
+	case DA9055_MIC_L_GAIN_STATUS:
+	case DA9055_MIC_R_GAIN_STATUS:
+	case DA9055_MIXIN_L_GAIN_STATUS:
+	case DA9055_MIXIN_R_GAIN_STATUS:
+	case DA9055_ADC_L_GAIN_STATUS:
+	case DA9055_ADC_R_GAIN_STATUS:
+	case DA9055_DAC_L_GAIN_STATUS:
+	case DA9055_DAC_R_GAIN_STATUS:
+	case DA9055_HP_L_GAIN_STATUS:
+	case DA9055_HP_R_GAIN_STATUS:
+	case DA9055_LINE_GAIN_STATUS:
+	case DA9055_ALC_CIC_OP_LVL_DATA:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+/* Set DAI word length */
+static int da9055_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 da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec);
+	u8 aif_ctrl, fs;
+	u32 sysclk;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		aif_ctrl = DA9055_AIF_WORD_S16_LE;
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		aif_ctrl = DA9055_AIF_WORD_S20_3LE;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		aif_ctrl = DA9055_AIF_WORD_S24_LE;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		aif_ctrl = DA9055_AIF_WORD_S32_LE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Set AIF format */
+	snd_soc_update_bits(codec, DA9055_AIF_CTRL, DA9055_AIF_WORD_LENGTH_MASK,
+			    aif_ctrl);
+
+	switch (params_rate(params)) {
+	case 8000:
+		fs		= DA9055_SR_8000;
+		sysclk		= 3072000;
+		break;
+	case 11025:
+		fs		= DA9055_SR_11025;
+		sysclk		= 2822400;
+		break;
+	case 12000:
+		fs		= DA9055_SR_12000;
+		sysclk		= 3072000;
+		break;
+	case 16000:
+		fs		= DA9055_SR_16000;
+		sysclk		= 3072000;
+		break;
+	case 22050:
+		fs		= DA9055_SR_22050;
+		sysclk		= 2822400;
+		break;
+	case 32000:
+		fs		= DA9055_SR_32000;
+		sysclk		= 3072000;
+		break;
+	case 44100:
+		fs		= DA9055_SR_44100;
+		sysclk		= 2822400;
+		break;
+	case 48000:
+		fs		= DA9055_SR_48000;
+		sysclk		= 3072000;
+		break;
+	case 88200:
+		fs		= DA9055_SR_88200;
+		sysclk		= 2822400;
+		break;
+	case 96000:
+		fs		= DA9055_SR_96000;
+		sysclk		= 3072000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (da9055->mclk_rate) {
+		/* PLL Mode, Write actual FS */
+		snd_soc_write(codec, DA9055_SR, fs);
+	} else {
+		/*
+		 * Non-PLL Mode
+		 * When PLL is bypassed, chip assumes constant MCLK of
+		 * 12.288MHz and uses sample rate value to divide this MCLK
+		 * to derive its sys clk. As sys clk has to be 256 * Fs, we
+		 * need to write constant sample rate i.e. 48KHz.
+		 */
+		snd_soc_write(codec, DA9055_SR, DA9055_SR_48000);
+	}
+
+	if (da9055->mclk_rate && (da9055->mclk_rate != sysclk)) {
+		/* PLL Mode */
+		if (!da9055->master) {
+			/* PLL slave mode, enable PLL and also SRM */
+			snd_soc_update_bits(codec, DA9055_PLL_CTRL,
+					    DA9055_PLL_EN | DA9055_PLL_SRM_EN,
+					    DA9055_PLL_EN | DA9055_PLL_SRM_EN);
+		} else {
+			/* PLL master mode, only enable PLL */
+			snd_soc_update_bits(codec, DA9055_PLL_CTRL,
+					    DA9055_PLL_EN, DA9055_PLL_EN);
+		}
+	} else {
+		/* Non PLL Mode, disable PLL */
+		snd_soc_update_bits(codec, DA9055_PLL_CTRL, DA9055_PLL_EN, 0);
+	}
+
+	return 0;
+}
+
+/* Set DAI mode and Format */
+static int da9055_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec);
+	u8 aif_clk_mode, aif_ctrl, mode;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		/* DA9055 in I2S Master Mode */
+		mode = 1;
+		aif_clk_mode = DA9055_AIF_CLK_EN_MASTER_MODE;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		/* DA9055 in I2S Slave Mode */
+		mode = 0;
+		aif_clk_mode = DA9055_AIF_CLK_EN_SLAVE_MODE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Don't allow change of mode if PLL is enabled */
+	if ((snd_soc_read(codec, DA9055_PLL_CTRL) & DA9055_PLL_EN) &&
+	    (da9055->master != mode))
+		return -EINVAL;
+
+	da9055->master = mode;
+
+	/* Only I2S is supported */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		aif_ctrl = DA9055_AIF_FORMAT_I2S_MODE;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		aif_ctrl = DA9055_AIF_FORMAT_LEFT_J;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		aif_ctrl = DA9055_AIF_FORMAT_RIGHT_J;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* By default only 32 BCLK per WCLK is supported */
+	aif_clk_mode |= DA9055_AIF_BCLKS_PER_WCLK_32;
+
+	snd_soc_update_bits(codec, DA9055_AIF_CLK_MODE,
+			    (DA9055_AIF_CLK_MODE_MASK | DA9055_AIF_BCLK_MASK),
+			    aif_clk_mode);
+	snd_soc_update_bits(codec, DA9055_AIF_CTRL, DA9055_AIF_FORMAT_MASK,
+			    aif_ctrl);
+	return 0;
+}
+
+static int da9055_mute(struct snd_soc_dai *dai, int mute)
+{
+	struct snd_soc_codec *codec = dai->codec;
+
+	if (mute) {
+		snd_soc_update_bits(codec, DA9055_DAC_L_CTRL,
+				    DA9055_DAC_L_MUTE_EN, DA9055_DAC_L_MUTE_EN);
+		snd_soc_update_bits(codec, DA9055_DAC_R_CTRL,
+				    DA9055_DAC_R_MUTE_EN, DA9055_DAC_R_MUTE_EN);
+	} else {
+		snd_soc_update_bits(codec, DA9055_DAC_L_CTRL,
+				    DA9055_DAC_L_MUTE_EN, 0);
+		snd_soc_update_bits(codec, DA9055_DAC_R_CTRL,
+				    DA9055_DAC_R_MUTE_EN, 0);
+	}
+
+	return 0;
+}
+
+#define DA9055_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+			SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static int da9055_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 da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec);
+
+	switch (clk_id) {
+	case DA9055_CLKSRC_MCLK:
+		switch (freq) {
+		case 11289600:
+		case 12000000:
+		case 12288000:
+		case 13000000:
+		case 13500000:
+		case 14400000:
+		case 19200000:
+		case 19680000:
+		case 19800000:
+			da9055->mclk_rate = freq;
+			return 0;
+		default:
+			dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
+				freq);
+			return -EINVAL;
+		}
+		break;
+	default:
+		dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
+		return -EINVAL;
+	}
+}
+
+/*
+ * da9055_set_dai_pll	: Configure the codec PLL
+ * @param codec_dai	: Pointer to codec DAI
+ * @param pll_id	: da9055 has only one pll, so pll_id is always zero
+ * @param fref		: Input MCLK frequency
+ * @param fout		: FsDM value
+ * @return int		: Zero for success, negative error code for error
+ *
+ * Note: Supported PLL input frequencies are 11.2896MHz, 12MHz, 12.288MHz,
+ *	 13MHz, 13.5MHz, 14.4MHz, 19.2MHz, 19.6MHz and 19.8MHz
+ */
+static int da9055_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+			      int source, unsigned int fref, unsigned int fout)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec);
+
+	u8 pll_frac_top, pll_frac_bot, pll_integer, cnt;
+
+	/* Disable PLL before setting the divisors */
+	snd_soc_update_bits(codec, DA9055_PLL_CTRL, DA9055_PLL_EN, 0);
+
+	/* In slave mode, there is only one set of divisors */
+	if (!da9055->master && (fout != 2822400))
+		goto pll_err;
+
+	/* Search pll div array for correct divisors */
+	for (cnt = 0; cnt < ARRAY_SIZE(da9055_pll_div); cnt++) {
+		/* Check fref, mode  and fout */
+		if ((fref == da9055_pll_div[cnt].fref) &&
+		    (da9055->master ==  da9055_pll_div[cnt].mode) &&
+		    (fout == da9055_pll_div[cnt].fout)) {
+			/* All match, pick up divisors */
+			pll_frac_top = da9055_pll_div[cnt].frac_top;
+			pll_frac_bot = da9055_pll_div[cnt].frac_bot;
+			pll_integer = da9055_pll_div[cnt].integer;
+			break;
+		}
+	}
+	if (cnt >= ARRAY_SIZE(da9055_pll_div))
+		goto pll_err;
+
+	/* Write PLL dividers */
+	snd_soc_write(codec, DA9055_PLL_FRAC_TOP, pll_frac_top);
+	snd_soc_write(codec, DA9055_PLL_FRAC_BOT, pll_frac_bot);
+	snd_soc_write(codec, DA9055_PLL_INTEGER, pll_integer);
+
+	return 0;
+pll_err:
+	dev_err(codec_dai->dev, "Error in setting up PLL\n");
+	return -EINVAL;
+}
+
+/* DAI operations */
+static const struct snd_soc_dai_ops da9055_dai_ops = {
+	.hw_params	= da9055_hw_params,
+	.set_fmt	= da9055_set_dai_fmt,
+	.set_sysclk	= da9055_set_dai_sysclk,
+	.set_pll	= da9055_set_dai_pll,
+	.digital_mute	= da9055_mute,
+};
+
+static struct snd_soc_dai_driver da9055_dai = {
+	.name = "da9055-hifi",
+	/* Playback Capabilities */
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = DA9055_FORMATS,
+	},
+	/* Capture Capabilities */
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = DA9055_FORMATS,
+	},
+	.ops = &da9055_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static int da9055_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+			/* Enable VMID reference & master bias */
+			snd_soc_update_bits(codec, DA9055_REFERENCES,
+					    DA9055_VMID_EN | DA9055_BIAS_EN,
+					    DA9055_VMID_EN | DA9055_BIAS_EN);
+		}
+		break;
+	case SND_SOC_BIAS_OFF:
+		/* Disable VMID reference & master bias */
+		snd_soc_update_bits(codec, DA9055_REFERENCES,
+				    DA9055_VMID_EN | DA9055_BIAS_EN, 0);
+		break;
+	}
+	codec->dapm.bias_level = level;
+	return 0;
+}
+
+static int da9055_probe(struct snd_soc_codec *codec)
+{
+	int ret;
+	struct da9055_priv *da9055 = snd_soc_codec_get_drvdata(codec);
+
+	codec->control_data = da9055->regmap;
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
+	}
+
+	/* Enable all Gain Ramps */
+	snd_soc_update_bits(codec, DA9055_AUX_L_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+	snd_soc_update_bits(codec, DA9055_AUX_R_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+	snd_soc_update_bits(codec, DA9055_MIXIN_L_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+	snd_soc_update_bits(codec, DA9055_MIXIN_R_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+	snd_soc_update_bits(codec, DA9055_ADC_L_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+	snd_soc_update_bits(codec, DA9055_ADC_R_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+	snd_soc_update_bits(codec, DA9055_DAC_L_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+	snd_soc_update_bits(codec, DA9055_DAC_R_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+	snd_soc_update_bits(codec, DA9055_HP_L_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+	snd_soc_update_bits(codec, DA9055_HP_R_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+	snd_soc_update_bits(codec, DA9055_LINE_CTRL,
+			    DA9055_GAIN_RAMPING_EN, DA9055_GAIN_RAMPING_EN);
+
+	/*
+	 * There are two separate control bits for input and output mixers as
+	 * well as headphone and line outs.
+	 * One to enable corresponding amplifier and other to enable its
+	 * output. As amplifier bits are related to power control, they are
+	 * being managed by DAPM while other (non power related) bits are
+	 * enabled here
+	 */
+	snd_soc_update_bits(codec, DA9055_MIXIN_L_CTRL,
+			    DA9055_MIXIN_L_MIX_EN, DA9055_MIXIN_L_MIX_EN);
+	snd_soc_update_bits(codec, DA9055_MIXIN_R_CTRL,
+			    DA9055_MIXIN_R_MIX_EN, DA9055_MIXIN_R_MIX_EN);
+
+	snd_soc_update_bits(codec, DA9055_MIXOUT_L_CTRL,
+			    DA9055_MIXOUT_L_MIX_EN, DA9055_MIXOUT_L_MIX_EN);
+	snd_soc_update_bits(codec, DA9055_MIXOUT_R_CTRL,
+			    DA9055_MIXOUT_R_MIX_EN, DA9055_MIXOUT_R_MIX_EN);
+
+	snd_soc_update_bits(codec, DA9055_HP_L_CTRL,
+			    DA9055_HP_L_AMP_OE, DA9055_HP_L_AMP_OE);
+	snd_soc_update_bits(codec, DA9055_HP_R_CTRL,
+			    DA9055_HP_R_AMP_OE, DA9055_HP_R_AMP_OE);
+
+	snd_soc_update_bits(codec, DA9055_LINE_CTRL,
+			    DA9055_LINE_AMP_OE, DA9055_LINE_AMP_OE);
+
+	/* Set this as per your system configuration */
+	snd_soc_write(codec, DA9055_PLL_CTRL, DA9055_PLL_INDIV_10_20_MHZ);
+
+	/* Set platform data values */
+	if (da9055->pdata) {
+		/* set mic bias source */
+		if (da9055->pdata->micbias_source) {
+			snd_soc_update_bits(codec, DA9055_MIXIN_R_SELECT,
+					    DA9055_MICBIAS2_EN,
+					    DA9055_MICBIAS2_EN);
+		} else {
+			snd_soc_update_bits(codec, DA9055_MIXIN_R_SELECT,
+					    DA9055_MICBIAS2_EN, 0);
+		}
+		/* set mic bias voltage */
+		switch (da9055->pdata->micbias) {
+		case DA9055_MICBIAS_2_2V:
+		case DA9055_MICBIAS_2_1V:
+		case DA9055_MICBIAS_1_8V:
+		case DA9055_MICBIAS_1_6V:
+			snd_soc_update_bits(codec, DA9055_MIC_CONFIG,
+					    DA9055_MICBIAS_LEVEL_MASK,
+					    (da9055->pdata->micbias) << 4);
+			break;
+		}
+	}
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_da9055 = {
+	.probe			= da9055_probe,
+	.set_bias_level		= da9055_set_bias_level,
+
+	.controls		= da9055_snd_controls,
+	.num_controls		= ARRAY_SIZE(da9055_snd_controls),
+
+	.dapm_widgets		= da9055_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(da9055_dapm_widgets),
+	.dapm_routes		= da9055_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(da9055_audio_map),
+};
+
+static const struct regmap_config da9055_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+
+	.reg_defaults = da9055_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(da9055_reg_defaults),
+	.volatile_reg = da9055_volatile_register,
+	.cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit da9055_i2c_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
+{
+	struct da9055_priv *da9055;
+	struct da9055_platform_data *pdata = dev_get_platdata(&i2c->dev);
+	int ret;
+
+	da9055 = devm_kzalloc(&i2c->dev, sizeof(struct da9055_priv),
+			      GFP_KERNEL);
+	if (!da9055)
+		return -ENOMEM;
+
+	if (pdata)
+		da9055->pdata = pdata;
+
+	i2c_set_clientdata(i2c, da9055);
+
+	da9055->regmap = devm_regmap_init_i2c(i2c, &da9055_regmap_config);
+	if (IS_ERR(da9055->regmap)) {
+		ret = PTR_ERR(da9055->regmap);
+		dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_register_codec(&i2c->dev,
+			&soc_codec_dev_da9055, &da9055_dai, 1);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to register da9055 codec: %d\n",
+			ret);
+	}
+	return ret;
+}
+
+static int __devexit da9055_remove(struct i2c_client *client)
+{
+	snd_soc_unregister_codec(&client->dev);
+	return 0;
+}
+
+static const struct i2c_device_id da9055_i2c_id[] = {
+	{ "da9055", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);
+
+/* I2C codec control layer */
+static struct i2c_driver da9055_i2c_driver = {
+	.driver = {
+		.name = "da9055",
+		.owner = THIS_MODULE,
+	},
+	.probe		= da9055_i2c_probe,
+	.remove		= __devexit_p(da9055_remove),
+	.id_table	= da9055_i2c_id,
+};
+
+module_i2c_driver(da9055_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC DA9055 Codec driver");
+MODULE_AUTHOR("David Chen, Ashish Chavan");
+MODULE_LICENSE("GPL");

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

@@ -168,7 +168,8 @@ static void wm0010_halt(struct snd_soc_codec *codec)
 	case WM0010_STAGE2:
 	case WM0010_FIRMWARE:
 		/* Remember to put chip back into reset */
-		gpio_set_value(wm0010->gpio_reset, wm0010->gpio_reset_value);
+		gpio_set_value_cansleep(wm0010->gpio_reset,
+					wm0010->gpio_reset_value);
 		/* Disable the regulators */
 		regulator_disable(wm0010->dbvdd);
 		regulator_bulk_disable(ARRAY_SIZE(wm0010->core_supplies),
@@ -387,7 +388,7 @@ static int wm0010_boot(struct snd_soc_codec *codec)
 	}
 
 	/* Release reset */
-	gpio_set_value(wm0010->gpio_reset, !wm0010->gpio_reset_value);
+	gpio_set_value_cansleep(wm0010->gpio_reset, !wm0010->gpio_reset_value);
 	spin_lock_irqsave(&wm0010->irq_lock, flags);
 	wm0010->state = WM0010_OUT_OF_RESET;
 	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
@@ -809,7 +810,6 @@ static int wm0010_probe(struct snd_soc_codec *codec)
 
 static int __devinit wm0010_spi_probe(struct spi_device *spi)
 {
-	unsigned long flags;
 	unsigned long gpio_flags;
 	int ret;
 	int trigger;
@@ -876,6 +876,8 @@ static int __devinit wm0010_spi_probe(struct spi_device *spi)
 		return -EINVAL;
 	}
 
+	wm0010->state = WM0010_POWER_OFF;
+
 	irq = spi->irq;
 	if (wm0010->pdata.irq_flags)
 		trigger = wm0010->pdata.irq_flags;
@@ -897,10 +899,6 @@ static int __devinit wm0010_spi_probe(struct spi_device *spi)
 	else
 		wm0010->board_max_spi_speed = 0;
 
-	spin_lock_irqsave(&wm0010->irq_lock, flags);
-	wm0010->state = WM0010_POWER_OFF;
-	spin_unlock_irqrestore(&wm0010->irq_lock, flags);
-
 	ret = snd_soc_register_codec(&spi->dev,
 				     &soc_codec_dev_wm0010, wm0010_dai,
 				     ARRAY_SIZE(wm0010_dai));
@@ -916,10 +914,8 @@ static int __devexit wm0010_spi_remove(struct spi_device *spi)
 
 	snd_soc_unregister_codec(&spi->dev);
 
-	if (wm0010->gpio_reset) {
-		/* Remember to put chip back into reset */
-		gpio_set_value(wm0010->gpio_reset, wm0010->gpio_reset_value);
-	}
+	gpio_set_value_cansleep(wm0010->gpio_reset,
+				wm0010->gpio_reset_value);
 
 	if (wm0010->irq)
 		free_irq(wm0010->irq, wm0010);

+ 48 - 12
sound/soc/codecs/wm2000.c

@@ -31,6 +31,7 @@
 #include <linux/i2c.h>
 #include <linux/regmap.h>
 #include <linux/debugfs.h>
+#include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -43,6 +44,14 @@
 
 #include "wm2000.h"
 
+#define WM2000_NUM_SUPPLIES 3
+
+static const char *wm2000_supplies[WM2000_NUM_SUPPLIES] = {
+	"SPKVDD",
+	"DBVDD",
+	"DCVDD",
+};
+
 enum wm2000_anc_mode {
 	ANC_ACTIVE = 0,
 	ANC_BYPASS = 1,
@@ -54,6 +63,8 @@ struct wm2000_priv {
 	struct i2c_client *i2c;
 	struct regmap *regmap;
 
+	struct regulator_bulk_data supplies[WM2000_NUM_SUPPLIES];
+
 	enum wm2000_anc_mode anc_mode;
 
 	unsigned int anc_active:1;
@@ -126,6 +137,12 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
 
 	dev_dbg(&i2c->dev, "Beginning power up\n");
 
+	ret = regulator_bulk_enable(WM2000_NUM_SUPPLIES, wm2000->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
 	if (!wm2000->mclk_div) {
 		dev_dbg(&i2c->dev, "Disabling MCLK divider\n");
 		wm2000_write(i2c, WM2000_REG_SYS_CTL2,
@@ -143,12 +160,14 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
 	if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT,
 			     WM2000_ANC_ENG_IDLE)) {
 		dev_err(&i2c->dev, "ANC engine failed to reset\n");
+		regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
 		return -ETIMEDOUT;
 	}
 
 	if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
 			     WM2000_STATUS_BOOT_COMPLETE)) {
 		dev_err(&i2c->dev, "ANC engine failed to initialise\n");
+		regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
 		return -ETIMEDOUT;
 	}
 
@@ -163,11 +182,13 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
 			      wm2000->anc_download_size);
 	if (ret < 0) {
 		dev_err(&i2c->dev, "i2c_transfer() failed: %d\n", ret);
+		regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
 		return ret;
 	}
 	if (ret != wm2000->anc_download_size) {
 		dev_err(&i2c->dev, "i2c_transfer() failed, %d != %d\n",
 			ret, wm2000->anc_download_size);
+		regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
 		return -EIO;
 	}
 
@@ -201,6 +222,7 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
 	if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
 			     WM2000_STATUS_MOUSE_ACTIVE)) {
 		dev_err(&i2c->dev, "Timed out waiting for device\n");
+		regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
 		return -ETIMEDOUT;
 	}
 
@@ -238,6 +260,8 @@ static int wm2000_power_down(struct i2c_client *i2c, int analogue)
 		return -ETIMEDOUT;
 	}
 
+	regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
+
 	dev_dbg(&i2c->dev, "powered off\n");
 	wm2000->anc_mode = ANC_OFF;
 
@@ -747,7 +771,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
 	struct wm2000_platform_data *pdata;
 	const char *filename;
 	const struct firmware *fw = NULL;
-	int ret;
+	int ret, i;
 	int reg;
 	u16 id;
 
@@ -760,7 +784,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
 
 	dev_set_drvdata(&i2c->dev, wm2000);
 
-	wm2000->regmap = regmap_init_i2c(i2c, &wm2000_regmap);
+	wm2000->regmap = devm_regmap_init_i2c(i2c, &wm2000_regmap);
 	if (IS_ERR(wm2000->regmap)) {
 		ret = PTR_ERR(wm2000->regmap);
 		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
@@ -768,6 +792,22 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
 		goto out;
 	}
 
+	for (i = 0; i < WM2000_NUM_SUPPLIES; i++)
+		wm2000->supplies[i].supply = wm2000_supplies[i];
+
+	ret = devm_regulator_bulk_get(&i2c->dev, WM2000_NUM_SUPPLIES,
+				      wm2000->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to get supplies: %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_bulk_enable(WM2000_NUM_SUPPLIES, wm2000->supplies);
+	if (ret != 0) {
+		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
+		return ret;
+	}
+
 	/* Verify that this is a WM2000 */
 	reg = wm2000_read(i2c, WM2000_REG_ID1);
 	id = reg << 8;
@@ -777,7 +817,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
 	if (id != 0x2000) {
 		dev_err(&i2c->dev, "Device is not a WM2000 - ID %x\n", id);
 		ret = -ENODEV;
-		goto out_regmap_exit;
+		goto err_supplies;
 	}
 
 	reg = wm2000_read(i2c, WM2000_REG_REVISON);
@@ -796,7 +836,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
 	ret = request_firmware(&fw, filename, &i2c->dev);
 	if (ret != 0) {
 		dev_err(&i2c->dev, "Failed to acquire ANC data: %d\n", ret);
-		goto out_regmap_exit;
+		goto err_supplies;
 	}
 
 	/* Pre-cook the concatenation of the register address onto the image */
@@ -807,7 +847,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
 	if (wm2000->anc_download == NULL) {
 		dev_err(&i2c->dev, "Out of memory\n");
 		ret = -ENOMEM;
-		goto out_regmap_exit;
+		goto err_supplies;
 	}
 
 	wm2000->anc_download[0] = 0x80;
@@ -822,11 +862,10 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
 	wm2000_reset(wm2000);
 
 	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm2000, NULL, 0);
-	if (!ret)
-		goto out;
 
-out_regmap_exit:
-	regmap_exit(wm2000->regmap);
+err_supplies:
+	regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
+
 out:
 	release_firmware(fw);
 	return ret;
@@ -834,10 +873,7 @@ out:
 
 static __devexit int wm2000_i2c_remove(struct i2c_client *i2c)
 {
-	struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
-
 	snd_soc_unregister_codec(&i2c->dev);
-	regmap_exit(wm2000->regmap);
 
 	return 0;
 }

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

@@ -308,7 +308,7 @@ SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
 SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0),
 SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0, 0),
 SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
-SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS),
 SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDL", 0, 0),
 SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0, 0),
 

+ 63 - 16
sound/soc/codecs/wm5110.c

@@ -153,6 +153,15 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
 SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
 SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
 
+ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP2R", ARIZONA_DSP2RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP3L", ARIZONA_DSP3LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP3R", ARIZONA_DSP3RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP4L", ARIZONA_DSP4LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DSP5R", ARIZONA_DSP4RMIX_INPUT_1_SOURCE),
+
 ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE),
 
@@ -163,7 +172,8 @@ ARIZONA_MIXER_CONTROLS("HPOUT1L", ARIZONA_OUT1LMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("HPOUT1R", ARIZONA_OUT1RMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("HPOUT2L", ARIZONA_OUT2LMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("HPOUT2R", ARIZONA_OUT2RMIX_INPUT_1_SOURCE),
-ARIZONA_MIXER_CONTROLS("EPOUT", ARIZONA_OUT3LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT3L", ARIZONA_OUT3LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT3R", ARIZONA_OUT3RMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("SPKOUTL", ARIZONA_OUT4LMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("SPKOUTR", ARIZONA_OUT4RMIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE),
@@ -175,7 +185,7 @@ SOC_SINGLE("HPOUT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_1L,
 	   ARIZONA_OUT1_OSR_SHIFT, 1, 0),
 SOC_SINGLE("OUT2 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_2L,
 	   ARIZONA_OUT2_OSR_SHIFT, 1, 0),
-SOC_SINGLE("EPOUT High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_3L,
+SOC_SINGLE("OUT3 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_3L,
 	   ARIZONA_OUT3_OSR_SHIFT, 1, 0),
 SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L,
 	   ARIZONA_OUT4_OSR_SHIFT, 1, 0),
@@ -188,8 +198,8 @@ SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,
 	     ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1),
 SOC_DOUBLE_R("OUT2 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_2L,
 	     ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_MUTE_SHIFT, 1, 1),
-SOC_SINGLE("EPOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_3L,
-	   ARIZONA_OUT3L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("OUT3 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_3L,
+	     ARIZONA_DAC_DIGITAL_VOLUME_3R, ARIZONA_OUT3L_MUTE_SHIFT, 1, 1),
 SOC_DOUBLE_R("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L,
 	     ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_MUTE_SHIFT, 1, 1),
 SOC_DOUBLE_R("SPKDAT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_5L,
@@ -203,8 +213,9 @@ SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L,
 SOC_DOUBLE_R_TLV("OUT2 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_2L,
 		 ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_VOL_SHIFT,
 		 0xbf, 0, digital_tlv),
-SOC_SINGLE_TLV("EPOUT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_3L,
-	       ARIZONA_OUT3L_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("OUT3 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_3L,
+		 ARIZONA_DAC_DIGITAL_VOLUME_3R, ARIZONA_OUT3L_VOL_SHIFT,
+		 0xbf, 0, digital_tlv),
 SOC_DOUBLE_R_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L,
 		 ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_VOL_SHIFT,
 		 0xbf, 0, digital_tlv),
@@ -223,8 +234,9 @@ SOC_DOUBLE_R_RANGE_TLV("OUT2 Volume", ARIZONA_OUTPUT_PATH_CONFIG_2L,
 		       ARIZONA_OUTPUT_PATH_CONFIG_2R,
 		       ARIZONA_OUT2L_PGA_VOL_SHIFT,
 		       0x34, 0x40, 0, ana_tlv),
-SOC_SINGLE_RANGE_TLV("EPOUT Volume", ARIZONA_OUTPUT_PATH_CONFIG_3L,
-		     ARIZONA_OUT3L_PGA_VOL_SHIFT, 0x34, 0x40, 0, ana_tlv),
+SOC_DOUBLE_R_RANGE_TLV("OUT3 Volume", ARIZONA_OUTPUT_PATH_CONFIG_3L,
+		       ARIZONA_OUTPUT_PATH_CONFIG_3R,
+		       ARIZONA_OUT3L_PGA_VOL_SHIFT, 0x34, 0x40, 0, ana_tlv),
 
 SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT,
 	   ARIZONA_SPK1R_MUTE_SHIFT, 1, 1),
@@ -272,7 +284,8 @@ ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(OUT2L, ARIZONA_OUT2LMIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(OUT2R, ARIZONA_OUT2RMIX_INPUT_1_SOURCE);
-ARIZONA_MIXER_ENUMS(OUT3, ARIZONA_OUT3LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT3L, ARIZONA_OUT3LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT3R, ARIZONA_OUT3RMIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(SPKOUTL, ARIZONA_OUT4LMIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(SPKOUTR, ARIZONA_OUT4RMIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(SPKDAT1L, ARIZONA_OUT5LMIX_INPUT_1_SOURCE);
@@ -300,6 +313,26 @@ ARIZONA_MIXER_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE);
 ARIZONA_MIXER_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE);
 
+static const char *wm5110_aec_loopback_texts[] = {
+	"HPOUT1L", "HPOUT1R", "HPOUT2L", "HPOUT2R", "HPOUT3L", "HPOUT3R",
+	"SPKOUTL", "SPKOUTR", "SPKDAT1L", "SPKDAT1R", "SPKDAT2L", "SPKDAT2R",
+};
+
+static const unsigned int wm5110_aec_loopback_values[] = {
+	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+};
+
+static const struct soc_enum wm5110_aec_loopback =
+	SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1,
+			      ARIZONA_AEC_LOOPBACK_SRC_SHIFT,
+			      ARIZONA_AEC_LOOPBACK_SRC_MASK,
+			      ARRAY_SIZE(wm5110_aec_loopback_texts),
+			      wm5110_aec_loopback_texts,
+			      wm5110_aec_loopback_values);
+
+static const struct snd_kcontrol_new wm5110_aec_loopback_mux =
+	SOC_DAPM_VALUE_ENUM("AEC Loopback", wm5110_aec_loopback);
+
 static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = {
 SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
 		    0, NULL, 0),
@@ -313,7 +346,7 @@ SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
 SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0),
 SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0, 0),
 SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
-SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS),
 SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDL", 0, 0),
 SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0, 0),
 
@@ -409,6 +442,9 @@ SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0,
 SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0,
 		 NULL, 0),
 
+SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
+		       ARIZONA_AEC_LOOPBACK_ENA, 0, &wm5110_aec_loopback_mux),
+
 SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
 		     ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
 SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
@@ -478,6 +514,9 @@ SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1,
 SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
 		   ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
 		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT3R", ARIZONA_OUTPUT_ENABLES_1,
+		   ARIZONA_OUT3R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1,
 		   ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
 		   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
@@ -522,7 +561,8 @@ ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUT1L"),
 ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUT1R"),
 ARIZONA_MIXER_WIDGETS(OUT2L, "HPOUT2L"),
 ARIZONA_MIXER_WIDGETS(OUT2R, "HPOUT2R"),
-ARIZONA_MIXER_WIDGETS(OUT3, "EPOUT"),
+ARIZONA_MIXER_WIDGETS(OUT3L, "HPOUT3L"),
+ARIZONA_MIXER_WIDGETS(OUT3R, "HPOUT3R"),
 ARIZONA_MIXER_WIDGETS(SPKOUTL, "SPKOUTL"),
 ARIZONA_MIXER_WIDGETS(SPKOUTR, "SPKOUTR"),
 ARIZONA_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"),
@@ -554,8 +594,8 @@ SND_SOC_DAPM_OUTPUT("HPOUT1L"),
 SND_SOC_DAPM_OUTPUT("HPOUT1R"),
 SND_SOC_DAPM_OUTPUT("HPOUT2L"),
 SND_SOC_DAPM_OUTPUT("HPOUT2R"),
-SND_SOC_DAPM_OUTPUT("EPOUTN"),
-SND_SOC_DAPM_OUTPUT("EPOUTP"),
+SND_SOC_DAPM_OUTPUT("HPOUT3L"),
+SND_SOC_DAPM_OUTPUT("HPOUT3R"),
 SND_SOC_DAPM_OUTPUT("SPKOUTLN"),
 SND_SOC_DAPM_OUTPUT("SPKOUTLP"),
 SND_SOC_DAPM_OUTPUT("SPKOUTRN"),
@@ -570,6 +610,7 @@ SND_SOC_DAPM_OUTPUT("SPKDAT2R"),
 	{ name, "Noise Generator", "Noise Generator" }, \
 	{ name, "Tone Generator 1", "Tone Generator 1" }, \
 	{ name, "Tone Generator 2", "Tone Generator 2" }, \
+	{ name, "AEC", "AEC Loopback" }, \
 	{ name, "IN1L", "IN1L PGA" }, \
 	{ name, "IN1R", "IN1R PGA" }, \
 	{ name, "IN2L", "IN2L PGA" }, \
@@ -620,6 +661,7 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
 	{ "OUT2L", NULL, "CPVDD" },
 	{ "OUT2R", NULL, "CPVDD" },
 	{ "OUT3L", NULL, "CPVDD" },
+	{ "OUT3R", NULL, "CPVDD" },
 
 	{ "OUT4L", NULL, "SPKVDDL" },
 	{ "OUT4R", NULL, "SPKVDDR" },
@@ -701,7 +743,8 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
 	ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
 	ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"),
 	ARIZONA_MIXER_ROUTES("OUT2R", "HPOUT2R"),
-	ARIZONA_MIXER_ROUTES("OUT3L", "EPOUT"),
+	ARIZONA_MIXER_ROUTES("OUT3L", "HPOUT3L"),
+	ARIZONA_MIXER_ROUTES("OUT3R", "HPOUT3R"),
 
 	ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUTL"),
 	ARIZONA_MIXER_ROUTES("OUT4R", "SPKOUTR"),
@@ -754,8 +797,8 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
 	{ "HPOUT2L", NULL, "OUT2L" },
 	{ "HPOUT2R", NULL, "OUT2R" },
 
-	{ "EPOUTN", NULL, "OUT3L" },
-	{ "EPOUTP", NULL, "OUT3L" },
+	{ "HPOUT3L", NULL, "OUT3L" },
+	{ "HPOUT3R", NULL, "OUT3L" },
 
 	{ "SPKOUTLN", NULL, "OUT4L" },
 	{ "SPKOUTLP", NULL, "OUT4L" },
@@ -873,6 +916,8 @@ static unsigned int wm5110_digital_vu[] = {
 	ARIZONA_ADC_DIGITAL_VOLUME_2R,
 	ARIZONA_ADC_DIGITAL_VOLUME_3L,
 	ARIZONA_ADC_DIGITAL_VOLUME_3R,
+	ARIZONA_ADC_DIGITAL_VOLUME_4L,
+	ARIZONA_ADC_DIGITAL_VOLUME_4R,
 
 	ARIZONA_DAC_DIGITAL_VOLUME_1L,
 	ARIZONA_DAC_DIGITAL_VOLUME_1R,
@@ -884,6 +929,8 @@ static unsigned int wm5110_digital_vu[] = {
 	ARIZONA_DAC_DIGITAL_VOLUME_4R,
 	ARIZONA_DAC_DIGITAL_VOLUME_5L,
 	ARIZONA_DAC_DIGITAL_VOLUME_5R,
+	ARIZONA_DAC_DIGITAL_VOLUME_6L,
+	ARIZONA_DAC_DIGITAL_VOLUME_6R,
 };
 
 static struct snd_soc_codec_driver soc_codec_dev_wm5110 = {

+ 5 - 0
sound/soc/codecs/wm_hubs.c

@@ -681,6 +681,11 @@ void wm_hubs_update_class_w(struct snd_soc_codec *codec)
 
 	snd_soc_update_bits(codec, WM8993_CLASS_W_0,
 			    WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ, enable);
+
+	snd_soc_write(codec, WM8993_LEFT_OUTPUT_VOLUME,
+		      snd_soc_read(codec, WM8993_LEFT_OUTPUT_VOLUME));
+	snd_soc_write(codec, WM8993_RIGHT_OUTPUT_VOLUME,
+		      snd_soc_read(codec, WM8993_RIGHT_OUTPUT_VOLUME));
 }
 EXPORT_SYMBOL_GPL(wm_hubs_update_class_w);
 

+ 19 - 18
sound/soc/fsl/eukrea-tlv320.c

@@ -93,9 +93,7 @@ static struct snd_soc_card eukrea_tlv320 = {
 	.num_links	= 1,
 };
 
-static struct platform_device *eukrea_tlv320_snd_device;
-
-static int __init eukrea_tlv320_init(void)
+static int __devinit eukrea_tlv320_probe(struct platform_device *pdev)
 {
 	int ret;
 	int int_port = 0, ext_port;
@@ -136,29 +134,32 @@ static int __init eukrea_tlv320_init(void)
 		return 0;
 	}
 
-	eukrea_tlv320_snd_device = platform_device_alloc("soc-audio", -1);
-	if (!eukrea_tlv320_snd_device)
-		return -ENOMEM;
-
-	platform_set_drvdata(eukrea_tlv320_snd_device, &eukrea_tlv320);
-	ret = platform_device_add(eukrea_tlv320_snd_device);
-
-	if (ret) {
-		printk(KERN_ERR "ASoC: Platform device allocation failed\n");
-		platform_device_put(eukrea_tlv320_snd_device);
-	}
+	eukrea_tlv320.dev = &pdev->dev;
+	ret = snd_soc_register_card(&eukrea_tlv320);
+	if (ret)
+		dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
 
 	return ret;
 }
 
-static void __exit eukrea_tlv320_exit(void)
+static int __devexit eukrea_tlv320_remove(struct platform_device *pdev)
 {
-	platform_device_unregister(eukrea_tlv320_snd_device);
+	snd_soc_unregister_card(&eukrea_tlv320);
+
+	return 0;
 }
 
-module_init(eukrea_tlv320_init);
-module_exit(eukrea_tlv320_exit);
+static struct platform_driver eukrea_tlv320_driver = {
+	.driver = {
+		.name = "eukrea_tlv320",
+		.owner = THIS_MODULE,
+	},
+	.probe = eukrea_tlv320_probe,
+	.remove = __devexit_p(eukrea_tlv320_remove),};
+
+module_platform_driver(eukrea_tlv320_driver);
 
 MODULE_AUTHOR("Eric Bénard <eric@eukrea.com>");
 MODULE_DESCRIPTION("CPUIMX ALSA SoC driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:eukrea_tlv320");

+ 21 - 2
sound/soc/soc-dapm.c

@@ -1017,10 +1017,29 @@ EXPORT_SYMBOL_GPL(dapm_reg_event);
 int dapm_regulator_event(struct snd_soc_dapm_widget *w,
 		   struct snd_kcontrol *kcontrol, int event)
 {
-	if (SND_SOC_DAPM_EVENT_ON(event))
+	int ret;
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
+			ret = regulator_allow_bypass(w->regulator, true);
+			if (ret != 0)
+				dev_warn(w->dapm->dev,
+					 "Failed to bypass %s: %d\n",
+					 w->name, ret);
+		}
+
 		return regulator_enable(w->regulator);
-	else
+	} else {
+		if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
+			ret = regulator_allow_bypass(w->regulator, false);
+			if (ret != 0)
+				dev_warn(w->dapm->dev,
+					 "Failed to unbypass %s: %d\n",
+					 w->name, ret);
+		}
+
 		return regulator_disable_deferred(w->regulator, w->shift);
+	}
 }
 EXPORT_SYMBOL_GPL(dapm_regulator_event);
 

+ 42 - 5
sound/soc/ux500/mop500.c

@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/spi/spi.h>
+#include <linux/of.h>
 
 #include <sound/soc.h>
 #include <sound/initval.h>
@@ -56,16 +57,47 @@ static struct snd_soc_card mop500_card = {
 	.num_links = ARRAY_SIZE(mop500_dai_links),
 };
 
+static int __devinit mop500_of_probe(struct platform_device *pdev,
+				struct device_node *np)
+{
+	struct device_node *codec_np, *msp_np[2];
+	int i;
+
+	msp_np[0] = of_parse_phandle(np, "stericsson,cpu-dai", 0);
+	msp_np[1] = of_parse_phandle(np, "stericsson,cpu-dai", 1);
+	codec_np  = of_parse_phandle(np, "stericsson,audio-codec", 0);
+
+	if (!(msp_np[0] && msp_np[1] && codec_np)) {
+		dev_err(&pdev->dev, "Phandle missing or invalid\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < 2; i++) {
+		mop500_dai_links[i].cpu_of_node = msp_np[i];
+		mop500_dai_links[i].cpu_dai_name = NULL;
+		mop500_dai_links[i].codec_of_node = codec_np;
+		mop500_dai_links[i].codec_name = NULL;
+	}
+
+	snd_soc_of_parse_card_name(&mop500_card, "stericsson,card-name");
+
+	return 0;
+}
 static int __devinit mop500_probe(struct platform_device *pdev)
 {
+	struct device_node *np = pdev->dev.of_node;
 	int ret;
 
-	pr_debug("%s: Enter.\n", __func__);
-
 	dev_dbg(&pdev->dev, "%s: Enter.\n", __func__);
 
 	mop500_card.dev = &pdev->dev;
 
+	if (np) {
+		ret = mop500_of_probe(pdev, np);
+		if (ret)
+			return ret;
+	}
+
 	dev_dbg(&pdev->dev, "%s: Card %s: Set platform drvdata.\n",
 		__func__, mop500_card.name);
 	platform_set_drvdata(pdev, &mop500_card);
@@ -83,8 +115,7 @@ static int __devinit mop500_probe(struct platform_device *pdev)
 	ret = snd_soc_register_card(&mop500_card);
 	if (ret)
 		dev_err(&pdev->dev,
-			"Error: snd_soc_register_card failed (%d)!\n",
-			ret);
+			"Error: snd_soc_register_card failed (%d)!\n", ret);
 
 	return ret;
 }
@@ -97,14 +128,20 @@ static int __devexit mop500_remove(struct platform_device *pdev)
 
 	snd_soc_unregister_card(mop500_card);
 	mop500_ab8500_remove(mop500_card);
-	
+
 	return 0;
 }
 
+static const struct of_device_id snd_soc_mop500_match[] = {
+	{ .compatible = "stericsson,snd-soc-mop500", },
+	{},
+};
+
 static struct platform_driver snd_soc_mop500_driver = {
 	.driver = {
 		.owner = THIS_MODULE,
 		.name = "snd-soc-mop500",
+		.of_match_table = snd_soc_mop500_match,
 	},
 	.probe = mop500_probe,
 	.remove = __devexit_p(mop500_remove),

+ 6 - 0
sound/soc/ux500/ux500_msp_dai.c

@@ -833,10 +833,16 @@ static int __devexit ux500_msp_drv_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct of_device_id ux500_msp_i2s_match[] = {
+	{ .compatible = "stericsson,ux500-msp-i2s", },
+	{},
+};
+
 static struct platform_driver msp_i2s_driver = {
 	.driver = {
 		.name = "ux500-msp-i2s",
 		.owner = THIS_MODULE,
+		.of_match_table = ux500_msp_i2s_match,
 	},
 	.probe = ux500_msp_drv_probe,
 	.remove = ux500_msp_drv_remove,

+ 70 - 19
sound/soc/ux500/ux500_msp_i2s.c

@@ -15,8 +15,10 @@
 
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/of.h>
 
 #include <mach/hardware.h>
 #include <mach/msp.h>
@@ -25,6 +27,9 @@
 
 #include "ux500_msp_i2s.h"
 
+/* MSP1/3 Tx/Rx usage protection */
+static DEFINE_SPINLOCK(msp_rxtx_lock);
+
  /* Protocol desciptors */
 static const struct msp_protdesc prot_descs[] = {
 	{ /* I2S */
@@ -352,17 +357,23 @@ static int configure_multichannel(struct ux500_msp *msp,
 
 static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config)
 {
-	int status = 0;
+	int status = 0, retval = 0;
 	u32 reg_val_DMACR, reg_val_GCR;
+	unsigned long flags;
 
 	/* Check msp state whether in RUN or CONFIGURED Mode */
-	if ((msp->msp_state == MSP_STATE_IDLE) && (msp->plat_init)) {
-		status = msp->plat_init();
-		if (status) {
-			dev_err(msp->dev, "%s: ERROR: Failed to init MSP (%d)!\n",
-				__func__, status);
-			return status;
+	if (msp->msp_state == MSP_STATE_IDLE) {
+		spin_lock_irqsave(&msp_rxtx_lock, flags);
+		if (msp->pinctrl_rxtx_ref == 0 &&
+			!(IS_ERR(msp->pinctrl_p) || IS_ERR(msp->pinctrl_def))) {
+			retval = pinctrl_select_state(msp->pinctrl_p,
+						msp->pinctrl_def);
+			if (retval)
+				pr_err("could not set MSP defstate\n");
 		}
+		if (!retval)
+			msp->pinctrl_rxtx_ref++;
+		spin_unlock_irqrestore(&msp_rxtx_lock, flags);
 	}
 
 	/* Configure msp with protocol dependent settings */
@@ -620,7 +631,8 @@ int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd, int direction)
 
 int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
 {
-	int status = 0;
+	int status = 0, retval = 0;
+	unsigned long flags;
 
 	dev_dbg(msp->dev, "%s: Enter (dir = 0x%01x).\n", __func__, dir);
 
@@ -631,12 +643,19 @@ int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
 		writel((readl(msp->registers + MSP_GCR) &
 			       (~(FRAME_GEN_ENABLE | SRG_ENABLE))),
 			      msp->registers + MSP_GCR);
-		if (msp->plat_exit)
-			status = msp->plat_exit();
-			if (status)
-				dev_warn(msp->dev,
-					"%s: WARN: ux500_msp_i2s_exit failed (%d)!\n",
-					__func__, status);
+
+		spin_lock_irqsave(&msp_rxtx_lock, flags);
+		WARN_ON(!msp->pinctrl_rxtx_ref);
+		msp->pinctrl_rxtx_ref--;
+		if (msp->pinctrl_rxtx_ref == 0 &&
+			!(IS_ERR(msp->pinctrl_p) || IS_ERR(msp->pinctrl_sleep))) {
+			retval = pinctrl_select_state(msp->pinctrl_p,
+						msp->pinctrl_sleep);
+			if (retval)
+				pr_err("could not set MSP sleepstate\n");
+		}
+		spin_unlock_irqrestore(&msp_rxtx_lock, flags);
+
 		writel(0, msp->registers + MSP_GCR);
 		writel(0, msp->registers + MSP_TCF);
 		writel(0, msp->registers + MSP_RCF);
@@ -665,20 +684,33 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
 {
 	struct resource *res = NULL;
 	struct i2s_controller *i2s_cont;
+	struct device_node *np = pdev->dev.of_node;
 	struct ux500_msp *msp;
 
-	dev_dbg(&pdev->dev, "%s: Enter (name: %s, id: %d).\n", __func__,
-		pdev->name, platform_data->id);
-
 	*msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL);
 	msp = *msp_p;
 	if (!msp)
 		return -ENOMEM;
 
+	if (np) {
+		if (!platform_data) {
+			platform_data = devm_kzalloc(&pdev->dev,
+				sizeof(struct msp_i2s_platform_data), GFP_KERNEL);
+			if (!platform_data)
+				ret = -ENOMEM;
+		}
+	} else
+		if (!platform_data)
+			ret = -EINVAL;
+
+	if (ret)
+		goto err_res;
+
+	dev_dbg(&pdev->dev, "%s: Enter (name: %s, id: %d).\n", __func__,
+		pdev->name, platform_data->id);
+
 	msp->id = platform_data->id;
 	msp->dev = &pdev->dev;
-	msp->plat_init = platform_data->msp_i2s_init;
-	msp->plat_exit = platform_data->msp_i2s_exit;
 	msp->dma_cfg_rx = platform_data->msp_i2s_dma_rx;
 	msp->dma_cfg_tx = platform_data->msp_i2s_dma_tx;
 
@@ -715,6 +747,25 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
 	dev_dbg(&pdev->dev, "I2S device-name: '%s'\n", i2s_cont->name);
 	msp->i2s_cont = i2s_cont;
 
+	msp->pinctrl_p = pinctrl_get(msp->dev);
+	if (IS_ERR(msp->pinctrl_p))
+		dev_err(&pdev->dev, "could not get MSP pinctrl\n");
+	else {
+		msp->pinctrl_def = pinctrl_lookup_state(msp->pinctrl_p,
+						PINCTRL_STATE_DEFAULT);
+		if (IS_ERR(msp->pinctrl_def)) {
+			dev_err(&pdev->dev,
+				"could not get MSP defstate (%li)\n",
+				PTR_ERR(msp->pinctrl_def));
+		}
+		msp->pinctrl_sleep = pinctrl_lookup_state(msp->pinctrl_p,
+						PINCTRL_STATE_SLEEP);
+		if (IS_ERR(msp->pinctrl_sleep))
+			dev_err(&pdev->dev,
+				"could not get MSP idlestate (%li)\n",
+				PTR_ERR(msp->pinctrl_def));
+	}
+
 	return 0;
 }
 

+ 6 - 2
sound/soc/ux500/ux500_msp_i2s.h

@@ -524,14 +524,18 @@ struct ux500_msp {
 	struct dma_chan *rx_pipeid;
 	enum msp_state msp_state;
 	int (*transfer) (struct ux500_msp *msp, struct i2s_message *message);
-	int (*plat_init) (void);
-	int (*plat_exit) (void);
 	struct timer_list notify_timer;
 	int def_elem_len;
 	unsigned int dir_busy;
 	int loopback_enable;
 	u32 backup_regs[MAX_MSP_BACKUP_REGS];
 	unsigned int f_bitclk;
+	/* Pin modes */
+	struct pinctrl *pinctrl_p;
+	struct pinctrl_state *pinctrl_def;
+	struct pinctrl_state *pinctrl_sleep;
+	/* Reference Count */
+	int pinctrl_rxtx_ref;
 };
 
 struct ux500_msp_dma_params {