All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/5] ASoC: add CSR SiRFSoC sound drivers
@ 2014-01-03  6:04 RongJun Ying
  2014-01-03  6:05 ` [PATCH v3 1/5] ASoC: sirf: add sirf platform driver which provides DMA RongJun Ying
                   ` (4 more replies)
  0 siblings, 5 replies; 15+ messages in thread
From: RongJun Ying @ 2014-01-03  6:04 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown
  Cc: Takashi Iwai, Rongjun Ying, alsa-devel, Workgroup.linux

From: Rongjun Ying <rongjun.ying@csr.com>

This patchset adds CSR SiRFSoC sound drivers including:
1. the platform DMA driver which will be shard by all DAI
2. the I2S CPU DAI driver
3. the USP-based PCM CPU DAI driver
4. CPU DAI and Codec driver for internal chip codec
5. the mach driver for EVB board using internal codec

-v3: 
1. Use devm_* API for driver
2. Remove the extcon stuff code
3. Calculated automatically the div vaule at runtime based on the sample rate
4. Automatically discovering the configuration of pcm hardware from the dmaengine driver
5. Add binding documents

Rongjun Ying (5):
  ASoC: sirf: add sirf platform driver which provides DMA
  ASoC: sirf: add I2S CPU DAI driver
  ASoC: usp-pcm: add CPU DAI driver for PCM simulated from USP
  ASoC: sirf-soc-inner: add drivers for both CPU and Codec DAIs
  ASoC: sirf-inner: add mach driver for SiRFSoC internal codec

 .../bindings/sound/sirf,inner-audio-codec.txt      |   41 ++
 sound/soc/Kconfig                                  |    1 +
 sound/soc/Makefile                                 |    1 +
 sound/soc/sirf/Kconfig                             |   18 +
 sound/soc/sirf/Makefile                            |   11 +
 sound/soc/sirf/sirf-audio.h                        |  268 ++++++++
 sound/soc/sirf/sirf-i2s.c                          |  435 +++++++++++++
 sound/soc/sirf/sirf-inner.c                        |  155 +++++
 sound/soc/sirf/sirf-pcm.c                          |   68 ++
 sound/soc/sirf/sirf-soc-inner.c                    |  653 ++++++++++++++++++++
 sound/soc/sirf/sirf-usp.c                          |  463 ++++++++++++++
 sound/soc/sirf/sirf-usp.h                          |  276 +++++++++
 12 files changed, 2390 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/sirf,inner-audio-codec.txt
 create mode 100644 sound/soc/sirf/Kconfig
 create mode 100644 sound/soc/sirf/Makefile
 create mode 100644 sound/soc/sirf/sirf-audio.h
 create mode 100644 sound/soc/sirf/sirf-i2s.c
 create mode 100644 sound/soc/sirf/sirf-inner.c
 create mode 100644 sound/soc/sirf/sirf-pcm.c
 create mode 100644 sound/soc/sirf/sirf-soc-inner.c
 create mode 100644 sound/soc/sirf/sirf-usp.c
 create mode 100644 sound/soc/sirf/sirf-usp.h

-- 
1.7.5.4

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

* [PATCH v3 1/5] ASoC: sirf: add sirf platform driver which provides DMA
  2014-01-03  6:04 [PATCH v3 0/5] ASoC: add CSR SiRFSoC sound drivers RongJun Ying
@ 2014-01-03  6:05 ` RongJun Ying
  2014-01-05 11:22   ` Lars-Peter Clausen
  2014-01-06 17:07   ` Mark Brown
  2014-01-03  6:05 ` [PATCH v3 2/5] ASoC: sirf: add I2S CPU DAI driver RongJun Ying
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 15+ messages in thread
From: RongJun Ying @ 2014-01-03  6:05 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown
  Cc: Takashi Iwai, Rongjun Ying, alsa-devel, Workgroup.linux

From: Rongjun Ying <Rongjun.Ying@csr.com>

this driver uses dmaengine APIs and provides DMA to the CPU DAIs
of I2S, USP and SiRF-soc-inner.
SiRFSoC has 3 audio DAIs: I2S, USP(Universal Serial Ports) and DAI
connected to soc-inner-codec, all of them will use the same DMA
driver here.

Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com>
---
 -v3:
 Automatically discovering the configuration of pcm hardware from
 the dmaengine driver
 
 sound/soc/Kconfig         |    1 +
 sound/soc/Makefile        |    1 +
 sound/soc/sirf/Kconfig    |    4 ++
 sound/soc/sirf/Makefile   |    3 ++
 sound/soc/sirf/sirf-pcm.c |   68 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 77 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/sirf/Kconfig
 create mode 100644 sound/soc/sirf/Makefile
 create mode 100644 sound/soc/sirf/sirf-pcm.c

diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index d62ce48..0060b31 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -50,6 +50,7 @@ source "sound/soc/pxa/Kconfig"
 source "sound/soc/samsung/Kconfig"
 source "sound/soc/s6000/Kconfig"
 source "sound/soc/sh/Kconfig"
+source "sound/soc/sirf/Kconfig"
 source "sound/soc/spear/Kconfig"
 source "sound/soc/tegra/Kconfig"
 source "sound/soc/txx9/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 62a1822..5f1df02 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_SND_SOC)	+= pxa/
 obj-$(CONFIG_SND_SOC)	+= samsung/
 obj-$(CONFIG_SND_SOC)	+= s6000/
 obj-$(CONFIG_SND_SOC)	+= sh/
+obj-$(CONFIG_SND_SOC)	+= sirf/
 obj-$(CONFIG_SND_SOC)	+= spear/
 obj-$(CONFIG_SND_SOC)	+= tegra/
 obj-$(CONFIG_SND_SOC)	+= txx9/
