devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 1/3] ASoC: zx-tdm: add documentation for zte's tdm controller
@ 2017-02-13  8:17 Baoyou Xie
  2017-02-13  8:17 ` [PATCH v1 2/3] MAINTAINERS: add zte tdm controller driver to ARM ZTE architecture Baoyou Xie
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Baoyou Xie @ 2017-02-13  8:17 UTC (permalink / raw)
  To: lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	jun.nie-QSEj5FYQhm4dnm+yROfE0A, shawn.guo-QSEj5FYQhm4dnm+yROfE0A
  Cc: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	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 tdm controller.

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

diff --git a/Documentation/devicetree/bindings/sound/zte,tdm.txt b/Documentation/devicetree/bindings/sound/zte,tdm.txt
new file mode 100644
index 0000000..f6e4f7f
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/zte,tdm.txt
@@ -0,0 +1,32 @@
+ZTE TDM DAI driver
+
+Required properties:
+
+- compatible : should be one of the following.
+       * zte,zx-tdm
+- reg : physical base address of the controller and length of memory mapped
+    region.
+- clocks : Pairs of phandle and specifier referencing the controller's clocks.
+- clock-names: "tdm_wclk" for the wclk.
+               "tdm_pclk" for the pclk.
+-#clock-cells: should be 1.
+- zte,tdm-dma-sysctrl : Reference to the sysctrl controller controlling
+    the dma. includes:
+	phandle of sysctrl.
+	register offset in sysctrl for control dma.
+	mask of the register that be written to dma.
+	value of the register that be written to dma.
+
+Example:
+
+	tdm: tdm@1487000 {
+		compatible = "zte,zx-tdm";
+		reg = <0x01487000 0x1000>;
+		clocks = <&audiocrm AUDIO_TDM_WCLK>, <&audiocrm AUDIO_TDM_PCLK>;
+		clock-names = "tdm_wclk", "tdm_pclk";
+		#clock-cells = <1>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&tdm_global_pin>;
+		zte,tdm-dma-sysctrl = <&sysctrl 0x10c 0xf 0xf>;
+		status = "ok";
+	};
-- 
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] 5+ messages in thread

* [PATCH v1 2/3] MAINTAINERS: add zte tdm controller driver to ARM ZTE architecture
  2017-02-13  8:17 [PATCH v1 1/3] ASoC: zx-tdm: add documentation for zte's tdm controller Baoyou Xie
@ 2017-02-13  8:17 ` Baoyou Xie
  2017-02-13  8:17 ` [PATCH v1 3/3] ASoC: zx-tdm: add zte's tdm controller driver Baoyou Xie
       [not found] ` <1486973853-25291-1-git-send-email-baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
  2 siblings, 0 replies; 5+ messages in thread
From: Baoyou Xie @ 2017-02-13  8:17 UTC (permalink / raw)
  To: lgirdwood, broonie, robh+dt, mark.rutland, perex, tiwai, jun.nie,
	shawn.guo
  Cc: devicetree, alsa-devel, xie.baoyou, linux-kernel, chen.chaokai,
	wang.qiang01, baoyou.xie, linux-arm-kernel

Add the zte tdm 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..1269eb6 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-tdm.txt
 F:	include/dt-bindings/soc/zx*.h
+F:	sound/soc/zte/zx-tdm.c
 
 ARM/ZYNQ ARCHITECTURE
 M:	Michal Simek <michal.simek@xilinx.com>
-- 
2.7.4

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

* [PATCH v1 3/3] ASoC: zx-tdm: add zte's tdm controller driver
  2017-02-13  8:17 [PATCH v1 1/3] ASoC: zx-tdm: add documentation for zte's tdm controller Baoyou Xie
  2017-02-13  8:17 ` [PATCH v1 2/3] MAINTAINERS: add zte tdm controller driver to ARM ZTE architecture Baoyou Xie
@ 2017-02-13  8:17 ` Baoyou Xie
  2017-02-14 13:31   ` Shawn Guo
       [not found] ` <1486973853-25291-1-git-send-email-baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
  2 siblings, 1 reply; 5+ messages in thread
From: Baoyou Xie @ 2017-02-13  8:17 UTC (permalink / raw)
  To: lgirdwood, broonie, robh+dt, mark.rutland, perex, tiwai, jun.nie,
	shawn.guo
  Cc: alsa-devel, devicetree, linux-kernel, linux-arm-kernel,
	baoyou.xie, xie.baoyou, chen.chaokai, wang.qiang01

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

Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
---
 sound/soc/zte/Kconfig  |   8 +
 sound/soc/zte/Makefile |   1 +
 sound/soc/zte/zx-tdm.c | 466 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 475 insertions(+)
 create mode 100644 sound/soc/zte/zx-tdm.c

diff --git a/sound/soc/zte/Kconfig b/sound/soc/zte/Kconfig
index 6d8a90d..75f67a5 100644
--- a/sound/soc/zte/Kconfig
+++ b/sound/soc/zte/Kconfig
@@ -15,3 +15,11 @@ config ZX_I2S
 	help
 	  Say Y or M if you want to add support for codecs attached to the
 	  ZTE ZX I2S interface
+
+config ZX_TDM
+        tristate "ZTE ZX TDM Driver Support"
+        depends on COMMON_CLK
+        select SND_SOC_GENERIC_DMAENGINE_PCM
+        help
+          Say Y or M if you want to add support for codecs attached to the
+          ZTE ZX TDM interface
diff --git a/sound/soc/zte/Makefile b/sound/soc/zte/Makefile
index 77768f5..1fc841a 100644
--- a/sound/soc/zte/Makefile
+++ b/sound/soc/zte/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_ZX_SPDIF)	+= zx-spdif.o
 obj-$(CONFIG_ZX_I2S)	+= zx-i2s.o
