alsa-devel.alsa-project.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/4] AM43xx-ePOS-EVM audio support with TLV320AIC31XX driver
@ 2014-03-04 13:54 Jyri Sarha
  2014-03-04 13:54 ` [PATCH v2 2/4] ASoC: davinci-evm: Add AM43xx-EPOS-EVM audio support Jyri Sarha
       [not found] ` <cover.1393941102.git.jsarha-l0cyMroinI0@public.gmane.org>
  0 siblings, 2 replies; 21+ messages in thread
From: Jyri Sarha @ 2014-03-04 13:54 UTC (permalink / raw)
  To: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw, devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: broonie-DgEjT+Ai2ygdnm+yROfE0A,
	liam.r.girdwood-VuQAYsv1563Yd54FQh9/CA,
	peter.ujfalusi-l0cyMroinI0, detheridge-l0cyMroinI0,
	bcousson-rdvid1DuHRBWk0Htik3J/w, Jyri Sarha

Since the RFC version of the patches [1] I have addressed Mark Browns
comments [2] as described in my mail here [3].

Besr regards,
Jyri

[1] http://mailman.alsa-project.org/pipermail/alsa-devel/2014-February/073289.html

[2] http://mailman.alsa-project.org/pipermail/alsa-devel/2014-March/073703.html
    http://mailman.alsa-project.org/pipermail/alsa-devel/2014-March/073704.html
    http://mailman.alsa-project.org/pipermail/alsa-devel/2014-March/073705.html
    
[3] http://mailman.alsa-project.org/pipermail/alsa-devel/2014-March/073807.html

Jyri Sarha (4):
  ASoC: tlv320aic31xx: Add basic codec driver implementation
  ASoC: davinci-evm: Add AM43xx-EPOS-EVM audio support
  ASoC: davinci: Add SND_AM43XX_SOC_EPOS_EVM build option
  ASoC: tlv320aic32x4: Sort Makefile in alphabetic order

 .../bindings/sound/davinci-evm-audio.txt           |    9 +-
 .../devicetree/bindings/sound/tlv320aic31xx.txt    |   58 +
 include/dt-bindings/sound/tlv320aic31xx-micbias.h  |    9 +
 sound/soc/codecs/Kconfig                           |    4 +
 sound/soc/codecs/Makefile                          |    6 +-
 sound/soc/codecs/tlv320aic31xx.c                   | 1345 ++++++++++++++++++++
 sound/soc/codecs/tlv320aic31xx.h                   |  258 ++++
 sound/soc/davinci/Kconfig                          |   12 +
 sound/soc/davinci/Makefile                         |    1 +
 sound/soc/davinci/davinci-evm.c                    |   41 +
 10 files changed, 1738 insertions(+), 5 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
 create mode 100644 include/dt-bindings/sound/tlv320aic31xx-micbias.h
 create mode 100644 sound/soc/codecs/tlv320aic31xx.c
 create mode 100644 sound/soc/codecs/tlv320aic31xx.h