diff --git a/sound/soc/sirf/Kconfig b/sound/soc/sirf/Kconfig
new file mode 100644
index 0000000..1637089
--- /dev/null
+++ b/sound/soc/sirf/Kconfig
@@ -0,0 +1,4 @@
+config SND_SIRF_SOC
+	tristate "Platform DMA driver for the SiRF SoC chips"
+	depends on ARCH_SIRF && SND_SOC
+	select SND_SOC_GENERIC_DMAENGINE_PCM
diff --git a/sound/soc/sirf/Makefile b/sound/soc/sirf/Makefile
new file mode 100644
index 0000000..f268b83
--- /dev/null
+++ b/sound/soc/sirf/Makefile
@@ -0,0 +1,3 @@
+snd-soc-sirf-objs := sirf-pcm.o
+
+obj-$(CONFIG_SND_SIRF_SOC) += snd-soc-sirf.o
diff --git a/sound/soc/sirf/sirf-pcm.c b/sound/soc/sirf/sirf-pcm.c
new file mode 100644
index 0000000..e4cb3a6
--- /dev/null
+++ b/sound/soc/sirf/sirf-pcm.c
@@ -0,0 +1,68 @@
+/*
+ * ALSA PCM interface for the SiRF SoC
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+static struct dma_chan *sirf_pcm_request_chan(struct snd_soc_pcm_runtime *rtd,
+	struct snd_pcm_substream *substream)
+{
+	struct snd_dmaengine_dai_dma_data *dma_data;
+
+	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
+	return dma_request_slave_channel(rtd->cpu_dai->dev,
+			dma_data->chan_name);
+}
+
+static const struct snd_dmaengine_pcm_config sirf_dmaengine_pcm_config = {
+	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+	.compat_request_channel = sirf_pcm_request_chan,
+};
+
+static int sirf_pcm_probe(struct platform_device *pdev)
+{
+	return devm_snd_dmaengine_pcm_register(&pdev->dev,
+		&sirf_dmaengine_pcm_config,
+		SND_DMAENGINE_PCM_FLAG_NO_DT |
+		SND_DMAENGINE_PCM_FLAG_COMPAT);
+}
+
+static struct platform_driver sirf_pcm_driver = {
+	.driver = {
+		.name = "sirf-pcm-audio",
+		.owner = THIS_MODULE,
+	},
+	.probe = sirf_pcm_probe,
+};
+
+static int __init sirf_pcm_init(void)
+{
+	int ret = 0;
+
+	ret = platform_driver_register(&sirf_pcm_driver);
+	if (ret)
+		pr_err("failed to register platform driver\n");
+	return ret;
+}
+
+static void __exit sirf_pcm_exit(void)
+{
+	platform_driver_unregister(&sirf_pcm_driver);
+}
+
+module_init(sirf_pcm_init);
+module_exit(sirf_pcm_exit);
+
+MODULE_DESCRIPTION("SiRF PCM audio interface driver");
+MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
+MODULE_LICENSE("GPL v2");
-- 
1.7.5.4

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

* [PATCH v3 2/5] ASoC: sirf: add I2S CPU DAI driver
  2014-01-03  6:04 [PATCH v3 0/5] ASoC: add CSR SiRFSoC sound drivers RongJun Ying
  2014-01-03  6:05 ` [PATCH v3 1/5] ASoC: sirf: add sirf platform driver which provides DMA RongJun Ying
@ 2014-01-03  6:05 ` RongJun Ying
  2014-01-05 11:52   ` Lars-Peter Clausen
  2014-01-06 17:12   ` Mark Brown
  2014-01-03  6:05 ` [PATCH v3 3/5] ASoC: usp-pcm: add CPU DAI driver for PCM simulated from USP RongJun Ying
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 15+ messages in thread
From: RongJun Ying @ 2014-01-03  6:05 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown
  Cc: Takashi Iwai, Rongjun Ying, alsa-devel, Workgroup.linux

From: Rongjun Ying <Rongjun.Ying@csr.com>

This patch adds I2S DAI driver for SiRFprima2 and SiRFatlas6. The hardware supports:
I2S bus specification compliant (Released by Philips Semiconductors in June, 1996)
Supports I2S master and I2S slave mode
Provides MCLK to I2S CODEC in I2S master mode
Supports 16-bit resolution playback
Supports 16-bit resolution record
Supports 2 channel record
Supports 2 channel and 6 channel mode playback
Frame length, left channel length and right channel length are all programmable
Supports two DMA channels for TXFIFO and RXFIFO
Supports floating mode (x_ac97_dout can be configured as input)

headfile sound/soc/sirf/sirf-audio.h will be shard by all I2S and soc-inner
DAIs.

Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com>
---
 -v3:
 Calculated automatically the div vaule at runtime based on the sample rate
 Move the master/slave mode setting from set_fmt to hw_parames

 sound/soc/sirf/Kconfig      |    3 +
 sound/soc/sirf/Makefile     |    2 +
 sound/soc/sirf/sirf-audio.h |  268 ++++++++++++++++++++++++++
 sound/soc/sirf/sirf-i2s.c   |  435 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 708 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/sirf/sirf-audio.h
 create mode 100644 sound/soc/sirf/sirf-i2s.c

diff --git a/sound/soc/sirf/Kconfig b/sound/soc/sirf/Kconfig
index 1637089..5064cfc 100644
--- a/sound/soc/sirf/Kconfig
+++ b/sound/soc/sirf/Kconfig
@@ -2,3 +2,6 @@ config SND_SIRF_SOC
 	tristate "Platform DMA driver for the SiRF SoC chips"
 	depends on ARCH_SIRF && SND_SOC
 	select SND_SOC_GENERIC_DMAENGINE_PCM
+
+config SND_SOC_SIRF_I2S
+	tristate
diff --git a/sound/soc/sirf/Makefile b/sound/soc/sirf/Makefile
index f268b83..9f754fe 100644
--- a/sound/soc/sirf/Makefile
+++ b/sound/soc/sirf/Makefile
@@ -1,3 +1,5 @@
 snd-soc-sirf-objs := sirf-pcm.o
+snd-soc-sirf-i2s-objs := sirf-i2s.o
 
 obj-$(CONFIG_SND_SIRF_SOC) += snd-soc-sirf.o
+obj-$(CONFIG_SND_SOC_SIRF_I2S) += snd-soc-sirf-i2s.o
diff --git a/sound/soc/sirf/sirf-audio.h b/sound/soc/sirf/sirf-audio.h
new file mode 100644
index 0000000..b6fdf06
--- /dev/null
+++ b/sound/soc/sirf/sirf-audio.h
@@ -0,0 +1,268 @@
+/*
+ * SiRF inner codec controllers define
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef _SIRF_INNER_AUDIO_CTRL_H
+#define _SIRF_INNER_AUDIO_CTRL_H
+
+#define AUDIO_CTRL_TX_FIFO_LEVEL_CHECK_MASK     0x3F
+#define AUDIO_CTRL_TX_FIFO_SC_OFFSET    0
+#define AUDIO_CTRL_TX_FIFO_LC_OFFSET    10
+#define AUDIO_CTRL_TX_FIFO_HC_OFFSET    20
+
+#define TX_FIFO_SC(x)           (((x) & AUDIO_CTRL_TX_FIFO_LEVEL_CHECK_MASK) \
+				<< AUDIO_CTRL_TX_FIFO_SC_OFFSET)
+#define TX_FIFO_LC(x)           (((x) & AUDIO_CTRL_TX_FIFO_LEVEL_CHECK_MASK) \
+				<< AUDIO_CTRL_TX_FIFO_LC_OFFSET)
+#define TX_FIFO_HC(x)           (((x) & AUDIO_CTRL_TX_FIFO_LEVEL_CHECK_MASK) \
+				<< AUDIO_CTRL_TX_FIFO_HC_OFFSET)
+
+#define AUDIO_CTRL_RX_FIFO_LEVEL_CHECK_MASK     0x0F
+#define AUDIO_CTRL_RX_FIFO_SC_OFFSET    0
+#define AUDIO_CTRL_RX_FIFO_LC_OFFSET    10
+#define AUDIO_CTRL_RX_FIFO_HC_OFFSET    20
+
+#define RX_FIFO_SC(x)           (((x) & AUDIO_CTRL_RX_FIFO_LEVEL_CHECK_MASK) \
+				<< AUDIO_CTRL_RX_FIFO_SC_OFFSET)
+#define RX_FIFO_LC(x)           (((x) & AUDIO_CTRL_RX_FIFO_LEVEL_CHECK_MASK) \
+				<< AUDIO_CTRL_RX_FIFO_LC_OFFSET)
+#define RX_FIFO_HC(x)           (((x) & AUDIO_CTRL_RX_FIFO_LEVEL_CHECK_MASK) \
+				<< AUDIO_CTRL_RX_FIFO_HC_OFFSET)
+
+#define AUDIO_CTRL_MODE_SEL			(0x0000)
+#define AUDIO_CTRL_AC97_CTRL			(0x0004)
+#define AUDIO_CTRL_AC97_CMD			(0x0008)
+#define AUDIO_CTRL_AC97_OP_STATUS		(0x000C)
+#define AUDIO_CTRL_AC97_RD_CODEC_REG		(0x0010)
+#define AUDIO_CTRL_TXSLOT_EN			(0x0014)
+#define AUDIO_CTRL_RXSLOT_EN			(0x0018)
+#define AUDIO_CTRL_AC97_AUX_SLOT_EN		(0x001c)
+#define AUDIO_CTRL_I2S_CTRL			(0x0020)
+#define AUDIO_CTRL_I2S_TX_RX_EN			(0x0024)
+
+#define AUDIO_CTRL_EXT_TXFIFO1_OP		(0x0040)
+#define AUDIO_CTRL_EXT_TXFIFO1_LEV_CHK		(0x0044)
+#define AUDIO_CTRL_EXT_TXFIFO1_STS		(0x0048)
+#define AUDIO_CTRL_EXT_TXFIFO1_INT		(0x004C)
+#define AUDIO_CTRL_EXT_TXFIFO1_INT_MSK		(0x0050)
+
+#define AUDIO_CTRL_EXT_TXFIFO2_OP		(0x0054)
+#define AUDIO_CTRL_EXT_TXFIFO2_LEV_CHK		(0x0058)
+#define AUDIO_CTRL_EXT_TXFIFO2_STS		(0x005C)
+#define AUDIO_CTRL_EXT_TXFIFO2_INT		(0x0060)
+#define AUDIO_CTRL_EXT_TXFIFO2_INT_MSK		(0x0064)
+
+#define AUDIO_CTRL_EXT_TXFIFO3_OP		(0x0068)
+#define AUDIO_CTRL_EXT_TXFIFO3_LEV_CHK		(0x006C)
+#define AUDIO_CTRL_EXT_TXFIFO3_STS		(0x0070)
+#define AUDIO_CTRL_EXT_TXFIFO3_INT		(0x0074)
+#define AUDIO_CTRL_EXT_TXFIFO3_INT_MSK		(0x0078)
+
+#define AUDIO_CTRL_EXT_TXFIFO4_OP		(0x007C)
+#define AUDIO_CTRL_EXT_TXFIFO4_LEV_CHK		(0x0080)
+#define AUDIO_CTRL_EXT_TXFIFO4_STS		(0x0084)
+#define AUDIO_CTRL_EXT_TXFIFO4_INT		(0x0088)
+#define AUDIO_CTRL_EXT_TXFIFO4_INT_MSK		(0x008C)
+
+#define AUDIO_CTRL_EXT_TXFIFO5_OP		(0x0090)
+#define AUDIO_CTRL_EXT_TXFIFO5_LEV_CHK		(0x0094)
+#define AUDIO_CTRL_EXT_TXFIFO5_STS		(0x0098)
+#define AUDIO_CTRL_EXT_TXFIFO5_INT		(0x009C)
+#define AUDIO_CTRL_EXT_TXFIFO5_INT_MSK		(0x00A0)
+
+#define AUDIO_CTRL_EXT_TXFIFO6_OP		(0x00A4)
+#define AUDIO_CTRL_EXT_TXFIFO6_LEV_CHK		(0x00A8)
+#define AUDIO_CTRL_EXT_TXFIFO6_STS		(0x00AC)
+#define AUDIO_CTRL_EXT_TXFIFO6_INT		(0x00B0)
+#define AUDIO_CTRL_EXT_TXFIFO6_INT_MSK		(0x00B4)
+
+#define AUDIO_CTRL_RXFIFO_OP			(0x00B8)
+#define AUDIO_CTRL_RXFIFO_LEV_CHK		(0x00BC)
+#define AUDIO_CTRL_RXFIFO_STS			(0x00C0)
+#define AUDIO_CTRL_RXFIFO_INT			(0x00C4)
+#define AUDIO_CTRL_RXFIFO_INT_MSK		(0x00C8)
+
+#define AUDIO_CTRL_AUXFIFO_OP			(0x00CC)
+#define AUDIO_CTRL_AUXFIFO_LEV_CHK		(0x00D0)
+#define AUDIO_CTRL_AUXFIFO_STS			(0x00D4)
+#define AUDIO_CTRL_AUXFIFO_INT			(0x00D8)
+#define AUDIO_CTRL_AUXFIFO_INT_MSK		(0x00DC)
+
+#define AUDIO_IC_CODEC_PWR			(0x00E0)
+#define AUDIO_IC_CODEC_CTRL0			(0x00E4)
+#define AUDIO_IC_CODEC_CTRL1			(0x00E8)
+#define AUDIO_IC_CODEC_CTRL2			(0x00EC)
+#define AUDIO_IC_CODEC_CTRL3			(0x00F0)
+
+#define AUDIO_CTRL_IC_CODEC_TX_CTRL		(0x00F4)
+#define AUDIO_CTRL_IC_CODEC_RX_CTRL		(0x00F8)
+
+#define AUDIO_CTRL_IC_TXFIFO_OP			(0x00FC)
+#define AUDIO_CTRL_IC_TXFIFO_LEV_CHK		(0x0100)
+#define AUDIO_CTRL_IC_TXFIFO_STS		(0x0104)
+#define AUDIO_CTRL_IC_TXFIFO_INT		(0x0108)
+#define AUDIO_CTRL_IC_TXFIFO_INT_MSK		(0x010C)
+
+#define AUDIO_CTRL_IC_RXFIFO_OP			(0x0110)
+#define AUDIO_CTRL_IC_RXFIFO_LEV_CHK		(0x0114)
+#define AUDIO_CTRL_IC_RXFIFO_STS		(0x0118)
+#define AUDIO_CTRL_IC_RXFIFO_INT		(0x011C)
+#define AUDIO_CTRL_IC_RXFIFO_INT_MSK		(0x0120)
+
+#define I2S_MODE				(1<<0)
+#define AC97_TX_SLOT3_WIDTH_MASK		(3<<1)
+#define AC97_TX_SLOT4_WIDTH_MASK		(3<<3)
+#define AC97_TX_SLOT6_WIDTH_MASK		(3<<5)
+#define AC97_TX_SLOT7_WIDTH_MASK		(3<<7)
+#define AC97_TX_SLOT8_WIDTH_MASK		(3<<9)
+#define AC97_TX_SLOT9_WIDTH_MASK		(3<<11)
+#define AC97_FIFO_SYNC_MASK			(3<<13)
+#define AC97_FIFO_SYNC_ALL			(1<<13)
+
+#define SYNC_START				(1<<0)
+#define AC97_START				(1<<1)
+#define WARM_WAKEUP				(1<<2)
+
+#define AC97_CMD_TYPE_MASK			(1<<7)
+#define AC97_CMD_ADDR_MASK			(0x7F)
+#define AC97_CMD_TYPE_WRITE			(0<<7)
+#define AC97_CMD_TYPE_READ			(1<<7)
+
+#define CMD_ISSUE_BIT				(1<<0)
+#define	RD_CMD_FINISH_BIT			(1<<1)
+#define	CODEC_READY_BIT				(1<<2)
+
+#define	AC97_RDBACK_ADDR_BITS			(0x7F)
+#define	AC97_RDBACK_DATA_BITS			(0xFF<<16)
+
+#define AC97_TX_SLOT3_EN			(1<<0)
+#define AC97_TX_SLOT4_EN			(1<<1)
+#define AC97_TX_SLOT6_EN			(1<<2)
+#define AC97_TX_SLOT7_EN			(1<<3)
+#define AC97_TX_SLOT8_EN			(1<<4)
+#define AC97_TX_SLOT9_EN			(1<<5)
+
+#define AC97_RX_SLOT3_EN			(1<<0)
+#define AC97_RX_SLOT4_EN			(1<<1)
+#define AC97_RX_SLOT5_EN			(1<<2)
+#define AC97_RX_SLOT6_EN			(1<<3)
+#define AC97_RX_SLOT7_EN			(1<<4)
+#define AC97_RX_SLOT8_EN			(1<<5)
+#define AC97_RX_SLOT9_EN			(1<<6)
+#define AC97_RX_SLOT10_EN			(1<<7)
+#define AC97_RX_SLOT11_EN			(1<<8)
+#define AC97_RX_SLOT12_EN			(1<<9)
+
+#define AC97_AUX_SLOT3_EN			(1<<0)
+#define AC97_AUX_SLOT4_EN			(1<<1)
+#define AC97_AUX_SLOT5_EN			(1<<2)
+#define AC97_AUX_SLOT6_EN			(1<<3)
+#define AC97_AUX_SLOT7_EN			(1<<4)
+#define AC97_AUX_SLOT8_EN			(1<<5)
+#define AC97_AUX_SLOT9_EN			(1<<6)
+#define AC97_AUX_SLOT10_EN			(1<<7)
+#define AC97_AUX_SLOT11_EN			(1<<8)
+#define AC97_AUX_SLOT12_EN			(1<<9)
+
+#define I2S_LOOP_BACK				(1<<3)
+#define	I2S_MCLK_DIV_SHIFT			15
+#define I2S_MCLK_DIV_MASK			(0x1FF<<I2S_MCLK_DIV_SHIFT)
+#define I2S_BITCLK_DIV_SHIFT			24
+#define I2S_BITCLK_DIV_MASK			(0xFF<<I2S_BITCLK_DIV_SHIFT)
+
+#define I2S_MCLK_EN				(1<<2)
+#define I2S_REF_CLK_SEL_EXT			(1<<3)
+#define I2S_DOUT_OE				(1<<4)
+#define i2s_R2X_LP_TO_TX0			(1<<30)
+#define i2s_R2X_LP_TO_TX1			(2<<30)
+#define i2s_R2X_LP_TO_TX2			(3<<30)
+
+#define AUDIO_FIFO_START		(1 << 0)
+#define AUDIO_FIFO_RESET		(1 << 1)
+
+#define AUDIO_FIFO_FULL			(1 << 0)
+#define AUDIO_FIFO_EMPTY		(1 << 1)
+#define AUDIO_FIFO_OFLOW		(1 << 2)
+#define AUDIO_FIFO_UFLOW		(1 << 3)
+
+#define I2S_RX_ENABLE			(1 << 0)
+#define I2S_TX_ENABLE			(1 << 1)
+
+/* Codec I2S Control Register defines */
+#define I2S_SLAVE_MODE			(1 << 0)
+#define I2S_SIX_CHANNELS		(1 << 1)
+#define I2S_L_CHAN_LEN_MASK		(0x1f << 4)
+#define I2S_FRAME_LEN_MASK		(0x3f << 9)
+
+#define AC97_WRITE_FRAME_VALID    0X10
+#define AC97_WRITE_SLOT1_VALID    0X08
+#define AC97_WRITE_SLOT2_VALID    0X04
+#define AC97_WRITE_SLOT3_VALID    0X02
+#define AC97_WRITE_SLOT4_VALID    0X01
+
+#define IC_TX_ENABLE		(0x03)
+#define IC_RX_ENABLE		(0x03)
+
+#define MICBIASEN		(1 << 3)
+
+#define IC_RDACEN		(1 << 0)
+#define IC_LDACEN		(1 << 1)
+#define IC_HSREN		(1 << 2)
+#define IC_HSLEN		(1 << 3)
+#define IC_SPEN			(1 << 4)
+#define IC_CPEN			(1 << 5)
+
+#define IC_HPRSELR		(1 << 6)
+#define IC_HPLSELR		(1 << 7)
+#define IC_HPRSELL		(1 << 8)
+#define IC_HPLSELL		(1 << 9)
+#define IC_SPSELR		(1 << 10)
+#define IC_SPSELL		(1 << 11)
+
+#define IC_MONOR		(1 << 12)
+#define IC_MONOL		(1 << 13)
+
+#define IC_RXOSRSEL		(1 << 28)
+#define IC_CPFREQ		(1 << 29)
+#define IC_HSINVEN		(1 << 30)
+
+#define IC_MICINREN		(1 << 0)
+#define IC_MICINLEN		(1 << 1)
+#define IC_MICIN1SEL		(1 << 2)
+#define IC_MICIN2SEL		(1 << 3)
+#define IC_MICDIFSEL		(1 << 4)
+#define	IC_LINEIN1SEL		(1 << 5)
+#define	IC_LINEIN2SEL		(1 << 6)
+#define	IC_RADCEN		(1 << 7)
+#define	IC_LADCEN		(1 << 8)
+#define	IC_ALM			(1 << 9)
+
+#define IC_DIGMICEN             (1 << 22)
+#define IC_DIGMICFREQ           (1 << 23)
+#define IC_ADC14B_12            (1 << 24)
+#define IC_FIRDAC_HSL_EN        (1 << 25)
+#define IC_FIRDAC_HSR_EN        (1 << 26)
+#define IC_FIRDAC_LOUT_EN       (1 << 27)
+#define IC_POR                  (1 << 28)
+#define IC_CODEC_CLK_EN         (1 << 29)
+#define IC_HP_3DB_BOOST         (1 << 30)
+
+#define IC_ADC_LEFT_GAIN_SHIFT	16
+#define IC_ADC_RIGHT_GAIN_SHIFT 10
+#define IC_ADC_GAIN_MASK	0x3F
+#define IC_MIC_MAX_GAIN		0x39
+
+#define IC_RXPGAR_MASK		0x3F
+#define IC_RXPGAR_SHIFT		14
+#define IC_RXPGAL_MASK		0x3F
+#define IC_RXPGAL_SHIFT		21
+#define IC_RXPGAR		0x7B
+#define IC_RXPGAL		0x7B
+
+#define SIRF_I2S_EXT_CLK	0x0
+#define SIRF_I2S_PWM_CLK	0x1
+#endif /*__SIRF_INNER_AUDIO_CTRL_H*/
diff --git a/sound/soc/sirf/sirf-i2s.c b/sound/soc/sirf/sirf-i2s.c
new file mode 100644
index 0000000..d8b8732
--- /dev/null
+++ b/sound/soc/sirf/sirf-i2s.c
@@ -0,0 +1,435 @@
+/*
+ * SiRF I2S driver
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "sirf-audio.h"
+
+struct sirf_i2s {
+	void __iomem		*base;
+	struct clk		*clk;
+	u32			i2s_ctrl;
+	u32			i2s_ctrl_tx_rx_en;
+	spinlock_t		lock;
+	struct platform_device	*sirf_pcm_pdev;
+	bool			master;
+	int			ext_clk;
+	int			src_clk_rate;
+};
+
+static struct snd_dmaengine_dai_dma_data dma_data[2];
+
+static int sirf_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+	dai->playback_dma_data = &dma_data[0];
+	dai->capture_dma_data = &dma_data[1];
+	return 0;
+}
+
+static int sirf_i2s_trigger(struct snd_pcm_substream *substream,
+		int cmd, struct snd_soc_dai *dai)
+{
+	struct sirf_i2s *si2s = snd_soc_dai_get_drvdata(dai);
+	int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		spin_lock(&si2s->lock);
+
+		if (playback) {
+			/* First start the FIFO, then enable the tx/rx */
+			writel(AUDIO_FIFO_RESET,
+				si2s->base + AUDIO_CTRL_EXT_TXFIFO1_OP);
+			writel(AUDIO_FIFO_START,
+				si2s->base + AUDIO_CTRL_EXT_TXFIFO1_OP);
+
+			writel(readl(si2s->base+AUDIO_CTRL_I2S_TX_RX_EN)
+				| I2S_TX_ENABLE | I2S_DOUT_OE,
+				si2s->base + AUDIO_CTRL_I2S_TX_RX_EN);
+
+		} else {
+			/* First start the FIFO, then enable the tx/rx */
+			writel(AUDIO_FIFO_RESET,
+				si2s->base + AUDIO_CTRL_RXFIFO_OP);
+			writel(AUDIO_FIFO_START,
+				si2s->base + AUDIO_CTRL_RXFIFO_OP);
+
+			writel(readl(si2s->base+AUDIO_CTRL_I2S_TX_RX_EN)
+				| I2S_RX_ENABLE,
+				si2s->base + AUDIO_CTRL_I2S_TX_RX_EN);
+		}
+
+		spin_unlock(&si2s->lock);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		spin_lock(&si2s->lock);
+
+		if (playback) {
+			writel(readl(si2s->base + AUDIO_CTRL_I2S_TX_RX_EN)
+				& ~(I2S_TX_ENABLE),
+				si2s->base + AUDIO_CTRL_I2S_TX_RX_EN);
+			/* First disable the tx/rx, then stop the FIFO */
+			writel(0, si2s->base + AUDIO_CTRL_EXT_TXFIFO1_OP);
+		} else {
+			writel(readl(si2s->base + AUDIO_CTRL_I2S_TX_RX_EN)
+				& ~(I2S_RX_ENABLE),
+				si2s->base+AUDIO_CTRL_I2S_TX_RX_EN);
+
+			/* First disable the tx/rx, then stop the FIFO */
+			writel(0, si2s->base + AUDIO_CTRL_RXFIFO_OP);
+		}
+
+		spin_unlock(&si2s->lock);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int sirf_i2s_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct sirf_i2s *si2s = snd_soc_dai_get_drvdata(dai);
+	u32 i2s_ctrl = readl(si2s->base + AUDIO_CTRL_I2S_CTRL);
+	u32 i2s_tx_rx_ctrl = readl(si2s->base + AUDIO_CTRL_I2S_TX_RX_EN);
+	u32 left_len, frame_len;
+	int channels = params_channels(params);
+	u32 bitclk;
+	u32 bclk_div;
+	u32 div;
+
+	/*
+	 * SiRFSoC I2S controller only support 2 and 6 channells output.
+	 * I2S_SIX_CHANNELS bit clear: select 2 channels mode.
+	 * I2S_SIX_CHANNELS bit set: select 6 channels mode.
+	 */
+	switch (channels) {
+	case 2:
+		i2s_ctrl &= ~I2S_SIX_CHANNELS;
+		break;
+	case 6:
+		i2s_ctrl |= I2S_SIX_CHANNELS;
+		break;
+	default:
+		dev_err(dai->dev, "%d channels unsupported\n", channels);
+		return -EINVAL;
+	}
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		left_len = 8;
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		left_len = 16;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		left_len = 24;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		left_len = 32;
+		break;
+	default:
+		dev_err(dai->dev, "Format unsupported\n");
+		return -EINVAL;
+	}
+
+	frame_len = left_len * 2;
+	i2s_ctrl &= ~(I2S_L_CHAN_LEN_MASK | I2S_FRAME_LEN_MASK);
+	/* Fill the actual len - 1 */
+	i2s_ctrl |= ((frame_len - 1) << 9) | ((left_len - 1) << 4)
+		| (0 << 15) | (3 << 24);
+
+	if (si2s->master) {
+		i2s_ctrl &= ~I2S_SLAVE_MODE;
+		i2s_tx_rx_ctrl |= I2S_MCLK_EN;
+		bitclk = params_rate(params) * frame_len;
+		div = si2s->src_clk_rate / bitclk;
+		/* MCLK divide-by-2 from source clk */
+		div /= 2;
+		bclk_div = div / 2 - 1;
+		i2s_ctrl |= (bclk_div << 24);
+		/*
+		 * MCLK coefficient must set to 0, means
+		 * divide-by-two from reference clock.
+		 */
+		i2s_ctrl &= ~(((1 << 10) - 1) << 15);
+	} else {
+		i2s_ctrl |= I2S_SLAVE_MODE;
+		i2s_tx_rx_ctrl &= ~I2S_MCLK_EN;
+	}
+
+	if (si2s->ext_clk)
+		i2s_tx_rx_ctrl |= I2S_REF_CLK_SEL_EXT;
+	else
+		i2s_tx_rx_ctrl &= ~I2S_REF_CLK_SEL_EXT;
+
+	writel(i2s_ctrl, si2s->base + AUDIO_CTRL_I2S_CTRL);
+	writel(i2s_tx_rx_ctrl, si2s->base + AUDIO_CTRL_I2S_TX_RX_EN);
+	writel(readl(si2s->base + AUDIO_CTRL_MODE_SEL)
+			| I2S_MODE,
+			si2s->base + AUDIO_CTRL_MODE_SEL);
+
+	return 0;
+}
+
+static int sirf_i2s_set_dai_fmt(struct snd_soc_dai *dai,
+		unsigned int fmt)
+{
+	struct sirf_i2s *si2s = snd_soc_dai_get_drvdata(dai);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		si2s->master = false;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		si2s->master = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		break;
+	default:
+		dev_err(dai->dev, "Only I2S format supported\n");
+		return -EINVAL;
+	}
+
+	/* clock inversion */
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	default:
+		dev_err(dai->dev, "Only normal bit clock, normal frame clock supported\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int sirf_i2s_set_clkdiv(struct snd_soc_dai *dai, int div_id, int src_rate)
+{
+	struct sirf_i2s *si2s = snd_soc_dai_get_drvdata(dai);
+
+	switch (div_id) {
+	case SIRF_I2S_EXT_CLK:
+		si2s->ext_clk = 1;
+		break;
+	case SIRF_I2S_PWM_CLK:
+		si2s->ext_clk = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	si2s->src_clk_rate = src_rate;
+	return 0;
+}
+
+struct snd_soc_dai_ops sirfsoc_i2s_dai_ops = {
+	.trigger	= sirf_i2s_trigger,
+	.hw_params	= sirf_i2s_hw_params,
+	.set_fmt	= sirf_i2s_set_dai_fmt,
+	.set_clkdiv	= sirf_i2s_set_clkdiv,
+};
+
+static struct snd_soc_dai_driver sirf_i2s_dai = {
+	.probe = sirf_i2s_dai_probe,
+	.name = "sirf-i2s",
+	.id = 0,
+	.playback = {
+		.stream_name = "SiRF I2S Playback",
+		.channels_min = 2,
+		.channels_max = 6,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = SNDRV_PCM_FMTBIT_S8 |
+			SNDRV_PCM_FMTBIT_S16_LE |
+			SNDRV_PCM_FMTBIT_S24_LE |
+			SNDRV_PCM_FMTBIT_S32_LE,
+	},
+	.capture = {
+		.stream_name = "SiRF I2S Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_8000_96000,
+		.formats = SNDRV_PCM_FMTBIT_S8 |
+			SNDRV_PCM_FMTBIT_S16_LE |
+			SNDRV_PCM_FMTBIT_S24_LE |
+			SNDRV_PCM_FMTBIT_S32_LE,
+	},
+	.ops = &sirfsoc_i2s_dai_ops,
+};
+#ifdef CONFIG_PM_RUNTIME
+static int sirf_i2s_runtime_suspend(struct device *dev)
+{
+	struct sirf_i2s *si2s = dev_get_drvdata(dev);
+	clk_disable_unprepare(si2s->clk);
+
+	return 0;
+}
+
+static int sirf_i2s_runtime_resume(struct device *dev)
+{
+	struct sirf_i2s *si2s = dev_get_drvdata(dev);
+	int ret;
+	ret = clk_prepare_enable(si2s->clk);
+	if (ret)
+		return ret;
+	return ret;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int sirf_i2s_suspend(struct device *dev)
+{
+	struct sirf_i2s *si2s = dev_get_drvdata(dev);
+
+	if (!pm_runtime_status_suspended(dev)) {
+		si2s->i2s_ctrl = readl(si2s->base + AUDIO_CTRL_I2S_CTRL);
+		si2s->i2s_ctrl_tx_rx_en =
+			readl(si2s->base + AUDIO_CTRL_I2S_TX_RX_EN);
+		sirf_i2s_runtime_suspend(dev);
+	}
+	return 0;
+}
+
+static int sirf_i2s_resume(struct device *dev)
+{
+	struct sirf_i2s *si2s = dev_get_drvdata(dev);
+	int ret;
+	if (!pm_runtime_status_suspended(dev)) {
+		ret = sirf_i2s_runtime_resume(dev);
+		if (ret)
+			return ret;
+		writel(readl(si2s->base + AUDIO_CTRL_MODE_SEL)
+				| I2S_MODE,
+				si2s->base + AUDIO_CTRL_MODE_SEL);
+		writel(si2s->i2s_ctrl, si2s->base + AUDIO_CTRL_I2S_CTRL);
+		/*Restore MCLK enable and reference clock select bits.*/
+		writel(si2s->i2s_ctrl_tx_rx_en &
+			(I2S_MCLK_EN | I2S_REF_CLK_SEL_EXT),
+			si2s->base + AUDIO_CTRL_I2S_TX_RX_EN);
+
+		writel(0, si2s->base + AUDIO_CTRL_EXT_TXFIFO1_INT_MSK);
+		writel(0, si2s->base + AUDIO_CTRL_RXFIFO_INT_MSK);
+	}
+
+	return 0;
+}
+#endif
+
+static const struct snd_soc_component_driver sirf_i2s_component = {
+	.name       = "sirf-i2s",
+};
+
+static int sirf_i2s_probe(struct platform_device *pdev)
+{
+	struct sirf_i2s *si2s;
+	int ret;
+	struct resource mem_res;
+
+	si2s = devm_kzalloc(&pdev->dev, sizeof(struct sirf_i2s),
+			GFP_KERNEL);
+	if (!si2s)
+		return -ENOMEM;
+
+	si2s->sirf_pcm_pdev = platform_device_register_simple("sirf-pcm-audio",
+			0, NULL, 0);
+	if (IS_ERR(si2s->sirf_pcm_pdev))
+		return PTR_ERR(si2s->sirf_pcm_pdev);
+
+	platform_set_drvdata(pdev, si2s);
+
+	spin_lock_init(&si2s->lock);
+
+	dma_data[0].chan_name = "tx";
+	dma_data[1].chan_name = "rx";
+
+	ret = of_address_to_resource(pdev->dev.of_node, 0, &mem_res);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Unable to get i2s memory resource.\n");
+		return ret;
+	}
+	si2s->base = devm_ioremap(&pdev->dev, mem_res.start,
+		resource_size(&mem_res));
+	if (!si2s->base)
+		return -ENOMEM;
+
+	si2s->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(si2s->clk)) {
+		dev_err(&pdev->dev, "Get clock failed.\n");
+		ret = PTR_ERR(si2s->clk);
+		goto err;
+	}
+
+	pm_runtime_enable(&pdev->dev);
+
+	ret = devm_snd_soc_register_component(&pdev->dev, &sirf_i2s_component,
+			&sirf_i2s_dai, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "Register Audio SoC dai failed.\n");
+		goto err;
+	}
+
+	return 0;
+
+err:
+	return ret;
+}
+
+static int sirf_i2s_remove(struct platform_device *pdev)
+{
+	struct sirf_i2s *si2s = platform_get_drvdata(pdev);
+
+	pm_runtime_disable(&pdev->dev);
+	platform_device_unregister(si2s->sirf_pcm_pdev);
+	return 0;
+}
+
+static const struct of_device_id sirf_i2s_of_match[] = {
+	{ .compatible = "sirf,prima2-i2s", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, sirf_i2s_of_match);
+
+static const struct dev_pm_ops sirf_i2s_pm_ops = {
+	SET_RUNTIME_PM_OPS(sirf_i2s_runtime_suspend, sirf_i2s_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(sirf_i2s_suspend, sirf_i2s_resume)
+};
+
+static struct platform_driver sirf_i2s_driver = {
+	.driver = {
+		.name = "sirf-i2s",
+		.owner = THIS_MODULE,
+		.of_match_table = sirf_i2s_of_match,
+		.pm = &sirf_i2s_pm_ops,
+	},
+	.probe = sirf_i2s_probe,
+	.remove = sirf_i2s_remove,
+};
+
+module_platform_driver(sirf_i2s_driver);
+
+MODULE_DESCRIPTION("SiRF SoC I2S driver");
+MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
+MODULE_LICENSE("GPL v2");
-- 
1.7.5.4

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

* [PATCH v3 3/5] ASoC: usp-pcm: add CPU DAI driver for PCM simulated from USP
  2014-01-03  6:04 [PATCH v3 0/5] ASoC: add CSR SiRFSoC sound drivers RongJun Ying
  2014-01-03  6:05 ` [PATCH v3 1/5] ASoC: sirf: add sirf platform driver which provides DMA RongJun Ying
  2014-01-03  6:05 ` [PATCH v3 2/5] ASoC: sirf: add I2S CPU DAI driver RongJun Ying
@ 2014-01-03  6:05 ` RongJun Ying
  2014-01-06 17:20   ` Mark Brown
  2014-01-03  6:05 ` [PATCH v3 4/5] ASoC: sirf-soc-inner: add drivers for both CPU and Codec DAIs RongJun Ying
  2014-01-03  6:05 ` [PATCH v3 5/5] ASoC: sirf-inner: add mach driver for SiRFSoC internal codec RongJun Ying
  4 siblings, 1 reply; 15+ messages in thread
From: RongJun Ying @ 2014-01-03  6:05 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown
  Cc: Takashi Iwai, Rongjun Ying, alsa-devel, Workgroup.linux

From: Rongjun Ying <Rongjun.Ying@csr.com>

Universal Serial Ports (USP) can be used as PCM. this patch
adds support for this functionality.

The USP provides 128-byte data FIFO which supports DMA and I/O
modes. Here we use the common DMA driver.

Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com>
---
 -v3:
 Use the generic dma dt-binding to get playback/capture dma channels
 Calculated automatically the div vaule at runtime based on the sample rate
 Move the master/slave mode setting from set_fmt to hw_parames
 Check the return value
 Remove the pm_runtime_get_sync and pm_runtime_put invoke

 sound/soc/sirf/Kconfig    |    3 +
 sound/soc/sirf/Makefile   |    2 +
 sound/soc/sirf/sirf-usp.c |  463 +++++++++++++++++++++++++++++++++++++++++++++
 sound/soc/sirf/sirf-usp.h |  276 +++++++++++++++++++++++++++
 4 files changed, 744 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/sirf/sirf-usp.c
 create mode 100644 sound/soc/sirf/sirf-usp.h

diff --git a/sound/soc/sirf/Kconfig b/sound/soc/sirf/Kconfig
index 5064cfc..5e395d3 100644
--- a/sound/soc/sirf/Kconfig
+++ b/sound/soc/sirf/Kconfig
@@ -5,3 +5,6 @@ config SND_SIRF_SOC
 
 config SND_SOC_SIRF_I2S
 	tristate
+
+config SND_SOC_SIRF_USP
+	tristate
diff --git a/sound/soc/sirf/Makefile b/sound/soc/sirf/Makefile
index 9f754fe..630c9be 100644
--- a/sound/soc/sirf/Makefile
+++ b/sound/soc/sirf/Makefile
@@ -1,5 +1,7 @@
 snd-soc-sirf-objs := sirf-pcm.o
 snd-soc-sirf-i2s-objs := sirf-i2s.o
+snd-soc-sirf-usp-objs := sirf-usp.o
 
 obj-$(CONFIG_SND_SIRF_SOC) += snd-soc-sirf.o
 obj-$(CONFIG_SND_SOC_SIRF_I2S) += snd-soc-sirf-i2s.o
+obj-$(CONFIG_SND_SOC_SIRF_USP) += snd-soc-sirf-usp.o
diff --git a/sound/soc/sirf/sirf-usp.c b/sound/soc/sirf/sirf-usp.c
new file mode 100644
index 0000000..ed2410f
--- /dev/null
+++ b/sound/soc/sirf/sirf-usp.c
@@ -0,0 +1,463 @@
+/*
+ * SiRF USP audio transfer interface like I2S
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "sirf-usp.h"
+
+#define FIFO_RESET  0
+#define FIFO_START	1
+#define FIFO_STOP	2
+
+#define AUDIO_WORD_SIZE 16
+
+struct sirf_usp {
+	void __iomem *base;
+	struct clk *clk;
+	u32 mode1_reg;
+	u32 mode2_reg;
+	struct platform_device *sirf_pcm_pdev;
+	int master;
+};
+
+static struct snd_dmaengine_dai_dma_data dma_data[2];
+
+static void sirf_usp_tx_fifo_op(struct sirf_usp *susp, int cmd)
+{
+	switch (cmd) {
+	case FIFO_RESET:
+		writel(USP_TX_FIFO_RESET, susp->base + USP_TX_FIFO_OP);
+		writel(0, susp->base + USP_TX_FIFO_OP);
+		break;
+	case FIFO_START:
+		writel(USP_TX_FIFO_START, susp->base + USP_TX_FIFO_OP);
+		break;
+	case FIFO_STOP:
+		writel(0, susp->base + USP_TX_FIFO_OP);
+		break;
+	}
+}
+
+static void sirf_usp_rx_fifo_op(struct sirf_usp *susp, int cmd)
+{
+	switch (cmd) {
+	case FIFO_RESET:
+		writel(USP_RX_FIFO_RESET, susp->base + USP_RX_FIFO_OP);
+		writel(0, susp->base + USP_RX_FIFO_OP);
+		break;
+	case FIFO_START:
+		writel(USP_RX_FIFO_START, susp->base + USP_RX_FIFO_OP);
+		break;
+	case FIFO_STOP:
+		writel(0, susp->base + USP_RX_FIFO_OP);
+		break;
+	}
+}
+
+static inline void sirf_usp_tx_enable(struct sirf_usp *susp)
+{
+	writel(readl(susp->base + USP_TX_RX_ENABLE) | USP_TX_ENA,
+			susp->base + USP_TX_RX_ENABLE);
+}
+
+static inline void sirf_usp_tx_disable(struct sirf_usp *susp)
+{
+	writel(readl(susp->base + USP_TX_RX_ENABLE) & ~USP_TX_ENA,
+			susp->base + USP_TX_RX_ENABLE);
+}
+
+static inline void sirf_usp_rx_enable(struct sirf_usp *susp)
+{
+	writel(readl(susp->base + USP_TX_RX_ENABLE) | USP_RX_ENA,
+			susp->base + USP_TX_RX_ENABLE);
+}
+
+static inline void sirf_usp_rx_disable(struct sirf_usp *susp)
+{
+	writel(readl(susp->base + USP_TX_RX_ENABLE) & ~USP_RX_ENA,
+			susp->base + USP_TX_RX_ENABLE);
+}
+
+static int sirf_usp_pcm_dai_probe(struct snd_soc_dai *dai)
+{
+	dai->playback_dma_data = &dma_data[0];
+	dai->capture_dma_data = &dma_data[1];
+	return 0;
+}
+
+static int sirf_usp_pcm_set_dai_fmt(struct snd_soc_dai *dai,
+		unsigned int fmt)
+{
+	struct sirf_usp *susp = snd_soc_dai_get_drvdata(dai);
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		susp->master = 1;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		susp->master = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int sirf_usp_pcm_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct sirf_usp *susp = snd_soc_dai_get_drvdata(dai);
+	u32 mode1 = readl(susp->base + USP_MODE1);
+	u32 mode2 = readl(susp->base + USP_MODE2);
+	u32 rate = params_rate(params);
+	u32 clk_rate, clk_div, clk_div_hi, clk_div_lo;
+
+	if (susp->master) {
+		mode1 &= ~USP_CLOCK_MODE_SLAVE;
+		mode2 &= ~USP_TFS_CLK_SLAVE_MODE;
+		mode2 &= ~USP_RFS_CLK_SLAVE_MODE;
+	} else {
+		mode1 |= USP_CLOCK_MODE_SLAVE;
+		mode2 |= USP_TFS_CLK_SLAVE_MODE;
+		mode2 |= USP_RFS_CLK_SLAVE_MODE;
+	}
+	writel(mode1, susp->base + USP_MODE1);
+	writel(mode2, susp->base + USP_MODE2);
+
+	clk_rate = clk_get_rate(susp->clk);
+	if (clk_rate < rate * 2) {
+		dev_err(dai->dev, "Can't get rate(%d) by need.\n", rate);
+		return -EINVAL;
+	}
+
+	clk_div = (clk_rate / (2 * rate)) - 1;
+	clk_div_hi = (clk_div & 0xC00) >> 10;
+	clk_div_lo = (clk_div & 0x3FF);
+
+	writel((clk_div_lo << 21) | readl(susp->base + USP_MODE2),
+		susp->base + USP_MODE2);
+	writel((clk_div_hi << 30) | readl(susp->base + USP_TX_FRAME_CTRL),
+		susp->base + USP_TX_FRAME_CTRL);
+
+	return 0;
+}
+
+static int sirf_usp_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
+				struct snd_soc_dai *dai)
+{
+	int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	struct sirf_usp *susp = snd_soc_dai_get_drvdata(dai);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		if (playback) {
+			sirf_usp_tx_fifo_op(susp, FIFO_RESET);
+			sirf_usp_tx_fifo_op(susp, FIFO_START);
+			sirf_usp_tx_enable(susp);
+		} else {
+			sirf_usp_rx_fifo_op(susp, FIFO_RESET);
+			sirf_usp_rx_fifo_op(susp, FIFO_START);
+			sirf_usp_rx_enable(susp);
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		if (playback) {
+			sirf_usp_tx_disable(susp);
+			sirf_usp_tx_fifo_op(susp, FIFO_STOP);
+		} else {
+			sirf_usp_rx_disable(susp);
+			sirf_usp_rx_fifo_op(susp, FIFO_STOP);
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static const struct snd_soc_dai_ops sirf_usp_pcm_dai_ops = {
+	.trigger = sirf_usp_pcm_trigger,
+	.set_fmt = sirf_usp_pcm_set_dai_fmt,
+	.hw_params = sirf_usp_pcm_hw_params,
+};
+
+static struct snd_soc_dai_driver sirf_usp_pcm_dai = {
+	.probe = sirf_usp_pcm_dai_probe,
+	.name		= "sirf-usp-pcm",
+	.id			= 0,
+	.playback = {
+		.stream_name = "SiRF USP PCM Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_48000
+			| SNDRV_PCM_RATE_44100
+			| SNDRV_PCM_RATE_32000
+			| SNDRV_PCM_RATE_22050
+			| SNDRV_PCM_RATE_16000
+			| SNDRV_PCM_RATE_11025
+			| SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.stream_name = "SiRF USP PCM Capture",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = SNDRV_PCM_RATE_48000
+			| SNDRV_PCM_RATE_44100
+			| SNDRV_PCM_RATE_32000
+			| SNDRV_PCM_RATE_22050
+			| SNDRV_PCM_RATE_16000
+			| SNDRV_PCM_RATE_11025
+			| SNDRV_PCM_RATE_8000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.ops = &sirf_usp_pcm_dai_ops,
+};
+
+static void sirf_usp_controller_init(struct sirf_usp *susp)
+{
+	u32 val;
+
+	/* Configure RISC mode */
+	writel(readl(susp->base + USP_RISC_DSP_MODE) & ~USP_RISC_DSP_SEL,
+		susp->base + USP_RISC_DSP_MODE);
+
+	/* Disable all interrupts status */
+	writel(readl(susp->base + USP_INT_STATUS), susp->base + USP_INT_STATUS);
+
+	/* Configure DMA IO Length register */
+	writel(0, susp->base + USP_TX_DMA_IO_LEN);
+	writel(0, susp->base + USP_RX_DMA_IO_LEN);
+
+	/* Configure RX Frame Control */
+	val = (AUDIO_WORD_SIZE * 2 - 1) << USP_RXC_DATA_LEN_OFFSET;
+	val |= (AUDIO_WORD_SIZE * 2 - 1) << USP_RXC_FRAME_LEN_OFFSET;
+	val |= (AUDIO_WORD_SIZE * 2 - 1) << USP_RXC_SHIFTER_LEN_OFFSET;
+	val |= USP_SINGLE_SYNC_MODE;
+	writel(val, susp->base + USP_RX_FRAME_CTRL);
+
+	/* Configure TX Frame Control */
+	val = (AUDIO_WORD_SIZE * 2 - 1) << USP_TXC_DATA_LEN_OFFSET;
+	val |= 0 << USP_TXC_SYNC_LEN_OFFSET;
+	val |= (AUDIO_WORD_SIZE * 2 - 1) << USP_TXC_FRAME_LEN_OFFSET;
+	val |= (AUDIO_WORD_SIZE * 2 - 1) << USP_TXC_SHIFTER_LEN_OFFSET;
+	val |= USP_TXC_SLAVE_CLK_SAMPLE;
+	writel(val, susp->base + USP_TX_FRAME_CTRL);
+
+	/* Configure Mode2 register */
+	val = (1 << USP_RXD_DELAY_LEN_OFFSET) | (0 << USP_TXD_DELAY_LEN_OFFSET);
+	val &= ~USP_ENA_CTRL_MODE;
+	val &= ~USP_FRAME_CTRL_MODE;
+	val &= ~USP_TFS_SOURCE_MODE;
+	writel(val, susp->base + USP_MODE2);
+
+	/* Configure Mode1 register */
+	val = 0;
+	val |= USP_SYNC_MODE;
+	val |= USP_ENDIAN_CTRL_LSBF;
+	val |= USP_EN;
+	val |= USP_RXD_ACT_EDGE_FALLING;
+	val &= ~USP_TXD_ACT_EDGE_FALLING;
+	val |= USP_RFS_ACT_LEVEL_LOGIC1;
+	val |= USP_TFS_ACT_LEVEL_LOGIC1;
+	val |= USP_SCLK_IDLE_MODE_TOGGLE;
+	val |= USP_SCLK_IDLE_LEVEL_LOGIC1;
+	val &= ~USP_SCLK_PIN_MODE_IO;
+	val &= ~USP_RFS_PIN_MODE_IO;
+	val &= ~USP_TFS_PIN_MODE_IO;
+	val &= ~USP_RXD_PIN_MODE_IO;
+	val &= ~USP_TXD_PIN_MODE_IO;
+	val |= USP_TX_UFLOW_REPEAT_ZERO;
+	writel(val, susp->base + USP_MODE1);
+
+	/* Configure RX DMA IO Control register */
+	writel(0x0, susp->base + USP_RX_DMA_IO_CTRL);
+
+	/* Congiure RX FIFO Control register */
+	writel((USP_RX_FIFO_THRESHOLD << USP_RX_FIFO_THD_OFFSET) |
+		(USP_TX_RX_FIFO_WIDTH_DWORD << USP_RX_FIFO_WIDTH_OFFSET),
+		susp->base + USP_RX_FIFO_CTRL);
+
+	/* Congiure RX FIFO Level Check register */
+	writel(RX_FIFO_SC(0x04) | RX_FIFO_LC(0x0E) | RX_FIFO_HC(0x1B),
+		susp->base + USP_RX_FIFO_LEVEL_CHK);
+
+	/* Configure TX DMA IO Control register*/
+	writel(0x0, susp->base + USP_TX_DMA_IO_CTRL);
+
+	/* Configure TX FIFO Control register */
+	writel((USP_TX_FIFO_THRESHOLD << USP_TX_FIFO_THD_OFFSET) |
+		(USP_TX_RX_FIFO_WIDTH_DWORD << USP_TX_FIFO_WIDTH_OFFSET),
+		susp->base + USP_TX_FIFO_CTRL);
+
+	/* Congiure TX FIFO Level Check register */
+	writel(TX_FIFO_SC(0x1B) | TX_FIFO_LC(0x0E) | TX_FIFO_HC(0x04),
+		susp->base + USP_TX_FIFO_LEVEL_CHK);
+
+	/* Configure RX FIFO */
+	writel(USP_RX_FIFO_RESET, susp->base + USP_RX_FIFO_OP);
+	writel(0, susp->base + USP_RX_FIFO_OP);
+
+	/* Configure TX FIFO */
+	writel(USP_TX_FIFO_RESET, susp->base + USP_TX_FIFO_OP);
+	writel(0, susp->base + USP_TX_FIFO_OP);
+}
+
+static void sirf_usp_controller_uninit(struct sirf_usp *susp)
+{
+	/* Disable RX/TX */
+	writel(0, susp->base + USP_INT_ENABLE);
+	writel(0, susp->base + USP_TX_RX_ENABLE);
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int sirf_usp_pcm_runtime_suspend(struct device *dev)
+{
+	struct sirf_usp *susp = dev_get_drvdata(dev);
+	sirf_usp_controller_uninit(susp);
+	clk_disable_unprepare(susp->clk);
+	return 0;
+}
+
+static int sirf_usp_pcm_runtime_resume(struct device *dev)
+{
+	struct sirf_usp *susp = dev_get_drvdata(dev);
+	int ret;
+	ret = clk_prepare_enable(susp->clk);
+	if (ret)
+		return ret;
+	sirf_usp_controller_init(susp);
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int sirf_usp_pcm_suspend(struct device *dev)
+{
+	struct sirf_usp *susp = dev_get_drvdata(dev);
+
+	if (!pm_runtime_status_suspended(dev)) {
+		susp->mode1_reg = readl(susp->base + USP_MODE1);
+		susp->mode2_reg = readl(susp->base + USP_MODE2);
+		sirf_usp_pcm_runtime_suspend(dev);
+	}
+	return 0;
+}
+
+static int sirf_usp_pcm_resume(struct device *dev)
+{
+	struct sirf_usp *susp = dev_get_drvdata(dev);
+	int ret;
+
+	if (!pm_runtime_status_suspended(dev)) {
+		ret = sirf_usp_pcm_runtime_resume(dev);
+		if (ret)
+			return ret;
+		writel(susp->mode1_reg, susp->base + USP_MODE1);
+		writel(susp->mode2_reg, susp->base + USP_MODE2);
+	}
+	return 0;
+}
+#endif
+
+static const struct snd_soc_component_driver sirf_usp_component = {
+	.name		= "sirf-usp",
+};
+
+static int sirf_usp_pcm_probe(struct platform_device *pdev)
+{
+	struct sirf_usp *susp;
+	int ret;
+	struct resource *mem_res;
+
+	susp = devm_kzalloc(&pdev->dev, sizeof(struct sirf_usp),
+			GFP_KERNEL);
+	if (!susp)
+		return -ENOMEM;
+
+	susp->sirf_pcm_pdev = platform_device_register_simple("sirf-pcm-audio",
+			2, NULL, 0);
+	if (IS_ERR(susp->sirf_pcm_pdev))
+		return PTR_ERR(susp->sirf_pcm_pdev);
+
+	platform_set_drvdata(pdev, susp);
+
+	dma_data[0].chan_name = "tx";
+	dma_data[1].chan_name = "rx";
+
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	susp->base = devm_ioremap_resource(&pdev->dev, mem_res);
+	if (susp->base == NULL)
+		return -ENOMEM;
+
+	susp->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(susp->clk)) {
+		dev_err(&pdev->dev, "Get clock failed.\n");
+		return PTR_ERR(susp->clk);
+	}
+
+	pm_runtime_enable(&pdev->dev);
+
+	ret = devm_snd_soc_register_component(&pdev->dev, &sirf_usp_component,
+		&sirf_usp_pcm_dai, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "Register Audio SoC dai failed.\n");
+		goto err;
+	}
+	return 0;
+
+err:
+	return ret;
+}
+
+static int sirf_usp_pcm_remove(struct platform_device *pdev)
+{
+	struct sirf_usp *susp = platform_get_drvdata(pdev);
+	pm_runtime_disable(&pdev->dev);
+	platform_device_unregister(susp->sirf_pcm_pdev);
+
+	return 0;
+}
+
+static const struct of_device_id sirf_usp_pcm_of_match[] = {
+	{ .compatible = "sirf,prima2-usp-pcm", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, sirf_usp_pcm_of_match);
+
+static const struct dev_pm_ops sirf_usp_pcm_pm_ops = {
+	SET_RUNTIME_PM_OPS(sirf_usp_pcm_runtime_suspend, sirf_usp_pcm_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(sirf_usp_pcm_suspend, sirf_usp_pcm_resume)
+};
+
+static struct platform_driver sirf_usp_pcm_driver = {
+	.driver = {
+		.name = "sirf-usp-pcm",
+		.owner = THIS_MODULE,
+		.of_match_table = sirf_usp_pcm_of_match,
+		.pm = &sirf_usp_pcm_pm_ops,
+	},
+	.probe = sirf_usp_pcm_probe,
+	.remove = sirf_usp_pcm_remove,
+};
+
+module_platform_driver(sirf_usp_pcm_driver);
+
+MODULE_DESCRIPTION("SiRF SoC USP PCM bus driver");
+MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/sirf/sirf-usp.h b/sound/soc/sirf/sirf-usp.h
new file mode 100644
index 0000000..cb9085f
--- /dev/null
+++ b/sound/soc/sirf/sirf-usp.h
@@ -0,0 +1,276 @@
+/*
+ * arch/arm/mach-prima2/include/mach/sirfsoc_usp.h
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef __SIRFSOC_USP__
+#define __SIRFSOC_USP__
+
+/* USP Registers */
+#define USP_MODE1		0x00
+#define USP_MODE2 		0x04
+#define USP_TX_FRAME_CTRL  	0x08
+#define USP_RX_FRAME_CTRL	0x0C
+#define USP_TX_RX_ENABLE	0x10
+#define USP_INT_ENABLE		0x14
+#define USP_INT_STATUS		0x18
+#define USP_PIN_IO_DATA		0x1C
+#define USP_RISC_DSP_MODE	0x20
+#define USP_AYSNC_PARAM_REG	0x24
+#define USP_IRDA_X_MODE_DIV	0x28
+#define USP_SM_CFG		0x2C
+#define USP_TX_DMA_IO_CTRL	0x100
+#define USP_TX_DMA_IO_LEN	0x104
+#define USP_TX_FIFO_CTRL	0x108
+#define USP_TX_FIFO_LEVEL_CHK	0x10C
+#define USP_TX_FIFO_OP		0x110
+#define USP_TX_FIFO_STATUS	0x114
+#define USP_TX_FIFO_DATA	0x118
+#define USP_RX_DMA_IO_CTRL	0x120
+#define USP_RX_DMA_IO_LEN	0x124
+#define USP_RX_FIFO_CTRL	0x128
+#define USP_RX_FIFO_LEVEL_CHK	0x12C
+#define USP_RX_FIFO_OP		0x130
+#define USP_RX_FIFO_STATUS	0x134
+#define USP_RX_FIFO_DATA	0x138
+
+/* USP MODE register-1 */
+#define USP_SYNC_MODE 			0x00000001
+#define USP_CLOCK_MODE_SLAVE 		0x00000002
+#define USP_LOOP_BACK_EN		0x00000004
+#define USP_HPSIR_EN			0x00000008
+#define USP_ENDIAN_CTRL_LSBF		0x00000010
+#define USP_EN				0x00000020
+#define USP_RXD_ACT_EDGE_FALLING	0x00000040
+#define USP_TXD_ACT_EDGE_FALLING	0x00000080
+#define USP_RFS_ACT_LEVEL_LOGIC1	0x00000100
+#define USP_TFS_ACT_LEVEL_LOGIC1	0x00000200
+#define USP_SCLK_IDLE_MODE_TOGGLE	0x00000400
+#define USP_SCLK_IDLE_LEVEL_LOGIC1	0x00000800
+#define USP_SCLK_PIN_MODE_IO	0x00001000
+#define USP_RFS_PIN_MODE_IO	0x00002000
+#define USP_TFS_PIN_MODE_IO	0x00004000
+#define USP_RXD_PIN_MODE_IO	0x00008000
+#define USP_TXD_PIN_MODE_IO	0x00010000
+#define USP_SCLK_IO_MODE_INPUT	0x00020000
+#define USP_RFS_IO_MODE_INPUT	0x00040000
+#define USP_TFS_IO_MODE_INPUT	0x00080000
+#define USP_RXD_IO_MODE_INPUT	0x00100000
+#define USP_TXD_IO_MODE_INPUT	0x00200000
+#define USP_IRDA_WIDTH_DIV_MASK	0x3FC00000
+#define USP_IRDA_WIDTH_DIV_OFFSET	0
+#define USP_IRDA_IDLE_LEVEL_HIGH	0x40000000
+#define USP_TX_UFLOW_REPEAT_ZERO	0x80000000
+#define USP_TX_ENDIAN_MODE		0x00000020
+#define USP_RX_ENDIAN_MODE		0x00000020
+
+/* USP Mode Register-2 */
+#define USP_RXD_DELAY_LEN_MASK		0x000000FF
+#define USP_RXD_DELAY_LEN_OFFSET	0
+
+#define USP_TXD_DELAY_LEN_MASK		0x0000FF00
+#define USP_TXD_DELAY_LEN_OFFSET	8
+
+#define USP_ENA_CTRL_MODE		0x00010000
+#define USP_FRAME_CTRL_MODE		0x00020000
+#define USP_TFS_SOURCE_MODE             0x00040000
+#define USP_TFS_MS_MODE                 0x00080000
+#define USP_CLK_DIVISOR_MASK		0x7FE00000
+#define USP_CLK_DIVISOR_OFFSET 		21
+
+#define USP_TFS_CLK_SLAVE_MODE		(1<<20)
+#define USP_RFS_CLK_SLAVE_MODE		(1<<19)
+
+#define USP_IRDA_DATA_WIDTH		0x80000000
+
+/* USP Transmit Frame Control Register */
+
+#define USP_TXC_DATA_LEN_MASK		0x000000FF
+#define USP_TXC_DATA_LEN_OFFSET		0
+
+#define USP_TXC_SYNC_LEN_MASK		0x0000FF00
+#define USP_TXC_SYNC_LEN_OFFSET		8
+
+#define USP_TXC_FRAME_LEN_MASK		0x00FF0000
+#define USP_TXC_FRAME_LEN_OFFSET 	16
+
+#define USP_TXC_SHIFTER_LEN_MASK	0x1F000000
+#define USP_TXC_SHIFTER_LEN_OFFSET	24
+
+#define USP_TXC_SLAVE_CLK_SAMPLE 	0x20000000
+
+#define USP_TXC_CLK_DIVISOR_MASK  	0xC0000000
+#define USP_TXC_CLK_DIVISOR_OFFSET 	30
+
+/* USP Receive Frame Control Register */
+
+#define USP_RXC_DATA_LEN_MASK 		0x000000FF
+#define USP_RXC_DATA_LEN_OFFSET		0
+
+#define USP_RXC_FRAME_LEN_MASK		0x0000FF00
+#define USP_RXC_FRAME_LEN_OFFSET  	8
+
+#define USP_RXC_SHIFTER_LEN_MASK 	0x001F0000
+#define USP_RXC_SHIFTER_LEN_OFFSET 	16
+
+#define USP_I2S_SYNC_CHG		0x00200000
+
+#define USP_RXC_CLK_DIVISOR_MASK  	0x0F000000
+#define USP_RXC_CLK_DIVISOR_OFFSET 	24
+#define USP_SINGLE_SYNC_MODE		0x00400000
+
+/* Tx - RX Enable Register */
+
+#define USP_RX_ENA		0x00000001
+#define USP_TX_ENA		0x00000002
+
+/* USP Interrupt Enable and status Register */
+#define USP_RX_DONE_INT			0x00000001
+#define USP_TX_DONE_INT			0x00000002
+#define USP_RX_OFLOW_INT		0x00000004
+#define USP_TX_UFLOW_INT		0x00000008
+#define USP_RX_IO_DMA_INT		0x00000010
+#define USP_TX_IO_DMA_INT		0x00000020
+#define USP_RXFIFO_FULL_INT		0x00000040
+#define USP_TXFIFO_EMPTY_INT		0x00000080
+#define USP_RXFIFO_THD_INT		0x00000100
+#define USP_TXFIFO_THD_INT		0x00000200
+#define USP_UART_FRM_ERR_INT		0x00000400
+#define USP_RX_TIMEOUT_INT 		0x00000800
+#define USP_TX_ALLOUT_INT  		0x00001000
+#define USP_RXD_BREAK_INT		0x00008000
+
+/* All possible TX interruots */
+#define USP_TX_INTERRUPT		(USP_TX_DONE_INT|USP_TX_UFLOW_INT|USP_TX_IO_DMA_INT|\
+					USP_TXFIFO_EMPTY_INT|USP_TXFIFO_THD_INT)
+/* All possible RX interruots */
+#define USP_RX_INTERRUPT		(USP_RX_DONE_INT|USP_RX_OFLOW_INT|USP_RX_IO_DMA_INT|\
+					USP_RXFIFO_FULL_INT|USP_RXFIFO_THD_INT|USP_RXFIFO_THD_INT|USP_RX_TIMEOUT_INT)
+
+#define USP_INT_ALL        0x1FFF
+
+/* USP Pin I/O Data Register */
+
+#define USP_RFS_PIN_VALUE_MASK	0x00000001
+#define USP_TFS_PIN_VALUE_MASK	0x00000002
+#define USP_RXD_PIN_VALUE_MASK	0x00000004
+#define USP_TXD_PIN_VALUE_MASK	0x00000008
+#define USP_SCLK_PIN_VALUE_MASK	0x00000010
+
+/* USP RISC/DSP Mode Register */
+#define USP_RISC_DSP_SEL	0x00000001
+
+/* USP ASYNC PARAMETER Register*/
+
+#define USP_ASYNC_TIMEOUT_MASK 	0x0000FFFF
+#define USP_ASYNC_TIMEOUT_OFFSET	0
+#define USP_ASYNC_TIMEOUT(x)	(((x)&USP_ASYNC_TIMEOUT_MASK)<<USP_ASYNC_TIMEOUT_OFFSET)
+
+#define USP_ASYNC_DIV2_MASK		0x003F0000
+#define USP_ASYNC_DIV2_OFFSET		16
+
+/* USP TX DMA I/O MODE Register */
+#define USP_TX_MODE_IO			0x00000001
+
+/* USP TX DMA I/O Length Register */
+#define USP_TX_DATA_LEN_MASK		0xFFFFFFFF
+#define USP_TX_DATA_LEN_OFFSET		0
+
+/* USP TX FIFO Control Register */
+#define USP_TX_FIFO_WIDTH_MASK		0x00000003
+#define USP_TX_FIFO_WIDTH_OFFSET	0
+
+#define USP_TX_FIFO_THD_MASK		0x000001FC
+#define USP_TX_FIFO_THD_OFFSET		2
+
+/* USP TX FIFO Level Check Register */
+#define USP_TX_FIFO_LEVEL_CHECK_MASK	0x1F
+#define USP_TX_FIFO_SC_OFFSET	0
+#define USP_TX_FIFO_LC_OFFSET	10
+#define USP_TX_FIFO_HC_OFFSET	20
+
+#define TX_FIFO_SC(x)		(((x) & USP_TX_FIFO_LEVEL_CHECK_MASK) << USP_TX_FIFO_SC_OFFSET)
+#define TX_FIFO_LC(x)		(((x) & USP_TX_FIFO_LEVEL_CHECK_MASK) << USP_TX_FIFO_LC_OFFSET)
+#define TX_FIFO_HC(x)		(((x) & USP_TX_FIFO_LEVEL_CHECK_MASK) << USP_TX_FIFO_HC_OFFSET)
+
+/* USP TX FIFO Operation Register */
+#define USP_TX_FIFO_RESET		0x00000001
+#define USP_TX_FIFO_START		0x00000002
+
+/* USP TX FIFO Status Register */
+#define USP_TX_FIFO_LEVEL_MASK		0x0000007F
+#define USP_TX_FIFO_LEVEL_OFFSET	0
+
+#define USP_TX_FIFO_FULL 		0x00000080
+#define USP_TX_FIFO_EMPTY		0x00000100
+
+/* USP TX FIFO Data Register */
+#define USP_TX_FIFO_DATA_MASK		0xFFFFFFFF
+#define USP_TX_FIFO_DATA_OFFSET		0
+
+/* USP RX DMA I/O MODE Register */
+#define USP_RX_MODE_IO			0x00000001
+#define USP_RX_DMA_FLUSH		0x00000004
+
+/* USP RX DMA I/O Length Register */
+#define USP_RX_DATA_LEN_MASK		0xFFFFFFFF
+#define USP_RX_DATA_LEN_OFFSET		0
+
+/* USP RX FIFO Control Register */
+#define USP_RX_FIFO_WIDTH_MASK		0x00000003
+#define USP_RX_FIFO_WIDTH_OFFSET	0
+
+#define USP_RX_FIFO_THD_MASK		0x000001FC
+#define USP_RX_FIFO_THD_OFFSET		2
+
+/* USP RX FIFO Level Check Register */
+
+#define USP_RX_FIFO_LEVEL_CHECK_MASK	0x1F
+#define USP_RX_FIFO_SC_OFFSET	0
+#define USP_RX_FIFO_LC_OFFSET	10
+#define USP_RX_FIFO_HC_OFFSET	20
+
+#define RX_FIFO_SC(x)		(((x) & USP_RX_FIFO_LEVEL_CHECK_MASK) << USP_RX_FIFO_SC_OFFSET)
+#define RX_FIFO_LC(x)		(((x) & USP_RX_FIFO_LEVEL_CHECK_MASK) << USP_RX_FIFO_LC_OFFSET)
+#define RX_FIFO_HC(x)		(((x) & USP_RX_FIFO_LEVEL_CHECK_MASK) << USP_RX_FIFO_HC_OFFSET)
+
+/* USP RX FIFO Operation Register */
+#define USP_RX_FIFO_RESET		0x00000001
+#define USP_RX_FIFO_START		0x00000002
+
+/* USP RX FIFO Status Register */
+
+#define USP_RX_FIFO_LEVEL_MASK		0x0000007F
+#define USP_RX_FIFO_LEVEL_OFFSET	0
+
+#define USP_RX_FIFO_FULL		0x00000080
+#define USP_RX_FIFO_EMPTY		0x00000100
+
+/* USP RX FIFO Data Register */
+
+#define USP_RX_FIFO_DATA_MASK		0xFFFFFFFF
+#define USP_RX_FIFO_DATA_OFFSET		0
+
+/*
+ * When rx thd irq occur, sender just disable tx empty irq,
+ * Remaining data in tx fifo wil also be sent out.
+ */
+#define USP_FIFO_SIZE           	128
+#define USP_TX_FIFO_THRESHOLD		(USP_FIFO_SIZE/2)
+#define USP_RX_FIFO_THRESHOLD		(USP_FIFO_SIZE/2)
+
+/* FIFO_WIDTH for the USP_TX_FIFO_CTRL and USP_RX_FIFO_CTRL registers */
+#define USP_FIFO_WIDTH_BYTE  0x00
+#define USP_FIFO_WIDTH_WORD  0x01
+#define USP_FIFO_WIDTH_DWORD 0x02
+
+#define USP_ASYNC_DIV2          16
+
+#define USP_PLUGOUT_RETRY_CNT	2
+
+#define USP_TX_RX_FIFO_WIDTH_DWORD    2
+
+#endif
-- 
1.7.5.4

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

* [PATCH v3 4/5] ASoC: sirf-soc-inner: add drivers for both CPU and Codec DAIs
  2014-01-03  6:04 [PATCH v3 0/5] ASoC: add CSR SiRFSoC sound drivers RongJun Ying
                   ` (2 preceding siblings ...)
  2014-01-03  6:05 ` [PATCH v3 3/5] ASoC: usp-pcm: add CPU DAI driver for PCM simulated from USP RongJun Ying
@ 2014-01-03  6:05 ` RongJun Ying
  2014-01-06 17:29   ` Mark Brown
  2014-01-03  6:05 ` [PATCH v3 5/5] ASoC: sirf-inner: add mach driver for SiRFSoC internal codec RongJun Ying
  4 siblings, 1 reply; 15+ messages in thread
From: RongJun Ying @ 2014-01-03  6:05 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown
  Cc: Takashi Iwai, Rongjun Ying, alsa-devel, Workgroup.linux

From: Rongjun Ying <Rongjun.Ying@csr.com>

there is an internal codec embedded in the SiRF SoC. this is not
a typical user scenerios of ASoC. but we can still get benefit by
sharing platform DMA codes instead of implementing a pure ALSA
driver.
This driver adds DAI drivers for this internal codec.

The features of  Internal Codec Controller include:
Support two channel 16-bit resolution playback with fix 48KHz sample rate
Support two channel 16-bit resolution record with fix 48KHz sample rate
Use dedicated Internal Codec TXFIFO and Internal Codec RXFIFO
Supports two DMA channels for Internal Codec TXFIFO and Internal Codec RXFIFO

Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com>
---
 -v3:
 Remove the pm_runtime_get_sync and pm_runtime_put invoke
 Use the generic dma dt-binding to get playback/capture dma channels
 Check the return value
 Use devm_snd_soc_register_component instead of snd_soc_register_component
 for inner, usp-pcm and i2s platform interface

 sound/soc/sirf/Kconfig          |    3 +
 sound/soc/sirf/Makefile         |    2 +
 sound/soc/sirf/sirf-soc-inner.c |  653 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 658 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/sirf/sirf-soc-inner.c

diff --git a/sound/soc/sirf/Kconfig b/sound/soc/sirf/Kconfig
index 5e395d3..afa3952 100644
--- a/sound/soc/sirf/Kconfig
+++ b/sound/soc/sirf/Kconfig
@@ -6,5 +6,8 @@ config SND_SIRF_SOC
 config SND_SOC_SIRF_I2S
 	tristate
 
+config SND_SIRF_SOC_INNER
+	tristate
+
 config SND_SOC_SIRF_USP
 	tristate
diff --git a/sound/soc/sirf/Makefile b/sound/soc/sirf/Makefile
index 630c9be..8517c67 100644
--- a/sound/soc/sirf/Makefile
+++ b/sound/soc/sirf/Makefile
@@ -1,7 +1,9 @@
 snd-soc-sirf-objs := sirf-pcm.o
+snd-soc-sirf-soc-inner-objs := sirf-soc-inner.o
 snd-soc-sirf-i2s-objs := sirf-i2s.o
 snd-soc-sirf-usp-objs := sirf-usp.o
 
 obj-$(CONFIG_SND_SIRF_SOC) += snd-soc-sirf.o
+obj-$(CONFIG_SND_SIRF_SOC_INNER) += snd-soc-sirf-soc-inner.o
 obj-$(CONFIG_SND_SOC_SIRF_I2S) += snd-soc-sirf-i2s.o
 obj-$(CONFIG_SND_SOC_SIRF_USP) += snd-soc-sirf-usp.o
diff --git a/sound/soc/sirf/sirf-soc-inner.c b/sound/soc/sirf/sirf-soc-inner.c
new file mode 100644
index 0000000..d542a6e
--- /dev/null
+++ b/sound/soc/sirf/sirf-soc-inner.c
@@ -0,0 +1,653 @@
+/*
+ * SiRF inner audio codec driver
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/rtc/sirfsoc_rtciobrg.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "sirf-audio.h"
+
+struct sirf_soc_inner_audio_reg_bits {
+	u32 dig_mic_en_bits;
+	u32 dig_mic_freq_bits;
+	u32 adc14b_12_bits;
+	u32 firdac_hsl_en_bits;
+	u32 firdac_hsr_en_bits;
+	u32 firdac_lout_en_bits;
+	u32 por_bits;
+	u32 codec_clk_en_bits;
+};
+
+struct sirf_soc_inner_audio {
+	void __iomem            *base;
+	struct clk              *clk;
+	spinlock_t              lock;
+	u32			sys_pwrc_reg_base;
+	struct sirf_soc_inner_audio_reg_bits *reg_bits;
+	u32			reg_ctrl0, reg_ctrl1;
+	struct platform_device	*sirf_pcm_pdev;
+};
+
+static struct sirf_soc_inner_audio_reg_bits sirf_soc_inner_audio_reg_bits_prima2 = {
+	20, 21, 22, 23, 24, 25, 26, 27,
+};
+
+static struct sirf_soc_inner_audio_reg_bits sirf_soc_inner_audio_reg_bits_atlas6 = {
+	22, 23, 24, 25, 26, 27, 28, 29,
+};
+static const char * const input_mode_mux[] = {"Single-ended",
+	"Differential"};
+
+static const struct soc_enum sirf_inner_enum[] = {
+	SOC_ENUM_SINGLE(AUDIO_IC_CODEC_CTRL1, 4, 2, input_mode_mux),
+};
+
+static const struct snd_kcontrol_new sirf_inner_input_mode_control =
+	SOC_DAPM_ENUM("Route", sirf_inner_enum[0]);
+
+static struct snd_kcontrol_new volume_controls_atlas6[] = {
+	SOC_DOUBLE("Playback Volume", AUDIO_IC_CODEC_CTRL0, 21, 14,
+			0x7F, 0),
+	SOC_DOUBLE("Capture Volume", AUDIO_IC_CODEC_CTRL1, 16, 10,
+			0x3F, 0),
+};
+
+static struct snd_kcontrol_new volume_controls_prima2[] = {
+	SOC_DOUBLE("Speaker Volume", AUDIO_IC_CODEC_CTRL0, 21, 14,
+			0x7F, 0),
+	SOC_DOUBLE("Capture Volume", AUDIO_IC_CODEC_CTRL1, 15, 10,
+			0x1F, 0),
+};
+
+static struct snd_kcontrol_new left_input_path_controls[] = {
+	SOC_DAPM_SINGLE("Line left Switch", AUDIO_IC_CODEC_CTRL1, 6, 1, 0),
+	SOC_DAPM_SINGLE("Mic left Switch", AUDIO_IC_CODEC_CTRL1, 3, 1, 0),
+};
+
+static struct snd_kcontrol_new right_input_path_controls[] = {
+	SOC_DAPM_SINGLE("Line right Switch", AUDIO_IC_CODEC_CTRL1, 5, 1, 0),
+	SOC_DAPM_SINGLE("Mic right Switch", AUDIO_IC_CODEC_CTRL1, 2, 1, 0),
+};
+
+static struct snd_kcontrol_new left_dac_to_hp_left_amp_switch_control =
+	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 9, 1, 0);
+
+static struct snd_kcontrol_new left_dac_to_hp_right_amp_switch_control =
+	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 8, 1, 0);
+
+static struct snd_kcontrol_new right_dac_to_hp_left_amp_switch_control =
+	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 7, 1, 0);
+
+static struct snd_kcontrol_new right_dac_to_hp_right_amp_switch_control =
+	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 6, 1, 0);
+
+static struct snd_kcontrol_new left_dac_to_speaker_lineout_switch_control =
+	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 11, 1, 0);
+
+static struct snd_kcontrol_new right_dac_to_speaker_lineout_switch_control =
+	SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 10, 1, 0);
+
+static int adc_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct sirf_soc_inner_audio *sinner_audio = dev_get_drvdata(codec->dev);
+	u32 val;
+
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		/* Enable capture power of codec*/
+		val = sirfsoc_rtc_iobrg_readl(sinner_audio->sys_pwrc_reg_base +
+			PWRC_PDN_CTRL_OFFSET);
+		val |= (1 << AUDIO_POWER_EN_BIT);
+		sirfsoc_rtc_iobrg_writel(val,
+			sinner_audio->sys_pwrc_reg_base + PWRC_PDN_CTRL_OFFSET);
+		break;
+	case SND_SOC_DAPM_POST_PMU:
+		/*After enable adc, Delay 200ms to avoid pop noise*/
+		msleep(200);
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int hp_amp_left_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct sirf_soc_inner_audio *sinner_audio = dev_get_drvdata(codec->dev);
+	u32 val;
+
+	val = snd_soc_read(codec, AUDIO_IC_CODEC_CTRL1);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		val |= (1 << sinner_audio->reg_bits->firdac_hsl_en_bits);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		val &= ~(1 << sinner_audio->reg_bits->firdac_hsl_en_bits);
+	default:
+		break;
+	}
+	snd_soc_write(codec, AUDIO_IC_CODEC_CTRL1, val);
+	return 0;
+}
+
+static int hp_amp_right_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct sirf_soc_inner_audio *sinner_audio = dev_get_drvdata(codec->dev);
+	u32 val;
+
+	val = snd_soc_read(codec, AUDIO_IC_CODEC_CTRL1);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		val |= (1 << sinner_audio->reg_bits->firdac_hsr_en_bits);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		val &= ~(1 << sinner_audio->reg_bits->firdac_hsr_en_bits);
+	default:
+		break;
+	}
+	snd_soc_write(codec, AUDIO_IC_CODEC_CTRL1, val);
+	return 0;
+}
+
+static int speaker_output_enable_event(struct snd_soc_dapm_widget *w,
+		struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	struct sirf_soc_inner_audio *sinner_audio = dev_get_drvdata(codec->dev);
+	u32 val;
+
+	val = snd_soc_read(codec, AUDIO_IC_CODEC_CTRL1);
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		val |= (1 << sinner_audio->reg_bits->firdac_lout_en_bits);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		val &= ~(1 << sinner_audio->reg_bits->firdac_lout_en_bits);
+	default:
+		break;
+	}
+	snd_soc_write(codec, AUDIO_IC_CODEC_CTRL1, val);
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget sirf_inner_dapm_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC left", NULL, AUDIO_IC_CODEC_CTRL0, 1, 0),
+	SND_SOC_DAPM_DAC("DAC right", NULL, AUDIO_IC_CODEC_CTRL0, 0, 0),
+	SND_SOC_DAPM_SWITCH("Left dac to hp left amp", SND_SOC_NOPM, 0, 0,
+			&left_dac_to_hp_left_amp_switch_control),
+	SND_SOC_DAPM_SWITCH("Left dac to hp right amp", SND_SOC_NOPM, 0, 0,
+			&left_dac_to_hp_right_amp_switch_control),
+	SND_SOC_DAPM_SWITCH("Right dac to hp left amp", SND_SOC_NOPM, 0, 0,
+			&right_dac_to_hp_left_amp_switch_control),
+	SND_SOC_DAPM_SWITCH("Right dac to hp right amp", SND_SOC_NOPM, 0, 0,
+			&right_dac_to_hp_right_amp_switch_control),
+	SND_SOC_DAPM_OUT_DRV_E("HP amp left driver", AUDIO_IC_CODEC_CTRL0, 3, 0,
+			NULL, 0, hp_amp_left_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_OUT_DRV_E("HP amp right driver", AUDIO_IC_CODEC_CTRL0, 2, 0,
+			NULL, 0, hp_amp_right_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_SWITCH("Left dac to speaker lineout", SND_SOC_NOPM, 0, 0,
+			&left_dac_to_speaker_lineout_switch_control),
+	SND_SOC_DAPM_SWITCH("Right dac to speaker lineout", SND_SOC_NOPM, 0, 0,
+			&right_dac_to_speaker_lineout_switch_control),
+	SND_SOC_DAPM_OUT_DRV_E("Speaker output driver", AUDIO_IC_CODEC_CTRL0, 4, 0,
+			NULL, 0, speaker_output_enable_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+	SND_SOC_DAPM_OUTPUT("HPOUTL"),
+	SND_SOC_DAPM_OUTPUT("HPOUTR"),
+	SND_SOC_DAPM_OUTPUT("SPKOUT"),
+
+	SND_SOC_DAPM_ADC_E("ADC left", NULL, AUDIO_IC_CODEC_CTRL1, 8, 0,
+			adc_event,
+			SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_ADC_E("ADC right", NULL, AUDIO_IC_CODEC_CTRL1, 7, 0,
+			adc_event, SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_MIXER("Left PGA mixer", AUDIO_IC_CODEC_CTRL1, 1, 0,
+		&left_input_path_controls[0],
+		ARRAY_SIZE(left_input_path_controls)),
+	SND_SOC_DAPM_MIXER("Right PGA mixer", AUDIO_IC_CODEC_CTRL1, 0, 0,
+		&right_input_path_controls[0],
+		ARRAY_SIZE(right_input_path_controls)),
+
+	SND_SOC_DAPM_MUX("Mic input mode mux", SND_SOC_NOPM, 0, 0,
+			&sirf_inner_input_mode_control),
+	SND_SOC_DAPM_MICBIAS("Mic Bias", AUDIO_IC_CODEC_PWR, 3, 0),
+	SND_SOC_DAPM_INPUT("MICIN1"),
+	SND_SOC_DAPM_INPUT("MICIN2"),
+	SND_SOC_DAPM_INPUT("LINEIN1"),
+	SND_SOC_DAPM_INPUT("LINEIN2"),
+
+	SND_SOC_DAPM_SUPPLY("HSL Phase Opposite", AUDIO_IC_CODEC_CTRL0,
+			30, 0, NULL, 0),
+};
+
+static const struct snd_soc_dapm_route sirf_inner_audio_map[] = {
+	{"SPKOUT", NULL, "Speaker output driver"},
+	{"Speaker output driver", NULL, "Left dac to speaker lineout"},
+	{"Speaker output driver", NULL, "Right dac to speaker lineout"},
+	{"Left dac to speaker lineout", "Switch", "DAC left"},
+	{"Right dac to speaker lineout", "Switch", "DAC right"},
+	{"HPOUTL", NULL, "HP amp left driver"},
+	{"HPOUTR", NULL, "HP amp right driver"},
+	{"HP amp left driver", NULL, "Right dac to hp left amp"},
+	{"HP amp right driver", NULL , "Right dac to hp right amp"},
+	{"HP amp left driver", NULL, "Left dac to hp left amp"},
+	{"HP amp right driver", NULL , "Right dac to hp right amp"},
+	{"Right dac to hp left amp", "Switch", "DAC left"},
+	{"Right dac to hp right amp", "Switch", "DAC right"},
+	{"Left dac to hp left amp", "Switch", "DAC left"},
+	{"Left dac to hp right amp", "Switch", "DAC right"},
+	{"DAC left", NULL, "Playback"},
+	{"DAC right", NULL, "Playback"},
+	{"DAC left", NULL, "HSL Phase Opposite"},
+	{"DAC right", NULL, "HSL Phase Opposite"},
+
+	{"Capture", NULL, "ADC left"},
+	{"Capture", NULL, "ADC right"},
+	{"ADC left", NULL, "Left PGA mixer"},
+	{"ADC right", NULL, "Right PGA mixer"},
+	{"Left PGA mixer", "Line left Switch", "LINEIN2"},
+	{"Right PGA mixer", "Line right Switch", "LINEIN1"},
+	{"Left PGA mixer", "Mic left Switch", "MICIN2"},
+	{"Right PGA mixer", "Mic right Switch", "Mic input mode mux"},
+	{"Mic input mode mux", "Single-ended", "MICIN1"},
+	{"Mic input mode mux", "Differential", "MICIN1"},
+};
+
+static int sirf_inner_codec_trigger(struct snd_pcm_substream *substream,
+		int cmd,
+		struct snd_soc_dai *dai)
+{
+	struct sirf_soc_inner_audio *sinner_audio = snd_soc_dai_get_drvdata(dai);
+	int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+	struct snd_soc_codec *codec = dai->codec;
+	u32 val;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		spin_lock(&sinner_audio->lock);
+		if (playback) {
+			/*Disconnect HP amp connect to avoid pop noise*/
+			val = snd_soc_read(codec, AUDIO_IC_CODEC_CTRL0);
+			val &= ~(IC_HSLEN | IC_HSREN);
+			snd_soc_write(codec, AUDIO_IC_CODEC_CTRL0, val);
+
+			snd_soc_write(codec, AUDIO_CTRL_IC_TXFIFO_OP, 0x0);
+
+			val = snd_soc_read(codec, AUDIO_CTRL_IC_CODEC_TX_CTRL);
+			val &= ~IC_TX_ENABLE;
+			snd_soc_write(codec, AUDIO_CTRL_IC_CODEC_TX_CTRL, val);
+		} else {
+			val = snd_soc_read(codec, AUDIO_CTRL_IC_CODEC_RX_CTRL);
+			val &= ~IC_RX_ENABLE;
+			snd_soc_write(codec, AUDIO_CTRL_IC_CODEC_RX_CTRL, val);
+		}
+		spin_unlock(&sinner_audio->lock);
+		break;
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		spin_lock(&sinner_audio->lock);
+		if (playback) {
+			snd_soc_write(codec, AUDIO_CTRL_IC_TXFIFO_OP, AUDIO_FIFO_RESET);
+			snd_soc_write(codec, AUDIO_CTRL_IC_TXFIFO_INT_MSK, 0);
+			snd_soc_write(codec, AUDIO_CTRL_IC_TXFIFO_OP, 0x0);
+			snd_soc_write(codec, AUDIO_CTRL_IC_TXFIFO_OP,
+				AUDIO_FIFO_START);
+			snd_soc_write(codec, AUDIO_CTRL_IC_CODEC_TX_CTRL,
+				IC_TX_ENABLE);
+			val = snd_soc_read(codec, AUDIO_IC_CODEC_CTRL0);
+			val |= (IC_HSLEN | IC_HSREN);
+			snd_soc_write(codec, AUDIO_IC_CODEC_CTRL0, val);
+		} else {
+			snd_soc_write(codec, AUDIO_CTRL_IC_RXFIFO_OP, AUDIO_FIFO_RESET);
+			/* unmask rx fifo interrupt */
+			snd_soc_write(codec, AUDIO_CTRL_IC_RXFIFO_INT_MSK, 0);
+
+			snd_soc_write(codec, AUDIO_CTRL_IC_RXFIFO_OP, 0x0);
+			/* First start the FIFO, then enable the tx/rx */
+			snd_soc_write(codec, AUDIO_CTRL_IC_RXFIFO_OP,
+					AUDIO_FIFO_START);
+			/* mono capture from dacr*/
+			if (substream->runtime->channels == 1)
+				snd_soc_write(codec,
+					AUDIO_CTRL_IC_CODEC_RX_CTRL, 0x1);
+			else
+				snd_soc_write(codec,
+					AUDIO_CTRL_IC_CODEC_RX_CTRL,
+					IC_RX_ENABLE);
+		}
+		spin_unlock(&sinner_audio->lock);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+struct snd_soc_dai_ops sirf_inner_codec_dai_ops = {
+	.trigger = sirf_inner_codec_trigger,
+};
+
+struct snd_soc_dai_driver sirf_inner_codec_dai = {
+	.name = "sirf-soc-inner",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.ops = &sirf_inner_codec_dai_ops,
+};
+EXPORT_SYMBOL_GPL(sirf_inner_codec_dai);
+
+static int sirf_inner_codec_probe(struct snd_soc_codec *codec)
+{
+	pm_runtime_enable(codec->dev);
+	if (of_device_is_compatible(codec->dev->of_node, "sirf,prima2-audio"))
+		return snd_soc_add_codec_controls(codec,
+			volume_controls_prima2,
+			ARRAY_SIZE(volume_controls_prima2));
+	if (of_device_is_compatible(codec->dev->of_node, "sirf,atlas6-audio"))
+		return snd_soc_add_codec_controls(codec,
+			volume_controls_atlas6,
+			ARRAY_SIZE(volume_controls_atlas6));
+
+	return -EINVAL;
+}
+
+static int sirf_inner_codec_remove(struct snd_soc_codec *codec)
+{
+	pm_runtime_disable(codec->dev);
+	return 0;
+}
+
+static unsigned int sirf_inner_codec_reg_read(struct snd_soc_codec *codec,
+		unsigned int reg)
+{
+	struct sirf_soc_inner_audio *sinner_audio = dev_get_drvdata(codec->dev);
+	return readl(sinner_audio->base + reg);
+}
+
+static int sirf_inner_codec_reg_write(struct snd_soc_codec *codec,
+	unsigned int reg, unsigned int val)
+{
+	struct sirf_soc_inner_audio *sinner_audio = dev_get_drvdata(codec->dev);
+	writel(val, sinner_audio->base + reg);
+	return 0;
+}
+
+
+static struct snd_soc_codec_driver soc_codec_device_sirf_inner_codec = {
+	.probe = sirf_inner_codec_probe,
+	.remove = sirf_inner_codec_remove,
+	.read = sirf_inner_codec_reg_read,
+	.write = sirf_inner_codec_reg_write,
+	.dapm_widgets = sirf_inner_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(sirf_inner_dapm_widgets),
+	.dapm_routes = sirf_inner_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(sirf_inner_audio_map),
+	.idle_bias_off = true,
+};
+
+static struct snd_dmaengine_dai_dma_data dma_data[2];
+
+static int sirf_soc_inner_dai_probe(struct snd_soc_dai *dai)
+{
+	dai->playback_dma_data = &dma_data[0];
+	dai->capture_dma_data = &dma_data[1];
+	return 0;
+}
+
+static struct snd_soc_dai_driver sirf_soc_inner_dai = {
+	.probe = sirf_soc_inner_dai_probe,
+	.name		= "sirf-soc-inner",
+	.id			= 0,
+	.playback = {
+		.stream_name = "inner Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+	.capture = {
+		.stream_name = "inner Capture",
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = SNDRV_PCM_RATE_48000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,
+	},
+};
+
+static const struct snd_soc_component_driver sirf_soc_inner_component = {
+	.name		= "sirf-soc-inner",
+};
+
+static const struct of_device_id sirf_soc_inner_of_match[] = {
+	{ .compatible = "sirf,prima2-audio", .data = &sirf_soc_inner_audio_reg_bits_prima2 },
+	{ .compatible = "sirf,atlas6-audio", .data = &sirf_soc_inner_audio_reg_bits_atlas6 },
+	{}
+};
+MODULE_DEVICE_TABLE(of, sirf_soc_inner_of_match);
+
+static int sirf_soc_inner_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct sirf_soc_inner_audio *sinner_audio;
+	struct resource *mem_res;
+	struct device_node *dn = NULL;
+	const struct of_device_id *match;
+	u32 val;
+
+	match = of_match_node(sirf_soc_inner_of_match, pdev->dev.of_node);
+
+	sinner_audio = devm_kzalloc(&pdev->dev,
+		sizeof(struct sirf_soc_inner_audio), GFP_KERNEL);
+	if (!sinner_audio)
+		return -ENOMEM;
+
+	sinner_audio->sirf_pcm_pdev = platform_device_register_simple("sirf-pcm-audio",
+			1, NULL, 0);
+	if (IS_ERR(sinner_audio->sirf_pcm_pdev))
+		return PTR_ERR(sinner_audio->sirf_pcm_pdev);
+
+	platform_set_drvdata(pdev, sinner_audio);
+
+	dma_data[0].chan_name = "tx";
+	dma_data[1].chan_name = "rx";
+
+	dn = of_find_compatible_node(dn, NULL, "sirf,prima2-pwrc");
+	if (!dn) {
+		dev_err(&pdev->dev, "Failed to get sirf,prima2-pwrc  node!\n");
+		return -ENODEV;
+	}
+
+	ret = of_property_read_u32(dn, "reg", &sinner_audio->sys_pwrc_reg_base);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed tp get pwrc register base address\n");
+		return -EINVAL;
+	}
+
+	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	sinner_audio->base = devm_ioremap_resource(&pdev->dev, mem_res);
+	if (sinner_audio->base == NULL)
+		return -ENOMEM;
+
+	sinner_audio->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(sinner_audio->clk)) {
+		dev_err(&pdev->dev, "Get clock failed.\n");
+		return PTR_ERR(sinner_audio->clk);
+	}
+
+	ret = clk_prepare_enable(sinner_audio->clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Enable clock failed.\n");
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_component(&pdev->dev, &sirf_soc_inner_component,
+		&sirf_soc_inner_dai, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "Register Audio SoC dai failed.\n");
+		goto err_clk_put;
+	}
+
+	ret = snd_soc_register_codec(&(pdev->dev),
+			&soc_codec_device_sirf_inner_codec,
+			&sirf_inner_codec_dai, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "Register Audio Codec dai failed.\n");
+		goto err_com_unreg;
+	}
+
+	sinner_audio->reg_bits = (struct sirf_soc_inner_audio_reg_bits *)match->data;
+	/*
+	 * Always open charge pump, if not, when the charge pump closed the
+	 * adc will not stable
+	 */
+	val = readl(sinner_audio->base + AUDIO_IC_CODEC_CTRL0);
+	val |= IC_CPFREQ;
+	writel(val, sinner_audio->base + AUDIO_IC_CODEC_CTRL0);
+
+	if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas6-audio")) {
+		val |= IC_CPEN;
+		writel(val, sinner_audio->base + AUDIO_IC_CODEC_CTRL0);
+	}
+	spin_lock_init(&sinner_audio->lock);
+	return 0;
+
+err_com_unreg:
+	snd_soc_unregister_component(&pdev->dev);
+err_clk_put:
+	clk_disable_unprepare(sinner_audio->clk);
+	return ret;
+}
+
+static int sirf_soc_inner_remove(struct platform_device *pdev)
+{
+	struct sirf_soc_inner_audio *sinner_audio = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(sinner_audio->clk);
+	snd_soc_unregister_codec(&(pdev->dev));
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int sirf_inner_runtime_suspend(struct device *dev)
+{
+	struct sirf_soc_inner_audio *sinner_audio = dev_get_drvdata(dev);
+	u32 val;
+	val = readl(sinner_audio->base + AUDIO_IC_CODEC_CTRL1);
+	val &= ~(1 << sinner_audio->reg_bits->codec_clk_en_bits);
+	writel(val, sinner_audio->base + AUDIO_IC_CODEC_CTRL1);
+	return 0;
+}
+
+static int sirf_inner_runtime_resume(struct device *dev)
+{
+	struct sirf_soc_inner_audio *sinner_audio = dev_get_drvdata(dev);
+	u32 val;
+	val = readl(sinner_audio->base + AUDIO_IC_CODEC_CTRL1);
+	val |= (1 << sinner_audio->reg_bits->codec_clk_en_bits);
+	val &= ~(1 << sinner_audio->reg_bits->por_bits);
+	writel(val, sinner_audio->base + AUDIO_IC_CODEC_CTRL1);
+
+	msleep(20);
+	val |= (1 << sinner_audio->reg_bits->por_bits);
+	writel(val, sinner_audio->base + AUDIO_IC_CODEC_CTRL1);
+
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int sirf_soc_inner_suspend(struct device *dev)
+{
+	struct sirf_soc_inner_audio *sinner_audio = dev_get_drvdata(dev);
+
+	sinner_audio->reg_ctrl0 = readl(sinner_audio->base + AUDIO_IC_CODEC_CTRL0);
+	sinner_audio->reg_ctrl1 = readl(sinner_audio->base + AUDIO_IC_CODEC_CTRL1);
+	sirf_inner_runtime_suspend(dev);
+	clk_disable_unprepare(sinner_audio->clk);
+
+	return 0;
+}
+
+static int sirf_soc_inner_resume(struct device *dev)
+{
+	struct sirf_soc_inner_audio *sinner_audio = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_prepare_enable(sinner_audio->clk);
+	if (ret)
+		return ret;
+
+	writel(sinner_audio->reg_ctrl0,
+		sinner_audio->base + AUDIO_IC_CODEC_CTRL0);
+	writel(sinner_audio->reg_ctrl1, sinner_audio->base + AUDIO_IC_CODEC_CTRL1);
+
+	if (!pm_runtime_status_suspended(dev))
+		sirf_inner_runtime_resume(dev);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops sirf_inner_pm_ops = {
+	SET_RUNTIME_PM_OPS(sirf_inner_runtime_suspend, sirf_inner_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(sirf_soc_inner_suspend, sirf_soc_inner_resume)
+};
+
+static struct platform_driver sirf_soc_inner_driver = {
+	.driver = {
+		.name = "sirf-soc-inner",
+		.owner = THIS_MODULE,
+		.of_match_table = sirf_soc_inner_of_match,
+		.pm = &sirf_inner_pm_ops,
+	},
+	.probe = sirf_soc_inner_probe,
+	.remove = sirf_soc_inner_remove,
+};
+
+module_platform_driver(sirf_soc_inner_driver);
+
+MODULE_DESCRIPTION("SiRF SoC inner bus and codec driver");
+MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
+MODULE_LICENSE("GPL v2");
-- 
1.7.5.4

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

* [PATCH v3 5/5] ASoC: sirf-inner: add mach driver for SiRFSoC internal codec
  2014-01-03  6:04 [PATCH v3 0/5] ASoC: add CSR SiRFSoC sound drivers RongJun Ying
                   ` (3 preceding siblings ...)
  2014-01-03  6:05 ` [PATCH v3 4/5] ASoC: sirf-soc-inner: add drivers for both CPU and Codec DAIs RongJun Ying
@ 2014-01-03  6:05 ` RongJun Ying
  2014-01-06 17:35   ` Mark Brown
  4 siblings, 1 reply; 15+ messages in thread
From: RongJun Ying @ 2014-01-03  6:05 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown
  Cc: Takashi Iwai, Rongjun Ying, alsa-devel, Workgroup.linux

From: Rongjun Ying <Rongjun.Ying@csr.com>

This connects DMA, CPU DAI and Codec DAI together and works
as a mach driver.

Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com>
---
 -v3:
 Use devm_gpio_request_one instead of gpio_request.
 Remove the extcon stuff code.
 Add binding document
 Use the devm_snd_soc_register_card instead of soc-audio device register

 .../bindings/sound/sirf,inner-audio-codec.txt      |   41 +++++
 sound/soc/sirf/Kconfig                             |    5 +
 sound/soc/sirf/Makefile                            |    2 +
 sound/soc/sirf/sirf-inner.c                        |  155 ++++++++++++++++++++
 4 files changed, 203 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/sirf,inner-audio-codec.txt
 create mode 100644 sound/soc/sirf/sirf-inner.c

diff --git a/Documentation/devicetree/bindings/sound/sirf,inner-audio-codec.txt b/Documentation/devicetree/bindings/sound/sirf,inner-audio-codec.txt
new file mode 100644
index 0000000..67393e3
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/sirf,inner-audio-codec.txt
@@ -0,0 +1,41 @@
+* SiRF atlas6 and prima2 inner audio codec based audio setups
+
+Required properties:
+- compatible: "sirf,sirf-inner"
+- sirf,inner-platform: phandle for the platform node
+- sirf,inner-codec: phandle for the SiRF inner codec node
+
+Optional properties:
+- hp-pa-gpios: Need to be present if the board need control external
+  headphone amplifier.
+- spk-pa-gpios: Need to be present if the board need control external
+  speaker amplifier.
+- hp-switch-gpios: Need to be present if the board capable to detect jack
+  insertion, removal.
+
+Available audio endpoints for the audio-routing table:
+
+Board connectors:
+ * Headset Stereophone
+ * Ext Spk
+ * Line In
+ * Mic
+
+SiRF inner codec pins:
+ * HPOUTL
+ * HPOUTR
+ * SPKOUT
+ * Ext Mic
+ * Mic Bias
+
+Example:
+
+sound {
+		compatible = "sirf,sirf-inner";
+		sirf,inner-codec = <&audio>;
+		sirf,inner-platform = <&audio>;
+		hp-pa-gpios = <&gpio 44 0>;
+		spk-pa-gpios = <&gpio 46 0>;
+		hp-switch-gpios = <&gpio 45 0>;
+};
+
diff --git a/sound/soc/sirf/Kconfig b/sound/soc/sirf/Kconfig
index afa3952..564b0ec 100644
--- a/sound/soc/sirf/Kconfig
+++ b/sound/soc/sirf/Kconfig
@@ -11,3 +11,8 @@ config SND_SIRF_SOC_INNER
 
 config SND_SOC_SIRF_USP
 	tristate
+
+config SND_SIRF_INNER
+	tristate "SoC Audio support for SiRF inner codec of SiRF EVB"
+	depends on SND_SIRF_SOC
+	select SND_SIRF_SOC_INNER
diff --git a/sound/soc/sirf/Makefile b/sound/soc/sirf/Makefile
index 8517c67..80abdf6 100644
--- a/sound/soc/sirf/Makefile
+++ b/sound/soc/sirf/Makefile
@@ -1,9 +1,11 @@
 snd-soc-sirf-objs := sirf-pcm.o
+snd-soc-sirf-inner-objs := sirf-inner.o
 snd-soc-sirf-soc-inner-objs := sirf-soc-inner.o
 snd-soc-sirf-i2s-objs := sirf-i2s.o
 snd-soc-sirf-usp-objs := sirf-usp.o
 
 obj-$(CONFIG_SND_SIRF_SOC) += snd-soc-sirf.o
+obj-$(CONFIG_SND_SIRF_INNER) += snd-soc-sirf-inner.o
 obj-$(CONFIG_SND_SIRF_SOC_INNER) += snd-soc-sirf-soc-inner.o
 obj-$(CONFIG_SND_SOC_SIRF_I2S) += snd-soc-sirf-i2s.o
 obj-$(CONFIG_SND_SOC_SIRF_USP) += snd-soc-sirf-usp.o
diff --git a/sound/soc/sirf/sirf-inner.c b/sound/soc/sirf/sirf-inner.c
new file mode 100644
index 0000000..1a10c55
--- /dev/null
+++ b/sound/soc/sirf/sirf-inner.c
@@ -0,0 +1,155 @@
+/*
+ * SiRF inner audio device driver
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+struct sirf_inner_card {
+	unsigned int            gpio_hp_pa;
+	unsigned int            gpio_spk_pa;
+};
+
+static int sirf_inner_hp_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *ctrl, int event)
+{
+	struct snd_soc_dapm_context *dapm = w->dapm;
+	struct snd_soc_card *card = dapm->card;
+	struct sirf_inner_card *sinner_card = snd_soc_card_get_drvdata(card);
+	int on = !SND_SOC_DAPM_EVENT_OFF(event);
+	if (gpio_is_valid(sinner_card->gpio_hp_pa))
+		gpio_set_value(sinner_card->gpio_hp_pa, on);
+	return 0;
+}
+
+static int sirf_inner_spk_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *ctrl, int event)
+{
+	struct snd_soc_dapm_context *dapm = w->dapm;
+	struct snd_soc_card *card = dapm->card;
+	struct sirf_inner_card *sinner_card = snd_soc_card_get_drvdata(card);
+	int on = !SND_SOC_DAPM_EVENT_OFF(event);
+
+	if (gpio_is_valid(sinner_card->gpio_spk_pa))
+		gpio_set_value(sinner_card->gpio_spk_pa, on);
+
+	return 0;
+}
+static const struct snd_soc_dapm_widget sirf_inner_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Hp", sirf_inner_hp_event),
+	SND_SOC_DAPM_SPK("Ext Spk", sirf_inner_spk_event),
+	SND_SOC_DAPM_MIC("Ext Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+	{"Hp", NULL, "HPOUTL"},
+	{"Hp", NULL, "HPOUTR"},
+	{"Ext Spk", NULL, "SPKOUT"},
+	{"MICIN1", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Ext Mic"},
+};
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link sirf_inner_dai_links[] = {
+	{
+		.name = "SiRF inner",
+		.stream_name = "SiRF inner",
+		.codec_dai_name = "sirf-soc-inner",
+		.platform_name = "sirf-pcm-audio.1",
+	},
+};
+
+/* Audio machine driver */
+static struct snd_soc_card snd_soc_sirf_inner_card = {
+	.name = "SiRF inner",
+	.owner = THIS_MODULE,
+	.dai_link = sirf_inner_dai_links,
+	.num_links = ARRAY_SIZE(sirf_inner_dai_links),
+	.dapm_widgets = sirf_inner_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(sirf_inner_dapm_widgets),
+	.dapm_routes = intercon,
+	.num_dapm_routes = ARRAY_SIZE(intercon),
+};
+
+static int sirf_inner_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &snd_soc_sirf_inner_card;
+	struct sirf_inner_card *sinner_card;
+	int ret;
+
+	sinner_card = devm_kzalloc(&pdev->dev, sizeof(struct sirf_inner_card),
+			GFP_KERNEL);
+	if (sinner_card == NULL)
+		return -ENOMEM;
+
+	sirf_inner_dai_links[0].cpu_of_node =
+		of_parse_phandle(pdev->dev.of_node, "sirf,inner-platform", 0);
+	sirf_inner_dai_links[0].codec_of_node =
+		of_parse_phandle(pdev->dev.of_node, "sirf,inner-codec", 0);
+	sinner_card->gpio_spk_pa = of_get_named_gpio(pdev->dev.of_node,
+			"spk-pa-gpios", 0);
+	sinner_card->gpio_hp_pa =  of_get_named_gpio(pdev->dev.of_node,
+			"hp-pa-gpios", 0);
+	if (gpio_is_valid(sinner_card->gpio_spk_pa)) {
+		ret = devm_gpio_request_one(&pdev->dev,
+				sinner_card->gpio_spk_pa,
+				GPIOF_OUT_INIT_LOW, "SPA_PA_SD");
+		if (ret) {
+			dev_err(&pdev->dev,
+				"Failed to request GPIO_%d for reset: %d\n",
+				sinner_card->gpio_spk_pa, ret);
+			return ret;
+		}
+	}
+	if (gpio_is_valid(sinner_card->gpio_hp_pa)) {
+		ret = devm_gpio_request_one(&pdev->dev,
+				sinner_card->gpio_hp_pa,
+				GPIOF_OUT_INIT_LOW, "HP_PA_SD");
+		if (ret) {
+			dev_err(&pdev->dev,
+				"Failed to request GPIO_%d for reset: %d\n",
+				sinner_card->gpio_hp_pa, ret);
+			return ret;
+		}
+	}
+
+	card->dev = &pdev->dev;
+	snd_soc_card_set_drvdata(card, sinner_card);
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret)
+		dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret);
+
+	return ret;
+}
+
+static const struct of_device_id sirf_inner_of_match[] = {
+	{.compatible = "sirf,sirf-inner", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, sirf_inner_of_match);
+
+static struct platform_driver sirf_inner_driver = {
+	.driver = {
+		.name = "sirf-inner",
+		.owner = THIS_MODULE,
+		.pm = &snd_soc_pm_ops,
+		.of_match_table = sirf_inner_of_match,
+	},
+	.probe = sirf_inner_probe,
+};
+module_platform_driver(sirf_inner_driver);
+
+MODULE_AUTHOR("RongJun Ying <RongJun.Ying@csr.com>");
+MODULE_DESCRIPTION("ALSA SoC SIRF inner AUDIO driver");
+MODULE_LICENSE("GPL v2");
-- 
1.7.5.4

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

* Re: [PATCH v3 1/5] ASoC: sirf: add sirf platform driver which provides DMA
  2014-01-03  6:05 ` [PATCH v3 1/5] ASoC: sirf: add sirf platform driver which provides DMA RongJun Ying
@ 2014-01-05 11:22   ` Lars-Peter Clausen
  2014-01-06 17:07   ` Mark Brown
  1 sibling, 0 replies; 15+ messages in thread
From: Lars-Peter Clausen @ 2014-01-05 11:22 UTC (permalink / raw)
  To: RongJun Ying
  Cc: alsa-devel, Takashi Iwai, Liam Girdwood, Workgroup.linux,
	Rongjun Ying, Mark Brown

On 01/03/2014 07:05 AM, RongJun Ying wrote:
> From: Rongjun Ying <Rongjun.Ying@csr.com>
> 
> this driver uses dmaengine APIs and provides DMA to the CPU DAIs
> of I2S, USP and SiRF-soc-inner.
> SiRFSoC has 3 audio DAIs: I2S, USP(Universal Serial Ports) and DAI
> connected to soc-inner-codec, all of them will use the same DMA
> driver here.
> 
> Signed-off-by: Rongjun Ying <Rongjun.Ying@csr.com>
> ---
>  -v3:
>  Automatically discovering the configuration of pcm hardware from
>  the dmaengine driver
>  
>  sound/soc/Kconfig         |    1 +
>  sound/soc/Makefile        |    1 +
>  sound/soc/sirf/Kconfig    |    4 ++
>  sound/soc/sirf/Makefile   |    3 ++
>  sound/soc/sirf/sirf-pcm.c |   68 +++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 77 insertions(+), 0 deletions(-)
>  create mode 100644 sound/soc/sirf/Kconfig
>  create mode 100644 sound/soc/sirf/Makefile
>  create mode 100644 sound/soc/sirf/sirf-pcm.c
> 
> diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
> index d62ce48..0060b31 100644
> --- a/sound/soc/Kconfig
> +++ b/sound/soc/Kconfig
> @@ -50,6 +50,7 @@ source "sound/soc/pxa/Kconfig"
>  source "sound/soc/samsung/Kconfig"
>  source "sound/soc/s6000/Kconfig"
>  source "sound/soc/sh/Kconfig"
> +source "sound/soc/sirf/Kconfig"
>  source "sound/soc/spear/Kconfig"
>  source "sound/soc/tegra/Kconfig"
>  source "sound/soc/txx9/Kconfig"
> diff --git a/sound/soc/Makefile b/sound/soc/Makefile
> index 62a1822..5f1df02 100644
> --- a/sound/soc/Makefile
> +++ b/sound/soc/Makefile
> @@ -27,6 +27,7 @@ obj-$(CONFIG_SND_SOC)	+= pxa/
>  obj-$(CONFIG_SND_SOC)	+= samsung/
>  obj-$(CONFIG_SND_SOC)	+= s6000/
>  obj-$(CONFIG_SND_SOC)	+= sh/
> +obj-$(CONFIG_SND_SOC)	+= sirf/
>  obj-$(CONFIG_SND_SOC)	+= spear/
>  obj-$(CONFIG_SND_SOC)	+= tegra/
>  obj-$(CONFIG_SND_SOC)	+= txx9/
> diff --git a/sound/soc/sirf/Kconfig b/sound/soc/sirf/Kconfig
> new file mode 100644
> index 0000000..1637089
> --- /dev/null
> +++ b/sound/soc/sirf/Kconfig
> @@ -0,0 +1,4 @@
> +config SND_SIRF_SOC
> +	tristate "Platform DMA driver for the SiRF SoC chips"
> +	depends on ARCH_SIRF && SND_SOC
> +	select SND_SOC_GENERIC_DMAENGINE_PCM
> diff --git a/sound/soc/sirf/Makefile b/sound/soc/sirf/Makefile
> new file mode 100644
> index 0000000..f268b83
> --- /dev/null
> +++ b/sound/soc/sirf/Makefile
> @@ -0,0 +1,3 @@
> +snd-soc-sirf-objs := sirf-pcm.o
> +
> +obj-$(CONFIG_SND_SIRF_SOC) += snd-soc-sirf.o
> diff --git a/sound/soc/sirf/sirf-pcm.c b/sound/soc/sirf/sirf-pcm.c
> new file mode 100644
> index 0000000..e4cb3a6
> --- /dev/null
> +++ b/sound/soc/sirf/sirf-pcm.c
> @@ -0,0 +1,68 @@
> +/*
> + * ALSA PCM interface for the SiRF SoC
> + *
> + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
> + *
> + * Licensed under GPLv2 or later.
> + */
> +
> +#include <linux/module.h>
> +#include <sound/dmaengine_pcm.h>
> +#include <sound/core.h>
> +#include <sound/pcm.h>
> +#include <sound/pcm_params.h>
> +#include <sound/soc.h>
> +
> +static struct dma_chan *sirf_pcm_request_chan(struct snd_soc_pcm_runtime *rtd,
> +	struct snd_pcm_substream *substream)
> +{
> +	struct snd_dmaengine_dai_dma_data *dma_data;
> +
> +	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
> +
> +	return dma_request_slave_channel(rtd->cpu_dai->dev,
> +			dma_data->chan_name);
> +}
> +
> +static const struct snd_dmaengine_pcm_config sirf_dmaengine_pcm_config = {
> +	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
> +	.compat_request_channel = sirf_pcm_request_chan,
> +};
> +
> +static int sirf_pcm_probe(struct platform_device *pdev)
> +{
> +	return devm_snd_dmaengine_pcm_register(&pdev->dev,
> +		&sirf_dmaengine_pcm_config,
> +		SND_DMAENGINE_PCM_FLAG_NO_DT |
> +		SND_DMAENGINE_PCM_FLAG_COMPAT);

Since your platform is using DT you should drop the NO_DT and COMPAT flags.
Your sirf_pcm_request_chan is essentially doing the same as what the DT path
in the generic driver does.

> +}
> +
> +static struct platform_driver sirf_pcm_driver = {
> +	.driver = {
> +		.name = "sirf-pcm-audio",
> +		.owner = THIS_MODULE,
> +	},
> +	.probe = sirf_pcm_probe,
> +};

Also I wouldn't bother to register a extra device for the PCM, just call
devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0) from the DAI drivers,
that's what everybody else is doing.

