All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 1/3] ASoC: zx-96p22: add documentation for zte's aud96p22  controller
@ 2017-02-15 10:55 ` Baoyou Xie
  0 siblings, 0 replies; 22+ messages in thread
From: Baoyou Xie @ 2017-02-15 10:55 UTC (permalink / raw)
  To: jun.nie, lgirdwood, broonie, robh+dt, mark.rutland, perex, tiwai,
	lars, arnd, kuninori.morimoto.gx, ckeepax, bardliao, nh6z,
	Paul.Handrigan, oder_chiou, axel.lin, petr, yesanishhere,
	srinivas.kandagatla
  Cc: linux-arm-kernel, alsa-devel, devicetree, linux-kernel, shawnguo,
	baoyou.xie, xie.baoyou, chen.chaokai, wang.qiang01

This patch adds dt-binding documentation for zte's aud96p22 controller.

Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
---
 .../devicetree/bindings/sound/zte,zx-96p22.txt     | 24 ++++++++++++++++++++++
 1 file changed, 24 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/zte,zx-96p22.txt

diff --git a/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt b/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
new file mode 100644
index 0000000..4184566
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
@@ -0,0 +1,24 @@
+ZTE zx96p22 controller
+
+Required properties:
+ - compatible : Must be "zte,zx-aud96p22"
+ - #sound-dai-cells: Should be 0
+ - reg : Offset of I2C register for zx96p22
+
+Example:
+
+	audio_i2c0: audio_i2c0@1486000 {
+		compatible = "zte,zx296718-i2c";
+		reg = <0x01486000 0x1000>;
+		interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clocks = <&audiocrm AUDIO_I2C0_WCLK>;
+		clock-frequency = <1600000>;
+		status = "ok";
+		inner_codec: aud96p22@22 {
+			compatible = "zte,zx-aud96p22";
+			#sound-dai-cells = <0>;
+			reg = <0x22>;
+		};
+	};
-- 
2.7.4

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

* [PATCH v1 1/3] ASoC: zx-96p22: add documentation for zte's aud96p22  controller
@ 2017-02-15 10:55 ` Baoyou Xie
  0 siblings, 0 replies; 22+ messages in thread
From: Baoyou Xie @ 2017-02-15 10:55 UTC (permalink / raw)
  To: jun.nie-QSEj5FYQhm4dnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	broonie-DgEjT+Ai2ygdnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	lars-Qo5EllUWu/uELgA04lAiVw, arnd-r2nGTMty4D4,
	kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	bardliao-Rasf1IRRPZFBDgjK7y7TUQ, nh6z-fFIq/eER6g8,
	Paul.Handrigan-jGc1dHjMKG3QT0dZR+AlfA,
	oder_chiou-Rasf1IRRPZFBDgjK7y7TUQ,
	axel.lin-8E1dMatC8ynQT0dZR+AlfA, petr-Qh/3xLP0EvwAvxtiuMwx3w,
	yesanishhere-Re5JQEeQqe8AvxtiuMwx3w,
	srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	shawnguo-DgEjT+Ai2ygdnm+yROfE0A,
	baoyou.xie-QSEj5FYQhm4dnm+yROfE0A,
	xie.baoyou-Th6q7B73Y6EnDS1+zs4M5A,
	chen.chaokai-Th6q7B73Y6EnDS1+zs4M5A,
	wang.qiang01-Th6q7B73Y6EnDS1+zs4M5A

This patch adds dt-binding documentation for zte's aud96p22 controller.

Signed-off-by: Baoyou Xie <baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
 .../devicetree/bindings/sound/zte,zx-96p22.txt     | 24 ++++++++++++++++++++++
 1 file changed, 24 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/zte,zx-96p22.txt

diff --git a/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt b/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
new file mode 100644
index 0000000..4184566
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
@@ -0,0 +1,24 @@
+ZTE zx96p22 controller
+
+Required properties:
+ - compatible : Must be "zte,zx-aud96p22"
+ - #sound-dai-cells: Should be 0
+ - reg : Offset of I2C register for zx96p22
+
+Example:
+
+	audio_i2c0: audio_i2c0@1486000 {
+		compatible = "zte,zx296718-i2c";
+		reg = <0x01486000 0x1000>;
+		interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clocks = <&audiocrm AUDIO_I2C0_WCLK>;
+		clock-frequency = <1600000>;
+		status = "ok";
+		inner_codec: aud96p22@22 {
+			compatible = "zte,zx-aud96p22";
+			#sound-dai-cells = <0>;
+			reg = <0x22>;
+		};
+	};
-- 
2.7.4

--
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] 22+ messages in thread

* [PATCH v1 1/3] ASoC: zx-96p22: add documentation for zte's aud96p22 controller
@ 2017-02-15 10:55 ` Baoyou Xie
  0 siblings, 0 replies; 22+ messages in thread
From: Baoyou Xie @ 2017-02-15 10:55 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds dt-binding documentation for zte's aud96p22 controller.

Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
---
 .../devicetree/bindings/sound/zte,zx-96p22.txt     | 24 ++++++++++++++++++++++
 1 file changed, 24 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/zte,zx-96p22.txt

diff --git a/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt b/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
new file mode 100644
index 0000000..4184566
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
@@ -0,0 +1,24 @@
+ZTE zx96p22 controller
+
+Required properties:
+ - compatible : Must be "zte,zx-aud96p22"
+ - #sound-dai-cells: Should be 0
+ - reg : Offset of I2C register for zx96p22
+
+Example:
+
+	audio_i2c0: audio_i2c0 at 1486000 {
+		compatible = "zte,zx296718-i2c";
+		reg = <0x01486000 0x1000>;
+		interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		clocks = <&audiocrm AUDIO_I2C0_WCLK>;
+		clock-frequency = <1600000>;
+		status = "ok";
+		inner_codec: aud96p22 at 22 {
+			compatible = "zte,zx-aud96p22";
+			#sound-dai-cells = <0>;
+			reg = <0x22>;
+		};
+	};
-- 
2.7.4

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

* [PATCH v1 2/3] MAINTAINERS: add zte 96p22 controller driver to ARM  ZTE  architecture
@ 2017-02-15 10:55   ` Baoyou Xie
  0 siblings, 0 replies; 22+ messages in thread
From: Baoyou Xie @ 2017-02-15 10:55 UTC (permalink / raw)
  To: jun.nie, lgirdwood, broonie, robh+dt, mark.rutland, perex, tiwai,
	lars, arnd, kuninori.morimoto.gx, ckeepax, bardliao, nh6z,
	Paul.Handrigan, oder_chiou, axel.lin, petr, yesanishhere,
	srinivas.kandagatla
  Cc: linux-arm-kernel, alsa-devel, devicetree, linux-kernel, shawnguo,
	baoyou.xie, xie.baoyou, chen.chaokai, wang.qiang01

Add the zte 96p22 controller driver as maintained by ARM ZTE
architecture maintainers, as they're parts of the core IP.

Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
---
 MAINTAINERS | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index e63063b..8146377 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1991,7 +1991,9 @@ F:	drivers/soc/zte/
 F:	Documentation/devicetree/bindings/arm/zte.txt
 F:	Documentation/devicetree/bindings/clock/zx296702-clk.txt
 F:	Documentation/devicetree/bindings/soc/zte/
+F:	Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
 F:	include/dt-bindings/soc/zx*.h
+F:	sound/soc/codecs/zx_aud96p22.c
 
 ARM/ZYNQ ARCHITECTURE
 M:	Michal Simek <michal.simek@xilinx.com>
-- 
2.7.4

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

* [PATCH v1 2/3] MAINTAINERS: add zte 96p22 controller driver to ARM  ZTE  architecture
@ 2017-02-15 10:55   ` Baoyou Xie
  0 siblings, 0 replies; 22+ messages in thread
From: Baoyou Xie @ 2017-02-15 10:55 UTC (permalink / raw)
  To: jun.nie-QSEj5FYQhm4dnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	broonie-DgEjT+Ai2ygdnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	lars-Qo5EllUWu/uELgA04lAiVw, arnd-r2nGTMty4D4,
	kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	bardliao-Rasf1IRRPZFBDgjK7y7TUQ, nh6z-fFIq/eER6g8,
	Paul.Handrigan-jGc1dHjMKG3QT0dZR+AlfA,
	oder_chiou-Rasf1IRRPZFBDgjK7y7TUQ,
	axel.lin-8E1dMatC8ynQT0dZR+AlfA, petr-Qh/3xLP0EvwAvxtiuMwx3w,
	yesanishhere-Re5JQEeQqe8AvxtiuMwx3w,
	srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	shawnguo-DgEjT+Ai2ygdnm+yROfE0A,
	baoyou.xie-QSEj5FYQhm4dnm+yROfE0A,
	xie.baoyou-Th6q7B73Y6EnDS1+zs4M5A,
	chen.chaokai-Th6q7B73Y6EnDS1+zs4M5A,
	wang.qiang01-Th6q7B73Y6EnDS1+zs4M5A

Add the zte 96p22 controller driver as maintained by ARM ZTE
architecture maintainers, as they're parts of the core IP.

Signed-off-by: Baoyou Xie <baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
 MAINTAINERS | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index e63063b..8146377 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1991,7 +1991,9 @@ F:	drivers/soc/zte/
 F:	Documentation/devicetree/bindings/arm/zte.txt
 F:	Documentation/devicetree/bindings/clock/zx296702-clk.txt
 F:	Documentation/devicetree/bindings/soc/zte/
+F:	Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
 F:	include/dt-bindings/soc/zx*.h
+F:	sound/soc/codecs/zx_aud96p22.c
 
 ARM/ZYNQ ARCHITECTURE
 M:	Michal Simek <michal.simek-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org>
-- 
2.7.4

--
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] 22+ messages in thread

* [PATCH v1 2/3] MAINTAINERS: add zte 96p22 controller driver to ARM ZTE architecture
@ 2017-02-15 10:55   ` Baoyou Xie
  0 siblings, 0 replies; 22+ messages in thread
From: Baoyou Xie @ 2017-02-15 10:55 UTC (permalink / raw)
  To: linux-arm-kernel

Add the zte 96p22 controller driver as maintained by ARM ZTE
architecture maintainers, as they're parts of the core IP.

Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
---
 MAINTAINERS | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index e63063b..8146377 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1991,7 +1991,9 @@ F:	drivers/soc/zte/
 F:	Documentation/devicetree/bindings/arm/zte.txt
 F:	Documentation/devicetree/bindings/clock/zx296702-clk.txt
 F:	Documentation/devicetree/bindings/soc/zte/
+F:	Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
 F:	include/dt-bindings/soc/zx*.h
+F:	sound/soc/codecs/zx_aud96p22.c
 
 ARM/ZYNQ ARCHITECTURE
 M:	Michal Simek <michal.simek@xilinx.com>
-- 
2.7.4

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