-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v2 1/4] ASoC: tlv320aic31xx: Add basic codec driver implementation
       [not found] ` <cover.1393941102.git.jsarha-l0cyMroinI0@public.gmane.org>
@ 2014-03-04 13:54   ` Jyri Sarha
       [not found]     ` <ba9718f573ca9195c80075a15fe114e0d4557da0.1393941102.git.jsarha-l0cyMroinI0@public.gmane.org>
  2014-03-04 13:54   ` [PATCH v2 3/4] ASoC: davinci: Add SND_AM43XX_SOC_EPOS_EVM build option Jyri Sarha
  2014-03-04 13:54   ` [PATCH v2 4/4] ASoC: tlv320aic32x4: Sort Makefile in alphabetic order Jyri Sarha
  2 siblings, 1 reply; 21+ messages in thread
From: Jyri Sarha @ 2014-03-04 13:54 UTC (permalink / raw)
  To: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw, devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: broonie-DgEjT+Ai2ygdnm+yROfE0A,
	liam.r.girdwood-VuQAYsv1563Yd54FQh9/CA,
	peter.ujfalusi-l0cyMroinI0, detheridge-l0cyMroinI0,
	bcousson-rdvid1DuHRBWk0Htik3J/w, Jyri Sarha

This commit adds a bare bones driver support for TLV320AIC31XX family
audio codecs. The driver adds basic stereo playback trough headphone
and speaker outputs and mono capture trough microphone inputs.

The driver is currently missing support at least for mini DSP features
and jack detection. I have tested the driver only on TLV320AIC3111,
but based on the data sheets TLV320AIC3100, TLV320AIC3110, and
TLV320AIC3120 should work Ok too.

The base for the implementation was taken from:
git-OGgr7I4mDcYgsBAKwltoeQ@public.gmane.org:ti-codecs/ti-codecs.git ajitk/topics/k3.10.1-aic31xx
-branch at commit 77504eba0294764e9e63b4a0c696b44db187cd13.

Signed-off-by: Jyri Sarha <jsarha-l0cyMroinI0@public.gmane.org>
---
 .../devicetree/bindings/sound/tlv320aic31xx.txt    |   58 +
 include/dt-bindings/sound/tlv320aic31xx-micbias.h  |    9 +
 sound/soc/codecs/Kconfig                           |    4 +
 sound/soc/codecs/Makefile                          |    2 +
 sound/soc/codecs/tlv320aic31xx.c                   | 1345 ++++++++++++++++++++
 sound/soc/codecs/tlv320aic31xx.h                   |  258 ++++
 6 files changed, 1676 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
 create mode 100644 include/dt-bindings/sound/tlv320aic31xx-micbias.h
 create mode 100644 sound/soc/codecs/tlv320aic31xx.c
 create mode 100644 sound/soc/codecs/tlv320aic31xx.h

diff --git a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
new file mode 100644
index 0000000..885668b
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
@@ -0,0 +1,58 @@
+Texas Instruments - tlv320aic31xx Codec module
+
+The tlv320aic31xx serial control bus communicates through I2C protocols
+
+Required properties:
+
+- compatible - "string" - One of:
+    "ti,tlv320aic310x" - Generic TLV320AIC31xx with mono speaker amp
+    "ti,tlv320aic311x" - Generic TLV320AIC31xx with stereo speaker amp
+    "ti,tlv320aic3100" - TLV320AIC3100 (mono speaker amp, no MiniDSP)
+    "ti,tlv320aic3110" - TLV320AIC3110 (stereo speaker amp, no MiniDSP)
+    "ti,tlv320aic3120" - TLV320AIC3120 (mono speaker amp, MiniDSP)
+    "ti,tlv320aic3111" - TLV320AIC3111 (stereo speaker amp, MiniDSP)
+
+- reg - <int> -  I2C slave address
+
+
+Optional properties:
+
+- gpio-reset - gpio pin number used for codec reset
+- ai31xx-micbias-vg - MicBias Voltage required.
+        MICBIAS_OFF - MICBIAS output it not powered
+        MICBIAS_2_0V - MICBIAS output is powered to 2.0V
+        MICBIAS_2_5V - MICBIAS output is powered to 2.5V
+        MICBIAS_AVDD - MICBIAS output is connected to AVDD
+	If this node is not mentioned or if the value is unknown, then
+	micbias	is set to 2.0V.
+- HPVDD-supply, SPRVDD-supply, SPLVDD-supply, AVDD-supply, IOVDD-supply,
+  DVDD-supply : power supplies for the device as covered in
+  Documentation/devicetree/bindings/regulator/regulator.txt
+
+CODEC output pins:
+  * HPL
+  * HPR
+  * SPL, devices with stereo speaker amp
+  * SPR, devices with stereo speaker amp
+  * SPK, devices with mono speaker amp
+
+CODEC input pins:
+  * MIC1LP
+  * MIC1RP
+  * MIC1LM
+
+The pins can be used in referring sound node's audio-routing property.
+
+Example:
+
+tlv320aic31xx: tlv320aic31xx@18 {
+	compatible = "ti,tlv320aic311x";
+	reg = <0x18>;
+
+	HPVDD-supply = <&regulator>;
+	SPRVDD-supply = <&regulator>;
+	SPLVDD-supply = <&regulator>;
+	AVDD-supply = <&regulator>;
+	IOVDD-supply = <&regulator>;
+	DVDD-supply = <&regulator>;
+};
diff --git a/include/dt-bindings/sound/tlv320aic31xx-micbias.h b/include/dt-bindings/sound/tlv320aic31xx-micbias.h
new file mode 100644
index 0000000..da9360f
--- /dev/null
+++ b/include/dt-bindings/sound/tlv320aic31xx-micbias.h
@@ -0,0 +1,9 @@
+#ifndef __DT_TLV320AIC31XX_MICBIAS_H
+#define __DT_TLV320AIC31XX_MICBIAS_H
+
+#define MICBIAS_OFF		0
+#define MICBIAS_2_0V		1
+#define MICBIAS_2_5V		2
+#define MICBIAS_AVDDV		3
+
+#endif /* __DT_TLV320AIC31XX_MICBIAS_H */
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 983d087a..66f6c53 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -73,6 +73,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_TAS5086 if I2C
 	select SND_SOC_TLV320AIC23 if I2C
 	select SND_SOC_TLV320AIC26 if SPI_MASTER
+	select SND_SOC_TLV320AIC31XX if I2C
 	select SND_SOC_TLV320AIC32X4 if I2C
 	select SND_SOC_TLV320AIC3X if I2C
 	select SND_SOC_TPA6130A2 if I2C
@@ -361,6 +362,9 @@ config SND_SOC_TLV320AIC26
 	tristate
 	depends on SPI
 
+config SND_SOC_TLV320AIC31XX
+        tristate
+
 config SND_SOC_TLV320AIC32X4
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index bc12676..23f8042 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -64,6 +64,7 @@ snd-soc-stac9766-objs := stac9766.o
 snd-soc-tas5086-objs := tas5086.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
+snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
 snd-soc-tlv320dac33-objs := tlv320dac33.o
@@ -194,6 +195,7 @@ obj-$(CONFIG_SND_SOC_STAC9766)	+= snd-soc-stac9766.o
 obj-$(CONFIG_SND_SOC_TAS5086)	+= snd-soc-tas5086.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)	+= snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)	+= snd-soc-tlv320aic26.o
+obj-$(CONFIG_SND_SOC_TLV320AIC31XX)     += snd-soc-tlv320aic31xx.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3X)	+= snd-soc-tlv320aic3x.o
 obj-$(CONFIG_SND_SOC_TLV320AIC32X4)     += snd-soc-tlv320aic32x4.o
 obj-$(CONFIG_SND_SOC_TLV320DAC33)	+= snd-soc-tlv320dac33.o
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
new file mode 100644
index 0000000..5ce06c3
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -0,0 +1,1345 @@
+/*
+ * ALSA SoC TLV320AIC31XX codec driver
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ *
+ * Author: Jyri Sarha <jsarha-l0cyMroinI0@public.gmane.org>
+ *
+ * Based on ground work by: Ajit Kulkarni <x0175765-l0cyMroinI0@public.gmane.org>
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED AS IS AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * The TLV320AIC31xx series of audio codec is a low-power, highly integrated
+ * high performance codec which provides a stereo DAC, a mono ADC,
+ * and mono/stereo Class-D speaker driver.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_gpio.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <dt-bindings/sound/tlv320aic31xx-micbias.h>
+
+#include "tlv320aic31xx.h"
+
+static const struct reg_default aic31xx_reg_defaults[] = {
+	{ AIC31XX_CLKMUX, 0x00 },
+	{ AIC31XX_PLLPR, 0x11 },
+	{ AIC31XX_PLLJ, 0x04 },
+	{ AIC31XX_PLLDMSB, 0x00 },
+	{ AIC31XX_PLLDLSB, 0x00 },
+	{ AIC31XX_NDAC, 0x01 },
+	{ AIC31XX_MDAC, 0x01 },
+	{ AIC31XX_DOSRMSB, 0x00 },
+	{ AIC31XX_DOSRLSB, 0x80 },
+	{ AIC31XX_NADC, 0x01 },
+	{ AIC31XX_MADC, 0x01 },
+	{ AIC31XX_AOSR, 0x80 },
+	{ AIC31XX_IFACE1, 0x00 },
+	{ AIC31XX_DATA_OFFSET, 0x00 },
+	{ AIC31XX_IFACE2, 0x00 },
+	{ AIC31XX_BCLKN, 0x01 },
+	{ AIC31XX_DACSETUP, 0x14 },
+	{ AIC31XX_DACMUTE, 0x0c },
+	{ AIC31XX_LDACVOL, 0x00 },
+	{ AIC31XX_RDACVOL, 0x00 },
+	{ AIC31XX_ADCSETUP, 0x00 },
+	{ AIC31XX_ADCFGA, 0x80 },
+	{ AIC31XX_ADCVOL, 0x00 },
+	{ AIC31XX_HPDRIVER, 0x04 },
+	{ AIC31XX_SPKAMP, 0x06 },
+	{ AIC31XX_DACMIXERROUTE, 0x00 },
+	{ AIC31XX_LANALOGHPL, 0x7f },
+	{ AIC31XX_RANALOGHPR, 0x7f },
+	{ AIC31XX_LANALOGSPL, 0x7f },
+	{ AIC31XX_RANALOGSPR, 0x7f },
+	{ AIC31XX_HPLGAIN, 0x02 },
+	{ AIC31XX_HPRGAIN, 0x02 },
+	{ AIC31XX_SPLGAIN, 0x00 },
+	{ AIC31XX_SPRGAIN, 0x00 },
+	{ AIC31XX_MICBIAS, 0x00 },
+	{ AIC31XX_MICPGA, 0x80 },
+	{ AIC31XX_MICPGAPI, 0x00 },
+	{ AIC31XX_MICPGAMI, 0x00 },
+};
+
+static bool aic31xx_volatile(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AIC31XX_PAGECTL: /* regmap implementation requires this */
+	case AIC31XX_RESET: /* always clears after write */
+	case AIC31XX_OT_FLAG:
+	case AIC31XX_ADCFLAG:
+	case AIC31XX_DACFLAG1:
+	case AIC31XX_DACFLAG2:
+	case AIC31XX_OFFLAG: /* Sticky interrupt flags */
+	case AIC31XX_INTRDACFLAG: /* Sticky interrupt flags */
+	case AIC31XX_INTRADCFLAG: /* Sticky interrupt flags */
+	case AIC31XX_INTRDACFLAG2:
+	case AIC31XX_INTRADCFLAG2:
+		return true;
+	}
+	return false;
+}
+
+static bool aic31xx_writeable(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case AIC31XX_OT_FLAG:
+	case AIC31XX_ADCFLAG:
+	case AIC31XX_DACFLAG1:
+	case AIC31XX_DACFLAG2:
+	case AIC31XX_OFFLAG: /* Sticky interrupt flags */
+	case AIC31XX_INTRDACFLAG: /* Sticky interrupt flags */
+	case AIC31XX_INTRADCFLAG: /* Sticky interrupt flags */
+	case AIC31XX_INTRDACFLAG2:
+	case AIC31XX_INTRADCFLAG2:
+		return false;
+	}
+	return true;
+}
+
+static const struct regmap_range_cfg aic31xx_ranges[] = {
+	{
+		.range_min = 0,
+		.range_max = 12 * 128,
+		.selector_reg = AIC31XX_PAGECTL,
+		.selector_mask = 0xff,
+		.selector_shift = 0,
+		.window_start = 0,
+		.window_len = 128,
+	},
+};
+
+struct regmap_config aic31xx_i2c_regmap = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.writeable_reg = aic31xx_writeable,
+	.volatile_reg = aic31xx_volatile,
+	.reg_defaults = aic31xx_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(aic31xx_reg_defaults),
+	.cache_type = REGCACHE_RBTREE,
+	.ranges = aic31xx_ranges,
+	.num_ranges = ARRAY_SIZE(aic31xx_ranges),
+	.max_register = 12 * 128,
+};
+
+#define AIC31XX_NUM_SUPPLIES	6
+static const char * const aic31xx_supply_names[AIC31XX_NUM_SUPPLIES] = {
+	"HPVDD",
+	"SPRVDD",
+	"SPLVDD",
+	"AVDD",
+	"IOVDD",
+	"DVDD",
+};
+
+struct aic31xx_disable_nb {
+	struct notifier_block nb;
+	struct aic31xx_priv *aic31xx;
+};
+
+struct aic31xx_priv {
+	struct snd_soc_codec *codec;
+	u8 i2c_regs_status;
+	struct device *dev;
+	struct regmap *regmap;
+	struct aic31xx_pdata pdata;
+	struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES];
+	struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES];
+	unsigned int sysclk;
+	int rate_div_line;
+	int codec_clk_on;
+};
+
+struct aic31xx_rate_divs {
+	u32 mclk;
+	u32 rate;
+	u8 p_val;
+	u8 pll_j;
+	u16 pll_d;
+	u16 dosr;
+	u8 ndac;
+	u8 mdac;
+	u8 aosr;
+	u8 nadc;
+	u8 madc;
+};
+
+/* ADC dividers can be disabled by cofiguring them to 0 */
+static const struct aic31xx_rate_divs aic31xx_divs[] = {
+	/* mclk      rate  pll: p  j	 d     dosr ndac mdac  aors nadc madc */
+	/* 8k rate */
+	{12000000,   8000,	1, 8, 1920,	128,  48,  2,	128,  48,  2},
+	{24000000,   8000,	2, 8, 1920,	128,  48,  2,	128,  48,  2},
+	{25000000,   8000,	2, 7, 8643,	128,  48,  2,	128,  48,  2},
+	/* 11.025k rate */
+	{12000000,  11025,	1, 7, 5264,	128,  32,  2,	128,  32,  2},
+	{24000000,  11025,	2, 7, 5264,	128,  32,  2,	128,  32,  2},
+	{25000000,  11025,	2, 7, 2253,	128,  32,  2,	128,  32,  2},
+	/* 16k rate */
+	{12000000,  16000,	1, 8, 1920,	128,  24,  2,	128,  24,  2},
+	{24000000,  16000,	2, 8, 1920,	128,  24,  2,	128,  24,  2},
+	{25000000,  16000,	2, 7, 8643,	128,  24,  2,	128,  24,  2},
+	/* 22.05k rate */
+	{12000000,  22050,	1, 7, 5264,	128,  16,  2,	128,  16,  2},
+	{24000000,  22050,	2, 7, 5264,	128,  16,  2,	128,  16,  2},
+	{25000000,  22050,	2, 7, 2253,	128,  16,  2,	128,  16,  2},
+	/* 32k rate */
+	{12000000,  32000,	1, 8, 1920,	128,  12,  2,	128,  12,  2},
+	{24000000,  32000,	2, 8, 1920,	128,  12,  2,	128,  12,  2},
+	{25000000,  32000,	2, 7, 8643,	128,  12,  2,	128,  12,  2},
+	/* 44.1k rate */
+	{12000000,  44100,	1, 7, 5264,	128,   8,  2,	128,   8,  2},
+	{24000000,  44100,	2, 7, 5264,	128,   8,  2,	128,   8,  2},
+	{25000000,  44100,	2, 7, 2253,	128,   8,  2,	128,   8,  2},
+	/* 48k rate */
+	{12000000,  48000,	1, 8, 1920,	128,   8,  2,	128,   8,  2},
+	{24000000,  48000,	2, 8, 1920,	128,   8,  2,	128,   8,  2},
+	{25000000,  48000,	2, 7, 8643,	128,   8,  2,	128,   8,  2},
+	/* 88.2k rate */
+	{12000000,  88200,	1, 7, 5264,	 64,   8,  2,	 64,   8,  2},
+	{24000000,  88200,	2, 7, 5264,	 64,   8,  2,	 64,   8,  2},
+	{25000000,  88200,	2, 7, 2253,	 64,   8,  2,	 64,   8,  2},
+	/* 96k rate */
+	{12000000,  96000,	1, 8, 1920,	 64,   8,  2,	 64,   8,  2},
+	{24000000,  96000,	2, 8, 1920,	 64,   8,  2,	 64,   8,  2},
+	{25000000,  96000,	2, 7, 8643,	 64,   8,  2,	 64,   8,  2},
+	/* 176.4k rate */
+	{12000000, 176400,	1, 7, 5264,	 32,   8,  2,	 32,   8,  2},
+	{24000000, 176400,	2, 7, 5264,	 32,   8,  2,	 32,   8,  2},
+	{25000000, 176400,	2, 7, 2253,	 32,   8,  2,	 32,   8,  2},
+	/* 192k rate */
+	{12000000, 192000,	1, 8, 1920,	 32,   8,  2,	 32,   8,  2},
+	{24000000, 192000,	2, 8, 1920,	 32,   8,  2,	 32,   8,  2},
+	{25000000, 192000,	2, 7, 8643,	 32,   8,  2,	 32,   8,  2},
+};
+
+static const char * const ldac_in_text[] = {
+	"Off", "Left Data", "Right Data", "Mono"
+};
+
+static const char * const rdac_in_text[] = {
+	"Off", "Right Data", "Left Data", "Mono"
+};
+
+static SOC_ENUM_SINGLE_DECL(ldac_in_enum, AIC31XX_DACSETUP, 4, ldac_in_text);
+
+static SOC_ENUM_SINGLE_DECL(rdac_in_enum, AIC31XX_DACSETUP, 2, rdac_in_text);
+
+static const char * const mic_select_text[] = {
+	"Off", "FFR 10 Ohm", "FFR 20 Ohm", "FFR 40 Ohm"
+};
+
+static const
+SOC_ENUM_SINGLE_DECL(mic1lp_p_enum, AIC31XX_MICPGAPI, 6, mic_select_text);
+static const
+SOC_ENUM_SINGLE_DECL(mic1rp_p_enum, AIC31XX_MICPGAPI, 4, mic_select_text);
+static const
+SOC_ENUM_SINGLE_DECL(mic1lm_p_enum, AIC31XX_MICPGAPI, 2, mic_select_text);
+
+static const
+SOC_ENUM_SINGLE_DECL(cm_m_enum, AIC31XX_MICPGAMI, 6, mic_select_text);
+static const
+SOC_ENUM_SINGLE_DECL(mic1lm_m_enum, AIC31XX_MICPGAMI, 4, mic_select_text);
+
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(adc_fgain_tlv, 0, 10, 0);
+static const DECLARE_TLV_DB_SCALE(adc_cgain_tlv, -2000, 50, 0);
+static const DECLARE_TLV_DB_SCALE(mic_pga_tlv, 0, 50, 0);
+static const DECLARE_TLV_DB_SCALE(hp_drv_tlv, 0, 100, 0);
+static const DECLARE_TLV_DB_SCALE(class_D_drv_tlv, 600, 600, 0);
+static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -6350, 50, 0);
+static const DECLARE_TLV_DB_SCALE(sp_vol_tlv, -6350, 50, 0);
+
+/*
+ * controls to be exported to the user space
+ */
+static const struct snd_kcontrol_new aic31xx_snd_controls[] = {
+	SOC_DOUBLE_R_SX_TLV("DAC Playback Volume", AIC31XX_LDACVOL,
+			    AIC31XX_RDACVOL, 0, 0x81, 0xaf, dac_vol_tlv),
+
+	SOC_SINGLE_TLV("ADC Fine Capture Volume", AIC31XX_ADCFGA, 4, 4, 1,
+		       adc_fgain_tlv),
+
+	SOC_SINGLE("ADC Capture Switch", AIC31XX_ADCFGA, 7, 1, 1),
+
+	/* ADC COARSE GAIN */
+	/* Writes to AIC31XX_ADCVOL should be masked with 0x7F, but there
+	   appears to be no side effect if writes are no masked. */
+	SOC_SINGLE_SX_TLV("ADC Capture Volume", AIC31XX_ADCVOL,
+			  0, 0x68, 0x40, adc_cgain_tlv),
+
+	SOC_SINGLE_TLV("Mic PGA Capture Volume", AIC31XX_MICPGA, 0,
+		       119, 0, mic_pga_tlv),
+
+	SOC_DOUBLE_R("HP Driver Playback Switch", AIC31XX_HPLGAIN,
+		     AIC31XX_HPRGAIN, 2, 1, 0),
+	SOC_DOUBLE_R_TLV("HP Driver Playback Volume", AIC31XX_HPLGAIN,
+			 AIC31XX_HPRGAIN, 3, 0x09, 0, hp_drv_tlv),
+
+	SOC_DOUBLE_R_TLV("HP Analog Playback Volume", AIC31XX_LANALOGHPL,
+			 AIC31XX_RANALOGHPR, 0, 0x7F, 1, hp_vol_tlv),
+};
+
+static const struct snd_kcontrol_new aic311x_snd_controls[] = {
+	SOC_DOUBLE_R("Speaker Driver Playback Switch", AIC31XX_SPLGAIN,
+		     AIC31XX_SPRGAIN, 2, 1, 0),
+	SOC_DOUBLE_R_TLV("Speaker Driver Playback Volume", AIC31XX_SPLGAIN,
+			 AIC31XX_SPRGAIN, 3, 3, 0, class_D_drv_tlv),
+
+	SOC_DOUBLE_R_TLV("Speaker Analog Playback Volume", AIC31XX_LANALOGSPL,
+			 AIC31XX_RANALOGSPR, 0, 0x7F, 1, sp_vol_tlv),
+};
+
+static const struct snd_kcontrol_new aic310x_snd_controls[] = {
+	SOC_SINGLE("Speaker Driver Playback Switch", AIC31XX_SPLGAIN,
+		   2, 1, 0),
+	SOC_SINGLE_TLV("Speaker Driver Playback Volume", AIC31XX_SPLGAIN,
+		       3, 3, 0, class_D_drv_tlv),
+
+	SOC_SINGLE_TLV("Speaker Analog Playback Volume", AIC31XX_LANALOGSPL,
+		       0, 0x7F, 1, sp_vol_tlv),
+};
+
+static const struct snd_kcontrol_new ldac_in_control =
+	SOC_DAPM_ENUM("DAC Left Input", ldac_in_enum);
+
+static const struct snd_kcontrol_new rdac_in_control =
+	SOC_DAPM_ENUM("DAC Right Input", rdac_in_enum);
+
+int aic31xx_wait_bits(struct aic31xx_priv *aic31xx, unsigned int reg,
+		      unsigned int mask, unsigned int wbits, int sleep,
+		      int count)
+{
+	unsigned int bits;
+	int counter = count;
+	int ret = regmap_read(aic31xx->regmap, reg, &bits);
+	while ((bits & mask) != wbits && counter && !ret) {
+		usleep_range(sleep, sleep * 2);
+		ret = regmap_read(aic31xx->regmap, reg, &bits);
+		counter--;
+	}
+	if ((bits & mask) != wbits) {
+		dev_err(aic31xx->dev,
+			"%s: Failed! 0x%x was 0x%x expected 0x%x (%d, 0x%x, %d us)\n",
+			__func__, reg, bits, wbits, ret, mask,
+			(count - counter) * sleep);
+		ret = -1;
+	}
+	return ret;
+}
+
+
+#define WIDGET_BIT(reg, shift) (((shift) << 8) | (reg))
+
+static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
+				    struct snd_kcontrol *kcontrol, int event)
+{
+	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(w->codec);
+	unsigned int reg = AIC31XX_DACFLAG1;
+	unsigned int mask;
+
+	dev_dbg(w->codec->dev, "%s -> %s (event: %d)\n", w->name,
+		event == SND_SOC_DAPM_POST_PMU ? "on" :
+		event == SND_SOC_DAPM_POST_PMD ? "off" :
+		"(unsupported event)", event);
+
+	switch (WIDGET_BIT(w->reg, w->shift)) {
+	case WIDGET_BIT(AIC31XX_DACSETUP, 7):
+		mask = AIC31XX_LDACPWRSTATUS_MASK;
+		break;
+	case WIDGET_BIT(AIC31XX_DACSETUP, 6):
+		mask = AIC31XX_RDACPWRSTATUS_MASK;
+		break;
+	case WIDGET_BIT(AIC31XX_HPDRIVER, 7):
+		mask = AIC31XX_HPLDRVPWRSTATUS_MASK;
+		break;
+	case WIDGET_BIT(AIC31XX_HPDRIVER, 6):
+		mask = AIC31XX_HPRDRVPWRSTATUS_MASK;
+		break;
+	case WIDGET_BIT(AIC31XX_SPKAMP, 7):
+		mask = AIC31XX_SPLDRVPWRSTATUS_MASK;
+		break;
+	case WIDGET_BIT(AIC31XX_SPKAMP, 6):
+		mask = AIC31XX_SPRDRVPWRSTATUS_MASK;
+		break;
+	case WIDGET_BIT(AIC31XX_ADCSETUP, 7):
+		mask = AIC31XX_ADCPWRSTATUS_MASK;
+		reg = AIC31XX_ADCFLAG;
+		break;
+	default:
+		dev_err(w->codec->dev, "Unknown widget '%s' calling %s/n",
+			w->name, __func__);
+		return -EINVAL;
+	}
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		return aic31xx_wait_bits(aic31xx, reg, mask, mask, 5000, 100);
+	case SND_SOC_DAPM_POST_PMD:
+		return aic31xx_wait_bits(aic31xx, reg, mask, 0, 5000, 100);
+	}
+
+	dev_dbg(w->codec->dev, "Unhandled dapm widget event %d from %s\n",
+		event, w->name);
+	return 0;
+}
+
+static const struct snd_kcontrol_new left_output_switches[] = {
+	SOC_DAPM_SINGLE("From Left DAC", AIC31XX_DACMIXERROUTE, 6, 1, 0),
+	SOC_DAPM_SINGLE("From MIC1LP", AIC31XX_DACMIXERROUTE, 5, 1, 0),
+	SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new right_output_switches[] = {
+	SOC_DAPM_SINGLE("From Right DAC", AIC31XX_DACMIXERROUTE, 2, 1, 0),
+	SOC_DAPM_SINGLE("From MIC1RP", AIC31XX_DACMIXERROUTE, 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new p_term_mic1lp =
+	SOC_DAPM_ENUM("MIC1LP P-Terminal", mic1lp_p_enum);
+
+static const struct snd_kcontrol_new p_term_mic1rp =
+	SOC_DAPM_ENUM("MIC1RP P-Terminal", mic1rp_p_enum);
+
+static const struct snd_kcontrol_new p_term_mic1lm =
+	SOC_DAPM_ENUM("MIC1LM P-Terminal", mic1lm_p_enum);
+
+static const struct snd_kcontrol_new m_term_mic1lm =
+	SOC_DAPM_ENUM("MIC1LM M-Terminal", mic1lm_m_enum);
+
+static const struct snd_kcontrol_new aic31xx_dapm_hpl_switch =
+	SOC_DAPM_SINGLE("Switch", AIC31XX_LANALOGHPL, 7, 1, 0);
+
+static const struct snd_kcontrol_new aic31xx_dapm_hpr_switch =
+	SOC_DAPM_SINGLE("Switch", AIC31XX_RANALOGHPR, 7, 1, 0);
+
+static const struct snd_kcontrol_new aic31xx_dapm_spl_switch =
+	SOC_DAPM_SINGLE("Switch", AIC31XX_LANALOGSPL, 7, 1, 0);
+
+static const struct snd_kcontrol_new aic31xx_dapm_spr_switch =
+	SOC_DAPM_SINGLE("Switch", AIC31XX_RANALOGSPR, 7, 1, 0);
+
+static int aic31xx_clk_pm_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+	u8 mask = AIC31XX_PM_MASK;
+	u8 on = AIC31XX_PM_MASK;
+	u8 off = 0;
+
+	if (SND_SOC_DAPM_EVENT_ON(event)) {
+		dev_dbg(codec->dev, "codec clock -> on (rate %d)\n",
+			aic31xx_divs[aic31xx->rate_div_line].rate);
+		snd_soc_update_bits(codec, AIC31XX_PLLPR, mask, on);
+		mdelay(10);
+		snd_soc_update_bits(codec, AIC31XX_NDAC, mask, on);
+		snd_soc_update_bits(codec, AIC31XX_MDAC, mask, on);
+		if (aic31xx_divs[aic31xx->rate_div_line].nadc)
+			snd_soc_update_bits(codec, AIC31XX_NADC, mask, on);
+		if (aic31xx_divs[aic31xx->rate_div_line].madc)
+			snd_soc_update_bits(codec, AIC31XX_MADC, mask, on);
+		snd_soc_update_bits(codec, AIC31XX_BCLKN, mask, on);
+		aic31xx->codec_clk_on = 1;
+	} else if (SND_SOC_DAPM_EVENT_OFF(event)) {
+		dev_dbg(codec->dev, "codec clock -> off\n");
+		snd_soc_update_bits(codec, AIC31XX_BCLKN, mask, off);
+		snd_soc_update_bits(codec, AIC31XX_MADC, mask, off);
+		snd_soc_update_bits(codec, AIC31XX_NADC, mask, off);
+		snd_soc_update_bits(codec, AIC31XX_MDAC, mask, off);
+		snd_soc_update_bits(codec, AIC31XX_NDAC, mask, off);
+		snd_soc_update_bits(codec, AIC31XX_PLLPR, mask, off);
+		aic31xx->codec_clk_on = 0;
+	}
+	return 0;
+}
+
+static int mic_bias_event(struct snd_soc_dapm_widget *w,
+			  struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		/* change mic bias voltage to user defined */
+		if (aic31xx->pdata.micbias_vg != MICBIAS_OFF) {
+			snd_soc_update_bits(codec, AIC31XX_MICBIAS,
+					    AIC31XX_MICBIAS_MASK,
+					    aic31xx->pdata.micbias_vg <<
+					    AIC31XX_MICBIAS_SHIFT);
+			dev_dbg(codec->dev, "%s: turned on\n", __func__);
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		if (aic31xx->pdata.micbias_vg != MICBIAS_OFF) {
+			snd_soc_update_bits(codec, AIC31XX_MICBIAS,
+					    AIC31XX_MICBIAS_MASK, MICBIAS_OFF);
+			dev_dbg(codec->dev, "%s: turned off\n", __func__);
+		}
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0),
+
+	SND_SOC_DAPM_MUX("DAC Left Input",
+			 SND_SOC_NOPM, 0, 0, &ldac_in_control),
+	SND_SOC_DAPM_MUX("DAC Right Input",
+			 SND_SOC_NOPM, 0, 0, &rdac_in_control),
+	/* DACs */
+	SND_SOC_DAPM_DAC_E("DAC Left", "Left Playback",
+			   AIC31XX_DACSETUP, 7, 0, aic31xx_dapm_power_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_DAC_E("DAC Right", "Right Playback",
+			   AIC31XX_DACSETUP, 6, 0, aic31xx_dapm_power_event,
+			   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* Output Mixers */
+	SND_SOC_DAPM_MIXER("Output Left", SND_SOC_NOPM, 0, 0,
+			   left_output_switches,
+			   ARRAY_SIZE(left_output_switches)),
+	SND_SOC_DAPM_MIXER("Output Right", SND_SOC_NOPM, 0, 0,
+			   right_output_switches,
+			   ARRAY_SIZE(right_output_switches)),
+
+	SND_SOC_DAPM_SWITCH("HP Left", SND_SOC_NOPM, 0, 0,
+			    &aic31xx_dapm_hpl_switch),
+	SND_SOC_DAPM_SWITCH("HP Right", SND_SOC_NOPM, 0, 0,
+			    &aic31xx_dapm_hpr_switch),
+
+	/* Output drivers */
+	SND_SOC_DAPM_OUT_DRV_E("HPL Driver", AIC31XX_HPDRIVER, 7, 0,
+			       NULL, 0, aic31xx_dapm_power_event,
+			       SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_OUT_DRV_E("HPR Driver", AIC31XX_HPDRIVER, 6, 0,
+			       NULL, 0, aic31xx_dapm_power_event,
+			       SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
+
+	/* ADC */
+	SND_SOC_DAPM_ADC_E("ADC", "Capture", AIC31XX_ADCSETUP, 7, 0,
+			   aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
+			   SND_SOC_DAPM_POST_PMD),
+
+	/* Input Selection to MIC_PGA */
+	SND_SOC_DAPM_MUX("MIC1LP P-Terminal", SND_SOC_NOPM, 0, 0,
+			 &p_term_mic1lp),
+	SND_SOC_DAPM_MUX("MIC1RP P-Terminal", SND_SOC_NOPM, 0, 0,
+			 &p_term_mic1rp),
+	SND_SOC_DAPM_MUX("MIC1LM P-Terminal", SND_SOC_NOPM, 0, 0,
+			 &p_term_mic1lm),
+
+	SND_SOC_DAPM_MUX("MIC1LM M-Terminal", SND_SOC_NOPM, 0, 0,
+			 &m_term_mic1lm),
+	/* Enabling & Disabling MIC Gain Ctl */
+	SND_SOC_DAPM_PGA("MIC_GAIN_CTL", AIC31XX_MICPGA,
+			 7, 1, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("CODEC_CLK_IN", SND_SOC_NOPM, 0, 0,
+			    aic31xx_clk_pm_event,
+			    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	/* Mic Bias */
+	SND_SOC_DAPM_SUPPLY("Mic Bias", SND_SOC_NOPM, 0, 0, mic_bias_event,
+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	/* Outputs */
+	SND_SOC_DAPM_OUTPUT("HPL"),
+	SND_SOC_DAPM_OUTPUT("HPR"),
+
+	SND_SOC_DAPM_OUTPUT("Internal DAC Sink"),
+
+	/* Inputs */
+	SND_SOC_DAPM_INPUT("MIC1LP"),
+	SND_SOC_DAPM_INPUT("MIC1RP"),
+	SND_SOC_DAPM_INPUT("MIC1LM"),
+
+	SND_SOC_DAPM_INPUT("Internal ADC Source"),
+};
+
+static const struct snd_soc_dapm_widget aic311x_dapm_widgets[] = {
+	/* AIC3111 and AIC3110 have stereo class-D amplifier */
+	SND_SOC_DAPM_OUT_DRV_E("SPL ClassD", AIC31XX_SPKAMP, 7, 0, NULL, 0,
+			       aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_OUT_DRV_E("SPR ClassD", AIC31XX_SPKAMP, 6, 0, NULL, 0,
+			       aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SWITCH("Speaker Left", SND_SOC_NOPM, 0, 0,
+			    &aic31xx_dapm_spl_switch),
+	SND_SOC_DAPM_SWITCH("Speaker Right", SND_SOC_NOPM, 0, 0,
+			    &aic31xx_dapm_spr_switch),
+	SND_SOC_DAPM_OUTPUT("SPL"),
+	SND_SOC_DAPM_OUTPUT("SPR"),
+};
+
+/* AIC3100 and AIC3120 have only mono class-D amplifier */
+static const struct snd_soc_dapm_widget aic310x_dapm_widgets[] = {
+	SND_SOC_DAPM_OUT_DRV_E("SPK ClassD", AIC31XX_SPKAMP, 7, 0, NULL, 0,
+			       aic31xx_dapm_power_event, SND_SOC_DAPM_POST_PMU |
+			       SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_SWITCH("Speaker", SND_SOC_NOPM, 0, 0,
+			    &aic31xx_dapm_spl_switch),
+	SND_SOC_DAPM_OUTPUT("SPK"),
+};
+
+static const struct snd_soc_dapm_route
+aic31xx_audio_map[] = {
+	/* Make DACs turn on when playing even if not mixed into any outputs */
+	{"Internal DAC Sink", NULL, "DAC Left"},
+	{"Internal DAC Sink", NULL, "DAC Right"},
+
+	/* Make ADC turn on when recording even if not mixed from any inputs */
+	{"ADC", NULL, "Internal ADC Source"},
+
+	/* Clocks for ADC */
+	{"ADC", NULL, "CODEC_CLK_IN"},
+
+	/* DAC Input Routing */
+	{"DAC Left Input", "Left Data", "DAC IN"},
+	{"DAC Left Input", "Right Data", "DAC IN"},
+	{"DAC Left Input", "Mono", "DAC IN"},
+	{"DAC Right Input", "Left Data", "DAC IN"},
+	{"DAC Right Input", "Right Data", "DAC IN"},
+	{"DAC Right Input", "Mono", "DAC IN"},
+	{"DAC Left", NULL, "DAC Left Input"},
+	{"DAC Right", NULL, "DAC Right Input"},
+
+	/* Mic input */
+	{"MIC1LP P-Terminal", "FFR 10 Ohm", "MIC1LP"},
+	{"MIC1LP P-Terminal", "FFR 20 Ohm", "MIC1LP"},
+	{"MIC1LP P-Terminal", "FFR 40 Ohm", "MIC1LP"},
+	{"MIC1RP P-Terminal", "FFR 10 Ohm", "MIC1RP"},
+	{"MIC1RP P-Terminal", "FFR 20 Ohm", "MIC1RP"},
+	{"MIC1RP P-Terminal", "FFR 40 Ohm", "MIC1RP"},
+	{"MIC1LM P-Terminal", "FFR 10 Ohm", "MIC1LM"},
+	{"MIC1LM P-Terminal", "FFR 20 Ohm", "MIC1LM"},
+	{"MIC1LM P-Terminal", "FFR 40 Ohm", "MIC1LM"},
+
+	{"MIC1LM M-Terminal", "FFR 10 Ohm", "MIC1LM"},
+	{"MIC1LM M-Terminal", "FFR 20 Ohm", "MIC1LM"},
+	{"MIC1LM M-Terminal", "FFR 40 Ohm", "MIC1LM"},
+
+	{"MIC_GAIN_CTL", NULL, "MIC1LP P-Terminal"},
+	{"MIC_GAIN_CTL", NULL, "MIC1RP P-Terminal"},
+	{"MIC_GAIN_CTL", NULL, "MIC1LM P-Terminal"},
+	{"MIC_GAIN_CTL", NULL, "MIC1LM M-Terminal"},
+
+	{"ADC", NULL, "MIC_GAIN_CTL"},
+	{"MIC_GAIN_CTL", NULL, "Mic Bias"},
+
+	/* Clocks for DAC */
+	{"DAC Left", NULL, "CODEC_CLK_IN" },
+	{"DAC Right", NULL, "CODEC_CLK_IN"},
+
+	/* Left Output */
+	{"Output Left", "From Left DAC", "DAC Left"},
+	{"Output Left", "From MIC1LP", "MIC1LP"},
+	{"Output Left", "From MIC1RP", "MIC1RP"},
+
+	/* Right Output */
+	{"Output Right", "From Right DAC", "DAC Right"},
+	{"Output Right", "From MIC1RP", "MIC1RP"},
+
+	/* HPL path */
+	{"HP Left", "Switch", "Output Left"},
+	{"HPL Driver", NULL, "HP Left"},
+	{"HPL", NULL, "HPL Driver"},
+
+	/* HPR path */
+	{"HP Right", "Switch", "Output Right"},
+	{"HPR Driver", NULL, "HP Right"},
+	{"HPR", NULL, "HPR Driver"},
+};
+
+static const struct snd_soc_dapm_route
+aic311x_audio_map[] = {
+	/* SP L path */
+	{"Speaker Left", "Switch", "Output Left"},
+	{"SPL ClassD", NULL, "Speaker Left"},
+	{"SPL", NULL, "SPL ClassD"},
+
+	/* SP R path */
+	{"Speaker Right", "Switch", "Output Right"},
+	{"SPR ClassD", NULL, "Speaker Right"},
+	{"SPR", NULL, "SPR ClassD"},
+};
+
+static const struct snd_soc_dapm_route
+aic310x_audio_map[] = {
+	/* SP L path */
+	{"Speaker", "Switch", "Output Left"},
+	{"SPK ClassD", NULL, "Speaker"},
+	{"SPK", NULL, "SPK ClassD"},
+};
+
+static int aic31xx_add_controls(struct snd_soc_codec *codec)
+{
+	int err = 0;
+	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+
+	if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) {
+		err = snd_soc_add_codec_controls(
+			codec, aic311x_snd_controls,
+			ARRAY_SIZE(aic311x_snd_controls));
+		if (err < 0)
+			dev_dbg(codec->dev, "Invalid control\n");
+
+	} else {
+		err = snd_soc_add_codec_controls(
+			codec, aic310x_snd_controls,
+			ARRAY_SIZE(aic310x_snd_controls));
+		if (err < 0)
+			dev_dbg(codec->dev, "Invalid Control\n");
+	}
+	return 0;
+}
+
+static int aic31xx_add_widgets(struct snd_soc_codec *codec)
+{
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
+
+	if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) {
+		ret = snd_soc_dapm_new_controls(
+			dapm, aic311x_dapm_widgets,
+			ARRAY_SIZE(aic311x_dapm_widgets));
+		if (ret)
+			dev_err(codec->dev,
+				"Adding %d dapm widgets failed: %d\n",
+				ARRAY_SIZE(aic311x_dapm_widgets), ret);
+		ret = snd_soc_dapm_add_routes(dapm, aic311x_audio_map,
+					      ARRAY_SIZE(aic311x_audio_map));
+		if (ret)
+			dev_err(codec->dev,
+				"Adding %d DAPM routes failed: %d\n",
+				ARRAY_SIZE(aic311x_audio_map), ret);
+	} else {
+		ret = snd_soc_dapm_new_controls(
+			dapm, aic310x_dapm_widgets,
+			ARRAY_SIZE(aic310x_dapm_widgets));
+		if (ret)
+			dev_err(codec->dev,
+				"Adding %d dapm widgets failed: %d\n",
+				ARRAY_SIZE(aic310x_dapm_widgets), ret);
+		ret = snd_soc_dapm_add_routes(dapm, aic310x_audio_map,
+					      ARRAY_SIZE(aic310x_audio_map));
+		if (ret)
+			dev_err(codec->dev,
+				"Adding %d DAPM routes failed: %d\n",
+				ARRAY_SIZE(aic310x_audio_map), ret);
+	}
+
+	return 0;
+}
+
+static int aic31xx_setup_pll(struct snd_soc_codec *codec,
+			     struct snd_pcm_hw_params *params)
+{
+	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+	int bclk_n = 0;
+	int i;
+
+	/* Use PLL as CODEC_CLKIN and DAC_CLK as BDIV_CLKIN */
+	snd_soc_update_bits(codec, AIC31XX_CLKMUX,
+			    AIC31XX_CODEC_CLKIN_MASK, AIC31XX_CODEC_CLKIN_PLL);
+	snd_soc_update_bits(codec, AIC31XX_IFACE2,
+			    AIC31XX_BDIVCLK_MASK, AIC31XX_DAC2BCLK);
+
+	for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++) {
+		if (aic31xx_divs[i].rate == params_rate(params) &&
+		    aic31xx_divs[i].mclk == aic31xx->sysclk)
+			break;
+	}
+
+	if (i == ARRAY_SIZE(aic31xx_divs)) {
+		dev_err(codec->dev, "%s: Sampling rate %u not supported\n",
+			__func__, params_rate(params));
+		return -EINVAL;
+	}
+
+	if (aic31xx->codec_clk_on) {
+		int old = aic31xx->rate_div_line;
+		if (aic31xx_divs[i].pll_j != aic31xx_divs[old].pll_j ||
+		    aic31xx_divs[i].pll_d != aic31xx_divs[old].pll_d ||
+		    aic31xx_divs[i].p_val != aic31xx_divs[old].p_val) {
+			dev_err(codec->dev,
+				"%s: Can't reconfigure PLL while it is on.\n",
+				__func__);
+			return -EBUSY;
+		}
+	} else {
+		/* PLL configuration */
+		snd_soc_update_bits(codec, AIC31XX_PLLPR, AIC31XX_PLL_MASK,
+				    (aic31xx_divs[i].p_val << 4) | 0x01);
+		snd_soc_write(codec, AIC31XX_PLLJ, aic31xx_divs[i].pll_j);
+
+		snd_soc_write(codec, AIC31XX_PLLDMSB,
+			      aic31xx_divs[i].pll_d >> 8);
+		snd_soc_write(codec, AIC31XX_PLLDLSB,
+			      aic31xx_divs[i].pll_d & 0xff);
+	}
+
+	/* DAC dividers configuration */
+	snd_soc_update_bits(codec, AIC31XX_NDAC, AIC31XX_PLL_MASK,
+			    aic31xx_divs[i].ndac);
+	snd_soc_update_bits(codec, AIC31XX_MDAC, AIC31XX_PLL_MASK,
+			    aic31xx_divs[i].mdac);
+
+	snd_soc_write(codec, AIC31XX_DOSRMSB, aic31xx_divs[i].dosr >> 8);
+	snd_soc_write(codec, AIC31XX_DOSRLSB, aic31xx_divs[i].dosr & 0xff);
+
+	/* ADC dividers configuration. Write reset value 1 if not used. */
+	snd_soc_update_bits(codec, AIC31XX_NADC, AIC31XX_PLL_MASK,
+			    aic31xx_divs[i].nadc ? aic31xx_divs[i].nadc : 1);
+	snd_soc_update_bits(codec, AIC31XX_MADC, AIC31XX_PLL_MASK,
+			    aic31xx_divs[i].madc ? aic31xx_divs[i].madc : 1);
+
+	snd_soc_write(codec, AIC31XX_AOSR, aic31xx_divs[i].aosr);
+
+	/* Bit clock divider configuration. */
+	bclk_n = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac)
+		/ snd_soc_params_to_frame_size(params);
+	if (bclk_n == 0) {
+		dev_err(codec->dev, "%s: Not enough BLCK bandwidth\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, AIC31XX_BCLKN,
+			    AIC31XX_PLL_MASK, bclk_n);
+
+	aic31xx->rate_div_line = i;
+
+	dev_dbg(codec->dev,
+		"pll %d.%04d/%d dosr %d n %d m %d aosr %d n %d m %d bclk_n %d\n",
+		aic31xx_divs[i].pll_j, aic31xx_divs[i].pll_d,
+		aic31xx_divs[i].p_val, aic31xx_divs[i].dosr,
+		aic31xx_divs[i].ndac, aic31xx_divs[i].mdac,
+		aic31xx_divs[i].aosr, aic31xx_divs[i].nadc,
+		aic31xx_divs[i].madc, bclk_n);
+
+	return 0;
+}
+
+static int aic31xx_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *tmp)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_codec *codec = rtd->codec;
+	u8 data = 0;
+
+	dev_dbg(codec->dev, "## %s: format %d rate %d\n",
+		__func__, params_format(params), params_rate(params));
+
+	switch (params_width(params)) {
+	case 16:
+		break;
+	case 20:
+		data = (AIC31XX_WORD_LEN_20BITS <<
+			AIC31XX_IFACE1_DATALEN_SHIFT);
+		break;
+	case 24:
+		data = (AIC31XX_WORD_LEN_24BITS <<
+			AIC31XX_IFACE1_DATALEN_SHIFT);
+		break;
+	case 32:
+		data = (AIC31XX_WORD_LEN_32BITS <<
+			AIC31XX_IFACE1_DATALEN_SHIFT);
+		break;
+	default:
+		dev_err(codec->dev, "%s: Unsupported format %d\n",
+			__func__, params_format(params));
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, AIC31XX_IFACE1,
+			    AIC31XX_IFACE1_DATALEN_MASK,
+			    data);
+
+	return aic31xx_setup_pll(codec, params);
+}
+
+static int aic31xx_dac_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+
+	if (mute) {
+		snd_soc_update_bits(codec, AIC31XX_DACMUTE,
+				    AIC31XX_DACMUTE_MASK,
+				    AIC31XX_DACMUTE_MASK);
+	} else {
+		snd_soc_update_bits(codec, AIC31XX_DACMUTE,
+				    AIC31XX_DACMUTE_MASK, 0x0);
+	}
+
+	return 0;
+}
+
+static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai,
+			       unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	u8 iface_reg1 = 0;
+	u8 iface_reg3 = 0;
+	u8 dsp_a_val = 0;
+
+	dev_dbg(codec->dev, "## %s: fmt = 0x%x\n", __func__, fmt);
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		iface_reg1 |= AIC31XX_BCLK_MASTER | AIC31XX_WCLK_MASTER;
+		break;
+	default:
+		dev_alert(codec->dev, "Invalid DAI master/slave interface\n");
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		dsp_a_val = 0x1;
+	case SND_SOC_DAIFMT_DSP_B:
+		/* NOTE: BCLKINV bit value 1 equas NB and 0 equals IB */
+		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+		case SND_SOC_DAIFMT_NB_NF:
+			iface_reg3 |= AIC31XX_BCLKINV_MASK;
+			break;
+		case SND_SOC_DAIFMT_IB_NF:
+			break;
+		default:
+			return -EINVAL;
+		}
+		iface_reg1 |= (AIC31XX_DSP_MODE <<
+			       AIC31XX_IFACE1_DATATYPE_SHIFT);
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		iface_reg1 |= (AIC31XX_RIGHT_JUSTIFIED_MODE <<
+			       AIC31XX_IFACE1_DATATYPE_SHIFT);
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		iface_reg1 |= (AIC31XX_LEFT_JUSTIFIED_MODE <<
+			       AIC31XX_IFACE1_DATATYPE_SHIFT);
+		break;
+	default:
+		dev_err(codec->dev, "Invalid DAI interface format\n");
+		return -EINVAL;
+	}
+
+	snd_soc_update_bits(codec, AIC31XX_IFACE1,
+			    AIC31XX_IFACE1_DATATYPE_MASK |
+			    AIC31XX_IFACE1_MASTER_MASK,
+			    iface_reg1);
+	snd_soc_update_bits(codec, AIC31XX_DATA_OFFSET,
+			    AIC31XX_DATA_OFFSET_MASK,
+			    dsp_a_val);
+	snd_soc_update_bits(codec, AIC31XX_IFACE2,
+			    AIC31XX_BCLKINV_MASK,
+			    iface_reg3);
+
+	return 0;
+}
+
+static int aic31xx_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 aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+	int i;
+
+	dev_dbg(codec->dev, "## %s: clk_id = %d, freq = %d, dir = %d\n",
+		__func__, clk_id, freq, dir);
+
+	for (i = 0; aic31xx_divs[i].mclk != freq; i++) {
+		if (i == ARRAY_SIZE(aic31xx_divs)) {
+			dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n",
+				__func__, freq);
+			return -EINVAL;
+		}
+	}
+
+	/* set clock on MCLK, BCLK, or GPIO1 as PLL input */
+	snd_soc_update_bits(codec, AIC31XX_CLKMUX, AIC31XX_PLL_CLKIN_MASK,
+			    clk_id << AIC31XX_PLL_CLKIN_SHIFT);
+
+	aic31xx->sysclk = freq;
+	return 0;
+}
+
+static int aic31xx_regulator_event(struct notifier_block *nb,
+				   unsigned long event, void *data)
+{
+	struct aic31xx_disable_nb *disable_nb =
+		container_of(nb, struct aic31xx_disable_nb, nb);
+	struct aic31xx_priv *aic31xx = disable_nb->aic31xx;
+
+	if (event & REGULATOR_EVENT_DISABLE) {
+		/*
+		 * Put codec to reset and as at least one of the
+		 * supplies was disabled. It may be to late to try
+		 * soft reset, but it should not do any harm.
+		 * Resetting the codec helps in minimizing leakage
+		 * in case some of the regulators remains turned on.
+		 */
+		if (gpio_is_valid(aic31xx->pdata.gpio_reset))
+			gpio_set_value(aic31xx->pdata.gpio_reset, 0);
+		else
+			snd_soc_write(aic31xx->codec, AIC31XX_RESET, 0x01);
+		regcache_mark_dirty(aic31xx->regmap);
+		dev_dbg(aic31xx->dev, "## %s: DISABLE received\n", __func__);
+	}
+
+	return 0;
+}
+
+static int aic31xx_set_power(struct snd_soc_codec *codec, int power)
+{
+	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+	int ret;
+
+	dev_dbg(codec->dev, "## %s: %d\n", __func__, power);
+
+	if (power) {
+		ret = regulator_bulk_enable(ARRAY_SIZE(aic31xx->supplies),
+					    aic31xx->supplies);
+		if (ret)
+			return ret;
+
+		if (gpio_is_valid(aic31xx->pdata.gpio_reset)) {
+			gpio_set_value(aic31xx->pdata.gpio_reset, 1);
+			udelay(100);
+		}
+		regcache_cache_only(aic31xx->regmap, false);
+		ret = regcache_sync(aic31xx->regmap);
+		if (ret != 0) {
+			dev_err(codec->dev,
+				"Failed to restore cache: %d\n", ret);
+			regcache_cache_only(aic31xx->regmap, true);
+			regulator_bulk_disable(ARRAY_SIZE(aic31xx->supplies),
+					       aic31xx->supplies);
+			return ret;
+		}
+	} else {
+		regcache_cache_only(aic31xx->regmap, true);
+		ret = regulator_bulk_disable(ARRAY_SIZE(aic31xx->supplies),
+					     aic31xx->supplies);
+	}
+
+	return ret;
+}
+
+static int aic31xx_set_bias_level(struct snd_soc_codec *codec,
+				  enum snd_soc_bias_level level)
+{
+	dev_dbg(codec->dev, "## %s: %d -> %d\n", __func__,
+		codec->dapm.bias_level, level);
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		/* All power is driven by DAPM system*/
+		break;
+	case SND_SOC_BIAS_PREPARE:
+		break;
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+			aic31xx_set_power(codec, 1);
+		break;
+	case SND_SOC_BIAS_OFF:
+		aic31xx_set_power(codec, 0);
+		break;
+	}
+	codec->dapm.bias_level = level;
+
+	return 0;
+}
+
+
+static int aic31xx_suspend(struct snd_soc_codec *codec)
+{
+	aic31xx_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static int aic31xx_resume(struct snd_soc_codec *codec)
+{
+	aic31xx_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+	return 0;
+}
+
+static int aic31xx_codec_probe(struct snd_soc_codec *codec)
+{
+	int ret = 0;
+	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+	int i;
+
+	dev_dbg(aic31xx->dev, "## %s\n", __func__);
+
+	aic31xx = snd_soc_codec_get_drvdata(codec);
+	codec->control_data = aic31xx->regmap;
+
+	aic31xx->codec = codec;
+
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
+
+	if (ret != 0) {
+		dev_err(codec->dev, "snd_soc_codec_set_cache_io failed %d\n",
+			ret);
+		return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) {
+		aic31xx->disable_nb[i].nb.notifier_call =
+			aic31xx_regulator_event;
+		aic31xx->disable_nb[i].aic31xx = aic31xx;
+		ret = regulator_register_notifier(aic31xx->supplies[i].consumer,
+						  &aic31xx->disable_nb[i].nb);
+		if (ret) {
+			dev_err(codec->dev,
+				"Failed to request regulator notifier: %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	regcache_cache_only(aic31xx->regmap, true);
+	regcache_mark_dirty(aic31xx->regmap);
+
+	aic31xx_add_controls(codec);
+	aic31xx_add_widgets(codec);
+
+	return ret;
+}
+
+static int aic31xx_codec_remove(struct snd_soc_codec *codec)
+{
+	struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
+	int i;
+	/* power down chip */
+	aic31xx_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++)
+		regulator_unregister_notifier(aic31xx->supplies[i].consumer,
+					      &aic31xx->disable_nb[i].nb);
+
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_driver_aic31xx = {
+	.probe			= aic31xx_codec_probe,
+	.remove			= aic31xx_codec_remove,
+	.suspend		= aic31xx_suspend,
+	.resume			= aic31xx_resume,
+	.set_bias_level		= aic31xx_set_bias_level,
+	.controls		= aic31xx_snd_controls,
+	.num_controls		= ARRAY_SIZE(aic31xx_snd_controls),
+	.dapm_widgets		= aic31xx_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(aic31xx_dapm_widgets),
+	.dapm_routes		= aic31xx_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(aic31xx_audio_map),
+};
+
+static struct snd_soc_dai_ops aic31xx_dai_ops = {
+	.hw_params	= aic31xx_hw_params,
+	.set_sysclk	= aic31xx_set_dai_sysclk,
+	.set_fmt	= aic31xx_set_dai_fmt,
+	.digital_mute	= aic31xx_dac_mute,
+};
+
+static struct snd_soc_dai_driver aic31xx_dai_driver[] = {
+	{
+		.name = "tlv320aic31xx-hifi",
+		.playback = {
+			.stream_name	 = "Playback",
+			.channels_min	 = 1,
+			.channels_max	 = 2,
+			.rates		 = AIC31XX_RATES,
+			.formats	 = AIC31XX_FORMATS,
+		},
+		.capture = {
+			.stream_name	 = "Capture",
+			.channels_min	 = 1,
+			.channels_max	 = 2,
+			.rates		 = AIC31XX_RATES,
+			.formats	 = AIC31XX_FORMATS,
+		},
+		.ops = &aic31xx_dai_ops,
+		.symmetric_rates = 1,
+	}
+};
+
+#if defined(CONFIG_OF)
+static const struct of_device_id tlv320aic31xx_of_match[] = {
+	{ .compatible = "ti,tlv320aic310x" },
+	{ .compatible = "ti,tlv320aic311x" },
+	{ .compatible = "ti,tlv320aic3100" },
+	{ .compatible = "ti,tlv320aic3110" },
+	{ .compatible = "ti,tlv320aic3120" },
+	{ .compatible = "ti,tlv320aic3111" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, tlv320aic31xx_of_match);
+
+static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx)
+{
+	struct device_node *np = aic31xx->dev->of_node;
+	unsigned int value = MICBIAS_2_0V;
+	int ret;
+
+	of_property_read_u32(np, "ai31xx-micbias-vg", &value);
+	switch (value) {
+	case MICBIAS_OFF:
+	case MICBIAS_2_0V:
+	case MICBIAS_2_5V:
+	case MICBIAS_AVDDV:
+		aic31xx->pdata.micbias_vg = value;
+		break;
+	default:
+		dev_err(aic31xx->dev,
+			"Bad ai31xx-micbias-vg value %d DT\n",
+			value);
+		aic31xx->pdata.micbias_vg = MICBIAS_2_0V;
+	}
+
+	ret = of_get_named_gpio(np, "gpio-reset", 0);
+	if (ret > 0)
+		aic31xx->pdata.gpio_reset = ret;
+}
+#else /* CONFIG_OF */
+static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx)
+{
+}
+#endif /* CONFIG_OF */
+
+void aic31xx_device_init(struct aic31xx_priv *aic31xx)
+{
+	int ret, i;
+
+	dev_set_drvdata(aic31xx->dev, aic31xx);
+
+	if (dev_get_platdata(aic31xx->dev))
+		memcpy(&aic31xx->pdata, dev_get_platdata(aic31xx->dev),
+		       sizeof(aic31xx->pdata));
+	else if (aic31xx->dev->of_node)
+		aic31xx_pdata_from_of(aic31xx);
+
+	if (aic31xx->pdata.gpio_reset) {
+		ret = devm_gpio_request_one(aic31xx->dev,
+					    aic31xx->pdata.gpio_reset,
+					    GPIOF_OUT_INIT_HIGH,
+					    "aic31xx-reset-pin");
+		if (ret < 0) {
+			dev_err(aic31xx->dev, "not able to acquire gpio\n");
+			return;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++)
+		aic31xx->supplies[i].supply = aic31xx_supply_names[i];
+
+	ret = devm_regulator_bulk_get(aic31xx->dev,
+				      ARRAY_SIZE(aic31xx->supplies),
+				      aic31xx->supplies);
+	if (ret != 0)
+		dev_err(aic31xx->dev, "Failed to request supplies: %d\n", ret);
+
+}
+
+static int aic31xx_i2c_probe(struct i2c_client *i2c,
+			     const struct i2c_device_id *id)
+{
+	struct aic31xx_priv *aic31xx;
+	int ret;
+	const struct regmap_config *regmap_config;
+
+	dev_dbg(&i2c->dev, "## %s: %s codec_type = %d\n", __func__,
+		id->name, (int) id->driver_data);
+
+	regmap_config = &aic31xx_i2c_regmap;
+
+	aic31xx = devm_kzalloc(&i2c->dev, sizeof(*aic31xx), GFP_KERNEL);
+	if (aic31xx == NULL)
+		return -ENOMEM;
+
+	aic31xx->regmap = devm_regmap_init_i2c(i2c, regmap_config);
+
+	if (IS_ERR(aic31xx->regmap)) {
+		ret = PTR_ERR(aic31xx->regmap);
+		dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+	aic31xx->dev = &i2c->dev;
+
+	aic31xx->pdata.codec_type = id->driver_data;
+
+	aic31xx_device_init(aic31xx);
+
+	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx,
+				     aic31xx_dai_driver,
+				     ARRAY_SIZE(aic31xx_dai_driver));
+
+	return ret;
+}
+
+static int aic31xx_i2c_remove(struct i2c_client *i2c)
+{
+	struct aic31xx_priv *aic31xx = dev_get_drvdata(&i2c->dev);
+
+	kfree(aic31xx);
+	return 0;
+}
+
+static const struct i2c_device_id aic31xx_i2c_id[] = {
+	{ "tlv320aic310x", AIC3100 },
+	{ "tlv320aic311x", AIC3110 },
+	{ "tlv320aic3100", AIC3100 },
+	{ "tlv320aic3110", AIC3110 },
+	{ "tlv320aic3120", AIC3120 },
+	{ "tlv320aic3111", AIC3111 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id);
+
+static struct i2c_driver aic31xx_i2c_driver = {
+	.driver = {
+		.name	= "tlv320aic31xx-codec",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(tlv320aic31xx_of_match),
+	},
+	.probe		= aic31xx_i2c_probe,
+	.remove		= (aic31xx_i2c_remove),
+	.id_table	= aic31xx_i2c_id,
+};
+
+module_i2c_driver(aic31xx_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC TLV320AIC3111 codec driver");
+MODULE_AUTHOR("Jyri Sarha");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h
new file mode 100644
index 0000000..52ed57c
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic31xx.h
@@ -0,0 +1,258 @@
+/*
+ * ALSA SoC TLV320AIC31XX codec driver
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+#ifndef _TLV320AIC31XX_H
+#define _TLV320AIC31XX_H
+
+#define AIC31XX_RATES	SNDRV_PCM_RATE_8000_192000
+
+#define AIC31XX_FORMATS	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
+			 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+
+#define AIC31XX_STEREO_CLASS_D_BIT	0x1
+#define AIC31XX_MINIDSP_BIT		0x2
+
+enum aic31xx_type {
+	AIC3100	= 0,
+	AIC3110 = AIC31XX_STEREO_CLASS_D_BIT,
+	AIC3120 = AIC31XX_MINIDSP_BIT,
+	AIC3111 = (AIC31XX_STEREO_CLASS_D_BIT | AIC31XX_MINIDSP_BIT),
+};
+
+struct aic31xx_pdata {
+	enum aic31xx_type codec_type;
+	unsigned int gpio_reset;
+	int micbias_vg;
+};
+
+/* Page Control Register */
+#define AIC31XX_PAGECTL				0x00
+
+/* Page 0 Registers */
+/* Software reset register */
+#define AIC31XX_RESET				0x01
+/* OT FLAG register */
+#define AIC31XX_OT_FLAG				0x03
+/* Clock clock Gen muxing, Multiplexers*/
+#define AIC31XX_CLKMUX				0x04
+/* PLL P and R-VAL register */
+#define AIC31XX_PLLPR				0x05
+/* PLL J-VAL register */
+#define AIC31XX_PLLJ				0x06
+/* PLL D-VAL MSB register */
+#define AIC31XX_PLLDMSB				0x07
+/* PLL D-VAL LSB register */
+#define AIC31XX_PLLDLSB				0x08
+/* DAC NDAC_VAL register*/
+#define AIC31XX_NDAC				0x0B
+/* DAC MDAC_VAL register */
+#define AIC31XX_MDAC				0x0C
+/* DAC OSR setting register 1, MSB value */
+#define AIC31XX_DOSRMSB				0x0D
+/* DAC OSR setting register 2, LSB value */
+#define AIC31XX_DOSRLSB				0x0E
+#define AIC31XX_MINI_DSP_INPOL			0x10
+/* Clock setting register 8, PLL */
+#define AIC31XX_NADC				0x12
+/* Clock setting register 9, PLL */
+#define AIC31XX_MADC				0x13
+/* ADC Oversampling (AOSR) Register */
+#define AIC31XX_AOSR				0x14
+/* Clock setting register 9, Multiplexers */
+#define AIC31XX_CLKOUTMUX			0x19
+/* Clock setting register 10, CLOCKOUT M divider value */
+#define AIC31XX_CLKOUTMVAL			0x1A
+/* Audio Interface Setting Register 1 */
+#define AIC31XX_IFACE1				0x1B
+/* Audio Data Slot Offset Programming */
+#define AIC31XX_DATA_OFFSET			0x1C
+/* Audio Interface Setting Register 2 */
+#define AIC31XX_IFACE2				0x1D
+/* Clock setting register 11, BCLK N Divider */
+#define AIC31XX_BCLKN				0x1E
+/* Audio Interface Setting Register 3, Secondary Audio Interface */
+#define AIC31XX_IFACESEC1			0x1F
+/* Audio Interface Setting Register 4 */
+#define AIC31XX_IFACESEC2			0x20
+/* Audio Interface Setting Register 5 */
+#define AIC31XX_IFACESEC3			0x21
+/* I2C Bus Condition */
+#define AIC31XX_I2C				0x22
+/* ADC FLAG */
+#define AIC31XX_ADCFLAG				0x24
+/* DAC Flag Registers */
+#define AIC31XX_DACFLAG1			0x25
+#define AIC31XX_DACFLAG2			0x26
+/* Sticky Interrupt flag (overflow) */
+#define AIC31XX_OFFLAG				0x27
+/* Sticy DAC Interrupt flags */
+#define AIC31XX_INTRDACFLAG			0x2C
+/* Sticy ADC Interrupt flags */
+#define AIC31XX_INTRADCFLAG			0x2D
+/* DAC Interrupt flags 2 */
+#define AIC31XX_INTRDACFLAG2			0x2E
+/* ADC Interrupt flags 2 */
+#define AIC31XX_INTRADCFLAG2			0x2F
+/* INT1 interrupt control */
+#define AIC31XX_INT1CTRL			0x30
+/* INT2 interrupt control */
+#define AIC31XX_INT2CTRL			0x31
+/* GPIO1 control */
+#define AIC31XX_GPIO1				0x33
+
+#define AIC31XX_DACPRB				0x3C
+/* ADC Instruction Set Register */
+#define AIC31XX_ADCPRB				0x3D
+/* DAC channel setup register */
+#define AIC31XX_DACSETUP			0x3F
+/* DAC Mute and volume control register */
+#define AIC31XX_DACMUTE				0x40
+/* Left DAC channel digital volume control */
+#define AIC31XX_LDACVOL				0x41
+/* Right DAC channel digital volume control */
+#define AIC31XX_RDACVOL				0x42
+/* Headset detection */
+#define AIC31XX_HSDETECT			0x43
+/* ADC Digital Mic */
+#define AIC31XX_ADCSETUP			0x51
+/* ADC Digital Volume Control Fine Adjust */
+#define AIC31XX_ADCFGA				0x52
+/* ADC Digital Volume Control Coarse Adjust */
+#define AIC31XX_ADCVOL				0x53
+
+
+/* Page 1 Registers */
+/* Headphone drivers */
+#define AIC31XX_HPDRIVER			0x9F
+/* Class-D Speakear Amplifier */
+#define AIC31XX_SPKAMP				0xA0
+/* HP Output Drivers POP Removal Settings */
+#define AIC31XX_HPPOP				0xA1
+/* Output Driver PGA Ramp-Down Period Control */
+#define AIC31XX_SPPGARAMP			0xA2
+/* DAC_L and DAC_R Output Mixer Routing */
+#define AIC31XX_DACMIXERROUTE			0xA3
+/* Left Analog Vol to HPL */
+#define AIC31XX_LANALOGHPL			0xA4
+/* Right Analog Vol to HPR */
+#define AIC31XX_RANALOGHPR			0xA5
+/* Left Analog Vol to SPL */
+#define AIC31XX_LANALOGSPL			0xA6
+/* Right Analog Vol to SPR */
+#define AIC31XX_RANALOGSPR			0xA7
+/* HPL Driver */
+#define AIC31XX_HPLGAIN				0xA8
+/* HPR Driver */
+#define AIC31XX_HPRGAIN				0xA9
+/* SPL Driver */
+#define AIC31XX_SPLGAIN				0xAA
+/* SPR Driver */
+#define AIC31XX_SPRGAIN				0xAB
+/* HP Driver Control */
+#define AIC31XX_HPCONTROL			0xAC
+/* MIC Bias Control */
+#define AIC31XX_MICBIAS				0xAE
+/* MIC PGA*/
+#define AIC31XX_MICPGA				0xAF
+/* Delta-Sigma Mono ADC Channel Fine-Gain Input Selection for P-Terminal */
+#define AIC31XX_MICPGAPI			0xB0
+/* ADC Input Selection for M-Terminal */
+#define AIC31XX_MICPGAMI			0xB1
+/* Input CM Settings */
+#define AIC31XX_MICPGACM			0xB2
+
+/* Bits, masks and shifts */
+
+/* AIC31XX_CLKMUX */
+#define AIC31XX_PLL_CLKIN_MASK			0x0c
+#define AIC31XX_PLL_CLKIN_SHIFT			2
+#define AIC31XX_PLL_CLKIN_MCLK			0
+#define AIC31XX_CODEC_CLKIN_MASK		0x03
+#define AIC31XX_CODEC_CLKIN_SHIFT		0
+#define AIC31XX_CODEC_CLKIN_PLL			3
+#define AIC31XX_CODEC_CLKIN_BCLK		1
+
+/* AIC31XX_PLLPR, AIC31XX_NDAC, AIC31XX_MDAC, AIC31XX_NADC, AIC31XX_MADC,
+   AIC31XX_BCLKN */
+#define AIC31XX_PLL_MASK		0x7f
+#define AIC31XX_PM_MASK			0x80
+
+/* AIC31XX_IFACE1 */
+#define AIC31XX_WORD_LEN_16BITS		0x00
+#define AIC31XX_WORD_LEN_20BITS		0x01
+#define AIC31XX_WORD_LEN_24BITS		0x02
+#define AIC31XX_WORD_LEN_32BITS		0x03
+#define AIC31XX_IFACE1_DATALEN_MASK	0x30
+#define AIC31XX_IFACE1_DATALEN_SHIFT	(4)
+#define AIC31XX_IFACE1_DATATYPE_MASK	0xC0
+#define AIC31XX_IFACE1_DATATYPE_SHIFT	(6)
+#define AIC31XX_I2S_MODE		0x00
+#define AIC31XX_DSP_MODE		0x01
+#define AIC31XX_RIGHT_JUSTIFIED_MODE	0x02
+#define AIC31XX_LEFT_JUSTIFIED_MODE	0x03
+#define AIC31XX_IFACE1_MASTER_MASK	0x0C
+#define AIC31XX_BCLK_MASTER		0x08
+#define AIC31XX_WCLK_MASTER		0x04
+
+/* AIC31XX_DATA_OFFSET */
+#define AIC31XX_DATA_OFFSET_MASK	0xFF
+
+/* AIC31XX_IFACE2 */
+#define AIC31XX_BCLKINV_MASK		0x08
+#define AIC31XX_BDIVCLK_MASK		0x03
+#define AIC31XX_DAC2BCLK		0x00
+#define AIC31XX_DACMOD2BCLK		0x01
+#define AIC31XX_ADC2BCLK		0x02
+#define AIC31XX_ADCMOD2BCLK		0x03
+
+/* AIC31XX_ADCFLAG */
+#define AIC31XX_ADCPWRSTATUS_MASK		0x40
+
+/* AIC31XX_DACFLAG1 */
+#define AIC31XX_LDACPWRSTATUS_MASK		0x80
+#define AIC31XX_RDACPWRSTATUS_MASK		0x08
+#define AIC31XX_HPLDRVPWRSTATUS_MASK		0x20
+#define AIC31XX_HPRDRVPWRSTATUS_MASK		0x02
+#define AIC31XX_SPLDRVPWRSTATUS_MASK		0x10
+#define AIC31XX_SPRDRVPWRSTATUS_MASK		0x01
+
+/* AIC31XX_INTRDACFLAG */
+#define AIC31XX_HPSCDETECT_MASK			0x80
+#define AIC31XX_BUTTONPRESS_MASK		0x20
+#define AIC31XX_HSPLUG_MASK			0x10
+#define AIC31XX_LDRCTHRES_MASK			0x08
+#define AIC31XX_RDRCTHRES_MASK			0x04
+#define AIC31XX_DACSINT_MASK			0x02
+#define AIC31XX_DACAINT_MASK			0x01
+
+/* AIC31XX_INT1CTRL */
+#define AIC31XX_HSPLUGDET_MASK			0x80
+#define AIC31XX_BUTTONPRESSDET_MASK		0x40
+#define AIC31XX_DRCTHRES_MASK			0x20
+#define AIC31XX_AGCNOISE_MASK			0x10
+#define AIC31XX_OC_MASK				0x08
+#define AIC31XX_ENGINE_MASK			0x04
+
+/* AIC31XX_DACSETUP */
+#define AIC31XX_SOFTSTEP_MASK			0x03
+
+/* AIC31XX_DACMUTE */
+#define AIC31XX_DACMUTE_MASK			0x0C
+
+/* AIC31XX_MICBIAS */
+#define AIC31XX_MICBIAS_MASK			0x03
+#define AIC31XX_MICBIAS_SHIFT			0
+
+#endif	/* _TLV320AIC31XX_H */
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 2/4] ASoC: davinci-evm: Add AM43xx-EPOS-EVM audio support
  2014-03-04 13:54 [PATCH v2 0/4] AM43xx-ePOS-EVM audio support with TLV320AIC31XX driver Jyri Sarha
@ 2014-03-04 13:54 ` Jyri Sarha
  2014-03-04 14:12   ` Lars-Peter Clausen
       [not found] ` <cover.1393941102.git.jsarha-l0cyMroinI0@public.gmane.org>
  1 sibling, 1 reply; 21+ messages in thread