- Lars

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

* Re: [PATCH v3 2/5] ASoC: sirf: add I2S CPU DAI driver
  2014-01-03  6:05 ` [PATCH v3 2/5] ASoC: sirf: add I2S CPU DAI driver RongJun Ying
@ 2014-01-05 11:52   ` Lars-Peter Clausen
  2014-01-06 17:12   ` Mark Brown
  1 sibling, 0 replies; 15+ messages in thread
From: Lars-Peter Clausen @ 2014-01-05 11:52 UTC (permalink / raw)
  To: RongJun Ying
  Cc: alsa-devel, Takashi Iwai, Liam Girdwood, Workgroup.linux,
	Rongjun Ying, Mark Brown

On 01/03/2014 07:05 AM, RongJun Ying wrote:
> diff --git a/sound/soc/sirf/sirf-audio.h b/sound/soc/sirf/sirf-audio.h
> new file mode 100644
> index 0000000..b6fdf06
> --- /dev/null
> +++ b/sound/soc/sirf/sirf-audio.h
> @@ -0,0 +1,268 @@
> +#ifndef _SIRF_INNER_AUDIO_CTRL_H
> +#define _SIRF_INNER_AUDIO_CTRL_H
> +
> +#define AUDIO_CTRL_TX_FIFO_LEVEL_CHECK_MASK     0x3F
[...]

Adding a prefix like SIRF_ to all those defines wouldn't hurt.

> +
> +#define SIRF_I2S_EXT_CLK	0x0
> +#define SIRF_I2S_PWM_CLK	0x1
> +#endif /*__SIRF_INNER_AUDIO_CTRL_H*/
> diff --git a/sound/soc/sirf/sirf-i2s.c b/sound/soc/sirf/sirf-i2s.c
> new file mode 100644
> index 0000000..d8b8732
> --- /dev/null
> +++ b/sound/soc/sirf/sirf-i2s.c
> @@ -0,0 +1,435 @@
> +/*
> + * SiRF I2S driver
> + *
> + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
> + *
> + * Licensed under GPLv2 or later.
> + */
> +#include <linux/module.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/clk.h>
> +
> +#include <sound/soc.h>
> +#include <sound/pcm_params.h>
> +#include <sound/dmaengine_pcm.h>
> +
> +#include "sirf-audio.h"
> +
> +struct sirf_i2s {
> +	void __iomem		*base;
> +	struct clk		*clk;
> +	u32			i2s_ctrl;
> +	u32			i2s_ctrl_tx_rx_en;
> +	spinlock_t		lock;
> +	struct platform_device	*sirf_pcm_pdev;
> +	bool			master;
> +	int			ext_clk;
> +	int			src_clk_rate;
> +};
> +
> +static struct snd_dmaengine_dai_dma_data dma_data[2];

This can be removed since you only use it to specify the channel names. But
since you use the default names there is no need to do that.

> +
> +static int sirf_i2s_dai_probe(struct snd_soc_dai *dai)
> +{
> +	dai->playback_dma_data = &dma_data[0];
> +	dai->capture_dma_data = &dma_data[1];
> +	return 0;
> +}
> +
> +static int sirf_i2s_trigger(struct snd_pcm_substream *substream,
> +		int cmd, struct snd_soc_dai *dai)
> +{
> +	struct sirf_i2s *si2s = snd_soc_dai_get_drvdata(dai);
> +	int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
> +
> +	switch (cmd) {
> +	case SNDRV_PCM_TRIGGER_START:
> +	case SNDRV_PCM_TRIGGER_RESUME:
> +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> +		spin_lock(&si2s->lock);

This is the only place where you use the spinlock. The trigger callback is
already protected by the ALSA core and can not race against itself, so you
do not need the lock.

> +
> +		if (playback) {
> +			/* First start the FIFO, then enable the tx/rx */
> +			writel(AUDIO_FIFO_RESET,
> +				si2s->base + AUDIO_CTRL_EXT_TXFIFO1_OP);
> +			writel(AUDIO_FIFO_START,
> +				si2s->base + AUDIO_CTRL_EXT_TXFIFO1_OP);
> +
> +			writel(readl(si2s->base+AUDIO_CTRL_I2S_TX_RX_EN)
> +				| I2S_TX_ENABLE | I2S_DOUT_OE,
> +				si2s->base + AUDIO_CTRL_I2S_TX_RX_EN);

For better legibility this should probably be split into multiple
statements, like

	val = read()
	val |= ...
	write(val);

> +
> +		} else {
> +			/* First start the FIFO, then enable the tx/rx */
> +			writel(AUDIO_FIFO_RESET,
> +				si2s->base + AUDIO_CTRL_RXFIFO_OP);
> +			writel(AUDIO_FIFO_START,
> +				si2s->base + AUDIO_CTRL_RXFIFO_OP);
> +
> +			writel(readl(si2s->base+AUDIO_CTRL_I2S_TX_RX_EN)
> +				| I2S_RX_ENABLE,
> +				si2s->base + AUDIO_CTRL_I2S_TX_RX_EN);

Same here

> +		}
> +
> +		spin_unlock(&si2s->lock);
> +		break;
> +	case SNDRV_PCM_TRIGGER_STOP:
> +	case SNDRV_PCM_TRIGGER_SUSPEND:
> +	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> +		spin_lock(&si2s->lock);
> +
> +		if (playback) {
> +			writel(readl(si2s->base + AUDIO_CTRL_I2S_TX_RX_EN)
> +				& ~(I2S_TX_ENABLE),
> +				si2s->base + AUDIO_CTRL_I2S_TX_RX_EN);

and here

> +			/* First disable the tx/rx, then stop the FIFO */
> +			writel(0, si2s->base + AUDIO_CTRL_EXT_TXFIFO1_OP);
> +		} else {
> +			writel(readl(si2s->base + AUDIO_CTRL_I2S_TX_RX_EN)
> +				& ~(I2S_RX_ENABLE),
> +				si2s->base+AUDIO_CTRL_I2S_TX_RX_EN);
> +

and here

> +			/* First disable the tx/rx, then stop the FIFO */
> +			writel(0, si2s->base + AUDIO_CTRL_RXFIFO_OP);
> +		}
> +
> +		spin_unlock(&si2s->lock);
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +	return 0;
> +}
> +
> +static int sirf_i2s_hw_params(struct snd_pcm_substream *substream,
> +		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
> +{
> +	struct sirf_i2s *si2s = snd_soc_dai_get_drvdata(dai);
> +	u32 i2s_ctrl = readl(si2s->base + AUDIO_CTRL_I2S_CTRL);
> +	u32 i2s_tx_rx_ctrl = readl(si2s->base + AUDIO_CTRL_I2S_TX_RX_EN);
> +	u32 left_len, frame_len;
> +	int channels = params_channels(params);
> +	u32 bitclk;
> +	u32 bclk_div;
> +	u32 div;
> +
> +	/*
> +	 * SiRFSoC I2S controller only support 2 and 6 channells output.
> +	 * I2S_SIX_CHANNELS bit clear: select 2 channels mode.
> +	 * I2S_SIX_CHANNELS bit set: select 6 channels mode.
> +	 */
> +	switch (channels) {
> +	case 2:
> +		i2s_ctrl &= ~I2S_SIX_CHANNELS;
> +		break;
> +	case 6:
> +		i2s_ctrl |= I2S_SIX_CHANNELS;
> +		break;
> +	default:
> +		dev_err(dai->dev, "%d channels unsupported\n", channels);
> +		return -EINVAL;

Since you only support 2 and 6 for the number of channels you should add a
constraint to that in your hwparams callback. Otherwise userspace will think
you support any number of channels between 2 and 6. You can do this using
this snippet:

static unsigned int sirf_i2s_channels[] = {2, 6};
static struct snd_pcm_hw_constraint_list sirf_i2s_channel_constraints = {
    .count = ARRAY_SIZE(sirf_i2s_channels),
    .list = sirf_i2s_channels,
};

snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&sirf_i2s_channel_constraints);

> +	}
> +
> +	switch (params_format(params)) {
> +	case SNDRV_PCM_FORMAT_S8:
> +		left_len = 8;
> +		break;
> +	case SNDRV_PCM_FORMAT_S16_LE:
> +		left_len = 16;
> +		break;
> +	case SNDRV_PCM_FORMAT_S24_LE:
> +		left_len = 24;
> +		break;
> +	case SNDRV_PCM_FORMAT_S32_LE:
> +		left_len = 32;
> +		break;
> +	default:
> +		dev_err(dai->dev, "Format unsupported\n");
> +		return -EINVAL;
> +	}
> +
> +	frame_len = left_len * 2;
> +	i2s_ctrl &= ~(I2S_L_CHAN_LEN_MASK | I2S_FRAME_LEN_MASK);
> +	/* Fill the actual len - 1 */
> +	i2s_ctrl |= ((frame_len - 1) << 9) | ((left_len - 1) << 4)
> +		| (0 << 15) | (3 << 24);

You set the bclk_div to 3 here

> +
> +	if (si2s->master) {
> +		i2s_ctrl &= ~I2S_SLAVE_MODE;
> +		i2s_tx_rx_ctrl |= I2S_MCLK_EN;
> +		bitclk = params_rate(params) * frame_len;
> +		div = si2s->src_clk_rate / bitclk;
> +		/* MCLK divide-by-2 from source clk */
> +		div /= 2;
> +		bclk_div = div / 2 - 1;
> +		i2s_ctrl |= (bclk_div << 24);

and never clear it before setting it here again, this will probably not work.

> +		/*
> +		 * MCLK coefficient must set to 0, means
> +		 * divide-by-two from reference clock.
> +		 */
> +		i2s_ctrl &= ~(((1 << 10) - 1) << 15);
> +	} else {
> +		i2s_ctrl |= I2S_SLAVE_MODE;
> +		i2s_tx_rx_ctrl &= ~I2S_MCLK_EN;
> +	}
> +
> +	if (si2s->ext_clk)
> +		i2s_tx_rx_ctrl |= I2S_REF_CLK_SEL_EXT;
> +	else
> +		i2s_tx_rx_ctrl &= ~I2S_REF_CLK_SEL_EXT;
> +
> +	writel(i2s_ctrl, si2s->base + AUDIO_CTRL_I2S_CTRL);
> +	writel(i2s_tx_rx_ctrl, si2s->base + AUDIO_CTRL_I2S_TX_RX_EN);
> +	writel(readl(si2s->base + AUDIO_CTRL_MODE_SEL)
> +			| I2S_MODE,
> +			si2s->base + AUDIO_CTRL_MODE_SEL);

again, break this into multiple statements.

> +
> +	return 0;
> +}
> +
> +
> +static int sirf_i2s_set_clkdiv(struct snd_soc_dai *dai, int div_id, int src_rate)

I think this should be set_sysclk not set_clkdiv.

> +{
> +	struct sirf_i2s *si2s = snd_soc_dai_get_drvdata(dai);
> +
> +	switch (div_id) {
> +	case SIRF_I2S_EXT_CLK:
> +		si2s->ext_clk = 1;
> +		break;
> +	case SIRF_I2S_PWM_CLK:
> +		si2s->ext_clk = 0;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	si2s->src_clk_rate = src_rate;
> +	return 0;
> +}
> +
> +struct snd_soc_dai_ops sirfsoc_i2s_dai_ops = {

static const

> +	.trigger	= sirf_i2s_trigger,
> +	.hw_params	= sirf_i2s_hw_params,
> +	.set_fmt	= sirf_i2s_set_dai_fmt,
> +	.set_clkdiv	= sirf_i2s_set_clkdiv,
> +};
> +
[...]
> +#ifdef CONFIG_PM_SLEEP
> +static int sirf_i2s_suspend(struct device *dev)
> +{
> +	struct sirf_i2s *si2s = dev_get_drvdata(dev);
> +
> +	if (!pm_runtime_status_suspended(dev)) {
> +		si2s->i2s_ctrl = readl(si2s->base + AUDIO_CTRL_I2S_CTRL);
> +		si2s->i2s_ctrl_tx_rx_en =
> +			readl(si2s->base + AUDIO_CTRL_I2S_TX_RX_EN);
> +		sirf_i2s_runtime_suspend(dev);

This will yield a compile error if CONFIG_PM_SLEEP is set, but
CONFIG_PM_RUNTIME is not set

> +	}
> +	return 0;
> +}
> +
> +static int sirf_i2s_resume(struct device *dev)
> +{
> +	struct sirf_i2s *si2s = dev_get_drvdata(dev);
> +	int ret;
> +	if (!pm_runtime_status_suspended(dev)) {
> +		ret = sirf_i2s_runtime_resume(dev);

Same here

> +		if (ret)
> +			return ret;
> +		writel(readl(si2s->base + AUDIO_CTRL_MODE_SEL)
> +				| I2S_MODE,
> +				si2s->base + AUDIO_CTRL_MODE_SEL);
> +		writel(si2s->i2s_ctrl, si2s->base + AUDIO_CTRL_I2S_CTRL);
> +		/*Restore MCLK enable and reference clock select bits.*/
> +		writel(si2s->i2s_ctrl_tx_rx_en &
> +			(I2S_MCLK_EN | I2S_REF_CLK_SEL_EXT),
> +			si2s->base + AUDIO_CTRL_I2S_TX_RX_EN);
> +
> +		writel(0, si2s->base + AUDIO_CTRL_EXT_TXFIFO1_INT_MSK);
> +		writel(0, si2s->base + AUDIO_CTRL_RXFIFO_INT_MSK);
> +	}
> +
> +	return 0;
> +}
> +#endif
> +
> +static const struct snd_soc_component_driver sirf_i2s_component = {
> +	.name       = "sirf-i2s",
> +};
> +
> +static int sirf_i2s_probe(struct platform_device *pdev)
> +{
> +	struct sirf_i2s *si2s;
> +	int ret;
> +	struct resource mem_res;
> +
> +	si2s = devm_kzalloc(&pdev->dev, sizeof(struct sirf_i2s),

sizeof(*si2s) is prefered by the coding style guidelines

> +			GFP_KERNEL);
> +	if (!si2s)
> +		return -ENOMEM;
> +
> +	si2s->sirf_pcm_pdev = platform_device_register_simple("sirf-pcm-audio",
> +			0, NULL, 0);
> +	if (IS_ERR(si2s->sirf_pcm_pdev))
> +		return PTR_ERR(si2s->sirf_pcm_pdev);
> +
> +	platform_set_drvdata(pdev, si2s);
> +
> +	spin_lock_init(&si2s->lock);
> +
> +	dma_data[0].chan_name = "tx";
> +	dma_data[1].chan_name = "rx";
> +
> +	ret = of_address_to_resource(pdev->dev.of_node, 0, &mem_res);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "Unable to get i2s memory resource.\n");
> +		return ret;
> +	}
> +	si2s->base = devm_ioremap(&pdev->dev, mem_res.start,
> +		resource_size(&mem_res));

I think using devm_ioremap_resource() is better here. It will first request
the region before remapping it.

> +	if (!si2s->base)
> +		return -ENOMEM;
> +
> +	si2s->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(si2s->clk)) {
> +		dev_err(&pdev->dev, "Get clock failed.\n");
> +		ret = PTR_ERR(si2s->clk);
> +		goto err;
> +	}
> +
> +	pm_runtime_enable(&pdev->dev);
> +
> +	ret = devm_snd_soc_register_component(&pdev->dev, &sirf_i2s_component,
> +			&sirf_i2s_dai, 1);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Register Audio SoC dai failed.\n");
> +		goto err;
> +	}
> +
> +	return 0;
> +
> +err:
> +	return ret;
> +}
[...]
> +
> +static const struct of_device_id sirf_i2s_of_match[] = {
> +	{ .compatible = "sirf,prima2-i2s", },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, sirf_i2s_of_match);

Binding documentation is missing.

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

* Re: [PATCH v3 1/5] ASoC: sirf: add sirf platform driver which provides DMA
  2014-01-03  6:05 ` [PATCH v3 1/5] ASoC: sirf: add sirf platform driver which provides DMA RongJun Ying
  2014-01-05 11:22   ` Lars-Peter Clausen
@ 2014-01-06 17:07   ` Mark Brown
  2014-01-08  9:01     ` Rongjun Ying
  1 sibling, 1 reply; 15+ messages in thread
From: Mark Brown @ 2014-01-06 17:07 UTC (permalink / raw)
  To: RongJun Ying
  Cc: alsa-devel, Takashi Iwai, Liam Girdwood, Workgroup.linux, Rongjun Ying


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

On Fri, Jan 03, 2014 at 02:05:00PM +0800, RongJun Ying wrote:

> index 0000000..1637089
> --- /dev/null
> +++ b/sound/soc/sirf/Kconfig
> @@ -0,0 +1,4 @@
> +config SND_SIRF_SOC
> +	tristate "Platform DMA driver for the SiRF SoC chips"
> +	depends on ARCH_SIRF && SND_SOC
> +	select SND_SOC_GENERIC_DMAENGINE_PCM

No need for the SND_SOC dependency, the subdirectories are only
enumerated if it is selected, and looking at the code I don't see a
build time dependency on ARCH_SIRF so it should be ARCH_SIRF ||
COMPILE_TEST.

> +static struct dma_chan *sirf_pcm_request_chan(struct snd_soc_pcm_runtime *rtd,
> +	struct snd_pcm_substream *substream)
> +{
> +	struct snd_dmaengine_dai_dma_data *dma_data;
> +
> +	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
> +
> +	return dma_request_slave_channel(rtd->cpu_dai->dev,
> +			dma_data->chan_name);
> +}
> +
> +static const struct snd_dmaengine_pcm_config sirf_dmaengine_pcm_config = {
> +	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
> +	.compat_request_channel = sirf_pcm_request_chan,

Do you need the compat_request_chan - I'd expect a newish ARM system to
be DT only and the code doesn't look like it's doing anything that the
core couldn't handle?

> +static struct platform_driver sirf_pcm_driver = {
> +	.driver = {
> +		.name = "sirf-pcm-audio",
> +		.owner = THIS_MODULE,
> +	},
> +	.probe = sirf_pcm_probe,
> +};

This doesn't look to ever access any hardware directly so it probably
shouldn't be a standalone driver as Lars-Peter says.

> +static int __init sirf_pcm_init(void)
> +{
> +	int ret = 0;
> +
> +	ret = platform_driver_register(&sirf_pcm_driver);
> +	if (ret)
> +		pr_err("failed to register platform driver\n");
> +	return ret;
> +}

module_platform_driver() if there is some real hardware here.

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

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



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

* Re: [PATCH v3 2/5] ASoC: sirf: add I2S CPU DAI driver
  2014-01-03  6:05 ` [PATCH v3 2/5] ASoC: sirf: add I2S CPU DAI driver RongJun Ying
  2014-01-05 11:52   ` Lars-Peter Clausen
@ 2014-01-06 17:12   ` Mark Brown
  1 sibling, 0 replies; 15+ messages in thread