+obj-$(CONFIG_ZX_TDM)	+= zx-tdm.o
diff --git a/sound/soc/zte/zx-tdm.c b/sound/soc/zte/zx-tdm.c
new file mode 100644
index 0000000..72e5136
--- /dev/null
+++ b/sound/soc/zte/zx-tdm.c
@@ -0,0 +1,466 @@
+/*
+ * ZTE's TDM driver
+ *
+ * Copyright (C) 2017 ZTE Ltd
+ *
+ * Author: Baoyou Xie <baoyou.xie@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#define REG_TIMING_CTRL		0x04
+#define	REG_TX_FIFO_CTRL	0x0C
+#define	REG_RX_FIFO_CTRL	0x10
+#define REG_INT_EN		0x1C
+#define REG_INT_STATUS		0x20
+#define REG_DATABUF		0x24
+#define REG_TS_MASK0		0x44
+#define REG_PROCESS_CTRL	0x54
+
+#define FIFO_CTRL_TX_RST	BIT(0)
+#define FIFO_CTRL_RX_RST	BIT(0)
+#define DEAGULT_FIFO_THRES	GENMASK(4, 2)
+
+#define FIFO_CTRL_TX_DMA_EN	BIT(1)
+#define FIFO_CTRL_RX_DMA_EN	BIT(1)
+
+#define TX_FIFO_RST_MASK	BIT(0)
+#define RX_FIFO_RST_MASK	BIT(0)
+
+#define FIFOCTRL_TX_FIFO_RST	BIT(0)
+#define FIFOCTRL_RX_FIFO_RST	BIT(0)
+
+#define TXTH_MASK		GENMASK(5, 2)
+#define RXTH_MASK		GENMASK(5, 2)
+
+#define FIFOCTRL_THRESHOLD(x)	(x << 2)
+
+#define TIMING_MS_MASK		BIT(1)
+/*
+ * 00: 8 clk cycles every timeslot
+ * 01: 16 clk cycles every timeslot
+ * 10: 32 clk cycles every timeslot
+ */
+#define TIMING_SYNC_WIDTH_MASK	GENMASK(6, 5)
+#define TIMING_WIDTH_SHIFT      5
+#define TIMING_DEFAULT_WIDTH    0
+#define TIMING_TS_WIDTH(x)	((x) << TIMING_WIDTH_SHIFT)
+#define TIMING_WIDTH_FACTOR     8
+
+#define TIMING_MASTER_MODE	BIT(21)
+#define TIMING_LSB_FIRST	BIT(20)
+#define TIMING_TS_NUM(x)	((x - 1) << 7)
+#define TIMING_CLK_SEL_MASK	GENMASK(2, 0)
+#define TIMING_CLK_SEL_DEF	BIT(2)
+
+#define PROCESS_TX_EN		BIT(0)
+#define PROCESS_RX_EN		BIT(1)
+#define PROCESS_TDM_EN		BIT(2)
+#define PROCESS_DISABLE_ALL	0
+
+#define INT_DISABLE_ALL		0
+#define INT_STATUS_MASK		GENMASK(6, 0)
+
+struct zx_tdm_info {
+	struct snd_dmaengine_dai_dma_data	dma_playback;
+	struct snd_dmaengine_dai_dma_data	dma_capture;
+	resource_size_t				phy_addr;
+	void __iomem				*regmap;
+	struct clk				*dai_wclk;
+	struct clk				*dai_pclk;
+	int					master;
+	struct device				*dev;
+};
+
+static inline u32 zx_tdm_readl(struct zx_tdm_info *tdm, u16 reg)
+{
+	return readl_relaxed(tdm->regmap + reg);
+}
+
+static inline void zx_tdm_writel(struct zx_tdm_info *tdm, u16 reg, u32 val)
+{
+	writel_relaxed(val, tdm->regmap + reg);
+}
+
+static void zx_tdm_tx_en(struct zx_tdm_info *tdm, bool on)
+{
+	unsigned long val;
+
+	val = zx_tdm_readl(tdm, REG_PROCESS_CTRL);
+	if (on)
+		val |= PROCESS_TX_EN | PROCESS_TDM_EN;
+	else
+		val &= ~(PROCESS_TX_EN | PROCESS_TDM_EN);
+	zx_tdm_writel(tdm, REG_PROCESS_CTRL, val);
+}
+
+static void zx_tdm_rx_en(struct zx_tdm_info *tdm, bool on)
+{
+	unsigned long val;
+
+	val = zx_tdm_readl(tdm, REG_PROCESS_CTRL);
+	if (on)
+		val |= PROCESS_RX_EN | PROCESS_TDM_EN;
+	else
+		val &= ~(PROCESS_RX_EN | PROCESS_TDM_EN);
+	zx_tdm_writel(tdm, REG_PROCESS_CTRL, val);
+}
+
+static void zx_tdm_tx_dma_en(struct zx_tdm_info *tdm, bool on)
+{
+	unsigned long val;
+
+	val = zx_tdm_readl(tdm, REG_TX_FIFO_CTRL);
+	val |= FIFO_CTRL_TX_RST | DEAGULT_FIFO_THRES;
+	if (on)
+		val |= FIFO_CTRL_TX_DMA_EN;
+	else
+		val &= ~FIFO_CTRL_TX_DMA_EN;
+	zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, val);
+}
+
+static void zx_tdm_rx_dma_en(struct zx_tdm_info *tdm, bool on)
+{
+	unsigned long val;
+
+	val = zx_tdm_readl(tdm, REG_RX_FIFO_CTRL);
+	val |= FIFO_CTRL_RX_RST | DEAGULT_FIFO_THRES;
+	if (on)
+		val |= FIFO_CTRL_RX_DMA_EN;
+	else
+		val &= ~FIFO_CTRL_RX_DMA_EN;
+	zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, val);
+}
+
+#define ZX_TDM_RATES	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000)
+
+#define ZX_TDM_FMTBIT \
+	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_MU_LAW | \
+	SNDRV_PCM_FORMAT_A_LAW)
+
+static int zx_tdm_dai_probe(struct snd_soc_dai *dai)
+{
+	struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
+
+	snd_soc_dai_set_drvdata(dai, zx_tdm);
+	zx_tdm->dma_playback.addr = zx_tdm->phy_addr + REG_DATABUF;
+	zx_tdm->dma_playback.maxburst = 16;
+	zx_tdm->dma_capture.addr = zx_tdm->phy_addr + REG_DATABUF;
+	zx_tdm->dma_capture.maxburst = 16;
+	snd_soc_dai_init_dma_data(dai, &zx_tdm->dma_playback,
+				  &zx_tdm->dma_capture);
+	return 0;
+}
+
+static int zx_tdm_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+	struct zx_tdm_info *tdm = snd_soc_dai_get_drvdata(cpu_dai);
+	unsigned long val;
+
+	val = zx_tdm_readl(tdm, REG_TIMING_CTRL);
+	val &= ~(TIMING_SYNC_WIDTH_MASK | TIMING_MS_MASK);
+	val |= TIMING_DEFAULT_WIDTH << TIMING_WIDTH_SHIFT;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		tdm->master = 1;
+		val |= TIMING_MASTER_MODE;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		tdm->master = 0;
+		val &= (~TIMING_MASTER_MODE);
+		break;
+	default:
+		dev_err(cpu_dai->dev, "Unknown master/slave format\n");
+		return -EINVAL;
+	}
+
+
+	zx_tdm_writel(tdm, REG_TIMING_CTRL, val);
+
+	return 0;
+}
+
+static int zx_tdm_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params,
+			    struct snd_soc_dai *socdai)
+{
+	struct zx_tdm_info *tdm = snd_soc_dai_get_drvdata(socdai);
+	struct snd_dmaengine_dai_dma_data *dma_data;
+	unsigned int ts_width = TIMING_DEFAULT_WIDTH;
+	unsigned int ch_num = 32;
+	unsigned int mask = 0;
+	unsigned int ret = 0;
+	unsigned long val;
+
+	dma_data = snd_soc_dai_get_dma_data(socdai, substream);
+	dma_data->addr_width = ch_num >> 3;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_MU_LAW:
+	case SNDRV_PCM_FORMAT_A_LAW:
+	case SNDRV_PCM_FORMAT_S16_LE:
+		ts_width = 1;
+		break;
+	default:
+		ts_width = 0;
+		dev_err(socdai->dev, "Unknown data format\n");
+		return -EINVAL;
+	}
+
+	val = zx_tdm_readl(tdm, REG_TIMING_CTRL);
+	val |= TIMING_TS_WIDTH(ts_width) | TIMING_TS_NUM(1);
+	zx_tdm_writel(tdm, REG_TIMING_CTRL, val);
+	zx_tdm_writel(tdm, REG_TS_MASK0, mask);
+
+	if (tdm->master)
+		ret = clk_set_rate(tdm->dai_wclk,
+			params_rate(params) * TIMING_WIDTH_FACTOR * ch_num);
+
+	return ret;
+}
+
+static int zx_tdm_trigger(struct snd_pcm_substream *substream, int cmd,
+			  struct snd_soc_dai *dai)
+{
+	int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
+	struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
+	unsigned int val;
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		if (capture) {
+			val = zx_tdm_readl(zx_tdm, REG_RX_FIFO_CTRL);
+			val |= FIFOCTRL_RX_FIFO_RST;
+			zx_tdm_writel(zx_tdm, REG_RX_FIFO_CTRL, val);
+
+			zx_tdm_rx_dma_en(zx_tdm, true);
+		} else {
+			val = zx_tdm_readl(zx_tdm, REG_TX_FIFO_CTRL);
+			val |= FIFOCTRL_TX_FIFO_RST;
+			zx_tdm_writel(zx_tdm, REG_TX_FIFO_CTRL, val);
+
+			zx_tdm_tx_dma_en(zx_tdm, true);
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if (capture)
+			zx_tdm_rx_en(zx_tdm, true);
+		else
+			zx_tdm_tx_en(zx_tdm, true);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		if (capture)
+			zx_tdm_rx_dma_en(zx_tdm, false);
+		else
+			zx_tdm_tx_dma_en(zx_tdm, false);
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if (capture)
+			zx_tdm_rx_en(zx_tdm, false);
+		else
+			zx_tdm_tx_en(zx_tdm, false);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int zx_tdm_startup(struct snd_pcm_substream *substream,
+			  struct snd_soc_dai *dai)
+{
+	struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
+	int ret;
+
+	ret = clk_prepare_enable(zx_tdm->dai_wclk);
+	if (ret)
+		return ret;
+
+	ret = clk_prepare_enable(zx_tdm->dai_pclk);
+	if (ret) {
+		clk_disable_unprepare(zx_tdm->dai_wclk);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void zx_tdm_shutdown(struct snd_pcm_substream *substream,
+			    struct snd_soc_dai *dai)
+{
+	struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
+
+	clk_disable_unprepare(zx_tdm->dai_pclk);
+	clk_disable_unprepare(zx_tdm->dai_wclk);
+}
+
+static struct snd_soc_dai_ops zx_tdm_dai_ops = {
+	.trigger	= zx_tdm_trigger,
+	.hw_params	= zx_tdm_hw_params,
+	.set_fmt	= zx_tdm_set_fmt,
+	.startup	= zx_tdm_startup,
+	.shutdown	= zx_tdm_shutdown,
+};
+
+static const struct snd_soc_component_driver zx_tdm_component = {
+	.name			= "zx-tdm",
+};
+
+static void zx_tdm_init_state(struct zx_tdm_info *tdm)
+{
+	unsigned int val;
+
+	zx_tdm_writel(tdm, REG_PROCESS_CTRL, PROCESS_DISABLE_ALL);
+
+	val = zx_tdm_readl(tdm, REG_TIMING_CTRL);
+	val |= TIMING_LSB_FIRST;
+	val &= (~TIMING_CLK_SEL_MASK);
+	val |= TIMING_CLK_SEL_DEF;
+	zx_tdm_writel(tdm, REG_TIMING_CTRL, val);
+
+	zx_tdm_writel(tdm, REG_INT_EN, INT_DISABLE_ALL);
+	/*
+	 * write INT_STATUS register to clear it.
+	 */
+	zx_tdm_writel(tdm, REG_INT_STATUS, INT_STATUS_MASK);
+	zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, FIFOCTRL_RX_FIFO_RST);
+	zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, FIFOCTRL_TX_FIFO_RST);
+
+	val = zx_tdm_readl(tdm, REG_RX_FIFO_CTRL);
+	val &= ~(RXTH_MASK | RX_FIFO_RST_MASK);
+	val |= FIFOCTRL_THRESHOLD(8);
+	zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, val);
+
+	val = zx_tdm_readl(tdm, REG_TX_FIFO_CTRL);
+	val &= ~(TXTH_MASK | TX_FIFO_RST_MASK);
+	val |= FIFOCTRL_THRESHOLD(8);
+	zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, val);
+}
+
+static struct snd_soc_dai_driver zx_tdm_dai = {
+	.name	= "zx-tdm-dai",
+	.id	= 0,
+	.probe	= zx_tdm_dai_probe,
+	.playback   = {
+		.channels_min	= 1,
+		.channels_max	= 4,
+		.rates		= ZX_TDM_RATES,
+		.formats	= ZX_TDM_FMTBIT,
+	},
+	.capture = {
+		.channels_min	= 1,
+		.channels_max	= 4,
+		.rates		= ZX_TDM_RATES,
+		.formats	= ZX_TDM_FMTBIT,
+	},
+	.ops	= &zx_tdm_dai_ops,
+};
+
+static int zx_tdm_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct of_phandle_args out_args;
+	unsigned int dma_reg_offset;
+	struct zx_tdm_info *zx_tdm;
+	unsigned int dma_config;
+	unsigned int dma_mask;
+	struct resource *res;
+	void __iomem *regmap;
+	int ret;
+
+	zx_tdm = devm_kzalloc(&pdev->dev, sizeof(*zx_tdm), GFP_KERNEL);
+	if (!zx_tdm)
+		return -ENOMEM;
+
+	zx_tdm->dev = dev;
+
+	zx_tdm->dai_wclk = devm_clk_get(&pdev->dev, "tdm_wclk");
+	if (IS_ERR(zx_tdm->dai_wclk)) {
+		dev_err(&pdev->dev, "Fail to get tdm_wclk\n");
+		return PTR_ERR(zx_tdm->dai_wclk);
+	}
+
+	zx_tdm->dai_pclk = devm_clk_get(&pdev->dev, "tdm_pclk");
+	if (IS_ERR(zx_tdm->dai_pclk)) {
+		dev_err(&pdev->dev, "Fail to get tdm_pclk\n");
+		return PTR_ERR(zx_tdm->dai_pclk);
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	zx_tdm->phy_addr = res->start;
+	zx_tdm->regmap = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(zx_tdm->regmap)) {
+		dev_err(&pdev->dev, "ioremap failed!\n");
+		return PTR_ERR(zx_tdm->regmap);
+	}
+
+	ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
+				"zte,tdm-dma-sysctrl", 3, 0, &out_args);
+	if (ret) {
+		dev_err(&pdev->dev, "Fail to get zte,tdm-dma-sysctrl\n");
+		return ret;
+	}
+
+	dma_reg_offset = out_args.args[0];
+	dma_mask = out_args.args[1];
+	dma_config = out_args.args[2];
+	regmap = syscon_node_to_regmap(out_args.np);
+	if (IS_ERR(regmap)) {
+		of_node_put(out_args.np);
+		return PTR_ERR(regmap);
+	}
+
+	regmap_update_bits(regmap, dma_reg_offset, dma_mask, dma_config);
+	of_node_put(out_args.np);
+
+	zx_tdm_init_state(zx_tdm);
+	platform_set_drvdata(pdev, zx_tdm);
+
+	ret = devm_snd_soc_register_component(&pdev->dev, &zx_tdm_component,
+						&zx_tdm_dai, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "Register DAI failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+	if (ret)
+		dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret);
+
+	return ret;
+}
+
+static const struct of_device_id zx_tdm_dt_ids[] = {
+	{ .compatible = "zte,zx-tdm", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, zx_tdm_dt_ids);
+
+static struct platform_driver tdm_driver = {
+	.probe = zx_tdm_probe,
+	.driver = {
+		.name = "zx-tdm",
+		.of_match_table = zx_tdm_dt_ids,
+	},
+};
+
+module_platform_driver(tdm_driver);
+
+MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
+MODULE_DESCRIPTION("ZTE TDM DAI driver");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4

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

* Re: [PATCH v1 1/3] ASoC: zx-tdm: add documentation for zte's tdm controller
       [not found] ` <1486973853-25291-1-git-send-email-baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
@ 2017-02-14  2:25   ` Shawn Guo
  0 siblings, 0 replies; 5+ messages in thread
From: Shawn Guo @ 2017-02-14  2:25 UTC (permalink / raw)
  To: Baoyou Xie
  Cc: lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, broonie-DgEjT+Ai2ygdnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	jun.nie-QSEj5FYQhm4dnm+yROfE0A, shawn.guo-QSEj5FYQhm4dnm+yROfE0A,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	xie.baoyou-Th6q7B73Y6EnDS1+zs4M5A,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	chen.chaokai-Th6q7B73Y6EnDS1+zs4M5A,
	wang.qiang01-Th6q7B73Y6EnDS1+zs4M5A,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Mon, Feb 13, 2017 at 04:17:31PM +0800, Baoyou Xie wrote:
> This patch adds dt-binding documentation for zte's tdm controller.
> 
> Signed-off-by: Baoyou Xie <baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

"bindings doc" instead of "documentation" in patch subject is more
clear.

> ---
>  .../devicetree/bindings/sound/zte,tdm.txt          | 32 ++++++++++++++++++++++
>  1 file changed, 32 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/sound/zte,tdm.txt
> 
> diff --git a/Documentation/devicetree/bindings/sound/zte,tdm.txt b/Documentation/devicetree/bindings/sound/zte,tdm.txt
> new file mode 100644
> index 0000000..f6e4f7f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/zte,tdm.txt
> @@ -0,0 +1,32 @@
> +ZTE TDM DAI driver
> +
> +Required properties:
> +
> +- compatible : should be one of the following.
> +       * zte,zx-tdm

We usually use particular SoC name (e.g. zx296702) rather than family
name (e.g. zx or zx2967) in the compatible string to specify the
programming model, because that's more explicit.

> +- reg : physical base address of the controller and length of memory mapped
> +    region.
> +- clocks : Pairs of phandle and specifier referencing the controller's clocks.
> +- clock-names: "tdm_wclk" for the wclk.
> +               "tdm_pclk" for the pclk.

The "tdm_" prefix in the name is redundant, as it's in tdm context
anyway.

> +-#clock-cells: should be 1.
> +- zte,tdm-dma-sysctrl : Reference to the sysctrl controller controlling
> +    the dma. includes:
> +	phandle of sysctrl.
> +	register offset in sysctrl for control dma.
> +	mask of the register that be written to dma.
> +	value of the register that be written to dma.

written to dma?  I think it gets written to sysctrl block.

> +
> +Example:
> +
> +	tdm: tdm@1487000 {
> +		compatible = "zte,zx-tdm";
> +		reg = <0x01487000 0x1000>;
> +		clocks = <&audiocrm AUDIO_TDM_WCLK>, <&audiocrm AUDIO_TDM_PCLK>;
> +		clock-names = "tdm_wclk", "tdm_pclk";
> +		#clock-cells = <1>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&tdm_global_pin>;
> +		zte,tdm-dma-sysctrl = <&sysctrl 0x10c 0xf 0xf>;

I think we only need to set up bit 2 instead of bits [3:0], since we
only need to select dma channel 20 and 21 for PCM/TDM from UART5.

> +		status = "ok";

We usually use "okay" instead of "ok" for status.  For example in
bindings doc, I would suggest that we simply omit 'status' property.

Shawn

> +	};
> -- 
> 2.7.4
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
--
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] 5+ messages in thread