From: Jyri Sarha @ 2014-03-04 13:54 UTC (permalink / raw)
  To: alsa-devel, devicetree
  Cc: peter.ujfalusi, detheridge, Jyri Sarha, liam.r.girdwood, broonie,
	bcousson

Add machine driver support for AM43xx-ePOS-EVM and update associated
device tree binding document.

Signed-off-by: Jyri Sarha <jsarha@ti.com>
---
 .../bindings/sound/davinci-evm-audio.txt           |    9 +++--
 sound/soc/davinci/davinci-evm.c                    |   41 ++++++++++++++++++++
 2 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
index 865178d..356cba1 100644
--- a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
+++ b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
@@ -2,8 +2,10 @@
 
 Required properties:
 - compatible : "ti,da830-evm-audio" : forDM365/DA8xx/OMAPL1x/AM33xx
+  	     : "ti,am43xx-epos-evm-audio" : for am43xx-epos-evm
 - ti,model : The user-visible name of this sound complex.
-- ti,audio-codec : The phandle of the TLV320AIC3x audio codec
+- ti,audio-codec : The phandle of the TLV320AIC3x audio codec,
+  		   or the TLV320AIC31xx audio codec.
 - ti,mcasp-controller : The phandle of the McASP controller
 - ti,codec-clock-rate : The Codec Clock rate (in Hz) applied to the Codec
 - ti,audio-routing : A list of the connections between audio components.