From: Mark Brown @ 2014-01-06 17:12 UTC (permalink / raw)
  To: RongJun Ying
  Cc: alsa-devel, Takashi Iwai, Liam Girdwood, Workgroup.linux, Rongjun Ying


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

On Fri, Jan 03, 2014 at 02:05:01PM +0800, RongJun Ying wrote:

> +static int sirf_i2s_dai_probe(struct snd_soc_dai *dai)
> +{
> +	dai->playback_dma_data = &dma_data[0];
> +	dai->capture_dma_data = &dma_data[1];
> +	return 0;
> +}

Call snd_soc_dai_init_dma_data() rather than assigning directly.

> +	},
> +	.ops = &sirfsoc_i2s_dai_ops,
> +};
> +#ifdef CONFIG_PM_RUNTIME

Blank line after the struct please.

> +		writel(si2s->i2s_ctrl, si2s->base + AUDIO_CTRL_I2S_CTRL);
> +		/*Restore MCLK enable and reference clock select bits.*/

/* text */

> +	si2s->sirf_pcm_pdev = platform_device_register_simple("sirf-pcm-audio",
> +			0, NULL, 0);
> +	if (IS_ERR(si2s->sirf_pcm_pdev))
> +		return PTR_ERR(si2s->sirf_pcm_pdev);

