* [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).