@@ -14,9 +16,10 @@ Required properties:
   Board connectors:
 
   * Headphone Jack
-  * Line Out
+  * Line Out - "ti,da830-evm-audio" only
   * Mic Jack
-  * Line In
+  * Line In - "ti,da830-evm-audio" only
+  * Speaker - "ti,am43xx-epos-evm-audio" only
 
 
 Example:
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 5e3bc3c..d4d965e 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -128,6 +128,33 @@ static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
 	return 0;
 }
 
+static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_SPK("Speaker", NULL),
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+/* Logic for EVMs with an aic31xx */
+static int evm_aic31xx_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	struct device_node *np = codec->card->dev->of_node;
+	int ret;
+
+	snd_soc_dapm_new_controls(dapm, aic31xx_dapm_widgets,
+				  ARRAY_SIZE(aic31xx_dapm_widgets));
+
+	if (np) {
+		ret = snd_soc_of_parse_audio_routing(codec->card,
+						     "ti,audio-routing");
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
 /* davinci-evm digital audio interface glue - connects codec <--> CPU */
 static struct snd_soc_dai_link dm6446_evm_dai = {
 	.name = "TLV320AIC3X",
@@ -326,11 +353,25 @@ static struct snd_soc_dai_link evm_dai_tlv320aic3x = {
 		   SND_SOC_DAIFMT_IB_NF,
 };
 
+static struct snd_soc_dai_link evm_dai_tlv320aic3111 = {
+	.name		= "TLV320AIC3111",
+	.stream_name	= "AIC3111",
+	.codec_dai_name	= "tlv320aic31xx-hifi",
+	.ops		= &evm_ops,
+	.init		= evm_aic31xx_init,
+	.dai_fmt	= (SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_DSP_B |
+			   SND_SOC_DAIFMT_IB_NF),
+};
+
 static const struct of_device_id davinci_evm_dt_ids[] = {
 	{
 		.compatible = "ti,da830-evm-audio",
 		.data = (void *) &evm_dai_tlv320aic3x,
 	},
+	{
+		.compatible = "ti,am43xx-epos-evm-audio",
+		.data = &evm_dai_tlv320aic3111,
+	},
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, davinci_evm_dt_ids);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 3/4] ASoC: davinci: Add SND_AM43XX_SOC_EPOS_EVM build option
       [not found] ` <cover.1393941102.git.jsarha-l0cyMroinI0@public.gmane.org>
  2014-03-04 13:54   ` [PATCH v2 1/4] ASoC: tlv320aic31xx: Add basic codec driver implementation Jyri Sarha
@ 2014-03-04 13:54   ` Jyri Sarha
  2014-03-04 13:54   ` [PATCH v2 4/4] ASoC: tlv320aic32x4: Sort Makefile in alphabetic order Jyri Sarha
  2 siblings, 0 replies; 21+ messages in thread
From: Jyri Sarha @ 2014-03-04 13:54 UTC (permalink / raw)
  To: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw, devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: broonie-DgEjT+Ai2ygdnm+yROfE0A,
	liam.r.girdwood-VuQAYsv1563Yd54FQh9/CA,
	peter.ujfalusi-l0cyMroinI0, detheridge-l0cyMroinI0,
	bcousson-rdvid1DuHRBWk0Htik3J/w, Jyri Sarha

Add support for am335x and am43x based boards with tlv320aic31xx
compatible codec connected to McASP.

Signed-off-by: Jyri Sarha <jsarha-l0cyMroinI0@public.gmane.org>
---
 sound/soc/davinci/Kconfig  |   12 ++++++++++++
 sound/soc/davinci/Makefile |    1 +
 2 files changed, 13 insertions(+)

diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig
index a8ec1fc..e1e3663 100644
--- a/sound/soc/davinci/Kconfig
+++ b/sound/soc/davinci/Kconfig
@@ -26,6 +26,18 @@ config SND_AM33XX_SOC_EVM
 	  AM335X-EVMSK, and BeagelBone with AudioCape boards have this
 	  setup.
 
+config SND_AM43XX_SOC_EPOS_EVM
+	tristate "SoC Audio for the AM33XX/AM43XX and TLV320AIC31XX based board"
+	depends on SND_DAVINCI_SOC
+	depends on SOC_AM33XX || SOC_AM43XX
+	select SND_SOC_TLV320AIC31XX
+	select SND_DAVINCI_SOC_MCASP
+	help
+	  Say Y or M if you want to add support for SoC audio on
+	  AM335X/AM43XX boards using McASP to connect to a codec of
+	  TLV320AIC31XX series. For example AM43XX-EPOS-EVM has such a
+	  setup.
+
 config SND_DAVINCI_SOC_EVM
 	tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
 	depends on SND_DAVINCI_SOC
diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile
index 744d4d9..d61998f 100644
--- a/sound/soc/davinci/Makefile
+++ b/sound/soc/davinci/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o
 snd-soc-evm-objs := davinci-evm.o
 
 obj-$(CONFIG_SND_DAVINCI_SOC_GENERIC_EVM) += snd-soc-evm.o
+obj-$(CONFIG_SND_AM43XX_SOC_EPOS_EVM) += snd-soc-evm.o
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 4/4] ASoC: tlv320aic32x4: Sort Makefile in alphabetic order
       [not found] ` <cover.1393941102.git.jsarha-l0cyMroinI0@public.gmane.org>
  2014-03-04 13:54   ` [PATCH v2 1/4] ASoC: tlv320aic31xx: Add basic codec driver implementation Jyri Sarha
  2014-03-04 13:54   ` [PATCH v2 3/4] ASoC: davinci: Add SND_AM43XX_SOC_EPOS_EVM build option Jyri Sarha
@ 2014-03-04 13:54   ` Jyri Sarha
       [not found]     ` <80b0f9ecd29b8bfb52fed22a0ca059591f89683d.1393941102.git.jsarha-l0cyMroinI0@public.gmane.org>
  2 siblings, 1 reply; 21+ messages in thread
From: Jyri Sarha @ 2014-03-04 13:54 UTC (permalink / raw)
  To: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw, devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: broonie-DgEjT+Ai2ygdnm+yROfE0A,
	liam.r.girdwood-VuQAYsv1563Yd54FQh9/CA,
	peter.ujfalusi-l0cyMroinI0, detheridge-l0cyMroinI0,
	bcousson-rdvid1DuHRBWk0Htik3J/w, Jyri Sarha

The tlv320aic32x4 related files were wrongly placed after tlv320aic3x files.

Signed-off-by: Jyri Sarha <jsarha-l0cyMroinI0@public.gmane.org>
---
 sound/soc/codecs/Makefile |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 23f8042..ff1775c 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -65,8 +65,8 @@ snd-soc-tas5086-objs := tas5086.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
 snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o
-snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
+snd-soc-tlv320aic3x-objs := tlv320aic3x.o
 snd-soc-tlv320dac33-objs := tlv320dac33.o
 snd-soc-twl4030-objs := twl4030.o
 snd-soc-twl6040-objs := twl6040.o
@@ -196,8 +196,8 @@ obj-$(CONFIG_SND_SOC_TAS5086)	+= snd-soc-tas5086.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)	+= snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)	+= snd-soc-tlv320aic26.o
 obj-$(CONFIG_SND_SOC_TLV320AIC31XX)     += snd-soc-tlv320aic31xx.o
-obj-$(CONFIG_SND_SOC_TLV320AIC3X)	+= snd-soc-tlv320aic3x.o
 obj-$(CONFIG_SND_SOC_TLV320AIC32X4)     += snd-soc-tlv320aic32x4.o
+obj-$(CONFIG_SND_SOC_TLV320AIC3X)	+= snd-soc-tlv320aic3x.o
 obj-$(CONFIG_SND_SOC_TLV320DAC33)	+= snd-soc-tlv320dac33.o
 obj-$(CONFIG_SND_SOC_TWL4030)	+= snd-soc-twl4030.o
 obj-$(CONFIG_SND_SOC_TWL6040)	+= snd-soc-twl6040.o
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 2/4] ASoC: davinci-evm: Add AM43xx-EPOS-EVM audio support
  2014-03-04 13:54 ` [PATCH v2 2/4] ASoC: davinci-evm: Add AM43xx-EPOS-EVM audio support Jyri Sarha