This should just be a call to register the DMA directly rather than
create a device to do it.

> +	ret = of_address_to_resource(pdev->dev.of_node, 0, &mem_res);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "Unable to get i2s memory resource.\n");
> +		return ret;
> +	}

It is more normal to use platform_get_resource(), it works fine with OF
resources and is more idiomatic than using the OF specific stuff.

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

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



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

* Re: [PATCH v3 3/5] ASoC: usp-pcm: add CPU DAI driver for PCM simulated from USP
  2014-01-03  6:05 ` [PATCH v3 3/5] ASoC: usp-pcm: add CPU DAI driver for PCM simulated from USP RongJun Ying
@ 2014-01-06 17:20   ` Mark Brown
  0 siblings, 0 replies; 15+ messages in thread
From: Mark Brown @ 2014-01-06 17:20 UTC (permalink / raw)
  To: RongJun Ying
  Cc: alsa-devel, Takashi Iwai, Liam Girdwood, Workgroup.linux, Rongjun Ying


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

On Fri, Jan 03, 2014 at 02:05:02PM +0800, RongJun Ying wrote:

> +static void sirf_usp_tx_fifo_op(struct sirf_usp *susp, int cmd)
> +{
> +	switch (cmd) {
> +	case FIFO_RESET:
> +		writel(USP_TX_FIFO_RESET, susp->base + USP_TX_FIFO_OP);
> +		writel(0, susp->base + USP_TX_FIFO_OP);
> +		break;
> +	case FIFO_START:
> +		writel(USP_TX_FIFO_START, susp->base + USP_TX_FIFO_OP);
> +		break;
> +	case FIFO_STOP:
> +		writel(0, susp->base + USP_TX_FIFO_OP);
> +		break;
> +	}
> +}