* Re: [PATCH v1 3/3] ASoC: zx-tdm: add zte's tdm controller driver
  2017-02-13  8:17 ` [PATCH v1 3/3] ASoC: zx-tdm: add zte's tdm controller driver Baoyou Xie
@ 2017-02-14 13:31   ` Shawn Guo
  0 siblings, 0 replies; 5+ messages in thread
From: Shawn Guo @ 2017-02-14 13:31 UTC (permalink / raw)
  To: Baoyou Xie
  Cc: mark.rutland, devicetree, alsa-devel, shawn.guo, linux-kernel,
	xie.baoyou, tiwai, robh+dt, lgirdwood, broonie, chen.chaokai,
	wang.qiang01, jun.nie, linux-arm-kernel

On Mon, Feb 13, 2017 at 04:17:33PM +0800, Baoyou Xie wrote:
> This patch adds tdm controller driver for zte's SoC family.
> 
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>

The patch looks rather pretty to me.  I have only a few small comments
below.

> ---
>  sound/soc/zte/Kconfig  |   8 +
>  sound/soc/zte/Makefile |   1 +
>  sound/soc/zte/zx-tdm.c | 466 +++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 475 insertions(+)
>  create mode 100644 sound/soc/zte/zx-tdm.c
> 
> diff --git a/sound/soc/zte/Kconfig b/sound/soc/zte/Kconfig
> index 6d8a90d..75f67a5 100644
> --- a/sound/soc/zte/Kconfig
> +++ b/sound/soc/zte/Kconfig
> @@ -15,3 +15,11 @@ config ZX_I2S
>  	help
>  	  Say Y or M if you want to add support for codecs attached to the
>  	  ZTE ZX I2S interface
> +
> +config ZX_TDM
> +        tristate "ZTE ZX TDM Driver Support"
> +        depends on COMMON_CLK
> +        select SND_SOC_GENERIC_DMAENGINE_PCM
> +        help
> +          Say Y or M if you want to add support for codecs attached to the
> +          ZTE ZX TDM interface
> diff --git a/sound/soc/zte/Makefile b/sound/soc/zte/Makefile
> index 77768f5..1fc841a 100644
> --- a/sound/soc/zte/Makefile
> +++ b/sound/soc/zte/Makefile
> @@ -1,2 +1,3 @@
>  obj-$(CONFIG_ZX_SPDIF)	+= zx-spdif.o
>  obj-$(CONFIG_ZX_I2S)	+= zx-i2s.o
> +obj-$(CONFIG_ZX_TDM)	+= zx-tdm.o
> diff --git a/sound/soc/zte/zx-tdm.c b/sound/soc/zte/zx-tdm.c
> new file mode 100644
> index 0000000..72e5136
> --- /dev/null
> +++ b/sound/soc/zte/zx-tdm.c
> @@ -0,0 +1,466 @@
> +/*
> + * ZTE's TDM driver
> + *
> + * Copyright (C) 2017 ZTE Ltd
> + *
> + * Author: Baoyou Xie <baoyou.xie@linaro.org>
> + *
> + * License terms: GNU General Public License (GPL) version 2
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/io.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <sound/dmaengine_pcm.h>
> +#include <sound/pcm_params.h>
> +#include <sound/soc.h>
> +#include <sound/soc-dai.h>
> +
> +#define REG_TIMING_CTRL		0x04
> +#define	REG_TX_FIFO_CTRL	0x0C
> +#define	REG_RX_FIFO_CTRL	0x10

Please consistently use space instead of tab right after #define.

> +#define REG_INT_EN		0x1C
> +#define REG_INT_STATUS		0x20
> +#define REG_DATABUF		0x24
> +#define REG_TS_MASK0		0x44
> +#define REG_PROCESS_CTRL	0x54
> +
> +#define FIFO_CTRL_TX_RST	BIT(0)
> +#define FIFO_CTRL_RX_RST	BIT(0)
> +#define DEAGULT_FIFO_THRES	GENMASK(4, 2)
> +
> +#define FIFO_CTRL_TX_DMA_EN	BIT(1)
> +#define FIFO_CTRL_RX_DMA_EN	BIT(1)
> +
> +#define TX_FIFO_RST_MASK	BIT(0)
> +#define RX_FIFO_RST_MASK	BIT(0)
> +
> +#define FIFOCTRL_TX_FIFO_RST	BIT(0)
> +#define FIFOCTRL_RX_FIFO_RST	BIT(0)
> +
> +#define TXTH_MASK		GENMASK(5, 2)
> +#define RXTH_MASK		GENMASK(5, 2)
> +
> +#define FIFOCTRL_THRESHOLD(x)	(x << 2)

((x) << 2)

> +
> +#define TIMING_MS_MASK		BIT(1)
> +/*
> + * 00: 8 clk cycles every timeslot
> + * 01: 16 clk cycles every timeslot
> + * 10: 32 clk cycles every timeslot
> + */
> +#define TIMING_SYNC_WIDTH_MASK	GENMASK(6, 5)
> +#define TIMING_WIDTH_SHIFT      5
> +#define TIMING_DEFAULT_WIDTH    0
> +#define TIMING_TS_WIDTH(x)	((x) << TIMING_WIDTH_SHIFT)
> +#define TIMING_WIDTH_FACTOR     8
> +
> +#define TIMING_MASTER_MODE	BIT(21)
> +#define TIMING_LSB_FIRST	BIT(20)
> +#define TIMING_TS_NUM(x)	((x - 1) << 7)