* [PATCH v1 3/3] ASoC: zx-96p22: add zte's aud96p22 controller driver
@ 2017-02-15 10:55   ` Baoyou Xie
  0 siblings, 0 replies; 22+ messages in thread
From: Baoyou Xie @ 2017-02-15 10:55 UTC (permalink / raw)
  To: jun.nie, lgirdwood, broonie, robh+dt, mark.rutland, perex, tiwai,
	lars, arnd, kuninori.morimoto.gx, ckeepax, bardliao, nh6z,
	Paul.Handrigan, oder_chiou, axel.lin, petr, yesanishhere,
	srinivas.kandagatla
  Cc: linux-arm-kernel, alsa-devel, devicetree, linux-kernel, shawnguo,
	baoyou.xie, xie.baoyou, chen.chaokai, wang.qiang01

This patch adds aud96p22 controller driver for zte's SoC family.

Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
---
 sound/soc/codecs/Kconfig       |   4 +
 sound/soc/codecs/Makefile      |   2 +
 sound/soc/codecs/zx_aud96p22.c | 588 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 594 insertions(+)
 create mode 100644 sound/soc/codecs/zx_aud96p22.c

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index cfc108e..120af32 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -1116,4 +1116,8 @@ config SND_SOC_TPA6130A2
 	tristate "Texas Instruments TPA6130A2 headphone amplifier"
 	depends on I2C
 
+config SND_SOC_ZX96P22
+	tristate "ZTE Inner AUD96P22 CODEC"
+	depends on I2C
+
 endmenu
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 2624c73..dbc3818 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -219,6 +219,7 @@ snd-soc-wm9705-objs := wm9705.o
 snd-soc-wm9712-objs := wm9712.o
 snd-soc-wm9713-objs := wm9713.o
 snd-soc-wm-hubs-objs := wm_hubs.o
+snd-soc-zx96p22-objs := zx_aud96p22.o
 # Amp
 snd-soc-max9877-objs := max9877.o
 snd-soc-max98504-objs := max98504.o
@@ -444,6 +445,7 @@ obj-$(CONFIG_SND_SOC_WM9712)	+= snd-soc-wm9712.o
 obj-$(CONFIG_SND_SOC_WM9713)	+= snd-soc-wm9713.o
 obj-$(CONFIG_SND_SOC_WM_ADSP)	+= snd-soc-wm-adsp.o
 obj-$(CONFIG_SND_SOC_WM_HUBS)	+= snd-soc-wm-hubs.o
+obj-$(CONFIG_SND_SOC_ZX96P22)	+= snd-soc-zx96p22.o
 
 # Amp
 obj-$(CONFIG_SND_SOC_MAX9877)	+= snd-soc-max9877.o
diff --git a/sound/soc/codecs/zx_aud96p22.c b/sound/soc/codecs/zx_aud96p22.c
new file mode 100644
index 0000000..f2979df
--- /dev/null
+++ b/sound/soc/codecs/zx_aud96p22.c
@@ -0,0 +1,588 @@
+/*
+ * ZTE's audio 96p22 driver
+ *
+ * Copyright (C) 2017 ZTE Ltd
+ *
+ * Author: Baoyou Xie <baoyou.xie@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/pcm.h>
+
+#define BGPIO64				(64)
+#define snd_kcontrol_dev(kcontrol)	\
+		((struct device *)((kcontrol)->private_value))
+
+struct i2c_reg {
+	unsigned char addr;
+	unsigned char high_data;
+	unsigned char low_data;
+};
+
+struct zx_aud96p22_info {
+	struct device   *dev;
+	int gpio;
+	bool capture;
+};
+
+static struct i2c_reg i2c_dac_master_volume_table[] = {
+	{ 0x34, 0xe7, 0xe7 },
+};
+
+static struct i2c_reg i2c_adc_master_volume_table[] = {
+	{ 0x24, 0xbf, 0xbf },
+};
+
+static struct i2c_reg i2c_dac_headset_volume_table[] = {
+	{ 0x38, 0x0d, 0x0d },
+};
+
+static struct i2c_reg i2c_dac_sleep_table[] = {
+	{ 0x18, 0x00, 0x00 }, //play power down
+};
+
+static struct i2c_reg i2c_dac_wakeup_table[] = {
+	{ 0x18, 0x00, 0xff }, //play power up
+};
+
+static struct i2c_reg i2c_adc_sleep_table[] = {
+	{ 0x16, 0x00, 0x00 }, //record power down
+};
+
+static struct i2c_reg i2c_adc_wakeup_table[] = {
+	{ 0x16, 0x00, 0x0f }, //record power up
+};
+
+static struct i2c_reg i2c_codec_start_table[] = {
+	{ 0x15, 0x00, 0x00 }, //power down control
+	{ 0x47, 0x00, 0x00 }, //record path slect
+	{ 0x24, 0xbf, 0xbf }, //record volume control
+	{ 0x26, 0x30, 0x30 }, //record pga volume control
+	{ 0xc8, 0x00, 0x00 }, //ALC control
+	{ 0xce, 0x00, 0xf5 }, //record noise gate
+	{ 0xf3, 0x00, 0xc0 }, //dac noise dithe
+	{ 0xcd, 0x00, 0x20 }, //max record volume
+	{ 0x15, 0x00, 0x01 }, //power down control
+	{ 0x18, 0x00, 0xff }, //play power  control
+	{ 0x16, 0x00, 0x0f }, //record power up
+	{ 0x19, 0x00, 0x04 }, //power down control
+	{ 0x02, 0x00, 0x05 }, //ext clock slect
+	{ 0x01, 0x00, 0x05 }, //ext clock slect
+	{ 0x00, 0x00, 0x00 }, //adc dpz reset
+	{ 0x00, 0x00, 0x03 }, //dac dpz reset
+	{ 0x04, 0x00, 0x40 }, //clk div
+	{ 0x05, 0x00, 0x04 }, //clk div0x4
+	{ 0x06, 0x00, 0x40 }, //clk div
+	{ 0x07, 0x00, 0x04 }, //clk div 0x4
+	{ 0x03, 0x00, 0x01 }, //slave 16bit i2s
+	{ 0x00, 0x00, 0x00 }, //adc dpz reset
+	{ 0x00, 0x00, 0x03 }, //dac dpz reset
+};
+
+static int zx_aud96p22_i2c_write(struct i2c_client *i2c_client,
+				 const void *data, size_t count)
+{
+	int xfer;
+
+	xfer = i2c_master_send(i2c_client, data, count);
+	if (xfer == count)
+		return 0;
+	else if (xfer < 0)
+		return xfer;
+	else
+		return -EIO;
+}
+
+static int zx_aud96p22_i2c_read(struct i2c_client *i2c_client,
+				unsigned char addr)
+{
+	int xfer;
+
+	xfer = i2c_smbus_read_word_data(i2c_client, addr);
+	if (xfer < 0)
+		dev_warn(&i2c_client->dev, "transfer error %d\n", xfer);
+
+	return xfer;
+}
+
+static int zx_aud96p22_i2c_update(struct i2c_client *i2c_client,
+			const struct i2c_reg *tbl, unsigned int tbl_size)
+{
+	int xfer;
+	unsigned int i = 0;
+	unsigned char buf[3];
+
+	for (i = 0; i < tbl_size; i++) {
+		buf[0] = tbl[i].addr;
+		buf[1] = tbl[i].low_data;
+		buf[2] = tbl[i].high_data;
+
+		xfer = zx_aud96p22_i2c_write(i2c_client, buf, ARRAY_SIZE(buf));
+		if (xfer < 0) {
+			dev_err(&i2c_client->dev, "write error %d\n", xfer);
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+static void
+zx_aud96p22_i2c_dac_amp_run_enable(struct i2c_client *i2c_client, bool on)
+{
+	int ret = 0;
+
+	ret = gpio_request(BGPIO64, "dac");
+	if (ret) {
+		dev_err(&i2c_client->dev, "request gpio BGPIO64 failed %d\n",
+			ret);
+		return;
+	}
+
+	/*
+	 * write 1 to gpio 64 to set MUTE_CTL for enable play.
+	 * otherwise disable it.
+	 */
+	if (on)
+		gpiod_direction_output(gpio_to_desc(BGPIO64), 1);
+	else
+		gpiod_direction_output(gpio_to_desc(BGPIO64), 0);
+
+	gpio_free(BGPIO64);
+}
+
+static void
+zx_aud96p22_i2c_dac_sleep_enable(struct i2c_client *i2c_client, bool on)
+{
+	if (on)
+		zx_aud96p22_i2c_update(i2c_client, i2c_dac_sleep_table,
+			ARRAY_SIZE(i2c_dac_sleep_table));
+	else
+		zx_aud96p22_i2c_update(i2c_client, i2c_dac_wakeup_table,
+			ARRAY_SIZE(i2c_dac_wakeup_table));
+}
+
+static void
+zx_aud96p22_i2c_adc_sleep_enable(struct i2c_client *i2c_client, bool on)
+{
+	if (on)
+		zx_aud96p22_i2c_update(i2c_client, i2c_adc_sleep_table,
+			ARRAY_SIZE(i2c_adc_sleep_table));
+	else
+		zx_aud96p22_i2c_update(i2c_client, i2c_adc_wakeup_table,
+			ARRAY_SIZE(i2c_adc_wakeup_table));
+}
+
+static void
+zx_aud96p22_i2c_codec_run_enable(struct i2c_client *i2c_client)
+{
+	zx_aud96p22_i2c_update(i2c_client, i2c_codec_start_table,
+			ARRAY_SIZE(i2c_codec_start_table));
+}
+
+static int zx_aud96p22_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *socdai)
+{
+	struct device *dev = socdai->dev;
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	struct zx_aud96p22_info *zx_aud96p22 = dev_get_drvdata(socdai->dev);
+	bool capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+	zx_aud96p22->capture = capture;
+	snd_soc_dai_set_drvdata(socdai, zx_aud96p22);
+
+	zx_aud96p22_i2c_adc_sleep_enable(i2c_client, false);
+	if (!capture)
+		zx_aud96p22_i2c_dac_amp_run_enable(i2c_client, true);
+
+	return 0;
+}
+
+static int zx_aud96p22_startup(struct snd_pcm_substream *substream,
+			struct snd_soc_dai *dai)
+{
+	struct device *dev = dai->dev;
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	bool capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+	zx_aud96p22_i2c_dac_sleep_enable(i2c_client, false);
+	if (!capture)
+		zx_aud96p22_i2c_dac_amp_run_enable(i2c_client, true);
+
+	return 0;
+}
+
+static void zx_aud96p22_shutdown(struct snd_pcm_substream *substream,
+			struct snd_soc_dai *dai)
+{
+	struct device *dev = dai->dev;
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	bool capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+	zx_aud96p22_i2c_dac_sleep_enable(i2c_client, true);
+	if (!capture)
+		zx_aud96p22_i2c_dac_amp_run_enable(i2c_client, false);
+}
+
+static int
+zx_aud96p22_i2c_read_regs(struct i2c_client *i2c_client,
+			struct i2c_reg *tbl, unsigned int tbl_size)
+{
+	int xfer = 0;
+	unsigned int i;
+
+	for (i = 0; i < tbl_size; i++) {
+		xfer = zx_aud96p22_i2c_read(i2c_client, tbl[i].addr);
+		if (xfer < 0) {
+			dev_err(&i2c_client->dev,
+				"read 0x%x, error is %d\n", tbl[i].addr, xfer);
+			return -EIO;
+		}
+		tbl[i].low_data = xfer & 0xff;
+		tbl[i].high_data = (xfer >> 8) & 0xff;
+	}
+
+	return 0;
+}
+
+static int
+zx_aud96p22_headset_playback_info_volsw(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xf;
+
+	return 0;
+}
+
+static int
+zx_aud96p22_headset_playback_get_volsw(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct device *dev = snd_kcontrol_dev(kcontrol);
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	int ret;
+	int l;
+	int r;
+
+	ret = zx_aud96p22_i2c_read_regs(i2c_client,
+			i2c_dac_headset_volume_table,
+			ARRAY_SIZE(i2c_dac_headset_volume_table));
+	if (ret)
+		return ret;
+
+	l = i2c_dac_headset_volume_table[0].low_data;
+	r = i2c_dac_headset_volume_table[0].high_data;
+
+	/* make sure value fall in (0x0,0xf) */
+	l = clamp(l, 0, 0xf);
+	r = clamp(r, 0, 0xf);
+
+	ucontrol->value.integer.value[0] = l;
+	ucontrol->value.integer.value[1] = r;
+
+	return 0;
+}
+
+static int
+zx_aud96p22_headset_playback_put_volsw(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct device *dev = snd_kcontrol_dev(kcontrol);
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	int l;
+	int r;
+
+	l = r = ucontrol->value.integer.value[0];
+
+	/* make sure value fall in (0x0,0xf) */
+	l = clamp(l, 0, 0xf);
+	r = clamp(r, 0, 0xf);
+
+	i2c_dac_headset_volume_table[0].low_data = l;
+	i2c_dac_headset_volume_table[0].high_data = r;
+
+	zx_aud96p22_i2c_update(i2c_client, i2c_dac_headset_volume_table,
+			ARRAY_SIZE(i2c_dac_headset_volume_table));
+	return 0;
+}
+
+
+static int
+zx_aud96p22_master_playback_info_volsw(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xff;
+
+	return 0;
+}
+
+static int
+zx_aud96p22_master_playback_get_volsw(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct device *dev = snd_kcontrol_dev(kcontrol);
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	int l;
+	int r;
+
+	zx_aud96p22_i2c_read_regs(i2c_client,
+			i2c_dac_master_volume_table,
+			ARRAY_SIZE(i2c_dac_master_volume_table));
+
+	l = i2c_dac_master_volume_table[0].low_data;
+	r = i2c_dac_master_volume_table[0].high_data;
+
+	/* make sure value fall in (0x0,0xf) */
+	l = clamp(l, 0, 0xff);
+	r = clamp(r, 0, 0xff);
+
+	ucontrol->value.integer.value[0] = l;
+	ucontrol->value.integer.value[1] = r;
+
+	return 0;
+}
+
+static int
+zx_aud96p22_master_playback_put_volsw(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct device *dev = snd_kcontrol_dev(kcontrol);
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	int l;
+	int r;
+
+	l = r = ucontrol->value.integer.value[0];
+
+	/* make sure value fall in (0x0,0xf) */
+	l = clamp(l, 0, 0xff);
+	r = clamp(r, 0, 0xff);
+
+	i2c_dac_master_volume_table[0].low_data = l;
+	i2c_dac_master_volume_table[0].high_data = r;
+
+	zx_aud96p22_i2c_update(i2c_client,
+			i2c_dac_master_volume_table,
+			ARRAY_SIZE(i2c_dac_master_volume_table));
+	return 0;
+}
+
+static int zx_aud96p22_master_record_info_volsw(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xff;
+
+	return 0;
+}
+
+static int zx_aud96p22_master_record_get_volsw(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct device *dev = snd_kcontrol_dev(kcontrol);
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	int l;
+	int r;
+
+	zx_aud96p22_i2c_read_regs(i2c_client,
+				i2c_adc_master_volume_table,
+				ARRAY_SIZE(i2c_adc_master_volume_table));
+
+	l = i2c_adc_master_volume_table[0].low_data;
+	r = i2c_adc_master_volume_table[0].high_data;
+
+	/* make sure value fall in (0x0,0xf) */
+	l = clamp(l, 0, 0xff);
+	r = clamp(r, 0, 0xff);
+
+	ucontrol->value.integer.value[0] = l;
+	ucontrol->value.integer.value[1] = r;
+
+	return 0;
+}
+
+
+static int zx_aud96p22_master_record_put_volsw(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct device *dev = snd_kcontrol_dev(kcontrol);
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	int l;
+	int r;
+
+	l = r = ucontrol->value.integer.value[0];
+
+	/* make sure value fall in (0x0,0xf) */
+	l = clamp(l, 0, 0xff);
+	r = clamp(r, 0, 0xff);
+
+	i2c_adc_master_volume_table[0].low_data = l;
+	i2c_adc_master_volume_table[0].high_data = r;
+
+	return zx_aud96p22_i2c_update(i2c_client, i2c_adc_master_volume_table,
+			ARRAY_SIZE(i2c_adc_master_volume_table));
+}
+static struct snd_kcontrol_new zx_playback_controls[] = {
+	/* Headset volume */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Headset Playback Volume",
+		.info = zx_aud96p22_headset_playback_info_volsw,
+		.get = zx_aud96p22_headset_playback_get_volsw,
+		.put = zx_aud96p22_headset_playback_put_volsw,
+	},
+	/* Master volume */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Volume",
+		.info = zx_aud96p22_master_playback_info_volsw,
+		.get = zx_aud96p22_master_playback_get_volsw,
+		.put = zx_aud96p22_master_playback_put_volsw,
+	},
+};
+
+static struct snd_kcontrol_new zx_record_controls[] = {
+	/* Master record volume */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Capture Volume",
+		.info = zx_aud96p22_master_record_info_volsw,
+		.get = zx_aud96p22_master_record_get_volsw,
+		.put = zx_aud96p22_master_record_put_volsw,
+	},
+};
+
+static int zx_aud96p22_probe(struct snd_soc_codec *codec)
+{
+	struct device *dev = codec->dev;
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	int ret = 0;
+	struct zx_aud96p22_info *zx_aud96p22;
+	int i;
+
+	zx_aud96p22 = devm_kzalloc(dev, sizeof(*zx_aud96p22), GFP_KERNEL);
+	if (!zx_aud96p22)
+		return -ENOMEM;
+
+	zx_aud96p22->dev = dev;
+	dev_set_drvdata(dev, zx_aud96p22);
+	zx_aud96p22_i2c_dac_amp_run_enable(i2c_client, false);
+	zx_aud96p22_i2c_codec_run_enable(i2c_client);
+
+	for (i = 0; i < ARRAY_SIZE(zx_playback_controls); i++)
+		zx_playback_controls[i].private_value =	(unsigned long)dev;
+	snd_soc_add_codec_controls(codec, zx_playback_controls,
+			ARRAY_SIZE(zx_playback_controls));
+
+	for (i = 0; i < ARRAY_SIZE(zx_record_controls); i++)
+		zx_record_controls[i].private_value = (unsigned long)dev;
+	snd_soc_add_codec_controls(codec, zx_record_controls,
+			ARRAY_SIZE(zx_record_controls));
+
+	return ret;
+}
+
+static struct snd_soc_codec_driver zx_aud96p22_driver = {
+	.probe = zx_aud96p22_probe,
+};
+
+static int zx_aud96p22_dai_probe(struct snd_soc_dai *dai)
+{
+	struct zx_aud96p22_info *zx_aud96p22 = dev_get_drvdata(dai->dev);
+
+	snd_soc_dai_set_drvdata(dai, zx_aud96p22);
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops zx_aud96p22_dai_ops = {
+	.hw_params = zx_aud96p22_hw_params,
+	.startup = zx_aud96p22_startup,
+	.shutdown = zx_aud96p22_shutdown,
+};
+
+#define ZX_I2S_RATES \
+	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
+	SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+	SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000| \
+	SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
+
+#define ZX_I2S_FMTBIT \
+	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+	SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver zx_aud96p22_dai = {
+	.name = "zx-aud96p22-dai",
+	.probe = zx_aud96p22_dai_probe,
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = ZX_I2S_RATES,
+		.formats = ZX_I2S_FMTBIT,
+	},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = ZX_I2S_RATES,
+		.formats = ZX_I2S_FMTBIT,
+	},
+	.ops = &zx_aud96p22_dai_ops,
+};
+
+static int zx_aud96p22_i2c_probe(struct i2c_client *i2c_client,
+				const struct i2c_device_id *id)
+{
+	int ret = 0;
+	struct device *pdev = &i2c_client->dev;
+
+	if (!i2c_client)
+		return -ENODEV;
+
+	ret = snd_soc_register_codec(pdev, &zx_aud96p22_driver,
+				&zx_aud96p22_dai, 1);
+
+	return ret;
+}
+
+static int zx_aud96p22_i2c_remove(struct i2c_client *i2c_client)
+{
+	struct device *pdev = &i2c_client->dev;
+
+	snd_soc_unregister_codec(pdev);
+
+	return 0;
+}
+
+const struct of_device_id zx_aud96p22_of_dt_ids[] = {
+	{ .compatible = "zte,zx-aud96p22", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, zx_aud96p22_of_dt_ids);
+
+static struct i2c_driver aud96p22_i2c_driver = {
+	.driver = {
+		.name = "zx-aud96p22",
+		.of_match_table = zx_aud96p22_of_dt_ids,
+	},
+	.probe = zx_aud96p22_i2c_probe,
+	.remove = zx_aud96p22_i2c_remove,
+};
+module_i2c_driver(aud96p22_i2c_driver);
+
+MODULE_DESCRIPTION("ZTE ASoC AUD96P22 driver");
+MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4

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

* [PATCH v1 3/3] ASoC: zx-96p22: add zte's aud96p22 controller driver
@ 2017-02-15 10:55   ` Baoyou Xie
  0 siblings, 0 replies; 22+ messages in thread