@ 2014-03-04 14:12   ` Lars-Peter Clausen
       [not found]     ` <5315DF41.1090302-Qo5EllUWu/uELgA04lAiVw@public.gmane.org>
  2014-03-04 15:43     ` [PATCH v3] " Jyri Sarha
  0 siblings, 2 replies; 21+ messages in thread
From: Lars-Peter Clausen @ 2014-03-04 14:12 UTC (permalink / raw)
  To: Jyri Sarha
  Cc: devicetree, alsa-devel, liam.r.girdwood, peter.ujfalusi,
	detheridge, broonie, bcousson


> +static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = {
> +	SND_SOC_DAPM_HP("Headphone Jack", NULL),
> +	SND_SOC_DAPM_SPK("Speaker", NULL),
> +	SND_SOC_DAPM_MIC("Mic Jack", NULL),
> +};
> +
> +/* Logic for EVMs with an aic31xx */
> +static int evm_aic31xx_init(struct snd_soc_pcm_runtime *rtd)
> +{
> +	struct snd_soc_codec *codec = rtd->codec;
> +	struct snd_soc_dapm_context *dapm = &codec->dapm;

Machine level DAPM elements should go into the card's DAPM context, not the 
CODEC context. Also use rtd->card to get a pointer to the card instead of 
rtd->codec->card.

> +	struct device_node *np = codec->card->dev->of_node;
> +	int ret;
> +
> +	snd_soc_dapm_new_controls(dapm, aic31xx_dapm_widgets,
> +				  ARRAY_SIZE(aic31xx_dapm_widgets));
> +
> +	if (np) {
> +		ret = snd_soc_of_parse_audio_routing(codec->card,
> +						     "ti,audio-routing");
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [alsa-devel] [PATCH v2 2/4] ASoC: davinci-evm: Add AM43xx-EPOS-EVM audio support
       [not found]     ` <5315DF41.1090302-Qo5EllUWu/uELgA04lAiVw@public.gmane.org>