Ditto

> +#define TIMING_CLK_SEL_MASK	GENMASK(2, 0)
> +#define TIMING_CLK_SEL_DEF	BIT(2)
> +
> +#define PROCESS_TX_EN		BIT(0)
> +#define PROCESS_RX_EN		BIT(1)
> +#define PROCESS_TDM_EN		BIT(2)
> +#define PROCESS_DISABLE_ALL	0
> +
> +#define INT_DISABLE_ALL		0
> +#define INT_STATUS_MASK		GENMASK(6, 0)
> +
> +struct zx_tdm_info {
> +	struct snd_dmaengine_dai_dma_data	dma_playback;
> +	struct snd_dmaengine_dai_dma_data	dma_capture;
> +	resource_size_t				phy_addr;
> +	void __iomem				*regmap;

Variable name 'regmap' is usually used with 'struct regmap *' type.

> +	struct clk				*dai_wclk;
> +	struct clk				*dai_pclk;
> +	int					master;
> +	struct device				*dev;
> +};
> +
> +static inline u32 zx_tdm_readl(struct zx_tdm_info *tdm, u16 reg)
> +{
> +	return readl_relaxed(tdm->regmap + reg);
> +}
> +
> +static inline void zx_tdm_writel(struct zx_tdm_info *tdm, u16 reg, u32 val)
> +{
> +	writel_relaxed(val, tdm->regmap + reg);
> +}
> +
> +static void zx_tdm_tx_en(struct zx_tdm_info *tdm, bool on)
> +{
> +	unsigned long val;
> +
> +	val = zx_tdm_readl(tdm, REG_PROCESS_CTRL);
> +	if (on)
> +		val |= PROCESS_TX_EN | PROCESS_TDM_EN;
> +	else
> +		val &= ~(PROCESS_TX_EN | PROCESS_TDM_EN);
> +	zx_tdm_writel(tdm, REG_PROCESS_CTRL, val);
> +}
> +
> +static void zx_tdm_rx_en(struct zx_tdm_info *tdm, bool on)
> +{
> +	unsigned long val;
> +
> +	val = zx_tdm_readl(tdm, REG_PROCESS_CTRL);
> +	if (on)
> +		val |= PROCESS_RX_EN | PROCESS_TDM_EN;
> +	else
> +		val &= ~(PROCESS_RX_EN | PROCESS_TDM_EN);
> +	zx_tdm_writel(tdm, REG_PROCESS_CTRL, val);
> +}
> +
> +static void zx_tdm_tx_dma_en(struct zx_tdm_info *tdm, bool on)
> +{
> +	unsigned long val;
> +
> +	val = zx_tdm_readl(tdm, REG_TX_FIFO_CTRL);
> +	val |= FIFO_CTRL_TX_RST | DEAGULT_FIFO_THRES;
> +	if (on)
> +		val |= FIFO_CTRL_TX_DMA_EN;
> +	else
> +		val &= ~FIFO_CTRL_TX_DMA_EN;
> +	zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, val);
> +}
> +
> +static void zx_tdm_rx_dma_en(struct zx_tdm_info *tdm, bool on)
> +{
> +	unsigned long val;
> +
> +	val = zx_tdm_readl(tdm, REG_RX_FIFO_CTRL);
> +	val |= FIFO_CTRL_RX_RST | DEAGULT_FIFO_THRES;
> +	if (on)
> +		val |= FIFO_CTRL_RX_DMA_EN;
> +	else
> +		val &= ~FIFO_CTRL_RX_DMA_EN;
> +	zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, val);
> +}
> +
> +#define ZX_TDM_RATES	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000)
> +
> +#define ZX_TDM_FMTBIT \
> +	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_MU_LAW | \
> +	SNDRV_PCM_FORMAT_A_LAW)
> +
> +static int zx_tdm_dai_probe(struct snd_soc_dai *dai)
> +{
> +	struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
> +
> +	snd_soc_dai_set_drvdata(dai, zx_tdm);
> +	zx_tdm->dma_playback.addr = zx_tdm->phy_addr + REG_DATABUF;
> +	zx_tdm->dma_playback.maxburst = 16;
> +	zx_tdm->dma_capture.addr = zx_tdm->phy_addr + REG_DATABUF;
> +	zx_tdm->dma_capture.maxburst = 16;
> +	snd_soc_dai_init_dma_data(dai, &zx_tdm->dma_playback,
> +				  &zx_tdm->dma_capture);
> +	return 0;
> +}
> +
> +static int zx_tdm_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
> +{
> +	struct zx_tdm_info *tdm = snd_soc_dai_get_drvdata(cpu_dai);
> +	unsigned long val;
> +
> +	val = zx_tdm_readl(tdm, REG_TIMING_CTRL);
> +	val &= ~(TIMING_SYNC_WIDTH_MASK | TIMING_MS_MASK);
> +	val |= TIMING_DEFAULT_WIDTH << TIMING_WIDTH_SHIFT;
> +
> +	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
> +	case SND_SOC_DAIFMT_CBM_CFM:
> +		tdm->master = 1;
> +		val |= TIMING_MASTER_MODE;
> +		break;
> +	case SND_SOC_DAIFMT_CBS_CFS:
> +		tdm->master = 0;
> +		val &= (~TIMING_MASTER_MODE);

Unnecessary parenthesis.

> +		break;
> +	default:
> +		dev_err(cpu_dai->dev, "Unknown master/slave format\n");
> +		return -EINVAL;
> +	}
> +
> +
> +	zx_tdm_writel(tdm, REG_TIMING_CTRL, val);
> +
> +	return 0;
> +}
> +
> +static int zx_tdm_hw_params(struct snd_pcm_substream *substream,
> +			    struct snd_pcm_hw_params *params,
> +			    struct snd_soc_dai *socdai)
> +{
> +	struct zx_tdm_info *tdm = snd_soc_dai_get_drvdata(socdai);
> +	struct snd_dmaengine_dai_dma_data *dma_data;
> +	unsigned int ts_width = TIMING_DEFAULT_WIDTH;
> +	unsigned int ch_num = 32;
> +	unsigned int mask = 0;
> +	unsigned int ret = 0;
> +	unsigned long val;
> +
> +	dma_data = snd_soc_dai_get_dma_data(socdai, substream);
> +	dma_data->addr_width = ch_num >> 3;
> +
> +	switch (params_format(params)) {
> +	case SNDRV_PCM_FORMAT_MU_LAW:
> +	case SNDRV_PCM_FORMAT_A_LAW:
> +	case SNDRV_PCM_FORMAT_S16_LE:
> +		ts_width = 1;
> +		break;
> +	default:
> +		ts_width = 0;
> +		dev_err(socdai->dev, "Unknown data format\n");
> +		return -EINVAL;
> +	}
> +
> +	val = zx_tdm_readl(tdm, REG_TIMING_CTRL);
> +	val |= TIMING_TS_WIDTH(ts_width) | TIMING_TS_NUM(1);
> +	zx_tdm_writel(tdm, REG_TIMING_CTRL, val);
> +	zx_tdm_writel(tdm, REG_TS_MASK0, mask);
> +
> +	if (tdm->master)
> +		ret = clk_set_rate(tdm->dai_wclk,
> +			params_rate(params) * TIMING_WIDTH_FACTOR * ch_num);
> +
> +	return ret;
> +}
> +
> +static int zx_tdm_trigger(struct snd_pcm_substream *substream, int cmd,
> +			  struct snd_soc_dai *dai)
> +{
> +	int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
> +	struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
> +	unsigned int val;
> +	int ret = 0;
> +
> +	switch (cmd) {
> +	case SNDRV_PCM_TRIGGER_START:
> +		if (capture) {
> +			val = zx_tdm_readl(zx_tdm, REG_RX_FIFO_CTRL);
> +			val |= FIFOCTRL_RX_FIFO_RST;
> +			zx_tdm_writel(zx_tdm, REG_RX_FIFO_CTRL, val);
> +
> +			zx_tdm_rx_dma_en(zx_tdm, true);
> +		} else {
> +			val = zx_tdm_readl(zx_tdm, REG_TX_FIFO_CTRL);
> +			val |= FIFOCTRL_TX_FIFO_RST;
> +			zx_tdm_writel(zx_tdm, REG_TX_FIFO_CTRL, val);
> +
> +			zx_tdm_tx_dma_en(zx_tdm, true);
> +		}
> +		break;
> +	case SNDRV_PCM_TRIGGER_RESUME:
> +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> +		if (capture)
> +			zx_tdm_rx_en(zx_tdm, true);
> +		else
> +			zx_tdm_tx_en(zx_tdm, true);
> +		break;
> +	case SNDRV_PCM_TRIGGER_STOP:
> +		if (capture)
> +			zx_tdm_rx_dma_en(zx_tdm, false);
> +		else
> +			zx_tdm_tx_dma_en(zx_tdm, false);
> +		break;
> +	case SNDRV_PCM_TRIGGER_SUSPEND:
> +	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> +		if (capture)
> +			zx_tdm_rx_en(zx_tdm, false);
> +		else
> +			zx_tdm_tx_en(zx_tdm, false);
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +static int zx_tdm_startup(struct snd_pcm_substream *substream,
> +			  struct snd_soc_dai *dai)
> +{
> +	struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
> +	int ret;
> +
> +	ret = clk_prepare_enable(zx_tdm->dai_wclk);
> +	if (ret)
> +		return ret;
> +
> +	ret = clk_prepare_enable(zx_tdm->dai_pclk);
> +	if (ret) {
> +		clk_disable_unprepare(zx_tdm->dai_wclk);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static void zx_tdm_shutdown(struct snd_pcm_substream *substream,
> +			    struct snd_soc_dai *dai)
> +{
> +	struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
> +
> +	clk_disable_unprepare(zx_tdm->dai_pclk);
> +	clk_disable_unprepare(zx_tdm->dai_wclk);
> +}
> +
> +static struct snd_soc_dai_ops zx_tdm_dai_ops = {
> +	.trigger	= zx_tdm_trigger,
> +	.hw_params	= zx_tdm_hw_params,
> +	.set_fmt	= zx_tdm_set_fmt,
> +	.startup	= zx_tdm_startup,
> +	.shutdown	= zx_tdm_shutdown,
> +};
> +
> +static const struct snd_soc_component_driver zx_tdm_component = {
> +	.name			= "zx-tdm",
> +};
> +
> +static void zx_tdm_init_state(struct zx_tdm_info *tdm)
> +{
> +	unsigned int val;
> +
> +	zx_tdm_writel(tdm, REG_PROCESS_CTRL, PROCESS_DISABLE_ALL);
> +
> +	val = zx_tdm_readl(tdm, REG_TIMING_CTRL);
> +	val |= TIMING_LSB_FIRST;
> +	val &= (~TIMING_CLK_SEL_MASK);

Unnecessary parenthesis.

> +	val |= TIMING_CLK_SEL_DEF;
> +	zx_tdm_writel(tdm, REG_TIMING_CTRL, val);
> +
> +	zx_tdm_writel(tdm, REG_INT_EN, INT_DISABLE_ALL);
> +	/*
> +	 * write INT_STATUS register to clear it.
> +	 */
> +	zx_tdm_writel(tdm, REG_INT_STATUS, INT_STATUS_MASK);
> +	zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, FIFOCTRL_RX_FIFO_RST);
> +	zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, FIFOCTRL_TX_FIFO_RST);
> +
> +	val = zx_tdm_readl(tdm, REG_RX_FIFO_CTRL);
> +	val &= ~(RXTH_MASK | RX_FIFO_RST_MASK);
> +	val |= FIFOCTRL_THRESHOLD(8);
> +	zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, val);
> +
> +	val = zx_tdm_readl(tdm, REG_TX_FIFO_CTRL);
> +	val &= ~(TXTH_MASK | TX_FIFO_RST_MASK);
> +	val |= FIFOCTRL_THRESHOLD(8);
> +	zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, val);
> +}
> +
> +static struct snd_soc_dai_driver zx_tdm_dai = {
> +	.name	= "zx-tdm-dai",
> +	.id	= 0,
> +	.probe	= zx_tdm_dai_probe,
> +	.playback   = {
> +		.channels_min	= 1,
> +		.channels_max	= 4,
> +		.rates		= ZX_TDM_RATES,
> +		.formats	= ZX_TDM_FMTBIT,
> +	},
> +	.capture = {
> +		.channels_min	= 1,
> +		.channels_max	= 4,
> +		.rates		= ZX_TDM_RATES,
> +		.formats	= ZX_TDM_FMTBIT,
> +	},
> +	.ops	= &zx_tdm_dai_ops,
> +};
> +
> +static int zx_tdm_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct of_phandle_args out_args;
> +	unsigned int dma_reg_offset;
> +	struct zx_tdm_info *zx_tdm;
> +	unsigned int dma_config;
> +	unsigned int dma_mask;
> +	struct resource *res;
> +	void __iomem *regmap;