From: Baoyou Xie @ 2017-02-15 10:55 UTC (permalink / raw)
  To: jun.nie-QSEj5FYQhm4dnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	broonie-DgEjT+Ai2ygdnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	lars-Qo5EllUWu/uELgA04lAiVw, arnd-r2nGTMty4D4,
	kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	bardliao-Rasf1IRRPZFBDgjK7y7TUQ, nh6z-fFIq/eER6g8,
	Paul.Handrigan-jGc1dHjMKG3QT0dZR+AlfA,
	oder_chiou-Rasf1IRRPZFBDgjK7y7TUQ,
	axel.lin-8E1dMatC8ynQT0dZR+AlfA, petr-Qh/3xLP0EvwAvxtiuMwx3w,
	yesanishhere-Re5JQEeQqe8AvxtiuMwx3w,
	srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	shawnguo-DgEjT+Ai2ygdnm+yROfE0A,
	baoyou.xie-QSEj5FYQhm4dnm+yROfE0A,
	xie.baoyou-Th6q7B73Y6EnDS1+zs4M5A,
	chen.chaokai-Th6q7B73Y6EnDS1+zs4M5A,
	wang.qiang01-Th6q7B73Y6EnDS1+zs4M5A

This patch adds aud96p22 controller driver for zte's SoC family.

Signed-off-by: Baoyou Xie <baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
 sound/soc/codecs/Kconfig       |   4 +
 sound/soc/codecs/Makefile      |   2 +
 sound/soc/codecs/zx_aud96p22.c | 588 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 594 insertions(+)
 create mode 100644 sound/soc/codecs/zx_aud96p22.c

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index cfc108e..120af32 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -1116,4 +1116,8 @@ config SND_SOC_TPA6130A2
 	tristate "Texas Instruments TPA6130A2 headphone amplifier"
 	depends on I2C
 
+config SND_SOC_ZX96P22
+	tristate "ZTE Inner AUD96P22 CODEC"
+	depends on I2C
+
 endmenu
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 2624c73..dbc3818 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -219,6 +219,7 @@ snd-soc-wm9705-objs := wm9705.o
 snd-soc-wm9712-objs := wm9712.o
 snd-soc-wm9713-objs := wm9713.o
 snd-soc-wm-hubs-objs := wm_hubs.o
+snd-soc-zx96p22-objs := zx_aud96p22.o
 # Amp
 snd-soc-max9877-objs := max9877.o
 snd-soc-max98504-objs := max98504.o
@@ -444,6 +445,7 @@ obj-$(CONFIG_SND_SOC_WM9712)	+= snd-soc-wm9712.o
 obj-$(CONFIG_SND_SOC_WM9713)	+= snd-soc-wm9713.o
 obj-$(CONFIG_SND_SOC_WM_ADSP)	+= snd-soc-wm-adsp.o
 obj-$(CONFIG_SND_SOC_WM_HUBS)	+= snd-soc-wm-hubs.o
+obj-$(CONFIG_SND_SOC_ZX96P22)	+= snd-soc-zx96p22.o
 
 # Amp
 obj-$(CONFIG_SND_SOC_MAX9877)	+= snd-soc-max9877.o