@ 2014-03-04 15:40       ` Jyri Sarha
  0 siblings, 0 replies; 21+ messages in thread
From: Jyri Sarha @ 2014-03-04 15:40 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA, peter.ujfalusi-l0cyMroinI0,
	detheridge-l0cyMroinI0, liam.r.girdwood-VuQAYsv1563Yd54FQh9/CA,
	broonie-DgEjT+Ai2ygdnm+yROfE0A, bcousson-rdvid1DuHRBWk0Htik3J/w

On 03/04/2014 04:12 PM, Lars-Peter Clausen wrote:
>
>> +static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = {
>> +    SND_SOC_DAPM_HP("Headphone Jack", NULL),
>> +    SND_SOC_DAPM_SPK("Speaker", NULL),
>> +    SND_SOC_DAPM_MIC("Mic Jack", NULL),
>> +};
>> +
>> +/* Logic for EVMs with an aic31xx */
>> +static int evm_aic31xx_init(struct snd_soc_pcm_runtime *rtd)
>> +{
>> +    struct snd_soc_codec *codec = rtd->codec;
>> +    struct snd_soc_dapm_context *dapm = &codec->dapm;
>
> Machine level DAPM elements should go into the card's DAPM context, not
> the CODEC context. Also use rtd->card to get a pointer to the card
> instead of rtd->codec->card.
>

Thanks, I'll fix those.

Best regards,
Jyri
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v3] ASoC: davinci-evm: Add AM43xx-EPOS-EVM audio support
  2014-03-04 14:12   ` Lars-Peter Clausen
       [not found]     ` <5315DF41.1090302-Qo5EllUWu/uELgA04lAiVw@public.gmane.org>
@ 2014-03-04 15:43     ` Jyri Sarha
  2014-03-05  1:42       ` Mark Brown
  1 sibling, 1 reply; 21+ messages in thread
From: Jyri Sarha @ 2014-03-04 15:43 UTC (permalink / raw)
  To: alsa-devel
  Cc: peter.ujfalusi, detheridge, lars, Jyri Sarha, liam.r.girdwood, broonie

Add machine driver support for AM43xx-ePOS-EVM and update associated
device tree binding document.

Signed-off-by: Jyri Sarha <jsarha@ti.com>
---
 .../bindings/sound/davinci-evm-audio.txt           |    9 +++--
 sound/soc/davinci/davinci-evm.c                    |   42 ++++++++++++++++++++
 2 files changed, 48 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
index 865178d..356cba1 100644
--- a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
+++ b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt
@@ -2,8 +2,10 @@
 
 Required properties:
 - compatible : "ti,da830-evm-audio" : forDM365/DA8xx/OMAPL1x/AM33xx
+  	     : "ti,am43xx-epos-evm-audio" : for am43xx-epos-evm
 - ti,model : The user-visible name of this sound complex.
-- ti,audio-codec : The phandle of the TLV320AIC3x audio codec
+- ti,audio-codec : The phandle of the TLV320AIC3x audio codec,
+  		   or the TLV320AIC31xx audio codec.
 - ti,mcasp-controller : The phandle of the McASP controller
 - ti,codec-clock-rate : The Codec Clock rate (in Hz) applied to the Codec
 - ti,audio-routing : A list of the connections between audio components.
@@ -14,9 +16,10 @@ Required properties:
   Board connectors:
 
   * Headphone Jack
-  * Line Out
+  * Line Out - "ti,da830-evm-audio" only
   * Mic Jack
-  * Line In
+  * Line In - "ti,da830-evm-audio" only
+  * Speaker - "ti,am43xx-epos-evm-audio" only
 
 
 Example:
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 5e3bc3c..75a6165 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -128,6 +128,34 @@ static int evm_aic3x_init(struct snd_soc_pcm_runtime *rtd)
 	return 0;
 }
 
+static const struct snd_soc_dapm_widget aic31xx_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_SPK("Speaker", NULL),
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+/* Logic for EVMs with an aic31xx */
+static int evm_aic31xx_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_card *card = rtd->card;
+	struct snd_soc_dapm_context *dapm = &card->dapm;
+	struct device_node *np = card->dev->of_node;
+	int ret;
+
+	snd_soc_dapm_new_controls(dapm, aic31xx_dapm_widgets,
+				  ARRAY_SIZE(aic31xx_dapm_widgets));
+
+	if (np) {
+		ret = snd_soc_of_parse_audio_routing(codec->card,
+						     "ti,audio-routing");
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
 /* davinci-evm digital audio interface glue - connects codec <--> CPU */
 static struct snd_soc_dai_link dm6446_evm_dai = {
 	.name = "TLV320AIC3X",
@@ -326,11 +354,25 @@ static struct snd_soc_dai_link evm_dai_tlv320aic3x = {
 		   SND_SOC_DAIFMT_IB_NF,
 };
 
+static struct snd_soc_dai_link evm_dai_tlv320aic3111 = {
+	.name		= "TLV320AIC3111",
+	.stream_name	= "AIC3111",
+	.codec_dai_name	= "tlv320aic31xx-hifi",
+	.ops		= &evm_ops,
+	.init		= evm_aic31xx_init,
+	.dai_fmt	= (SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_DSP_B |
+			   SND_SOC_DAIFMT_IB_NF),
+};
+
 static const struct of_device_id davinci_evm_dt_ids[] = {
 	{
 		.compatible = "ti,da830-evm-audio",
 		.data = (void *) &evm_dai_tlv320aic3x,
 	},
+	{
+		.compatible = "ti,am43xx-epos-evm-audio",
+		.data = &evm_dai_tlv320aic3111,
+	},
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, davinci_evm_dt_ids);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH v3] ASoC: davinci-evm: Add AM43xx-EPOS-EVM audio support
  2014-03-04 15:43     ` [PATCH v3] " Jyri Sarha