I'm not sure these functions and the switch statements in them are
adding anything - none of the statements share any code.  Either
refactor this so that the callers pass in USP_TX_FIFO_blah for the
argument or just inline the register operations.

> +static inline void sirf_usp_tx_enable(struct sirf_usp *susp)
> +{
> +	writel(readl(susp->base + USP_TX_RX_ENABLE) | USP_TX_ENA,
> +			susp->base + USP_TX_RX_ENABLE);
> +}

Similar thing here, just inline.

> +static int sirf_usp_pcm_dai_probe(struct snd_soc_dai *dai)
> +{
> +	dai->playback_dma_data = &dma_data[0];
> +	dai->capture_dma_data = &dma_data[1];

snd_soc_dai_init_dma_data().

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

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



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

* Re: [PATCH v3 4/5] ASoC: sirf-soc-inner: add drivers for both CPU and Codec DAIs
  2014-01-03  6:05 ` [PATCH v3 4/5] ASoC: sirf-soc-inner: add drivers for both CPU and Codec DAIs RongJun Ying
@ 2014-01-06 17:29   ` Mark Brown
  0 siblings, 0 replies; 15+ messages in thread
From: Mark Brown @ 2014-01-06 17:29 UTC (permalink / raw)
  To: RongJun Ying
  Cc: alsa-devel, Takashi Iwai, Liam Girdwood, Workgroup.linux, Rongjun Ying


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

On Fri, Jan 03, 2014 at 02:05:03PM +0800, RongJun Ying wrote:

> @@ -6,5 +6,8 @@ config SND_SIRF_SOC
>  config SND_SOC_SIRF_I2S
>  	tristate
>  
> +config SND_SIRF_SOC_INNER
> +	tristate
> +
>  config SND_SOC_SIRF_USP

Everything else is SND_SOC_SIRF_, please keep this consistent.

> +static struct sirf_soc_inner_audio_reg_bits sirf_soc_inner_audio_reg_bits_prima2 = {
> +	20, 21, 22, 23, 24, 25, 26, 27,
> +};

> +static struct sirf_soc_inner_audio_reg_bits sirf_soc_inner_audio_reg_bits_atlas6 = {
> +	22, 23, 24, 25, 26, 27, 28, 29,
> +};

Please used named initialisers to set these values rather than just a
list of numbers, this isn't very easy to read.

> +static const struct snd_kcontrol_new sirf_inner_input_mode_control =
> +	SOC_DAPM_ENUM("Route", sirf_inner_enum[0]);

Either use constants to reference the array or (better) use named
variables for each enum.  This is more readable and less error prone.

> +static struct snd_kcontrol_new volume_controls_atlas6[] = {
> +	SOC_DOUBLE("Playback Volume", AUDIO_IC_CODEC_CTRL0, 21, 14,
> +			0x7F, 0),
> +	SOC_DOUBLE("Capture Volume", AUDIO_IC_CODEC_CTRL1, 16, 10,
> +			0x3F, 0),

Please provide TLV information.

> +static struct snd_kcontrol_new left_input_path_controls[] = {
> +	SOC_DAPM_SINGLE("Line left Switch", AUDIO_IC_CODEC_CTRL1, 6, 1, 0),

Line Left Switch.

> +	switch (event) {
> +	case SND_SOC_DAPM_PRE_PMU:
> +		/* Enable capture power of codec*/
> +		val = sirfsoc_rtc_iobrg_readl(sinner_audio->sys_pwrc_reg_base +
> +			PWRC_PDN_CTRL_OFFSET);
> +		val |= (1 << AUDIO_POWER_EN_BIT);
> +		sirfsoc_rtc_iobrg_writel(val,
> +			sinner_audio->sys_pwrc_reg_base + PWRC_PDN_CTRL_OFFSET);
> +		break;
> +	case SND_SOC_DAPM_POST_PMU:
> +		/*After enable adc, Delay 200ms to avoid pop noise*/
> +		msleep(200);

No need to split these operations, just have one callback.  Why is there
no power down callback?

> +static int hp_amp_left_event(struct snd_soc_dapm_widget *w,
> +		struct snd_kcontrol *kcontrol, int event)
> +{
> +	struct snd_soc_codec *codec = w->codec;
> +	struct sirf_soc_inner_audio *sinner_audio = dev_get_drvdata(codec->dev);
> +	u32 val;
> +
> +	val = snd_soc_read(codec, AUDIO_IC_CODEC_CTRL1);
> +	switch (event) {
> +	case SND_SOC_DAPM_PRE_PMU:
> +		val |= (1 << sinner_audio->reg_bits->firdac_hsl_en_bits);
> +		break;
> +	case SND_SOC_DAPM_POST_PMD:
> +		val &= ~(1 << sinner_audio->reg_bits->firdac_hsl_en_bits);
> +	default:
> +		break;
> +	}
> +	snd_soc_write(codec, AUDIO_IC_CODEC_CTRL1, val);
> +	return 0;

snd_soc_update_bits().  Can this not be represented as multiple widgets
- remember that DAPM will coalesce writes as much as it can.

> +	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> +		spin_lock(&sinner_audio->lock);
> +		if (playback) {

The lock only gets used in the trigger function, is it needed?

> +static struct snd_soc_codec_driver soc_codec_device_sirf_inner_codec = {
> +	.probe = sirf_inner_codec_probe,
> +	.remove = sirf_inner_codec_remove,
> +	.read = sirf_inner_codec_reg_read,
> +	.write = sirf_inner_codec_reg_write,

Don't use custom read and write callbacks, use a MMIO regmap.

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

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



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

* Re: [PATCH v3 5/5] ASoC: sirf-inner: add mach driver for SiRFSoC internal codec
  2014-01-03  6:05 ` [PATCH v3 5/5] ASoC: sirf-inner: add mach driver for SiRFSoC internal codec RongJun Ying
@ 2014-01-06 17:35   ` Mark Brown
  0 siblings, 0 replies; 15+ messages in thread
From: Mark Brown @ 2014-01-06 17:35 UTC (permalink / raw)
  To: RongJun Ying
  Cc: alsa-devel, Takashi Iwai, Liam Girdwood, Workgroup.linux, Rongjun Ying


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

On Fri, Jan 03, 2014 at 02:05:04PM +0800, RongJun Ying wrote:

> +	struct sirf_inner_card *sinner_card = snd_soc_card_get_drvdata(card);

I see where it comes from but "sinner" is a really odd abbrevation to
use in a mostly English context.

Otherwise this looks fine.

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

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



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

* Re: [PATCH v3 1/5] ASoC: sirf: add sirf platform driver which provides DMA
  2014-01-06 17:07   ` Mark Brown
@ 2014-01-08  9:01     ` Rongjun Ying
  2014-01-08 12:25       ` Mark Brown
  0 siblings, 1 reply; 15+ messages in thread
From: Rongjun Ying @ 2014-01-08  9:01 UTC (permalink / raw)
  To: Mark Brown, RongJun Ying
  Cc: Takashi Iwai, alsa-devel, Liam Girdwood, DL-SHA-WorkGroupLinux



> -----Original Message-----
> From: Mark Brown [mailto:broonie@kernel.org]
> Sent: Tuesday, January 07, 2014 1:07 AM
> To: RongJun Ying
> Cc: Liam Girdwood; Jaroslav Kysela; Takashi Iwai; alsa-devel@alsa-
> project.org; DL-SHA-WorkGroupLinux; Rongjun Ying
> Subject: Re: [PATCH v3 1/5] ASoC: sirf: add sirf platform driver which
> provides DMA
> 
> On Fri, Jan 03, 2014 at 02:05:00PM +0800, RongJun Ying wrote:
> 
> > index 0000000..1637089
> > --- /dev/null
> > +++ b/sound/soc/sirf/Kconfig
> > @@ -0,0 +1,4 @@
> > +config SND_SIRF_SOC
> > +	tristate "Platform DMA driver for the SiRF SoC chips"
> > +	depends on ARCH_SIRF && SND_SOC
> > +	select SND_SOC_GENERIC_DMAENGINE_PCM
> 
> No need for the SND_SOC dependency, the subdirectories are only
> enumerated if it is selected, and looking at the code I don't see a
> build time dependency on ARCH_SIRF so it should be ARCH_SIRF ||
> COMPILE_TEST.
> 
> > +static struct dma_chan *sirf_pcm_request_chan(struct
> snd_soc_pcm_runtime *rtd,
> > +	struct snd_pcm_substream *substream) {
> > +	struct snd_dmaengine_dai_dma_data *dma_data;
> > +
> > +	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
> > +
> > +	return dma_request_slave_channel(rtd->cpu_dai->dev,
> > +			dma_data->chan_name);
> > +}
> > +
> > +static const struct snd_dmaengine_pcm_config
> sirf_dmaengine_pcm_config = {
> > +	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
> > +	.compat_request_channel = sirf_pcm_request_chan,
> 
> Do you need the compat_request_chan - I'd expect a newish ARM system to
> be DT only and the code doesn't look like it's doing anything that the
> core couldn't handle?
> 
> > +static struct platform_driver sirf_pcm_driver = {
> > +	.driver = {
> > +		.name = "sirf-pcm-audio",
> > +		.owner = THIS_MODULE,
> > +	},
> > +	.probe = sirf_pcm_probe,
> > +};
> 
> This doesn't look to ever access any hardware directly so it probably
> shouldn't be a standalone driver as Lars-Peter says.
> 
> > +static int __init sirf_pcm_init(void) {
> > +	int ret = 0;
> > +
> > +	ret = platform_driver_register(&sirf_pcm_driver);
> > +	if (ret)
> > +		pr_err("failed to register platform driver\n");
> > +	return ret;
> > +}
> 
> module_platform_driver() if there is some real hardware here.

Do you mean to add pcm device into dts?

pcm {
   compatible = "sirf,pcm-audio";
}

-------------------
BR
RongJun Ying


Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom
More information can be found at www.csr.com. Keep up to date with CSR on our technical blog, www.csr.com/blog, CSR people blog, www.csr.com/people, YouTube, www.youtube.com/user/CSRplc, Facebook, www.facebook.com/pages/CSR/191038434253534, or follow us on Twitter at www.twitter.com/CSR_plc.
New for 2014, you can now access the wide range of products powered by aptX at www.aptx.com.

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

* Re: [PATCH v3 1/5] ASoC: sirf: add sirf platform driver which provides DMA
  2014-01-08  9:01     ` Rongjun Ying
@ 2014-01-08 12:25       ` Mark Brown
  0 siblings, 0 replies; 15+ messages in thread
From: Mark Brown @ 2014-01-08 12:25 UTC (permalink / raw)
  To: Rongjun Ying
  Cc: alsa-devel, Takashi Iwai, DL-SHA-WorkGroupLinux, Liam Girdwood,
	RongJun Ying


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

On Wed, Jan 08, 2014 at 09:01:15AM +0000, Rongjun Ying wrote:

> > module_platform_driver() if there is some real hardware here.

> Do you mean to add pcm device into dts?

> pcm {
>    compatible = "sirf,pcm-audio";
> }

Only if this is an actual dedicated hardware block which as myself and
Lars said doesn't seem to be the case.

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

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



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

end of thread, other threads:[~2014-01-08 12:25 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-01-03  6:04 [PATCH v3 0/5] ASoC: add CSR SiRFSoC sound drivers RongJun Ying
2014-01-03  6:05 ` [PATCH v3 1/5] ASoC: sirf: add sirf platform driver which provides DMA RongJun Ying
2014-01-05 11:22   ` Lars-Peter Clausen
2014-01-06 17:07   ` Mark Brown
2014-01-08  9:01     ` Rongjun Ying
2014-01-08 12:25       ` Mark Brown
2014-01-03  6:05 ` [PATCH v3 2/5] ASoC: sirf: add I2S CPU DAI driver RongJun Ying
2014-01-05 11:52   ` Lars-Peter Clausen
2014-01-06 17:12   ` Mark Brown
2014-01-03  6:05 ` [PATCH v3 3/5] ASoC: usp-pcm: add CPU DAI driver for PCM simulated from USP RongJun Ying
2014-01-06 17:20   ` Mark Brown
2014-01-03  6:05 ` [PATCH v3 4/5] ASoC: sirf-soc-inner: add drivers for both CPU and Codec DAIs RongJun Ying
2014-01-06 17:29   ` Mark Brown
2014-01-03  6:05 ` [PATCH v3 5/5] ASoC: sirf-inner: add mach driver for SiRFSoC internal codec RongJun Ying
2014-01-06 17:35   ` Mark Brown

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.