diff --git a/sound/soc/codecs/zx_aud96p22.c b/sound/soc/codecs/zx_aud96p22.c
new file mode 100644
index 0000000..f2979df
--- /dev/null
+++ b/sound/soc/codecs/zx_aud96p22.c
@@ -0,0 +1,588 @@
+/*
+ * ZTE's audio 96p22 driver
+ *
+ * Copyright (C) 2017 ZTE Ltd
+ *
+ * Author: Baoyou Xie <baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/pcm.h>
+
+#define BGPIO64				(64)
+#define snd_kcontrol_dev(kcontrol)	\
+		((struct device *)((kcontrol)->private_value))
+
+struct i2c_reg {
+	unsigned char addr;
+	unsigned char high_data;
+	unsigned char low_data;
+};
+
+struct zx_aud96p22_info {
+	struct device   *dev;
+	int gpio;
+	bool capture;
+};
+
+static struct i2c_reg i2c_dac_master_volume_table[] = {
+	{ 0x34, 0xe7, 0xe7 },
+};
+
+static struct i2c_reg i2c_adc_master_volume_table[] = {
+	{ 0x24, 0xbf, 0xbf },
+};
+
+static struct i2c_reg i2c_dac_headset_volume_table[] = {
+	{ 0x38, 0x0d, 0x0d },
+};
+
+static struct i2c_reg i2c_dac_sleep_table[] = {
+	{ 0x18, 0x00, 0x00 }, //play power down
+};
+
+static struct i2c_reg i2c_dac_wakeup_table[] = {
+	{ 0x18, 0x00, 0xff }, //play power up
+};
+
+static struct i2c_reg i2c_adc_sleep_table[] = {
+	{ 0x16, 0x00, 0x00 }, //record power down
+};
+
+static struct i2c_reg i2c_adc_wakeup_table[] = {
+	{ 0x16, 0x00, 0x0f }, //record power up
+};
+
+static struct i2c_reg i2c_codec_start_table[] = {
+	{ 0x15, 0x00, 0x00 }, //power down control
+	{ 0x47, 0x00, 0x00 }, //record path slect
+	{ 0x24, 0xbf, 0xbf }, //record volume control
+	{ 0x26, 0x30, 0x30 }, //record pga volume control
+	{ 0xc8, 0x00, 0x00 }, //ALC control
+	{ 0xce, 0x00, 0xf5 }, //record noise gate
+	{ 0xf3, 0x00, 0xc0 }, //dac noise dithe
+	{ 0xcd, 0x00, 0x20 }, //max record volume
+	{ 0x15, 0x00, 0x01 }, //power down control
+	{ 0x18, 0x00, 0xff }, //play power  control
+	{ 0x16, 0x00, 0x0f }, //record power up
+	{ 0x19, 0x00, 0x04 }, //power down control
+	{ 0x02, 0x00, 0x05 }, //ext clock slect
+	{ 0x01, 0x00, 0x05 }, //ext clock slect
+	{ 0x00, 0x00, 0x00 }, //adc dpz reset
+	{ 0x00, 0x00, 0x03 }, //dac dpz reset
+	{ 0x04, 0x00, 0x40 }, //clk div
+	{ 0x05, 0x00, 0x04 }, //clk div0x4
+	{ 0x06, 0x00, 0x40 }, //clk div
+	{ 0x07, 0x00, 0x04 }, //clk div 0x4
+	{ 0x03, 0x00, 0x01 }, //slave 16bit i2s
+	{ 0x00, 0x00, 0x00 }, //adc dpz reset
+	{ 0x00, 0x00, 0x03 }, //dac dpz reset
+};
+
+static int zx_aud96p22_i2c_write(struct i2c_client *i2c_client,
+				 const void *data, size_t count)
+{
+	int xfer;
+
+	xfer = i2c_master_send(i2c_client, data, count);
+	if (xfer == count)
+		return 0;
+	else if (xfer < 0)
+		return xfer;
+	else
+		return -EIO;
+}
+
+static int zx_aud96p22_i2c_read(struct i2c_client *i2c_client,
+				unsigned char addr)
+{
+	int xfer;
+
+	xfer = i2c_smbus_read_word_data(i2c_client, addr);
+	if (xfer < 0)
+		dev_warn(&i2c_client->dev, "transfer error %d\n", xfer);
+
+	return xfer;
+}
+
+static int zx_aud96p22_i2c_update(struct i2c_client *i2c_client,
+			const struct i2c_reg *tbl, unsigned int tbl_size)
+{
+	int xfer;
+	unsigned int i = 0;
+	unsigned char buf[3];
+
+	for (i = 0; i < tbl_size; i++) {
+		buf[0] = tbl[i].addr;
+		buf[1] = tbl[i].low_data;
+		buf[2] = tbl[i].high_data;
+
+		xfer = zx_aud96p22_i2c_write(i2c_client, buf, ARRAY_SIZE(buf));
+		if (xfer < 0) {
+			dev_err(&i2c_client->dev, "write error %d\n", xfer);
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+static void
+zx_aud96p22_i2c_dac_amp_run_enable(struct i2c_client *i2c_client, bool on)
+{
+	int ret = 0;
+
+	ret = gpio_request(BGPIO64, "dac");
+	if (ret) {
+		dev_err(&i2c_client->dev, "request gpio BGPIO64 failed %d\n",
+			ret);
+		return;
+	}
+
+	/*
+	 * write 1 to gpio 64 to set MUTE_CTL for enable play.
+	 * otherwise disable it.
+	 */
+	if (on)
+		gpiod_direction_output(gpio_to_desc(BGPIO64), 1);
+	else
+		gpiod_direction_output(gpio_to_desc(BGPIO64), 0);
+
+	gpio_free(BGPIO64);
+}
+
+static void
+zx_aud96p22_i2c_dac_sleep_enable(struct i2c_client *i2c_client, bool on)
+{
+	if (on)
+		zx_aud96p22_i2c_update(i2c_client, i2c_dac_sleep_table,
+			ARRAY_SIZE(i2c_dac_sleep_table));
+	else
+		zx_aud96p22_i2c_update(i2c_client, i2c_dac_wakeup_table,
+			ARRAY_SIZE(i2c_dac_wakeup_table));
+}
+
+static void
+zx_aud96p22_i2c_adc_sleep_enable(struct i2c_client *i2c_client, bool on)
+{
+	if (on)
+		zx_aud96p22_i2c_update(i2c_client, i2c_adc_sleep_table,
+			ARRAY_SIZE(i2c_adc_sleep_table));
+	else
+		zx_aud96p22_i2c_update(i2c_client, i2c_adc_wakeup_table,
+			ARRAY_SIZE(i2c_adc_wakeup_table));
+}
+
+static void
+zx_aud96p22_i2c_codec_run_enable(struct i2c_client *i2c_client)
+{
+	zx_aud96p22_i2c_update(i2c_client, i2c_codec_start_table,
+			ARRAY_SIZE(i2c_codec_start_table));
+}
+
+static int zx_aud96p22_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *socdai)
+{
+	struct device *dev = socdai->dev;
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	struct zx_aud96p22_info *zx_aud96p22 = dev_get_drvdata(socdai->dev);
+	bool capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+	zx_aud96p22->capture = capture;
+	snd_soc_dai_set_drvdata(socdai, zx_aud96p22);
+
+	zx_aud96p22_i2c_adc_sleep_enable(i2c_client, false);
+	if (!capture)
+		zx_aud96p22_i2c_dac_amp_run_enable(i2c_client, true);
+
+	return 0;
+}
+
+static int zx_aud96p22_startup(struct snd_pcm_substream *substream,
+			struct snd_soc_dai *dai)
+{
+	struct device *dev = dai->dev;
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	bool capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+	zx_aud96p22_i2c_dac_sleep_enable(i2c_client, false);
+	if (!capture)
+		zx_aud96p22_i2c_dac_amp_run_enable(i2c_client, true);
+
+	return 0;
+}
+
+static void zx_aud96p22_shutdown(struct snd_pcm_substream *substream,
+			struct snd_soc_dai *dai)
+{
+	struct device *dev = dai->dev;
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	bool capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+	zx_aud96p22_i2c_dac_sleep_enable(i2c_client, true);
+	if (!capture)
+		zx_aud96p22_i2c_dac_amp_run_enable(i2c_client, false);
+}
+
+static int
+zx_aud96p22_i2c_read_regs(struct i2c_client *i2c_client,
+			struct i2c_reg *tbl, unsigned int tbl_size)
+{
+	int xfer = 0;
+	unsigned int i;
+
+	for (i = 0; i < tbl_size; i++) {
+		xfer = zx_aud96p22_i2c_read(i2c_client, tbl[i].addr);
+		if (xfer < 0) {
+			dev_err(&i2c_client->dev,
+				"read 0x%x, error is %d\n", tbl[i].addr, xfer);
+			return -EIO;
+		}
+		tbl[i].low_data = xfer & 0xff;
+		tbl[i].high_data = (xfer >> 8) & 0xff;
+	}
+
+	return 0;
+}
+
+static int
+zx_aud96p22_headset_playback_info_volsw(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xf;
+
+	return 0;
+}
+
+static int
+zx_aud96p22_headset_playback_get_volsw(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct device *dev = snd_kcontrol_dev(kcontrol);
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	int ret;
+	int l;
+	int r;
+
+	ret = zx_aud96p22_i2c_read_regs(i2c_client,
+			i2c_dac_headset_volume_table,
+			ARRAY_SIZE(i2c_dac_headset_volume_table));
+	if (ret)
+		return ret;
+
+	l = i2c_dac_headset_volume_table[0].low_data;
+	r = i2c_dac_headset_volume_table[0].high_data;
+
+	/* make sure value fall in (0x0,0xf) */
+	l = clamp(l, 0, 0xf);
+	r = clamp(r, 0, 0xf);
+
+	ucontrol->value.integer.value[0] = l;
+	ucontrol->value.integer.value[1] = r;
+
+	return 0;
+}
+
+static int
+zx_aud96p22_headset_playback_put_volsw(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct device *dev = snd_kcontrol_dev(kcontrol);
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	int l;
+	int r;
+
+	l = r = ucontrol->value.integer.value[0];
+
+	/* make sure value fall in (0x0,0xf) */
+	l = clamp(l, 0, 0xf);
+	r = clamp(r, 0, 0xf);
+
+	i2c_dac_headset_volume_table[0].low_data = l;
+	i2c_dac_headset_volume_table[0].high_data = r;
+
+	zx_aud96p22_i2c_update(i2c_client, i2c_dac_headset_volume_table,
+			ARRAY_SIZE(i2c_dac_headset_volume_table));
+	return 0;
+}
+
+
+static int
+zx_aud96p22_master_playback_info_volsw(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xff;
+
+	return 0;
+}
+
+static int
+zx_aud96p22_master_playback_get_volsw(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct device *dev = snd_kcontrol_dev(kcontrol);
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	int l;
+	int r;
+
+	zx_aud96p22_i2c_read_regs(i2c_client,
+			i2c_dac_master_volume_table,
+			ARRAY_SIZE(i2c_dac_master_volume_table));
+
+	l = i2c_dac_master_volume_table[0].low_data;
+	r = i2c_dac_master_volume_table[0].high_data;
+
+	/* make sure value fall in (0x0,0xf) */
+	l = clamp(l, 0, 0xff);
+	r = clamp(r, 0, 0xff);
+
+	ucontrol->value.integer.value[0] = l;
+	ucontrol->value.integer.value[1] = r;
+
+	return 0;
+}
+
+static int
+zx_aud96p22_master_playback_put_volsw(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct device *dev = snd_kcontrol_dev(kcontrol);
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	int l;
+	int r;
+
+	l = r = ucontrol->value.integer.value[0];
+
+	/* make sure value fall in (0x0,0xf) */
+	l = clamp(l, 0, 0xff);
+	r = clamp(r, 0, 0xff);
+
+	i2c_dac_master_volume_table[0].low_data = l;
+	i2c_dac_master_volume_table[0].high_data = r;
+
+	zx_aud96p22_i2c_update(i2c_client,
+			i2c_dac_master_volume_table,
+			ARRAY_SIZE(i2c_dac_master_volume_table));
+	return 0;
+}
+
+static int zx_aud96p22_master_record_info_volsw(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xff;
+
+	return 0;
+}
+
+static int zx_aud96p22_master_record_get_volsw(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct device *dev = snd_kcontrol_dev(kcontrol);
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	int l;
+	int r;
+
+	zx_aud96p22_i2c_read_regs(i2c_client,
+				i2c_adc_master_volume_table,
+				ARRAY_SIZE(i2c_adc_master_volume_table));
+
+	l = i2c_adc_master_volume_table[0].low_data;
+	r = i2c_adc_master_volume_table[0].high_data;
+
+	/* make sure value fall in (0x0,0xf) */
+	l = clamp(l, 0, 0xff);
+	r = clamp(r, 0, 0xff);
+
+	ucontrol->value.integer.value[0] = l;
+	ucontrol->value.integer.value[1] = r;
+
+	return 0;
+}
+
+
+static int zx_aud96p22_master_record_put_volsw(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct device *dev = snd_kcontrol_dev(kcontrol);
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	int l;
+	int r;
+
+	l = r = ucontrol->value.integer.value[0];
+
+	/* make sure value fall in (0x0,0xf) */
+	l = clamp(l, 0, 0xff);
+	r = clamp(r, 0, 0xff);
+
+	i2c_adc_master_volume_table[0].low_data = l;
+	i2c_adc_master_volume_table[0].high_data = r;
+
+	return zx_aud96p22_i2c_update(i2c_client, i2c_adc_master_volume_table,
+			ARRAY_SIZE(i2c_adc_master_volume_table));
+}
+static struct snd_kcontrol_new zx_playback_controls[] = {
+	/* Headset volume */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Headset Playback Volume",
+		.info = zx_aud96p22_headset_playback_info_volsw,
+		.get = zx_aud96p22_headset_playback_get_volsw,
+		.put = zx_aud96p22_headset_playback_put_volsw,
+	},
+	/* Master volume */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Volume",
+		.info = zx_aud96p22_master_playback_info_volsw,
+		.get = zx_aud96p22_master_playback_get_volsw,
+		.put = zx_aud96p22_master_playback_put_volsw,
+	},
+};
+
+static struct snd_kcontrol_new zx_record_controls[] = {
+	/* Master record volume */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Capture Volume",
+		.info = zx_aud96p22_master_record_info_volsw,
+		.get = zx_aud96p22_master_record_get_volsw,
+		.put = zx_aud96p22_master_record_put_volsw,
+	},
+};
+
+static int zx_aud96p22_probe(struct snd_soc_codec *codec)
+{
+	struct device *dev = codec->dev;
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	int ret = 0;
+	struct zx_aud96p22_info *zx_aud96p22;
+	int i;
+
+	zx_aud96p22 = devm_kzalloc(dev, sizeof(*zx_aud96p22), GFP_KERNEL);
+	if (!zx_aud96p22)
+		return -ENOMEM;
+
+	zx_aud96p22->dev = dev;
+	dev_set_drvdata(dev, zx_aud96p22);
+	zx_aud96p22_i2c_dac_amp_run_enable(i2c_client, false);
+	zx_aud96p22_i2c_codec_run_enable(i2c_client);
+
+	for (i = 0; i < ARRAY_SIZE(zx_playback_controls); i++)
+		zx_playback_controls[i].private_value =	(unsigned long)dev;
+	snd_soc_add_codec_controls(codec, zx_playback_controls,
+			ARRAY_SIZE(zx_playback_controls));
+
+	for (i = 0; i < ARRAY_SIZE(zx_record_controls); i++)
+		zx_record_controls[i].private_value = (unsigned long)dev;
+	snd_soc_add_codec_controls(codec, zx_record_controls,
+			ARRAY_SIZE(zx_record_controls));
+
+	return ret;
+}
+
+static struct snd_soc_codec_driver zx_aud96p22_driver = {
+	.probe = zx_aud96p22_probe,
+};
+
+static int zx_aud96p22_dai_probe(struct snd_soc_dai *dai)
+{
+	struct zx_aud96p22_info *zx_aud96p22 = dev_get_drvdata(dai->dev);
+
+	snd_soc_dai_set_drvdata(dai, zx_aud96p22);
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops zx_aud96p22_dai_ops = {
+	.hw_params = zx_aud96p22_hw_params,
+	.startup = zx_aud96p22_startup,
+	.shutdown = zx_aud96p22_shutdown,
+};
+
+#define ZX_I2S_RATES \
+	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
+	SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+	SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000| \
+	SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
+
+#define ZX_I2S_FMTBIT \
+	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+	SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver zx_aud96p22_dai = {
+	.name = "zx-aud96p22-dai",
+	.probe = zx_aud96p22_dai_probe,
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = ZX_I2S_RATES,
+		.formats = ZX_I2S_FMTBIT,
+	},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = ZX_I2S_RATES,
+		.formats = ZX_I2S_FMTBIT,
+	},
+	.ops = &zx_aud96p22_dai_ops,
+};
+
+static int zx_aud96p22_i2c_probe(struct i2c_client *i2c_client,
+				const struct i2c_device_id *id)
+{
+	int ret = 0;
+	struct device *pdev = &i2c_client->dev;
+
+	if (!i2c_client)
+		return -ENODEV;
+
+	ret = snd_soc_register_codec(pdev, &zx_aud96p22_driver,
+				&zx_aud96p22_dai, 1);
+
+	return ret;
+}
+
+static int zx_aud96p22_i2c_remove(struct i2c_client *i2c_client)
+{
+	struct device *pdev = &i2c_client->dev;
+
+	snd_soc_unregister_codec(pdev);
+
+	return 0;
+}
+
+const struct of_device_id zx_aud96p22_of_dt_ids[] = {
+	{ .compatible = "zte,zx-aud96p22", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, zx_aud96p22_of_dt_ids);
+
+static struct i2c_driver aud96p22_i2c_driver = {
+	.driver = {
+		.name = "zx-aud96p22",
+		.of_match_table = zx_aud96p22_of_dt_ids,
+	},
+	.probe = zx_aud96p22_i2c_probe,
+	.remove = zx_aud96p22_i2c_remove,
+};
+module_i2c_driver(aud96p22_i2c_driver);
+
+MODULE_DESCRIPTION("ZTE ASoC AUD96P22 driver");
+MODULE_AUTHOR("Baoyou Xie <baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4

--
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] 22+ messages in thread

* [PATCH v1 3/3] ASoC: zx-96p22: add zte's aud96p22 controller driver
@ 2017-02-15 10:55   ` Baoyou Xie
  0 siblings, 0 replies; 22+ messages in thread
From: Baoyou Xie @ 2017-02-15 10:55 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds aud96p22 controller driver for zte's SoC family.

Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
---
 sound/soc/codecs/Kconfig       |   4 +
 sound/soc/codecs/Makefile      |   2 +
 sound/soc/codecs/zx_aud96p22.c | 588 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 594 insertions(+)
 create mode 100644 sound/soc/codecs/zx_aud96p22.c

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index cfc108e..120af32 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -1116,4 +1116,8 @@ config SND_SOC_TPA6130A2
 	tristate "Texas Instruments TPA6130A2 headphone amplifier"
 	depends on I2C
 
+config SND_SOC_ZX96P22
+	tristate "ZTE Inner AUD96P22 CODEC"
+	depends on I2C
+
 endmenu
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 2624c73..dbc3818 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -219,6 +219,7 @@ snd-soc-wm9705-objs := wm9705.o
 snd-soc-wm9712-objs := wm9712.o
 snd-soc-wm9713-objs := wm9713.o
 snd-soc-wm-hubs-objs := wm_hubs.o
+snd-soc-zx96p22-objs := zx_aud96p22.o
 # Amp
 snd-soc-max9877-objs := max9877.o
 snd-soc-max98504-objs := max98504.o
@@ -444,6 +445,7 @@ obj-$(CONFIG_SND_SOC_WM9712)	+= snd-soc-wm9712.o
 obj-$(CONFIG_SND_SOC_WM9713)	+= snd-soc-wm9713.o
 obj-$(CONFIG_SND_SOC_WM_ADSP)	+= snd-soc-wm-adsp.o
 obj-$(CONFIG_SND_SOC_WM_HUBS)	+= snd-soc-wm-hubs.o
+obj-$(CONFIG_SND_SOC_ZX96P22)	+= snd-soc-zx96p22.o
 
 # Amp
 obj-$(CONFIG_SND_SOC_MAX9877)	+= snd-soc-max9877.o
diff --git a/sound/soc/codecs/zx_aud96p22.c b/sound/soc/codecs/zx_aud96p22.c
new file mode 100644
index 0000000..f2979df
--- /dev/null
+++ b/sound/soc/codecs/zx_aud96p22.c
@@ -0,0 +1,588 @@
+/*
+ * ZTE's audio 96p22 driver
+ *
+ * Copyright (C) 2017 ZTE Ltd
+ *
+ * Author: Baoyou Xie <baoyou.xie@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/pcm.h>
+
+#define BGPIO64				(64)
+#define snd_kcontrol_dev(kcontrol)	\
+		((struct device *)((kcontrol)->private_value))
+
+struct i2c_reg {
+	unsigned char addr;
+	unsigned char high_data;
+	unsigned char low_data;
+};
+
+struct zx_aud96p22_info {
+	struct device   *dev;
+	int gpio;
+	bool capture;
+};
+
+static struct i2c_reg i2c_dac_master_volume_table[] = {
+	{ 0x34, 0xe7, 0xe7 },
+};
+
+static struct i2c_reg i2c_adc_master_volume_table[] = {
+	{ 0x24, 0xbf, 0xbf },
+};
+
+static struct i2c_reg i2c_dac_headset_volume_table[] = {
+	{ 0x38, 0x0d, 0x0d },
+};
+
+static struct i2c_reg i2c_dac_sleep_table[] = {
+	{ 0x18, 0x00, 0x00 }, //play power down
+};
+
+static struct i2c_reg i2c_dac_wakeup_table[] = {
+	{ 0x18, 0x00, 0xff }, //play power up
+};
+
+static struct i2c_reg i2c_adc_sleep_table[] = {
+	{ 0x16, 0x00, 0x00 }, //record power down
+};
+
+static struct i2c_reg i2c_adc_wakeup_table[] = {
+	{ 0x16, 0x00, 0x0f }, //record power up
+};
+
+static struct i2c_reg i2c_codec_start_table[] = {
+	{ 0x15, 0x00, 0x00 }, //power down control
+	{ 0x47, 0x00, 0x00 }, //record path slect
+	{ 0x24, 0xbf, 0xbf }, //record volume control
+	{ 0x26, 0x30, 0x30 }, //record pga volume control
+	{ 0xc8, 0x00, 0x00 }, //ALC control
+	{ 0xce, 0x00, 0xf5 }, //record noise gate
+	{ 0xf3, 0x00, 0xc0 }, //dac noise dithe
+	{ 0xcd, 0x00, 0x20 }, //max record volume
+	{ 0x15, 0x00, 0x01 }, //power down control
+	{ 0x18, 0x00, 0xff }, //play power  control
+	{ 0x16, 0x00, 0x0f }, //record power up
+	{ 0x19, 0x00, 0x04 }, //power down control
+	{ 0x02, 0x00, 0x05 }, //ext clock slect
+	{ 0x01, 0x00, 0x05 }, //ext clock slect
+	{ 0x00, 0x00, 0x00 }, //adc dpz reset
+	{ 0x00, 0x00, 0x03 }, //dac dpz reset
+	{ 0x04, 0x00, 0x40 }, //clk div
+	{ 0x05, 0x00, 0x04 }, //clk div0x4
+	{ 0x06, 0x00, 0x40 }, //clk div
+	{ 0x07, 0x00, 0x04 }, //clk div 0x4
+	{ 0x03, 0x00, 0x01 }, //slave 16bit i2s
+	{ 0x00, 0x00, 0x00 }, //adc dpz reset
+	{ 0x00, 0x00, 0x03 }, //dac dpz reset
+};
+
+static int zx_aud96p22_i2c_write(struct i2c_client *i2c_client,
+				 const void *data, size_t count)
+{
+	int xfer;
+
+	xfer = i2c_master_send(i2c_client, data, count);
+	if (xfer == count)
+		return 0;
+	else if (xfer < 0)
+		return xfer;
+	else
+		return -EIO;
+}
+
+static int zx_aud96p22_i2c_read(struct i2c_client *i2c_client,
+				unsigned char addr)
+{
+	int xfer;
+
+	xfer = i2c_smbus_read_word_data(i2c_client, addr);
+	if (xfer < 0)
+		dev_warn(&i2c_client->dev, "transfer error %d\n", xfer);
+
+	return xfer;
+}
+
+static int zx_aud96p22_i2c_update(struct i2c_client *i2c_client,
+			const struct i2c_reg *tbl, unsigned int tbl_size)
+{
+	int xfer;
+	unsigned int i = 0;
+	unsigned char buf[3];
+
+	for (i = 0; i < tbl_size; i++) {
+		buf[0] = tbl[i].addr;
+		buf[1] = tbl[i].low_data;
+		buf[2] = tbl[i].high_data;
+
+		xfer = zx_aud96p22_i2c_write(i2c_client, buf, ARRAY_SIZE(buf));
+		if (xfer < 0) {
+			dev_err(&i2c_client->dev, "write error %d\n", xfer);
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+static void
+zx_aud96p22_i2c_dac_amp_run_enable(struct i2c_client *i2c_client, bool on)
+{
+	int ret = 0;
+
+	ret = gpio_request(BGPIO64, "dac");
+	if (ret) {
+		dev_err(&i2c_client->dev, "request gpio BGPIO64 failed %d\n",
+			ret);
+		return;
+	}
+
+	/*
+	 * write 1 to gpio 64 to set MUTE_CTL for enable play.
+	 * otherwise disable it.
+	 */
+	if (on)
+		gpiod_direction_output(gpio_to_desc(BGPIO64), 1);
+	else
+		gpiod_direction_output(gpio_to_desc(BGPIO64), 0);
+
+	gpio_free(BGPIO64);
+}
+
+static void
+zx_aud96p22_i2c_dac_sleep_enable(struct i2c_client *i2c_client, bool on)
+{
+	if (on)
+		zx_aud96p22_i2c_update(i2c_client, i2c_dac_sleep_table,
+			ARRAY_SIZE(i2c_dac_sleep_table));
+	else
+		zx_aud96p22_i2c_update(i2c_client, i2c_dac_wakeup_table,
+			ARRAY_SIZE(i2c_dac_wakeup_table));
+}
+
+static void
+zx_aud96p22_i2c_adc_sleep_enable(struct i2c_client *i2c_client, bool on)
+{
+	if (on)
+		zx_aud96p22_i2c_update(i2c_client, i2c_adc_sleep_table,
+			ARRAY_SIZE(i2c_adc_sleep_table));
+	else
+		zx_aud96p22_i2c_update(i2c_client, i2c_adc_wakeup_table,
+			ARRAY_SIZE(i2c_adc_wakeup_table));
+}
+
+static void
+zx_aud96p22_i2c_codec_run_enable(struct i2c_client *i2c_client)
+{
+	zx_aud96p22_i2c_update(i2c_client, i2c_codec_start_table,
+			ARRAY_SIZE(i2c_codec_start_table));
+}
+
+static int zx_aud96p22_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *socdai)
+{
+	struct device *dev = socdai->dev;
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	struct zx_aud96p22_info *zx_aud96p22 = dev_get_drvdata(socdai->dev);
+	bool capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+	zx_aud96p22->capture = capture;
+	snd_soc_dai_set_drvdata(socdai, zx_aud96p22);
+
+	zx_aud96p22_i2c_adc_sleep_enable(i2c_client, false);
+	if (!capture)
+		zx_aud96p22_i2c_dac_amp_run_enable(i2c_client, true);
+
+	return 0;
+}
+
+static int zx_aud96p22_startup(struct snd_pcm_substream *substream,
+			struct snd_soc_dai *dai)
+{
+	struct device *dev = dai->dev;
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	bool capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+	zx_aud96p22_i2c_dac_sleep_enable(i2c_client, false);
+	if (!capture)
+		zx_aud96p22_i2c_dac_amp_run_enable(i2c_client, true);
+
+	return 0;
+}
+
+static void zx_aud96p22_shutdown(struct snd_pcm_substream *substream,
+			struct snd_soc_dai *dai)
+{
+	struct device *dev = dai->dev;
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	bool capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+
+	zx_aud96p22_i2c_dac_sleep_enable(i2c_client, true);
+	if (!capture)
+		zx_aud96p22_i2c_dac_amp_run_enable(i2c_client, false);
+}
+
+static int
+zx_aud96p22_i2c_read_regs(struct i2c_client *i2c_client,
+			struct i2c_reg *tbl, unsigned int tbl_size)
+{
+	int xfer = 0;
+	unsigned int i;
+
+	for (i = 0; i < tbl_size; i++) {
+		xfer = zx_aud96p22_i2c_read(i2c_client, tbl[i].addr);
+		if (xfer < 0) {
+			dev_err(&i2c_client->dev,
+				"read 0x%x, error is %d\n", tbl[i].addr, xfer);
+			return -EIO;
+		}
+		tbl[i].low_data = xfer & 0xff;
+		tbl[i].high_data = (xfer >> 8) & 0xff;
+	}
+
+	return 0;
+}
+
+static int
+zx_aud96p22_headset_playback_info_volsw(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xf;
+
+	return 0;
+}
+
+static int
+zx_aud96p22_headset_playback_get_volsw(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct device *dev = snd_kcontrol_dev(kcontrol);
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	int ret;
+	int l;
+	int r;
+
+	ret = zx_aud96p22_i2c_read_regs(i2c_client,
+			i2c_dac_headset_volume_table,
+			ARRAY_SIZE(i2c_dac_headset_volume_table));
+	if (ret)
+		return ret;
+
+	l = i2c_dac_headset_volume_table[0].low_data;
+	r = i2c_dac_headset_volume_table[0].high_data;
+
+	/* make sure value fall in (0x0,0xf) */
+	l = clamp(l, 0, 0xf);
+	r = clamp(r, 0, 0xf);
+
+	ucontrol->value.integer.value[0] = l;
+	ucontrol->value.integer.value[1] = r;
+
+	return 0;
+}
+
+static int
+zx_aud96p22_headset_playback_put_volsw(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct device *dev = snd_kcontrol_dev(kcontrol);
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	int l;
+	int r;
+
+	l = r = ucontrol->value.integer.value[0];
+
+	/* make sure value fall in (0x0,0xf) */
+	l = clamp(l, 0, 0xf);
+	r = clamp(r, 0, 0xf);
+
+	i2c_dac_headset_volume_table[0].low_data = l;
+	i2c_dac_headset_volume_table[0].high_data = r;
+
+	zx_aud96p22_i2c_update(i2c_client, i2c_dac_headset_volume_table,
+			ARRAY_SIZE(i2c_dac_headset_volume_table));
+	return 0;
+}
+
+
+static int
+zx_aud96p22_master_playback_info_volsw(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xff;
+
+	return 0;
+}
+
+static int
+zx_aud96p22_master_playback_get_volsw(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct device *dev = snd_kcontrol_dev(kcontrol);
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	int l;
+	int r;
+
+	zx_aud96p22_i2c_read_regs(i2c_client,
+			i2c_dac_master_volume_table,
+			ARRAY_SIZE(i2c_dac_master_volume_table));
+
+	l = i2c_dac_master_volume_table[0].low_data;
+	r = i2c_dac_master_volume_table[0].high_data;
+
+	/* make sure value fall in (0x0,0xf) */
+	l = clamp(l, 0, 0xff);
+	r = clamp(r, 0, 0xff);
+
+	ucontrol->value.integer.value[0] = l;
+	ucontrol->value.integer.value[1] = r;
+
+	return 0;
+}
+
+static int
+zx_aud96p22_master_playback_put_volsw(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_value *ucontrol)
+{
+	struct device *dev = snd_kcontrol_dev(kcontrol);
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	int l;
+	int r;
+
+	l = r = ucontrol->value.integer.value[0];
+
+	/* make sure value fall in (0x0,0xf) */
+	l = clamp(l, 0, 0xff);
+	r = clamp(r, 0, 0xff);
+
+	i2c_dac_master_volume_table[0].low_data = l;
+	i2c_dac_master_volume_table[0].high_data = r;
+
+	zx_aud96p22_i2c_update(i2c_client,
+			i2c_dac_master_volume_table,
+			ARRAY_SIZE(i2c_dac_master_volume_table));
+	return 0;
+}
+
+static int zx_aud96p22_master_record_info_volsw(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_info *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 0xff;
+
+	return 0;
+}
+
+static int zx_aud96p22_master_record_get_volsw(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct device *dev = snd_kcontrol_dev(kcontrol);
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	int l;
+	int r;
+
+	zx_aud96p22_i2c_read_regs(i2c_client,
+				i2c_adc_master_volume_table,
+				ARRAY_SIZE(i2c_adc_master_volume_table));
+
+	l = i2c_adc_master_volume_table[0].low_data;
+	r = i2c_adc_master_volume_table[0].high_data;
+
+	/* make sure value fall in (0x0,0xf) */
+	l = clamp(l, 0, 0xff);
+	r = clamp(r, 0, 0xff);
+
+	ucontrol->value.integer.value[0] = l;
+	ucontrol->value.integer.value[1] = r;
+
+	return 0;
+}
+
+
+static int zx_aud96p22_master_record_put_volsw(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct device *dev = snd_kcontrol_dev(kcontrol);
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	int l;
+	int r;
+
+	l = r = ucontrol->value.integer.value[0];
+
+	/* make sure value fall in (0x0,0xf) */
+	l = clamp(l, 0, 0xff);
+	r = clamp(r, 0, 0xff);
+
+	i2c_adc_master_volume_table[0].low_data = l;
+	i2c_adc_master_volume_table[0].high_data = r;
+
+	return zx_aud96p22_i2c_update(i2c_client, i2c_adc_master_volume_table,
+			ARRAY_SIZE(i2c_adc_master_volume_table));
+}
+static struct snd_kcontrol_new zx_playback_controls[] = {
+	/* Headset volume */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Headset Playback Volume",
+		.info = zx_aud96p22_headset_playback_info_volsw,
+		.get = zx_aud96p22_headset_playback_get_volsw,
+		.put = zx_aud96p22_headset_playback_put_volsw,
+	},
+	/* Master volume */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Playback Volume",
+		.info = zx_aud96p22_master_playback_info_volsw,
+		.get = zx_aud96p22_master_playback_get_volsw,
+		.put = zx_aud96p22_master_playback_put_volsw,
+	},
+};
+
+static struct snd_kcontrol_new zx_record_controls[] = {
+	/* Master record volume */
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Master Capture Volume",
+		.info = zx_aud96p22_master_record_info_volsw,
+		.get = zx_aud96p22_master_record_get_volsw,
+		.put = zx_aud96p22_master_record_put_volsw,
+	},
+};
+
+static int zx_aud96p22_probe(struct snd_soc_codec *codec)
+{
+	struct device *dev = codec->dev;
+	struct i2c_client *i2c_client = to_i2c_client(dev);
+	int ret = 0;
+	struct zx_aud96p22_info *zx_aud96p22;
+	int i;
+
+	zx_aud96p22 = devm_kzalloc(dev, sizeof(*zx_aud96p22), GFP_KERNEL);
+	if (!zx_aud96p22)
+		return -ENOMEM;
+
+	zx_aud96p22->dev = dev;
+	dev_set_drvdata(dev, zx_aud96p22);
+	zx_aud96p22_i2c_dac_amp_run_enable(i2c_client, false);
+	zx_aud96p22_i2c_codec_run_enable(i2c_client);
+
+	for (i = 0; i < ARRAY_SIZE(zx_playback_controls); i++)
+		zx_playback_controls[i].private_value =	(unsigned long)dev;
+	snd_soc_add_codec_controls(codec, zx_playback_controls,
+			ARRAY_SIZE(zx_playback_controls));
+
+	for (i = 0; i < ARRAY_SIZE(zx_record_controls); i++)
+		zx_record_controls[i].private_value = (unsigned long)dev;
+	snd_soc_add_codec_controls(codec, zx_record_controls,
+			ARRAY_SIZE(zx_record_controls));
+
+	return ret;
+}
+
+static struct snd_soc_codec_driver zx_aud96p22_driver = {
+	.probe = zx_aud96p22_probe,
+};
+
+static int zx_aud96p22_dai_probe(struct snd_soc_dai *dai)
+{
+	struct zx_aud96p22_info *zx_aud96p22 = dev_get_drvdata(dai->dev);
+
+	snd_soc_dai_set_drvdata(dai, zx_aud96p22);
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops zx_aud96p22_dai_ops = {
+	.hw_params = zx_aud96p22_hw_params,
+	.startup = zx_aud96p22_startup,
+	.shutdown = zx_aud96p22_shutdown,
+};
+
+#define ZX_I2S_RATES \
+	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
+	SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+	SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000| \
+	SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
+
+#define ZX_I2S_FMTBIT \
+	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+	SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver zx_aud96p22_dai = {
+	.name = "zx-aud96p22-dai",
+	.probe = zx_aud96p22_dai_probe,
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = ZX_I2S_RATES,
+		.formats = ZX_I2S_FMTBIT,
+	},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = ZX_I2S_RATES,
+		.formats = ZX_I2S_FMTBIT,
+	},
+	.ops = &zx_aud96p22_dai_ops,
+};
+
+static int zx_aud96p22_i2c_probe(struct i2c_client *i2c_client,
+				const struct i2c_device_id *id)
+{
+	int ret = 0;
+	struct device *pdev = &i2c_client->dev;
+
+	if (!i2c_client)
+		return -ENODEV;
+
+	ret = snd_soc_register_codec(pdev, &zx_aud96p22_driver,
+				&zx_aud96p22_dai, 1);
+
+	return ret;
+}
+
+static int zx_aud96p22_i2c_remove(struct i2c_client *i2c_client)
+{
+	struct device *pdev = &i2c_client->dev;
+
+	snd_soc_unregister_codec(pdev);
+
+	return 0;
+}
+
+const struct of_device_id zx_aud96p22_of_dt_ids[] = {
+	{ .compatible = "zte,zx-aud96p22", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, zx_aud96p22_of_dt_ids);
+
+static struct i2c_driver aud96p22_i2c_driver = {
+	.driver = {
+		.name = "zx-aud96p22",
+		.of_match_table = zx_aud96p22_of_dt_ids,
+	},
+	.probe = zx_aud96p22_i2c_probe,
+	.remove = zx_aud96p22_i2c_remove,
+};
+module_i2c_driver(aud96p22_i2c_driver);
+
+MODULE_DESCRIPTION("ZTE ASoC AUD96P22 driver");
+MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4

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

* Re: [PATCH v1 3/3] ASoC: zx-96p22: add zte's aud96p22 controller driver
  2017-02-15 10:55   ` Baoyou Xie
  (?)
@ 2017-02-15 11:24     ` Charles Keepax
  -1 siblings, 0 replies; 22+ messages in thread
From: Charles Keepax @ 2017-02-15 11:24 UTC (permalink / raw)
  To: Baoyou Xie
  Cc: jun.nie, lgirdwood, broonie, robh+dt, mark.rutland, perex, tiwai,
	lars, arnd, kuninori.morimoto.gx, bardliao, nh6z, Paul.Handrigan,
	oder_chiou, axel.lin, petr, yesanishhere, srinivas.kandagatla,
	linux-arm-kernel, alsa-devel, devicetree, linux-kernel, shawnguo,
	xie.baoyou, chen.chaokai, wang.qiang01

On Wed, Feb 15, 2017 at 06:55:10PM +0800, Baoyou Xie wrote:
> This patch adds aud96p22 controller driver for zte's SoC family.
> 
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
> ---
<snip>
> +static int zx_aud96p22_i2c_write(struct i2c_client *i2c_client,
> +				 const void *data, size_t count)
> +{
> +	int xfer;
> +
> +	xfer = i2c_master_send(i2c_client, data, count);
> +	if (xfer == count)
> +		return 0;
> +	else if (xfer < 0)
> +		return xfer;
> +	else
> +		return -EIO;
> +}
> +
> +static int zx_aud96p22_i2c_read(struct i2c_client *i2c_client,
> +				unsigned char addr)
> +{
> +	int xfer;
> +
> +	xfer = i2c_smbus_read_word_data(i2c_client, addr);
> +	if (xfer < 0)
> +		dev_warn(&i2c_client->dev, "transfer error %d\n", xfer);
> +
> +	return xfer;
> +}
> +

Is there any reason this isn't using regmap? It looks like it
should be, have a look at any of the other mainline CODECs for an
example.

Thanks,
Charles

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

* Re: [PATCH v1 3/3] ASoC: zx-96p22: add zte's aud96p22 controller driver
@ 2017-02-15 11:24     ` Charles Keepax
  0 siblings, 0 replies; 22+ messages in thread
From: Charles Keepax @ 2017-02-15 11:24 UTC (permalink / raw)
  To: Baoyou Xie
  Cc: mark.rutland, alsa-devel, kuninori.morimoto.gx, lgirdwood, tiwai,
	srinivas.kandagatla, bardliao, lars, axel.lin, Paul.Handrigan,
	chen.chaokai, wang.qiang01, devicetree, arnd, yesanishhere,
	xie.baoyou, nh6z, robh+dt, linux-arm-kernel, oder_chiou,
	linux-kernel, petr, broonie, jun.nie, shawnguo

On Wed, Feb 15, 2017 at 06:55:10PM +0800, Baoyou Xie wrote:
> This patch adds aud96p22 controller driver for zte's SoC family.
> 
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
> ---
<snip>
> +static int zx_aud96p22_i2c_write(struct i2c_client *i2c_client,
> +				 const void *data, size_t count)
> +{
> +	int xfer;
> +
> +	xfer = i2c_master_send(i2c_client, data, count);
> +	if (xfer == count)
> +		return 0;
> +	else if (xfer < 0)
> +		return xfer;
> +	else
> +		return -EIO;
> +}
> +
> +static int zx_aud96p22_i2c_read(struct i2c_client *i2c_client,
> +				unsigned char addr)
> +{
> +	int xfer;
> +
> +	xfer = i2c_smbus_read_word_data(i2c_client, addr);
> +	if (xfer < 0)
> +		dev_warn(&i2c_client->dev, "transfer error %d\n", xfer);
> +
> +	return xfer;
> +}
> +

Is there any reason this isn't using regmap? It looks like it
should be, have a look at any of the other mainline CODECs for an
example.

Thanks,
Charles

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

* [PATCH v1 3/3] ASoC: zx-96p22: add zte's aud96p22 controller driver
@ 2017-02-15 11:24     ` Charles Keepax
  0 siblings, 0 replies; 22+ messages in thread
From: Charles Keepax @ 2017-02-15 11:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 15, 2017 at 06:55:10PM +0800, Baoyou Xie wrote:
> This patch adds aud96p22 controller driver for zte's SoC family.
> 
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
> ---
<snip>
> +static int zx_aud96p22_i2c_write(struct i2c_client *i2c_client,
> +				 const void *data, size_t count)
> +{
> +	int xfer;
> +
> +	xfer = i2c_master_send(i2c_client, data, count);
> +	if (xfer == count)
> +		return 0;
> +	else if (xfer < 0)
> +		return xfer;
> +	else
> +		return -EIO;
> +}
> +
> +static int zx_aud96p22_i2c_read(struct i2c_client *i2c_client,
> +				unsigned char addr)
> +{
> +	int xfer;
> +
> +	xfer = i2c_smbus_read_word_data(i2c_client, addr);
> +	if (xfer < 0)
> +		dev_warn(&i2c_client->dev, "transfer error %d\n", xfer);
> +
> +	return xfer;
> +}
> +

Is there any reason this isn't using regmap? It looks like it
should be, have a look at any of the other mainline CODECs for an
example.

Thanks,
Charles

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

* Re: [PATCH v1 3/3] ASoC: zx-96p22: add zte's aud96p22 controller driver
  2017-02-15 11:24     ` Charles Keepax
  (?)
  (?)
@ 2017-02-16  0:24     ` Baoyou Xie
  -1 siblings, 0 replies; 22+ messages in thread
From: Baoyou Xie @ 2017-02-16  0:24 UTC (permalink / raw)
  To: Charles Keepax
  Cc: Mark Rutland, alsa-devel, Kuninori Morimoto, Liam Girdwood,
	tiwai, Srinivas Kandagatla, bardliao, lars, Axel Lin,
	Paul.Handrigan, chen.chaokai, wang.qiang01, devicetree,
	Arnd Bergmann, anish kumar, xie.baoyou, nh6z, Rob Herring,
	linux-arm Mailing List, oder_chiou, Linux Kernel Mailing List,
	petr, broonie, Jun Nie, Shawn Guo

Hi, Charles:

On 15 February 2017 at 19:24, Charles Keepax <
ckeepax@opensource.wolfsonmicro.com> wrote:

> On Wed, Feb 15, 2017 at 06:55:10PM +0800, Baoyou Xie wrote:
> > This patch adds aud96p22 controller driver for zte's SoC family.
> >
> > Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
> > ---
> <snip>
> > +static int zx_aud96p22_i2c_write(struct i2c_client *i2c_client,
> > +                              const void *data, size_t count)
> > +{
> > +     int xfer;
> > +
> > +     xfer = i2c_master_send(i2c_client, data, count);
> > +     if (xfer == count)
> > +             return 0;
> > +     else if (xfer < 0)
> > +             return xfer;
> > +     else
> > +             return -EIO;
> > +}
> > +
> > +static int zx_aud96p22_i2c_read(struct i2c_client *i2c_client,
> > +                             unsigned char addr)
> > +{
> > +     int xfer;
> > +
> > +     xfer = i2c_smbus_read_word_data(i2c_client, addr);
> > +     if (xfer < 0)
> > +             dev_warn(&i2c_client->dev, "transfer error %d\n", xfer);
> > +
> > +     return xfer;
> > +}
> > +
>
> Is there any reason this isn't using regmap? It looks like it
> should be, have a look at any of the other mainline CODECs for an
> example.
>
> We can not read the i2c register directly, cause of the i2c is responded
asynchronous, and involves i2c irq.

I suggest that we access i2c through general i2c interface.


> Thanks,
> Charles
>

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

* Re: [PATCH v1 3/3] ASoC: zx-96p22: add zte's aud96p22 controller driver
  2017-02-15 11:24     ` Charles Keepax
                       ` (2 preceding siblings ...)
  (?)
@ 2017-02-16  3:09     ` Baoyou Xie
  -1 siblings, 0 replies; 22+ messages in thread
From: Baoyou Xie @ 2017-02-16  3:09 UTC (permalink / raw)
  To: Charles Keepax
  Cc: Mark Rutland, alsa-devel, Kuninori Morimoto, Liam Girdwood,
	tiwai, Srinivas Kandagatla, bardliao, lars, Axel Lin,
	Paul.Handrigan, chen.chaokai, wang.qiang01, devicetree,
	Arnd Bergmann, anish kumar, xie.baoyou, nh6z, Rob Herring,
	linux-arm Mailing List, oder_chiou, Linux Kernel Mailing List,
	petr, broonie, Jun Nie, Shawn Guo

On 15 February 2017 at 19:24, Charles Keepax <
ckeepax@opensource.wolfsonmicro.com> wrote:

> On Wed, Feb 15, 2017 at 06:55:10PM +0800, Baoyou Xie wrote:
> > This patch adds aud96p22 controller driver for zte's SoC family.
> >
> > Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
> > ---
> <snip>
> > +static int zx_aud96p22_i2c_write(struct i2c_client *i2c_client,
> > +                              const void *data, size_t count)
> > +{
> > +     int xfer;
> > +
> > +     xfer = i2c_master_send(i2c_client, data, count);
> > +     if (xfer == count)
> > +             return 0;
> > +     else if (xfer < 0)
> > +             return xfer;
> > +     else
> > +             return -EIO;
> > +}
> > +
> > +static int zx_aud96p22_i2c_read(struct i2c_client *i2c_client,
> > +                             unsigned char addr)
> > +{
> > +     int xfer;
> > +
> > +     xfer = i2c_smbus_read_word_data(i2c_client, addr);
> > +     if (xfer < 0)
> > +             dev_warn(&i2c_client->dev, "transfer error %d\n", xfer);
> > +
> > +     return xfer;
> > +}
> > +
>
> Is there any reason this isn't using regmap? It looks like it
> should be, have a look at any of the other mainline CODECs for an
> example.
>
>
Hi, Charles:

oh, I understood what you said. Please wait for my next version.


Thanks,
> Charles
>

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

* Re: [PATCH v1 1/3] ASoC: zx-96p22: add documentation for zte's aud96p22 controller
  2017-02-15 10:55 ` Baoyou Xie
@ 2017-02-16 11:00   ` Shawn Guo
  -1 siblings, 0 replies; 22+ messages in thread
From: Shawn Guo @ 2017-02-16 11:00 UTC (permalink / raw)
  To: Baoyou Xie
  Cc: jun.nie, lgirdwood, broonie, robh+dt, mark.rutland, perex, tiwai,
	lars, arnd, kuninori.morimoto.gx, ckeepax, bardliao, nh6z,
	Paul.Handrigan, oder_chiou, axel.lin, petr, yesanishhere,
	srinivas.kandagatla, linux-arm-kernel, alsa-devel, devicetree,
	linux-kernel, xie.baoyou, chen.chaokai, wang.qiang01

On Wed, Feb 15, 2017 at 06:55:08PM +0800, Baoyou Xie wrote:
> This patch adds dt-binding documentation for zte's aud96p22 controller.
> 
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>

Suggest to replace "documentation" with "bindings doc" in patch subject.

> ---
>  .../devicetree/bindings/sound/zte,zx-96p22.txt     | 24 ++++++++++++++++++++++
>  1 file changed, 24 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
> 
> diff --git a/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt b/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
> new file mode 100644
> index 0000000..4184566
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
> @@ -0,0 +1,24 @@
> +ZTE zx96p22 controller
> +
> +Required properties:
> + - compatible : Must be "zte,zx-aud96p22"
> + - #sound-dai-cells: Should be 0
> + - reg : Offset of I2C register for zx96p22

"zte,zx-96p22.txt", "zte,zx-aud96p22" and "zx96p22".  Can we make these
names consistent?

> +
> +Example:
> +
> +	audio_i2c0: audio_i2c0@1486000 {

Node name should be as generic as possible.  I think the following one
is what we want.

	audio_i2c0: i2c@1486000 {

> +		compatible = "zte,zx296718-i2c";
> +		reg = <0x01486000 0x1000>;
> +		interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		clocks = <&audiocrm AUDIO_I2C0_WCLK>;
> +		clock-frequency = <1600000>;
> +		status = "ok";

Drop this 'status' property, which is not so meaningful for example in
bindings doc.

And have a newline between properties and child node.

> +		inner_codec: aud96p22@22 {

		aud96p22: codec@22 {

Shawn

> +			compatible = "zte,zx-aud96p22";
> +			#sound-dai-cells = <0>;
> +			reg = <0x22>;
> +		};
> +	};
> -- 
> 2.7.4
> 

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

* [PATCH v1 1/3] ASoC: zx-96p22: add documentation for zte's aud96p22 controller
@ 2017-02-16 11:00   ` Shawn Guo
  0 siblings, 0 replies; 22+ messages in thread
From: Shawn Guo @ 2017-02-16 11:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 15, 2017 at 06:55:08PM +0800, Baoyou Xie wrote:
> This patch adds dt-binding documentation for zte's aud96p22 controller.
> 
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>

Suggest to replace "documentation" with "bindings doc" in patch subject.

> ---
>  .../devicetree/bindings/sound/zte,zx-96p22.txt     | 24 ++++++++++++++++++++++
>  1 file changed, 24 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
> 
> diff --git a/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt b/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
> new file mode 100644
> index 0000000..4184566
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
> @@ -0,0 +1,24 @@
> +ZTE zx96p22 controller
> +
> +Required properties:
> + - compatible : Must be "zte,zx-aud96p22"
> + - #sound-dai-cells: Should be 0
> + - reg : Offset of I2C register for zx96p22

"zte,zx-96p22.txt", "zte,zx-aud96p22" and "zx96p22".  Can we make these
names consistent?

> +
> +Example:
> +
> +	audio_i2c0: audio_i2c0 at 1486000 {

Node name should be as generic as possible.  I think the following one
is what we want.

	audio_i2c0: i2c at 1486000 {

> +		compatible = "zte,zx296718-i2c";
> +		reg = <0x01486000 0x1000>;
> +		interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		clocks = <&audiocrm AUDIO_I2C0_WCLK>;
> +		clock-frequency = <1600000>;
> +		status = "ok";

Drop this 'status' property, which is not so meaningful for example in
bindings doc.

And have a newline between properties and child node.

> +		inner_codec: aud96p22 at 22 {

		aud96p22: codec at 22 {

Shawn

> +			compatible = "zte,zx-aud96p22";
> +			#sound-dai-cells = <0>;
> +			reg = <0x22>;
> +		};
> +	};
> -- 
> 2.7.4
> 

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

* Re: [PATCH v1 3/3] ASoC: zx-96p22: add zte's aud96p22 controller driver
@ 2017-02-16 11:17     ` Shawn Guo
  0 siblings, 0 replies; 22+ messages in thread
From: Shawn Guo @ 2017-02-16 11:17 UTC (permalink / raw)
  To: Baoyou Xie
  Cc: jun.nie, lgirdwood, broonie, robh+dt, mark.rutland, perex, tiwai,
	lars, arnd, kuninori.morimoto.gx, ckeepax, bardliao, nh6z,
	Paul.Handrigan, oder_chiou, axel.lin, petr, yesanishhere,
	srinivas.kandagatla, linux-arm-kernel, alsa-devel, devicetree,
	linux-kernel, xie.baoyou, chen.chaokai, wang.qiang01

On Wed, Feb 15, 2017 at 06:55:10PM +0800, Baoyou Xie wrote:
> This patch adds aud96p22 controller driver for zte's SoC family.
> 
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>

s/controller/codec in patch subject.

> ---
>  sound/soc/codecs/Kconfig       |   4 +
>  sound/soc/codecs/Makefile      |   2 +
>  sound/soc/codecs/zx_aud96p22.c | 588 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 594 insertions(+)
>  create mode 100644 sound/soc/codecs/zx_aud96p22.c
> 
> diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
> index cfc108e..120af32 100644
> --- a/sound/soc/codecs/Kconfig
> +++ b/sound/soc/codecs/Kconfig
> @@ -1116,4 +1116,8 @@ config SND_SOC_TPA6130A2
>  	tristate "Texas Instruments TPA6130A2 headphone amplifier"
>  	depends on I2C
>  
> +config SND_SOC_ZX96P22
> +	tristate "ZTE Inner AUD96P22 CODEC"
> +	depends on I2C
> +
>  endmenu
> diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
> index 2624c73..dbc3818 100644
> --- a/sound/soc/codecs/Makefile
> +++ b/sound/soc/codecs/Makefile
> @@ -219,6 +219,7 @@ snd-soc-wm9705-objs := wm9705.o
>  snd-soc-wm9712-objs := wm9712.o
>  snd-soc-wm9713-objs := wm9713.o
>  snd-soc-wm-hubs-objs := wm_hubs.o
> +snd-soc-zx96p22-objs := zx_aud96p22.o
>  # Amp
>  snd-soc-max9877-objs := max9877.o
>  snd-soc-max98504-objs := max98504.o
> @@ -444,6 +445,7 @@ obj-$(CONFIG_SND_SOC_WM9712)	+= snd-soc-wm9712.o
>  obj-$(CONFIG_SND_SOC_WM9713)	+= snd-soc-wm9713.o
>  obj-$(CONFIG_SND_SOC_WM_ADSP)	+= snd-soc-wm-adsp.o
>  obj-$(CONFIG_SND_SOC_WM_HUBS)	+= snd-soc-wm-hubs.o
> +obj-$(CONFIG_SND_SOC_ZX96P22)	+= snd-soc-zx96p22.o
>  
>  # Amp
>  obj-$(CONFIG_SND_SOC_MAX9877)	+= snd-soc-max9877.o
> diff --git a/sound/soc/codecs/zx_aud96p22.c b/sound/soc/codecs/zx_aud96p22.c
> new file mode 100644
> index 0000000..f2979df
> --- /dev/null
> +++ b/sound/soc/codecs/zx_aud96p22.c
> @@ -0,0 +1,588 @@
> +/*
> + * ZTE's audio 96p22 driver
> + *
> + * Copyright (C) 2017 ZTE Ltd
> + *
> + * Author: Baoyou Xie <baoyou.xie@linaro.org>
> + *
> + * License terms: GNU General Public License (GPL) version 2
> + */
> +
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/gpio.h>
> +#include <sound/soc.h>
> +#include <sound/soc-dai.h>
> +#include <sound/pcm.h>
> +
> +#define BGPIO64				(64)

GPIO resource is a board level configuration, which might be different
from one board to another.  Instead of hard-coding, it should be
retrieved from device tree.

> +#define snd_kcontrol_dev(kcontrol)	\
> +		((struct device *)((kcontrol)->private_value))
> +
> +struct i2c_reg {
> +	unsigned char addr;
> +	unsigned char high_data;
> +	unsigned char low_data;
> +};
> +
> +struct zx_aud96p22_info {
> +	struct device   *dev;

One space is good enough between type and variable.

> +	int gpio;
> +	bool capture;
> +};
> +
> +static struct i2c_reg i2c_dac_master_volume_table[] = {
> +	{ 0x34, 0xe7, 0xe7 },
> +};
> +
> +static struct i2c_reg i2c_adc_master_volume_table[] = {
> +	{ 0x24, 0xbf, 0xbf },
> +};
> +
> +static struct i2c_reg i2c_dac_headset_volume_table[] = {
> +	{ 0x38, 0x0d, 0x0d },
> +};
> +
> +static struct i2c_reg i2c_dac_sleep_table[] = {
> +	{ 0x18, 0x00, 0x00 }, //play power down

/* single line comment */ please.

> +};
> +
> +static struct i2c_reg i2c_dac_wakeup_table[] = {
> +	{ 0x18, 0x00, 0xff }, //play power up
> +};
> +
> +static struct i2c_reg i2c_adc_sleep_table[] = {
> +	{ 0x16, 0x00, 0x00 }, //record power down
> +};
> +
> +static struct i2c_reg i2c_adc_wakeup_table[] = {
> +	{ 0x16, 0x00, 0x0f }, //record power up
> +};
> +
> +static struct i2c_reg i2c_codec_start_table[] = {
> +	{ 0x15, 0x00, 0x00 }, //power down control
> +	{ 0x47, 0x00, 0x00 }, //record path slect
> +	{ 0x24, 0xbf, 0xbf }, //record volume control
> +	{ 0x26, 0x30, 0x30 }, //record pga volume control
> +	{ 0xc8, 0x00, 0x00 }, //ALC control
> +	{ 0xce, 0x00, 0xf5 }, //record noise gate
> +	{ 0xf3, 0x00, 0xc0 }, //dac noise dithe
> +	{ 0xcd, 0x00, 0x20 }, //max record volume
> +	{ 0x15, 0x00, 0x01 }, //power down control
> +	{ 0x18, 0x00, 0xff }, //play power  control
> +	{ 0x16, 0x00, 0x0f }, //record power up
> +	{ 0x19, 0x00, 0x04 }, //power down control
> +	{ 0x02, 0x00, 0x05 }, //ext clock slect
> +	{ 0x01, 0x00, 0x05 }, //ext clock slect
> +	{ 0x00, 0x00, 0x00 }, //adc dpz reset
> +	{ 0x00, 0x00, 0x03 }, //dac dpz reset
> +	{ 0x04, 0x00, 0x40 }, //clk div
> +	{ 0x05, 0x00, 0x04 }, //clk div0x4
> +	{ 0x06, 0x00, 0x40 }, //clk div
> +	{ 0x07, 0x00, 0x04 }, //clk div 0x4
> +	{ 0x03, 0x00, 0x01 }, //slave 16bit i2s
> +	{ 0x00, 0x00, 0x00 }, //adc dpz reset
> +	{ 0x00, 0x00, 0x03 }, //dac dpz reset
> +};

<snip>

I skipped the code in between, and will review them in the next version,
since most of them needs update anyway to use regmap interface.

> +static int zx_aud96p22_i2c_probe(struct i2c_client *i2c_client,
> +				const struct i2c_device_id *id)
> +{
> +	int ret = 0;
> +	struct device *pdev = &i2c_client->dev;

'pdev' is usually used for struct platform_device type.  Please use
'dev' here.

> +
> +	if (!i2c_client)
> +		return -ENODEV;
> +
> +	ret = snd_soc_register_codec(pdev, &zx_aud96p22_driver,
> +				&zx_aud96p22_dai, 1);
> +
> +	return ret;
> +}
> +
> +static int zx_aud96p22_i2c_remove(struct i2c_client *i2c_client)
> +{
> +	struct device *pdev = &i2c_client->dev;

Ditto

Shawn

> +
> +	snd_soc_unregister_codec(pdev);
> +
> +	return 0;
> +}
> +
> +const struct of_device_id zx_aud96p22_of_dt_ids[] = {
> +	{ .compatible = "zte,zx-aud96p22", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, zx_aud96p22_of_dt_ids);
> +
> +static struct i2c_driver aud96p22_i2c_driver = {
> +	.driver = {
> +		.name = "zx-aud96p22",
> +		.of_match_table = zx_aud96p22_of_dt_ids,
> +	},
> +	.probe = zx_aud96p22_i2c_probe,
> +	.remove = zx_aud96p22_i2c_remove,
> +};
> +module_i2c_driver(aud96p22_i2c_driver);
> +
> +MODULE_DESCRIPTION("ZTE ASoC AUD96P22 driver");
> +MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
> +MODULE_LICENSE("GPL v2");
> -- 
> 2.7.4
> 

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

* Re: [PATCH v1 3/3] ASoC: zx-96p22: add zte's aud96p22 controller driver
@ 2017-02-16 11:17     ` Shawn Guo
  0 siblings, 0 replies; 22+ messages in thread
From: Shawn Guo @ 2017-02-16 11:17 UTC (permalink / raw)
  To: Baoyou Xie
  Cc: jun.nie-QSEj5FYQhm4dnm+yROfE0A, lgirdwood-Re5JQEeQqe8AvxtiuMwx3w,
	broonie-DgEjT+Ai2ygdnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	lars-Qo5EllUWu/uELgA04lAiVw, arnd-r2nGTMty4D4,
	kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ,
	ckeepax-yzvPICuk2AATkU/dhu1WVueM+bqZidxxQQ4Iyu8u01E,
	bardliao-Rasf1IRRPZFBDgjK7y7TUQ, nh6z-fFIq/eER6g8,
	Paul.Handrigan-jGc1dHjMKG3QT0dZR+AlfA,
	oder_chiou-Rasf1IRRPZFBDgjK7y7TUQ,
	axel.lin-8E1dMatC8ynQT0dZR+AlfA, petr-Qh/3xLP0EvwAvxtiuMwx3w,
	yesanishhere-Re5JQEeQqe8AvxtiuMwx3w,
	srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	xie.baoyou-Th6q7B73Y6EnDS1+zs4M5A,
	chen.chaokai-Th6q7B73Y6EnDS1+zs4M5A,
	wang.qiang01-Th6q7B73Y6EnDS1+zs4M5A

On Wed, Feb 15, 2017 at 06:55:10PM +0800, Baoyou Xie wrote:
> This patch adds aud96p22 controller driver for zte's SoC family.
> 
> Signed-off-by: Baoyou Xie <baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

s/controller/codec in patch subject.

> ---
>  sound/soc/codecs/Kconfig       |   4 +
>  sound/soc/codecs/Makefile      |   2 +
>  sound/soc/codecs/zx_aud96p22.c | 588 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 594 insertions(+)
>  create mode 100644 sound/soc/codecs/zx_aud96p22.c
> 
> diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
> index cfc108e..120af32 100644
> --- a/sound/soc/codecs/Kconfig
> +++ b/sound/soc/codecs/Kconfig
> @@ -1116,4 +1116,8 @@ config SND_SOC_TPA6130A2
>  	tristate "Texas Instruments TPA6130A2 headphone amplifier"
>  	depends on I2C
>  
> +config SND_SOC_ZX96P22
> +	tristate "ZTE Inner AUD96P22 CODEC"
> +	depends on I2C
> +
>  endmenu
> diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
> index 2624c73..dbc3818 100644
> --- a/sound/soc/codecs/Makefile
> +++ b/sound/soc/codecs/Makefile
> @@ -219,6 +219,7 @@ snd-soc-wm9705-objs := wm9705.o
>  snd-soc-wm9712-objs := wm9712.o
>  snd-soc-wm9713-objs := wm9713.o
>  snd-soc-wm-hubs-objs := wm_hubs.o
> +snd-soc-zx96p22-objs := zx_aud96p22.o
>  # Amp
>  snd-soc-max9877-objs := max9877.o
>  snd-soc-max98504-objs := max98504.o
> @@ -444,6 +445,7 @@ obj-$(CONFIG_SND_SOC_WM9712)	+= snd-soc-wm9712.o
>  obj-$(CONFIG_SND_SOC_WM9713)	+= snd-soc-wm9713.o
>  obj-$(CONFIG_SND_SOC_WM_ADSP)	+= snd-soc-wm-adsp.o
>  obj-$(CONFIG_SND_SOC_WM_HUBS)	+= snd-soc-wm-hubs.o
> +obj-$(CONFIG_SND_SOC_ZX96P22)	+= snd-soc-zx96p22.o
>  
>  # Amp
>  obj-$(CONFIG_SND_SOC_MAX9877)	+= snd-soc-max9877.o
> diff --git a/sound/soc/codecs/zx_aud96p22.c b/sound/soc/codecs/zx_aud96p22.c
> new file mode 100644
> index 0000000..f2979df
> --- /dev/null
> +++ b/sound/soc/codecs/zx_aud96p22.c
> @@ -0,0 +1,588 @@
> +/*
> + * ZTE's audio 96p22 driver
> + *
> + * Copyright (C) 2017 ZTE Ltd
> + *
> + * Author: Baoyou Xie <baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> + *
> + * License terms: GNU General Public License (GPL) version 2
> + */
> +
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/gpio.h>
> +#include <sound/soc.h>
> +#include <sound/soc-dai.h>
> +#include <sound/pcm.h>
> +
> +#define BGPIO64				(64)

GPIO resource is a board level configuration, which might be different
from one board to another.  Instead of hard-coding, it should be
retrieved from device tree.

> +#define snd_kcontrol_dev(kcontrol)	\
> +		((struct device *)((kcontrol)->private_value))
> +
> +struct i2c_reg {
> +	unsigned char addr;
> +	unsigned char high_data;
> +	unsigned char low_data;
> +};
> +
> +struct zx_aud96p22_info {
> +	struct device   *dev;

One space is good enough between type and variable.

> +	int gpio;
> +	bool capture;
> +};
> +
> +static struct i2c_reg i2c_dac_master_volume_table[] = {
> +	{ 0x34, 0xe7, 0xe7 },
> +};
> +
> +static struct i2c_reg i2c_adc_master_volume_table[] = {
> +	{ 0x24, 0xbf, 0xbf },
> +};
> +
> +static struct i2c_reg i2c_dac_headset_volume_table[] = {
> +	{ 0x38, 0x0d, 0x0d },
> +};
> +
> +static struct i2c_reg i2c_dac_sleep_table[] = {
> +	{ 0x18, 0x00, 0x00 }, //play power down

/* single line comment */ please.

> +};
> +
> +static struct i2c_reg i2c_dac_wakeup_table[] = {
> +	{ 0x18, 0x00, 0xff }, //play power up
> +};
> +
> +static struct i2c_reg i2c_adc_sleep_table[] = {
> +	{ 0x16, 0x00, 0x00 }, //record power down
> +};
> +
> +static struct i2c_reg i2c_adc_wakeup_table[] = {
> +	{ 0x16, 0x00, 0x0f }, //record power up
> +};
> +
> +static struct i2c_reg i2c_codec_start_table[] = {
> +	{ 0x15, 0x00, 0x00 }, //power down control
> +	{ 0x47, 0x00, 0x00 }, //record path slect
> +	{ 0x24, 0xbf, 0xbf }, //record volume control
> +	{ 0x26, 0x30, 0x30 }, //record pga volume control
> +	{ 0xc8, 0x00, 0x00 }, //ALC control
> +	{ 0xce, 0x00, 0xf5 }, //record noise gate
> +	{ 0xf3, 0x00, 0xc0 }, //dac noise dithe
> +	{ 0xcd, 0x00, 0x20 }, //max record volume
> +	{ 0x15, 0x00, 0x01 }, //power down control
> +	{ 0x18, 0x00, 0xff }, //play power  control
> +	{ 0x16, 0x00, 0x0f }, //record power up
> +	{ 0x19, 0x00, 0x04 }, //power down control
> +	{ 0x02, 0x00, 0x05 }, //ext clock slect
> +	{ 0x01, 0x00, 0x05 }, //ext clock slect
> +	{ 0x00, 0x00, 0x00 }, //adc dpz reset
> +	{ 0x00, 0x00, 0x03 }, //dac dpz reset
> +	{ 0x04, 0x00, 0x40 }, //clk div
> +	{ 0x05, 0x00, 0x04 }, //clk div0x4
> +	{ 0x06, 0x00, 0x40 }, //clk div
> +	{ 0x07, 0x00, 0x04 }, //clk div 0x4
> +	{ 0x03, 0x00, 0x01 }, //slave 16bit i2s
> +	{ 0x00, 0x00, 0x00 }, //adc dpz reset
> +	{ 0x00, 0x00, 0x03 }, //dac dpz reset
> +};

<snip>

I skipped the code in between, and will review them in the next version,
since most of them needs update anyway to use regmap interface.

> +static int zx_aud96p22_i2c_probe(struct i2c_client *i2c_client,
> +				const struct i2c_device_id *id)
> +{
> +	int ret = 0;
> +	struct device *pdev = &i2c_client->dev;

'pdev' is usually used for struct platform_device type.  Please use
'dev' here.

> +
> +	if (!i2c_client)
> +		return -ENODEV;
> +
> +	ret = snd_soc_register_codec(pdev, &zx_aud96p22_driver,
> +				&zx_aud96p22_dai, 1);
> +
> +	return ret;
> +}
> +
> +static int zx_aud96p22_i2c_remove(struct i2c_client *i2c_client)
> +{
> +	struct device *pdev = &i2c_client->dev;

Ditto

Shawn

> +
> +	snd_soc_unregister_codec(pdev);
> +
> +	return 0;
> +}
> +
> +const struct of_device_id zx_aud96p22_of_dt_ids[] = {
> +	{ .compatible = "zte,zx-aud96p22", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, zx_aud96p22_of_dt_ids);
> +
> +static struct i2c_driver aud96p22_i2c_driver = {
> +	.driver = {
> +		.name = "zx-aud96p22",
> +		.of_match_table = zx_aud96p22_of_dt_ids,
> +	},
> +	.probe = zx_aud96p22_i2c_probe,
> +	.remove = zx_aud96p22_i2c_remove,
> +};
> +module_i2c_driver(aud96p22_i2c_driver);
> +
> +MODULE_DESCRIPTION("ZTE ASoC AUD96P22 driver");
> +MODULE_AUTHOR("Baoyou Xie <baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>");
> +MODULE_LICENSE("GPL v2");
> -- 
> 2.7.4
> 
--
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] 22+ messages in thread

* [PATCH v1 3/3] ASoC: zx-96p22: add zte's aud96p22 controller driver
@ 2017-02-16 11:17     ` Shawn Guo
  0 siblings, 0 replies; 22+ messages in thread
From: Shawn Guo @ 2017-02-16 11:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 15, 2017 at 06:55:10PM +0800, Baoyou Xie wrote:
> This patch adds aud96p22 controller driver for zte's SoC family.
> 
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>

s/controller/codec in patch subject.

> ---
>  sound/soc/codecs/Kconfig       |   4 +
>  sound/soc/codecs/Makefile      |   2 +
>  sound/soc/codecs/zx_aud96p22.c | 588 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 594 insertions(+)
>  create mode 100644 sound/soc/codecs/zx_aud96p22.c
> 
> diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
> index cfc108e..120af32 100644
> --- a/sound/soc/codecs/Kconfig
> +++ b/sound/soc/codecs/Kconfig
> @@ -1116,4 +1116,8 @@ config SND_SOC_TPA6130A2
>  	tristate "Texas Instruments TPA6130A2 headphone amplifier"
>  	depends on I2C
>  
> +config SND_SOC_ZX96P22
> +	tristate "ZTE Inner AUD96P22 CODEC"
> +	depends on I2C
> +
>  endmenu
> diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
> index 2624c73..dbc3818 100644
> --- a/sound/soc/codecs/Makefile
> +++ b/sound/soc/codecs/Makefile
> @@ -219,6 +219,7 @@ snd-soc-wm9705-objs := wm9705.o
>  snd-soc-wm9712-objs := wm9712.o
>  snd-soc-wm9713-objs := wm9713.o
>  snd-soc-wm-hubs-objs := wm_hubs.o
> +snd-soc-zx96p22-objs := zx_aud96p22.o
>  # Amp
>  snd-soc-max9877-objs := max9877.o
>  snd-soc-max98504-objs := max98504.o
> @@ -444,6 +445,7 @@ obj-$(CONFIG_SND_SOC_WM9712)	+= snd-soc-wm9712.o
>  obj-$(CONFIG_SND_SOC_WM9713)	+= snd-soc-wm9713.o
>  obj-$(CONFIG_SND_SOC_WM_ADSP)	+= snd-soc-wm-adsp.o
>  obj-$(CONFIG_SND_SOC_WM_HUBS)	+= snd-soc-wm-hubs.o
> +obj-$(CONFIG_SND_SOC_ZX96P22)	+= snd-soc-zx96p22.o
>  
>  # Amp
>  obj-$(CONFIG_SND_SOC_MAX9877)	+= snd-soc-max9877.o
> diff --git a/sound/soc/codecs/zx_aud96p22.c b/sound/soc/codecs/zx_aud96p22.c
> new file mode 100644
> index 0000000..f2979df
> --- /dev/null
> +++ b/sound/soc/codecs/zx_aud96p22.c
> @@ -0,0 +1,588 @@
> +/*
> + * ZTE's audio 96p22 driver
> + *
> + * Copyright (C) 2017 ZTE Ltd
> + *
> + * Author: Baoyou Xie <baoyou.xie@linaro.org>
> + *
> + * License terms: GNU General Public License (GPL) version 2
> + */
> +
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/gpio.h>
> +#include <sound/soc.h>
> +#include <sound/soc-dai.h>
> +#include <sound/pcm.h>
> +
> +#define BGPIO64				(64)

GPIO resource is a board level configuration, which might be different
from one board to another.  Instead of hard-coding, it should be
retrieved from device tree.

> +#define snd_kcontrol_dev(kcontrol)	\
> +		((struct device *)((kcontrol)->private_value))
> +
> +struct i2c_reg {
> +	unsigned char addr;
> +	unsigned char high_data;
> +	unsigned char low_data;
> +};
> +
> +struct zx_aud96p22_info {
> +	struct device   *dev;

One space is good enough between type and variable.

> +	int gpio;
> +	bool capture;
> +};
> +
> +static struct i2c_reg i2c_dac_master_volume_table[] = {
> +	{ 0x34, 0xe7, 0xe7 },
> +};
> +
> +static struct i2c_reg i2c_adc_master_volume_table[] = {
> +	{ 0x24, 0xbf, 0xbf },
> +};
> +
> +static struct i2c_reg i2c_dac_headset_volume_table[] = {
> +	{ 0x38, 0x0d, 0x0d },
> +};
> +
> +static struct i2c_reg i2c_dac_sleep_table[] = {
> +	{ 0x18, 0x00, 0x00 }, //play power down

/* single line comment */ please.

> +};
> +
> +static struct i2c_reg i2c_dac_wakeup_table[] = {
> +	{ 0x18, 0x00, 0xff }, //play power up
> +};
> +
> +static struct i2c_reg i2c_adc_sleep_table[] = {
> +	{ 0x16, 0x00, 0x00 }, //record power down
> +};
> +
> +static struct i2c_reg i2c_adc_wakeup_table[] = {
> +	{ 0x16, 0x00, 0x0f }, //record power up
> +};
> +
> +static struct i2c_reg i2c_codec_start_table[] = {
> +	{ 0x15, 0x00, 0x00 }, //power down control
> +	{ 0x47, 0x00, 0x00 }, //record path slect
> +	{ 0x24, 0xbf, 0xbf }, //record volume control
> +	{ 0x26, 0x30, 0x30 }, //record pga volume control
> +	{ 0xc8, 0x00, 0x00 }, //ALC control
> +	{ 0xce, 0x00, 0xf5 }, //record noise gate
> +	{ 0xf3, 0x00, 0xc0 }, //dac noise dithe
> +	{ 0xcd, 0x00, 0x20 }, //max record volume
> +	{ 0x15, 0x00, 0x01 }, //power down control
> +	{ 0x18, 0x00, 0xff }, //play power  control
> +	{ 0x16, 0x00, 0x0f }, //record power up
> +	{ 0x19, 0x00, 0x04 }, //power down control
> +	{ 0x02, 0x00, 0x05 }, //ext clock slect
> +	{ 0x01, 0x00, 0x05 }, //ext clock slect
> +	{ 0x00, 0x00, 0x00 }, //adc dpz reset
> +	{ 0x00, 0x00, 0x03 }, //dac dpz reset
> +	{ 0x04, 0x00, 0x40 }, //clk div
> +	{ 0x05, 0x00, 0x04 }, //clk div0x4
> +	{ 0x06, 0x00, 0x40 }, //clk div
> +	{ 0x07, 0x00, 0x04 }, //clk div 0x4
> +	{ 0x03, 0x00, 0x01 }, //slave 16bit i2s
> +	{ 0x00, 0x00, 0x00 }, //adc dpz reset
> +	{ 0x00, 0x00, 0x03 }, //dac dpz reset
> +};

<snip>

I skipped the code in between, and will review them in the next version,
since most of them needs update anyway to use regmap interface.

> +static int zx_aud96p22_i2c_probe(struct i2c_client *i2c_client,
> +				const struct i2c_device_id *id)
> +{
> +	int ret = 0;
> +	struct device *pdev = &i2c_client->dev;

'pdev' is usually used for struct platform_device type.  Please use
'dev' here.

> +
> +	if (!i2c_client)
> +		return -ENODEV;
> +
> +	ret = snd_soc_register_codec(pdev, &zx_aud96p22_driver,
> +				&zx_aud96p22_dai, 1);
> +
> +	return ret;
> +}
> +
> +static int zx_aud96p22_i2c_remove(struct i2c_client *i2c_client)
> +{
> +	struct device *pdev = &i2c_client->dev;

Ditto

Shawn

> +
> +	snd_soc_unregister_codec(pdev);
> +
> +	return 0;
> +}
> +
> +const struct of_device_id zx_aud96p22_of_dt_ids[] = {
> +	{ .compatible = "zte,zx-aud96p22", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, zx_aud96p22_of_dt_ids);
> +
> +static struct i2c_driver aud96p22_i2c_driver = {
> +	.driver = {
> +		.name = "zx-aud96p22",
> +		.of_match_table = zx_aud96p22_of_dt_ids,
> +	},
> +	.probe = zx_aud96p22_i2c_probe,
> +	.remove = zx_aud96p22_i2c_remove,
> +};
> +module_i2c_driver(aud96p22_i2c_driver);
> +
> +MODULE_DESCRIPTION("ZTE ASoC AUD96P22 driver");
> +MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
> +MODULE_LICENSE("GPL v2");
> -- 
> 2.7.4
> 

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

* Re: [PATCH v1 1/3] ASoC: zx-96p22: add documentation for zte's aud96p22  controller
  2017-02-15 10:55 ` Baoyou Xie
  (?)
@ 2017-02-27 17:20   ` Rob Herring
  -1 siblings, 0 replies; 22+ messages in thread
From: Rob Herring @ 2017-02-27 17:20 UTC (permalink / raw)
  To: Baoyou Xie
  Cc: jun.nie, lgirdwood, broonie, mark.rutland, perex, tiwai, lars,
	arnd, kuninori.morimoto.gx, ckeepax, bardliao, nh6z,
	Paul.Handrigan, oder_chiou, axel.lin, petr, yesanishhere,
	srinivas.kandagatla, linux-arm-kernel, alsa-devel, devicetree,
	linux-kernel, shawnguo, xie.baoyou, chen.chaokai, wang.qiang01

On Wed, Feb 15, 2017 at 06:55:08PM +0800, Baoyou Xie wrote:
> This patch adds dt-binding documentation for zte's aud96p22 controller.
> 
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
> ---
>  .../devicetree/bindings/sound/zte,zx-96p22.txt     | 24 ++++++++++++++++++++++
>  1 file changed, 24 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
> 
> diff --git a/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt b/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
> new file mode 100644
> index 0000000..4184566
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
> @@ -0,0 +1,24 @@
> +ZTE zx96p22 controller
> +
> +Required properties:
> + - compatible : Must be "zte,zx-aud96p22"
> + - #sound-dai-cells: Should be 0
> + - reg : Offset of I2C register for zx96p22
> +
> +Example:
> +
> +	audio_i2c0: audio_i2c0@1486000 {

i2c@...

> +		compatible = "zte,zx296718-i2c";
> +		reg = <0x01486000 0x1000>;
> +		interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		clocks = <&audiocrm AUDIO_I2C0_WCLK>;
> +		clock-frequency = <1600000>;
> +		status = "ok";

No need for status in examples.

With that,

Acked-by: Rob Herring <robh@kernel.org>


> +		inner_codec: aud96p22@22 {
> +			compatible = "zte,zx-aud96p22";
> +			#sound-dai-cells = <0>;
> +			reg = <0x22>;
> +		};
> +	};
> -- 
> 2.7.4
> 

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

* Re: [PATCH v1 1/3] ASoC: zx-96p22: add documentation for zte's aud96p22 controller
@ 2017-02-27 17:20   ` Rob Herring
  0 siblings, 0 replies; 22+ messages in thread
From: Rob Herring @ 2017-02-27 17:20 UTC (permalink / raw)
  To: Baoyou Xie
  Cc: mark.rutland, alsa-devel, kuninori.morimoto.gx, lgirdwood, tiwai,
	srinivas.kandagatla, bardliao, lars, axel.lin, Paul.Handrigan,
	chen.chaokai, wang.qiang01, devicetree, arnd, yesanishhere,
	xie.baoyou, nh6z, broonie, ckeepax, linux-arm-kernel, oder_chiou,
	linux-kernel, petr, jun.nie, shawnguo

On Wed, Feb 15, 2017 at 06:55:08PM +0800, Baoyou Xie wrote:
> This patch adds dt-binding documentation for zte's aud96p22 controller.
> 
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
> ---
>  .../devicetree/bindings/sound/zte,zx-96p22.txt     | 24 ++++++++++++++++++++++
>  1 file changed, 24 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
> 
> diff --git a/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt b/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
> new file mode 100644
> index 0000000..4184566
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
> @@ -0,0 +1,24 @@
> +ZTE zx96p22 controller
> +
> +Required properties:
> + - compatible : Must be "zte,zx-aud96p22"
> + - #sound-dai-cells: Should be 0
> + - reg : Offset of I2C register for zx96p22
> +
> +Example:
> +
> +	audio_i2c0: audio_i2c0@1486000 {

i2c@...

> +		compatible = "zte,zx296718-i2c";
> +		reg = <0x01486000 0x1000>;
> +		interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		clocks = <&audiocrm AUDIO_I2C0_WCLK>;
> +		clock-frequency = <1600000>;
> +		status = "ok";

No need for status in examples.

With that,

Acked-by: Rob Herring <robh@kernel.org>


> +		inner_codec: aud96p22@22 {
> +			compatible = "zte,zx-aud96p22";
> +			#sound-dai-cells = <0>;
> +			reg = <0x22>;
> +		};
> +	};
> -- 
> 2.7.4
> 

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

* [PATCH v1 1/3] ASoC: zx-96p22: add documentation for zte's aud96p22  controller
@ 2017-02-27 17:20   ` Rob Herring
  0 siblings, 0 replies; 22+ messages in thread
From: Rob Herring @ 2017-02-27 17:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 15, 2017 at 06:55:08PM +0800, Baoyou Xie wrote:
> This patch adds dt-binding documentation for zte's aud96p22 controller.
> 
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
> ---
>  .../devicetree/bindings/sound/zte,zx-96p22.txt     | 24 ++++++++++++++++++++++
>  1 file changed, 24 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
> 
> diff --git a/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt b/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
> new file mode 100644
> index 0000000..4184566
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/zte,zx-96p22.txt
> @@ -0,0 +1,24 @@
> +ZTE zx96p22 controller
> +
> +Required properties:
> + - compatible : Must be "zte,zx-aud96p22"
> + - #sound-dai-cells: Should be 0
> + - reg : Offset of I2C register for zx96p22
> +
> +Example:
> +
> +	audio_i2c0: audio_i2c0 at 1486000 {

i2c at ...

> +		compatible = "zte,zx296718-i2c";
> +		reg = <0x01486000 0x1000>;
> +		interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		clocks = <&audiocrm AUDIO_I2C0_WCLK>;
> +		clock-frequency = <1600000>;
> +		status = "ok";

No need for status in examples.

With that,

Acked-by: Rob Herring <robh@kernel.org>


> +		inner_codec: aud96p22 at 22 {
> +			compatible = "zte,zx-aud96p22";
> +			#sound-dai-cells = <0>;
> +			reg = <0x22>;
> +		};
> +	};
> -- 
> 2.7.4
> 

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

end of thread, other threads:[~2017-02-27 17:22 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-15 10:55 [PATCH v1 1/3] ASoC: zx-96p22: add documentation for zte's aud96p22 controller Baoyou Xie
2017-02-15 10:55 ` Baoyou Xie
2017-02-15 10:55 ` Baoyou Xie
2017-02-15 10:55 ` [PATCH v1 2/3] MAINTAINERS: add zte 96p22 controller driver to ARM ZTE architecture Baoyou Xie
2017-02-15 10:55   ` Baoyou Xie
2017-02-15 10:55   ` Baoyou Xie
2017-02-15 10:55 ` [PATCH v1 3/3] ASoC: zx-96p22: add zte's aud96p22 controller driver Baoyou Xie
2017-02-15 10:55   ` Baoyou Xie
2017-02-15 10:55   ` Baoyou Xie
2017-02-15 11:24   ` Charles Keepax
2017-02-15 11:24     ` Charles Keepax
2017-02-15 11:24     ` Charles Keepax
2017-02-16  0:24     ` Baoyou Xie
2017-02-16  3:09     ` Baoyou Xie
2017-02-16 11:17   ` Shawn Guo
2017-02-16 11:17     ` Shawn Guo
2017-02-16 11:17     ` Shawn Guo
2017-02-16 11:00 ` [PATCH v1 1/3] ASoC: zx-96p22: add documentation for zte's aud96p22 controller Shawn Guo
2017-02-16 11:00   ` Shawn Guo
2017-02-27 17:20 ` Rob Herring
2017-02-27 17:20   ` Rob Herring
2017-02-27 17:20   ` Rob Herring

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.