@ 2014-03-05  1:42       ` Mark Brown
  2014-03-07 12:45         ` Jyri Sarha
  0 siblings, 1 reply; 21+ messages in thread
From: Mark Brown @ 2014-03-05  1:42 UTC (permalink / raw)
  To: Jyri Sarha; +Cc: liam.r.girdwood, peter.ujfalusi, alsa-devel, lars, detheridge


[-- Attachment #1.1: Type: text/plain, Size: 1307 bytes --]

On Tue, Mar 04, 2014 at 05:43:51PM +0200, Jyri Sarha wrote:
> Add machine driver support for AM43xx-ePOS-EVM and update associated
> device tree binding document.

Don't send new patches in replies to the middle of threads, that is just
confusing and hard to follow.  Send a new series.

> +/* Logic for EVMs with an aic31xx */
> +static int evm_aic31xx_init(struct snd_soc_pcm_runtime *rtd)
> +{
> +	struct snd_soc_codec *codec = rtd->codec;
> +	struct snd_soc_card *card = rtd->card;
> +	struct snd_soc_dapm_context *dapm = &card->dapm;
> +	struct device_node *np = card->dev->of_node;
> +	int ret;
> +
> +	snd_soc_dapm_new_controls(dapm, aic31xx_dapm_widgets,
> +				  ARRAY_SIZE(aic31xx_dapm_widgets));
> +
> +	if (np) {
> +		ret = snd_soc_of_parse_audio_routing(codec->card,
> +						     "ti,audio-routing");
> +		if (ret)
> +			return ret;
> +	}

Why not add the DAPM widget table to...

> +	{
> +		.compatible = "ti,am43xx-epos-evm-audio",
> +		.data = &evm_dai_tlv320aic3111,
> +	},

...the data here?

Or alternatively should support for the widgets binding that was
recently added by added to the kernel - that way the binding becomes
more general and doesnn't need individual boards adding?  Indeed ideally
the simple-card binding (which that was added for) could just be used
for these boards.

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 1/4] ASoC: tlv320aic31xx: Add basic codec driver implementation
       [not found]     ` <ba9718f573ca9195c80075a15fe114e0d4557da0.1393941102.git.jsarha-l0cyMroinI0@public.gmane.org>
@ 2014-03-05  1:55       ` Mark Brown
       [not found]         ` <20140305015501.GS13126-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
  0 siblings, 1 reply; 21+ messages in thread
From: Mark Brown @ 2014-03-05  1:55 UTC (permalink / raw)
  To: Jyri Sarha
  Cc: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	liam.r.girdwood-VuQAYsv1563Yd54FQh9/CA,
	peter.ujfalusi-l0cyMroinI0, detheridge-l0cyMroinI0,
	bcousson-rdvid1DuHRBWk0Htik3J/w

[-- Attachment #1: Type: text/plain, Size: 1528 bytes --]

On Tue, Mar 04, 2014 at 03:54:49PM +0200, Jyri Sarha wrote:

> +- ai31xx-micbias-vg - MicBias Voltage required.
> +        MICBIAS_OFF - MICBIAS output it not powered

Same comment as last time - why is this something which can be selected
in the binding?

> +        MICBIAS_2_0V - MICBIAS output is powered to 2.0V
> +        MICBIAS_2_5V - MICBIAS output is powered to 2.5V
> +        MICBIAS_AVDD - MICBIAS output is connected to AVDD

The numbers still need to be defined in the binding, the point with the
defines is to make both code and DTs more readable but we need to know
what is actually going to go into the binary.

> +	/* Mic Bias */
> +	SND_SOC_DAPM_SUPPLY("Mic Bias", SND_SOC_NOPM, 0, 0, mic_bias_event,
> +			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),

The idiomatic thing would be to use the pin name.

> +	/* Make ADC turn on when recording even if not mixed from any inputs */
> +	{"ADC", NULL, "Internal ADC Source"},

Don't do this (or the equivalent from the DACs) - we don't do this for
any other drivers, we shouldn't do it for this one.  If we're going to
do something like this it should be generic not per driver hacks.

> +	case SND_SOC_BIAS_STANDBY:
> +		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
> +			aic31xx_set_power(codec, 1);
> +		break;
> +	case SND_SOC_BIAS_OFF:
> +		aic31xx_set_power(codec, 0);
> +		break;

Just inline the set power function, or at the very least split it into
separate on and off functions - there is zero shared code between the
power on and off paths.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 4/4] ASoC: tlv320aic32x4: Sort Makefile in alphabetic order
       [not found]     ` <80b0f9ecd29b8bfb52fed22a0ca059591f89683d.1393941102.git.jsarha-l0cyMroinI0@public.gmane.org>
@ 2014-03-05  3:28       ` Mark Brown
       [not found]         ` <20140305032808.GW13126-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
  0 siblings, 1 reply; 21+ messages in thread
From: Mark Brown @ 2014-03-05  3:28 UTC (permalink / raw)
  To: Jyri Sarha
  Cc: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	liam.r.girdwood-VuQAYsv1563Yd54FQh9/CA,
	peter.ujfalusi-l0cyMroinI0, detheridge-l0cyMroinI0,
	bcousson-rdvid1DuHRBWk0Htik3J/w

[-- Attachment #1: Type: text/plain, Size: 206 bytes --]

On Tue, Mar 04, 2014 at 03:54:52PM +0200, Jyri Sarha wrote:
> The tlv320aic32x4 related files were wrongly placed after tlv320aic3x files.

This doesn't apply against current code, please check and resend.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 4/4] ASoC: tlv320aic32x4: Sort Makefile in alphabetic order
       [not found]         ` <20140305032808.GW13126-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
@ 2014-03-05  7:14           ` Jyri Sarha
  0 siblings, 0 replies; 21+ messages in thread
From: Jyri Sarha @ 2014-03-05  7:14 UTC (permalink / raw)
  To: Mark Brown
  Cc: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	liam.r.girdwood-VuQAYsv1563Yd54FQh9/CA,
	peter.ujfalusi-l0cyMroinI0, detheridge-l0cyMroinI0,
	bcousson-rdvid1DuHRBWk0Htik3J/w

On 03/05/2014 05:28 AM, Mark Brown wrote:
> On Tue, Mar 04, 2014 at 03:54:52PM +0200, Jyri Sarha wrote:
>> The tlv320aic32x4 related files were wrongly placed after tlv320aic3x files.
>
> This doesn't apply against current code, please check and resend.
>

That is because it depends on the first patch in this series. I'll move 
it to first in the next one.

Best regards,
Jyri
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3] ASoC: davinci-evm: Add AM43xx-EPOS-EVM audio support
  2014-03-05  1:42       ` Mark Brown
@ 2014-03-07 12:45         ` Jyri Sarha
  2014-03-09  8:11           ` Mark Brown
  0 siblings, 1 reply; 21+ messages in thread
From: Jyri Sarha @ 2014-03-07 12:45 UTC (permalink / raw)
  To: Mark Brown; +Cc: liam.r.girdwood, peter.ujfalusi, alsa-devel, lars, detheridge

On 03/05/2014 03:42 AM, Mark Brown wrote:
> On Tue, Mar 04, 2014 at 05:43:51PM +0200, Jyri Sarha wrote:
>> Add machine driver support for AM43xx-ePOS-EVM and update associated
>> device tree binding document.
>
> Don't send new patches in replies to the middle of threads, that is just
> confusing and hard to follow.  Send a new series.
>
Ok, won't do that anymore.

>> +/* Logic for EVMs with an aic31xx */
>> +static int evm_aic31xx_init(struct snd_soc_pcm_runtime *rtd)
>> +{
>> +	struct snd_soc_codec *codec = rtd->codec;
>> +	struct snd_soc_card *card = rtd->card;
>> +	struct snd_soc_dapm_context *dapm = &card->dapm;
>> +	struct device_node *np = card->dev->of_node;
>> +	int ret;
>> +
>> +	snd_soc_dapm_new_controls(dapm, aic31xx_dapm_widgets,
>> +				  ARRAY_SIZE(aic31xx_dapm_widgets));
>> +
>> +	if (np) {
>> +		ret = snd_soc_of_parse_audio_routing(codec->card,
>> +						     "ti,audio-routing");
>> +		if (ret)
>> +			return ret;
>> +	}
>
> Why not add the DAPM widget table to...
>
>> +	{
>> +		.compatible = "ti,am43xx-epos-evm-audio",
>> +		.data = &evm_dai_tlv320aic3111,
>> +	},
>
> ...the data here?
>
> Or alternatively should support for the widgets binding that was
> recently added by added to the kernel - that way the binding becomes
> more general and doesnn't need individual boards adding?  Indeed ideally
> the simple-card binding (which that was added for) could just be used
> for these boards.
>

I got am43x-epos-evm audio working on simple-card directly. I guess we 
can forget about this patch.

However, I think there is a problem with simple-card. It does not invert 
bitclock-master and frame-master values when converting them to CB[SM] 
and CF[SM] for cpu_dai as I think it should. I can get around it by 
setting the both cpu-dai and the codec as bclk and frame masters in the 
sound node. I volunteer to fix this if you agree.

Best regards,
Jyri

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 1/4] ASoC: tlv320aic31xx: Add basic codec driver implementation
       [not found]         ` <20140305015501.GS13126-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
@ 2014-03-07 12:53           ` Jyri Sarha
       [not found]             ` <5319C13B.4090101-l0cyMroinI0@public.gmane.org>
  0 siblings, 1 reply; 21+ messages in thread
From: Jyri Sarha @ 2014-03-07 12:53 UTC (permalink / raw)
  To: Mark Brown
  Cc: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	liam.r.girdwood-VuQAYsv1563Yd54FQh9/CA,
	peter.ujfalusi-l0cyMroinI0, detheridge-l0cyMroinI0,
	bcousson-rdvid1DuHRBWk0Htik3J/w

On 03/05/2014 03:55 AM, Mark Brown wrote:
> On Tue, Mar 04, 2014 at 03:54:49PM +0200, Jyri Sarha wrote:
>
>> +- ai31xx-micbias-vg - MicBias Voltage required.
>> +        MICBIAS_OFF - MICBIAS output it not powered
>
> Same comment as last time - why is this something which can be selected
> in the binding?
>

Fixed.

>> +        MICBIAS_2_0V - MICBIAS output is powered to 2.0V
>> +        MICBIAS_2_5V - MICBIAS output is powered to 2.5V
>> +        MICBIAS_AVDD - MICBIAS output is connected to AVDD
>
> The numbers still need to be defined in the binding, the point with the
> defines is to make both code and DTs more readable but we need to know
> what is actually going to go into the binary.
>

Numbers added.

>> +	/* Mic Bias */
>> +	SND_SOC_DAPM_SUPPLY("Mic Bias", SND_SOC_NOPM, 0, 0, mic_bias_event,
>> +			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
>
> The idiomatic thing would be to use the pin name.
>

In this case the mic bias comes out of the chip trough a separate pin 
and it is up to board designer to connect it with any (or all) of the 
three mic pins.

>> +	/* Make ADC turn on when recording even if not mixed from any inputs */
>> +	{"ADC", NULL, "Internal ADC Source"},
>
> Don't do this (or the equivalent from the DACs) - we don't do this for
> any other drivers, we shouldn't do it for this one.  If we're going to
> do something like this it should be generic not per driver hacks.
>

Similar approach is used at least in wm8400.c, wm8990.c, wm8991.c, and 
in ab8500-codec.c. But I see your point. I'll roll back that change. I 
moved the clock enable/disable code to set_bias_level() to avoid 
unwanted behavior (codec clocks not turning on at playback/capture start 
if damp switches are not set correctly).

>> +	case SND_SOC_BIAS_STANDBY:
>> +		if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
>> +			aic31xx_set_power(codec, 1);
>> +		break;
>> +	case SND_SOC_BIAS_OFF:
>> +		aic31xx_set_power(codec, 0);
>> +		break;
>
> Just inline the set power function, or at the very least split it into
> separate on and off functions - there is zero shared code between the
> power on and off paths.
>

After adding the clock enable/disable code to set_bias_level, it started 
to look hairy when everything was inlined. I split the set_power 
function to *_on and *_off functions.

In addition to these, after rebasing on top of linux-next branch, I 
started to use use the new SOC_DOUBLE_R_S_TLV macro for the signed 
integer mixers.

Best regards,
Jyri
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3] ASoC: davinci-evm: Add AM43xx-EPOS-EVM audio support
  2014-03-07 12:45         ` Jyri Sarha
@ 2014-03-09  8:11           ` Mark Brown
  2014-03-10 10:49             ` Jyri Sarha
  0 siblings, 1 reply; 21+ messages in thread
From: Mark Brown @ 2014-03-09  8:11 UTC (permalink / raw)
  To: Jyri Sarha; +Cc: liam.r.girdwood, peter.ujfalusi, alsa-devel, lars, detheridge


[-- Attachment #1.1: Type: text/plain, Size: 606 bytes --]

On Fri, Mar 07, 2014 at 02:45:27PM +0200, Jyri Sarha wrote:

> However, I think there is a problem with simple-card. It does not
> invert bitclock-master and frame-master values when converting them
> to CB[SM] and CF[SM] for cpu_dai as I think it should. I can get
> around it by setting the both cpu-dai and the codec as bclk and
> frame masters in the sound node. I volunteer to fix this if you
> agree.

No, it shouldn't do any inversion.  If inversion is required one of the
drivers is buggy, they are CODEC bit master and CPU bit master so for a
CPU driver the sense should be inverted when parsing.

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 1/4] ASoC: tlv320aic31xx: Add basic codec driver implementation
       [not found]             ` <5319C13B.4090101-l0cyMroinI0@public.gmane.org>
@ 2014-03-09  8:12               ` Mark Brown
       [not found]                 ` <20140309081229.GM28112-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
  0 siblings, 1 reply; 21+ messages in thread
From: Mark Brown @ 2014-03-09  8:12 UTC (permalink / raw)
  To: Jyri Sarha
  Cc: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	liam.r.girdwood-VuQAYsv1563Yd54FQh9/CA,
	peter.ujfalusi-l0cyMroinI0, detheridge-l0cyMroinI0,
	bcousson-rdvid1DuHRBWk0Htik3J/w

[-- Attachment #1: Type: text/plain, Size: 609 bytes --]

On Fri, Mar 07, 2014 at 02:53:15PM +0200, Jyri Sarha wrote:
> On 03/05/2014 03:55 AM, Mark Brown wrote:

> >>+	/* Mic Bias */
> >>+	SND_SOC_DAPM_SUPPLY("Mic Bias", SND_SOC_NOPM, 0, 0, mic_bias_event,
> >>+			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),

> >The idiomatic thing would be to use the pin name.

> In this case the mic bias comes out of the chip trough a separate
> pin and it is up to board designer to connect it with any (or all)
> of the three mic pins.

Yes, exactly - you should be using the name of the pin that supplies the
bias.  This is how essentially all microphone biases work.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 1/4] ASoC: tlv320aic31xx: Add basic codec driver implementation
       [not found]                 ` <20140309081229.GM28112-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
@ 2014-03-10  8:47                   ` Jyri Sarha
  0 siblings, 0 replies; 21+ messages in thread
From: Jyri Sarha @ 2014-03-10  8:47 UTC (permalink / raw)
  To: Mark Brown
  Cc: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	liam.r.girdwood-VuQAYsv1563Yd54FQh9/CA,
	peter.ujfalusi-l0cyMroinI0, detheridge-l0cyMroinI0,
	bcousson-rdvid1DuHRBWk0Htik3J/w

On 03/09/2014 10:12 AM, Mark Brown wrote:
> On Fri, Mar 07, 2014 at 02:53:15PM +0200, Jyri Sarha wrote:
>> On 03/05/2014 03:55 AM, Mark Brown wrote:
>
>>>> +	/* Mic Bias */
>>>> +	SND_SOC_DAPM_SUPPLY("Mic Bias", SND_SOC_NOPM, 0, 0, mic_bias_event,
>>>> +			    SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
>
>>> The idiomatic thing would be to use the pin name.
>
>> In this case the mic bias comes out of the chip trough a separate
>> pin and it is up to board designer to connect it with any (or all)
>> of the three mic pins.
>
> Yes, exactly - you should be using the name of the pin that supplies the
> bias.  This is how essentially all microphone biases work.
>

Changed widget name from "Mic Bias" to "MICBIAS".

BR,
Jyri
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3] ASoC: davinci-evm: Add AM43xx-EPOS-EVM audio support
  2014-03-09  8:11           ` Mark Brown
@ 2014-03-10 10:49             ` Jyri Sarha
  2014-03-10 11:09               ` Mark Brown
  0 siblings, 1 reply; 21+ messages in thread
From: Jyri Sarha @ 2014-03-10 10:49 UTC (permalink / raw)
  To: Mark Brown; +Cc: liam.r.girdwood, peter.ujfalusi, alsa-devel, lars, detheridge

On 03/09/2014 10:11 AM, Mark Brown wrote:
> On Fri, Mar 07, 2014 at 02:45:27PM +0200, Jyri Sarha wrote:
>
>> >However, I think there is a problem with simple-card. It does not
>> >invert bitclock-master and frame-master values when converting them
>> >to CB[SM] and CF[SM] for cpu_dai as I think it should. I can get
>> >around it by setting the both cpu-dai and the codec as bclk and
>> >frame masters in the sound node. I volunteer to fix this if you
>> >agree.
> No, it shouldn't do any inversion.  If inversion is required one of the
> drivers is buggy, they are CODEC bit master and CPU bit master so for a
> CPU driver the sense should be inverted when parsing.

Yes, that is the problem. The same code in simple-card parses the codec 
node and cpu-dai node and they produce the same SND_SOC_DAIFMT_C??_C?? 
flags for both codec and cpu-dai drivers.

For example:

	simple-audio-card,cpu {
		sound-dai = <&mcasp1>;
	};

causes SND_SOC_DAIFMT_CBS_CFS flags to be set to mcasp driver in 
set_dai_fmt() call. So omitting the bitclock-master and frame-master 
parameters from cpu-dai node strangely indicates that the cpu-dai should 
be the bitclock and frame master. Can this be right?

If you do not want to have the inversion, could we at least call the 
parameters codec-bitclock-master and codec-frame-master.

Best regards,
Jyri

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3] ASoC: davinci-evm: Add AM43xx-EPOS-EVM audio support
  2014-03-10 10:49             ` Jyri Sarha
@ 2014-03-10 11:09               ` Mark Brown
  2014-03-10 11:31                 ` Peter Ujfalusi
  0 siblings, 1 reply; 21+ messages in thread
From: Mark Brown @ 2014-03-10 11:09 UTC (permalink / raw)
  To: Jyri Sarha; +Cc: liam.r.girdwood, peter.ujfalusi, alsa-devel, lars, detheridge


[-- Attachment #1.1: Type: text/plain, Size: 661 bytes --]

On Mon, Mar 10, 2014 at 12:49:56PM +0200, Jyri Sarha wrote:
> On 03/09/2014 10:11 AM, Mark Brown wrote:

> >No, it shouldn't do any inversion.  If inversion is required one of the
> >drivers is buggy, they are CODEC bit master and CPU bit master so for a
> >CPU driver the sense should be inverted when parsing.

> Yes, that is the problem. The same code in simple-card parses the
> codec node and cpu-dai node and they produce the same
> SND_SOC_DAIFMT_C??_C?? flags for both codec and cpu-dai drivers.

Sorry, thinko above - the master flags are specified in terms of the
CODEC.  Anything interpreting them that isn't a CODEC needs to be
inverting the sense.

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3] ASoC: davinci-evm: Add AM43xx-EPOS-EVM audio support
  2014-03-10 11:09               ` Mark Brown
@ 2014-03-10 11:31                 ` Peter Ujfalusi
  2014-03-10 11:57                   ` Mark Brown
  0 siblings, 1 reply; 21+ messages in thread
From: Peter Ujfalusi @ 2014-03-10 11:31 UTC (permalink / raw)
  To: Mark Brown, Jyri Sarha; +Cc: liam.r.girdwood, detheridge, alsa-devel, lars

On 03/10/2014 01:09 PM, Mark Brown wrote:
> On Mon, Mar 10, 2014 at 12:49:56PM +0200, Jyri Sarha wrote:
>> On 03/09/2014 10:11 AM, Mark Brown wrote:
> 
>>> No, it shouldn't do any inversion.  If inversion is required one of the
>>> drivers is buggy, they are CODEC bit master and CPU bit master so for a
>>> CPU driver the sense should be inverted when parsing.
> 
>> Yes, that is the problem. The same code in simple-card parses the
>> codec node and cpu-dai node and they produce the same
>> SND_SOC_DAIFMT_C??_C?? flags for both codec and cpu-dai drivers.
> 
> Sorry, thinko above - the master flags are specified in terms of the
> CODEC.  Anything interpreting them that isn't a CODEC needs to be
> inverting the sense.

Exactly, CBM_CFM means that the codec is the master of both clocks. Codec is
configured as master and the cpu side is configured as slave.

But the issue is that with simple card (when you want to have the codec as
master for both clocks):

simple-audio-card,codec {
	sound-dai = <&aic3106>;
	bitclock-master;
	frame-master;
};

simple-audio-card,cpu {
	sound-dai = <&mcasp1 0>;
};


The codec will get CBM_CFM, however the cpu_dai will end up having CBS_CFS
(since *-master is not specified in the dts).

So when the simple card parses the master/slave configuration it has to invert
the cpu_dai settings it got back from snd_soc_of_parse_daifmt() to get it right.

Since:

simple-audio-card,codec {
	sound-dai = <&aic3106>;
};

simple-audio-card,cpu {
	sound-dai = <&mcasp1 0>;
	bitclock-master;
	frame-master;
};


Will end up as: codec is CBS_CFS and cpu_dai as CBM_CFM which means that both
cpu and codec is supposed to be slave...

-- 
Péter

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v3] ASoC: davinci-evm: Add AM43xx-EPOS-EVM audio support
  2014-03-10 11:31                 ` Peter Ujfalusi
@ 2014-03-10 11:57                   ` Mark Brown
  0 siblings, 0 replies; 21+ messages in thread
From: Mark Brown @ 2014-03-10 11:57 UTC (permalink / raw)
  To: Peter Ujfalusi; +Cc: liam.r.girdwood, detheridge, alsa-devel, lars, Jyri Sarha


[-- Attachment #1.1: Type: text/plain, Size: 1341 bytes --]

On Mon, Mar 10, 2014 at 01:31:15PM +0200, Peter Ujfalusi wrote:

> Exactly, CBM_CFM means that the codec is the master of both clocks. Codec is
> configured as master and the cpu side is configured as slave.

> But the issue is that with simple card (when you want to have the codec as
> master for both clocks):

> simple-audio-card,codec {
> 	sound-dai = <&aic3106>;
> 	bitclock-master;
> 	frame-master;
> };

> simple-audio-card,cpu {
> 	sound-dai = <&mcasp1 0>;
> };

> The codec will get CBM_CFM, however the cpu_dai will end up having CBS_CFS
> (since *-master is not specified in the dts).

What I would expect the code to be doing here is coming up with the same
setting for both ends of the link rather than trying to parse the two
ends of the link independently - though that *is* more flexible it's
unlikely to actually work in a system.  The properties on each end of
the link aren't independent of each other.

> So when the simple card parses the master/slave configuration it has to invert
> the cpu_dai settings it got back from snd_soc_of_parse_daifmt() to get it right.

Or there should just be one unified parse.  When reading Jiri's mail the
lack of any reference to the code it really sounded like he was asking
for the result of a single parse to inverted between passing to the
CODEC and CPU sides.

Needs looking at.

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2014-03-10 11:57 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-03-04 13:54 [PATCH v2 0/4] AM43xx-ePOS-EVM audio support with TLV320AIC31XX driver Jyri Sarha
2014-03-04 13:54 ` [PATCH v2 2/4] ASoC: davinci-evm: Add AM43xx-EPOS-EVM audio support Jyri Sarha
2014-03-04 14:12   ` Lars-Peter Clausen
     [not found]     ` <5315DF41.1090302-Qo5EllUWu/uELgA04lAiVw@public.gmane.org>
2014-03-04 15:40       ` [alsa-devel] " Jyri Sarha
2014-03-04 15:43     ` [PATCH v3] " Jyri Sarha
2014-03-05  1:42       ` Mark Brown
2014-03-07 12:45         ` Jyri Sarha
2014-03-09  8:11           ` Mark Brown
2014-03-10 10:49             ` Jyri Sarha
2014-03-10 11:09               ` Mark Brown
2014-03-10 11:31                 ` Peter Ujfalusi
2014-03-10 11:57                   ` Mark Brown
     [not found] ` <cover.1393941102.git.jsarha-l0cyMroinI0@public.gmane.org>
2014-03-04 13:54   ` [PATCH v2 1/4] ASoC: tlv320aic31xx: Add basic codec driver implementation Jyri Sarha
     [not found]     ` <ba9718f573ca9195c80075a15fe114e0d4557da0.1393941102.git.jsarha-l0cyMroinI0@public.gmane.org>
2014-03-05  1:55       ` Mark Brown
     [not found]         ` <20140305015501.GS13126-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2014-03-07 12:53           ` Jyri Sarha
     [not found]             ` <5319C13B.4090101-l0cyMroinI0@public.gmane.org>
2014-03-09  8:12               ` Mark Brown
     [not found]                 ` <20140309081229.GM28112-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2014-03-10  8:47                   ` Jyri Sarha
2014-03-04 13:54   ` [PATCH v2 3/4] ASoC: davinci: Add SND_AM43XX_SOC_EPOS_EVM build option Jyri Sarha
2014-03-04 13:54   ` [PATCH v2 4/4] ASoC: tlv320aic32x4: Sort Makefile in alphabetic order Jyri Sarha
     [not found]     ` <80b0f9ecd29b8bfb52fed22a0ca059591f89683d.1393941102.git.jsarha-l0cyMroinI0@public.gmane.org>
2014-03-05  3:28       ` Mark Brown
     [not found]         ` <20140305032808.GW13126-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2014-03-05  7:14           ` Jyri Sarha

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).