Do not name it regmap.

> +	int ret;
> +
> +	zx_tdm = devm_kzalloc(&pdev->dev, sizeof(*zx_tdm), GFP_KERNEL);
> +	if (!zx_tdm)
> +		return -ENOMEM;
> +
> +	zx_tdm->dev = dev;
> +
> +	zx_tdm->dai_wclk = devm_clk_get(&pdev->dev, "tdm_wclk");
> +	if (IS_ERR(zx_tdm->dai_wclk)) {
> +		dev_err(&pdev->dev, "Fail to get tdm_wclk\n");
> +		return PTR_ERR(zx_tdm->dai_wclk);
> +	}
> +
> +	zx_tdm->dai_pclk = devm_clk_get(&pdev->dev, "tdm_pclk");
> +	if (IS_ERR(zx_tdm->dai_pclk)) {
> +		dev_err(&pdev->dev, "Fail to get tdm_pclk\n");
> +		return PTR_ERR(zx_tdm->dai_pclk);
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	zx_tdm->phy_addr = res->start;
> +	zx_tdm->regmap = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(zx_tdm->regmap)) {
> +		dev_err(&pdev->dev, "ioremap failed!\n");

As function devm_ioremap_resource() already has error messages for all
error conditions, we can save our own here.

> +		return PTR_ERR(zx_tdm->regmap);
> +	}
> +
> +	ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
> +				"zte,tdm-dma-sysctrl", 3, 0, &out_args);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Fail to get zte,tdm-dma-sysctrl\n");
> +		return ret;
> +	}
> +
> +	dma_reg_offset = out_args.args[0];
> +	dma_mask = out_args.args[1];
> +	dma_config = out_args.args[2];
> +	regmap = syscon_node_to_regmap(out_args.np);
> +	if (IS_ERR(regmap)) {
> +		of_node_put(out_args.np);
> +		return PTR_ERR(regmap);
> +	}
> +
> +	regmap_update_bits(regmap, dma_reg_offset, dma_mask, dma_config);
> +	of_node_put(out_args.np);
> +
> +	zx_tdm_init_state(zx_tdm);
> +	platform_set_drvdata(pdev, zx_tdm);
> +
> +	ret = devm_snd_soc_register_component(&pdev->dev, &zx_tdm_component,
> +						&zx_tdm_dai, 1);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Register DAI failed: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
> +	if (ret)
> +		dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret);
> +
> +	return ret;
> +}
> +
> +static const struct of_device_id zx_tdm_dt_ids[] = {
> +	{ .compatible = "zte,zx-tdm", },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, zx_tdm_dt_ids);
> +
> +static struct platform_driver tdm_driver = {
> +	.probe = zx_tdm_probe,
> +	.driver = {
> +		.name = "zx-tdm",
> +		.of_match_table = zx_tdm_dt_ids,
> +	},
> +};
> +

Drop this newline.

Shawn

> +module_platform_driver(tdm_driver);
> +
> +MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
> +MODULE_DESCRIPTION("ZTE TDM DAI driver");
> +MODULE_LICENSE("GPL v2");
> -- 
> 2.7.4
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

end of thread, other threads:[~2017-02-14 13:31 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-02-13  8:17 [PATCH v1 1/3] ASoC: zx-tdm: add documentation for zte's tdm controller Baoyou Xie
2017-02-13  8:17 ` [PATCH v1 2/3] MAINTAINERS: add zte tdm controller driver to ARM ZTE architecture Baoyou Xie
2017-02-13  8:17 ` [PATCH v1 3/3] ASoC: zx-tdm: add zte's tdm controller driver Baoyou Xie
2017-02-14 13:31   ` Shawn Guo
     [not found] ` <1486973853-25291-1-git-send-email-baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2017-02-14  2:25   ` [PATCH v1 1/3] ASoC: zx-tdm: add documentation for zte's tdm controller Shawn Guo

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