Skip to contentSkip to conversation

ASoC: dwc: Add device tree support to designware I2S

PATCH Superseded Andrew Jackson 1 participant 8 messages Dec 23, 2014 – Dec 24, 2014

Subsystems (3)

v4 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

v4 cover ASoC: dwc: Add device tree support to designware I2S

From: Andrew Jackson <[email protected]>

This patch set extends the DesignWare I2S driver to provide device tree support and fixes a couple of small faults.

Changes v3->v4
+ Drop applied patches
+ Use combined function to prepare clock [Mark Brown]
+ Use managed clock resources to avoid clk_put [Mark Brown]
+ Read configuration prameters from hardware for both platform data and device tree [Mark Brown]
+ Re-order patch sequence [Mark Brown]
+ Change union name to avoid future collisions [Mark Brown]
+ Check return code from clk_set_rate [Mark Brown]
+ Check parametsrs read from hardware agaist array limits and add further comments [Mark Brown]
+ Add of_match_ptr [Mark Brown]

Changes v2->v3
+ Drop applied patch
+ Flush FIFOs in prepare rather than hw_params [Lars-Peter Clausen]

Changes v1->v2
+ Drop negative use count patch [Mark Brown]
+ Remove unnecessary debug print messages [Lars-Peter Clausen]
+ Rewrite iteration as for loop rather than do...while [Mark Brown]
+ Reorder patches to send fixes first [Mark Brown]
+ Simplify device tree code [Mark Brown]
+ Split device tree patch in two [Mark Brown]
+ Expand explanatory comment on channel configuration [Rajeev Kumar]

Arnd: I've not forgotten about updating the spear entries and
will submit as a separate patch.

Andrew Jackson (5):
ASoC: dwc: Prepare clock before use
ASoC: dwc: Switch to managed clock resource
ASoC: dwc: Read I2S block configuration from registers
ASoC: dwc: Add documentation for I2S DT
ASoC: dwc: Add devicetree support for Designware I2S

 .../devicetree/bindings/sound/designware-i2s.txt   |   31 +++
 sound/soc/dwc/Kconfig                              |    1 +
 sound/soc/dwc/designware_i2s.c                     |  275 ++++++++++++++++----
 3 files changed, 260 insertions(+), 47 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/designware-i2s.txt
#1 lore raw

PATCH v4 1/5 ASoC: dwc: Prepare clock before use

From: Andrew Jackson <[email protected]>

Some I2S clocks may require some time to get the clock ready for operation and so need to be prepared before they are enabled. So, prepare the clock as well as enabling it, but combine the two through clk_prepare_enable.

---
 sound/soc/dwc/designware_i2s.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
sound/soc/dwc/designware_i2s.c +1 -1
index 06d3a34..9573ec7 100644
@@ -411,7 +411,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
 	if (IS_ERR(dev->clk))
 		return  PTR_ERR(dev->clk);
 
-	ret = clk_enable(dev->clk);
+	ret = clk_prepare_enable(dev->clk);
 	if (ret < 0)
 		goto err_clk_put;
 
Signature · 1 line
1.7.1
#2 lore raw

Re: [PATCH v4 1/5] ASoC: dwc: Prepare clock before use

Quoted 6 lines · Andrew Jackson

From: Andrew Jackson <[email protected]>

Some I2S clocks may require some time to get the clock ready for operation and so need to be prepared before they are enabled. So, prepare the clock as well as enabling it, but combine the two through clk_prepare_enable.

More turkey-focussed issues: this should have a clk_disable_unprepare too. Sigh

Andrew

Quoted 19 lines
---
 sound/soc/dwc/designware_i2s.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
sound/soc/dwc/designware_i2s.c +1 -1
index 06d3a34..9573ec7 100644
@@ -411,7 +411,7 @@ static int dw_i2s_probe(struct platform_device *pdev)
 	if (IS_ERR(dev->clk))
 		return  PTR_ERR(dev->clk);
 
-	ret = clk_enable(dev->clk);
+	ret = clk_prepare_enable(dev->clk);
 	if (ret < 0)
 		goto err_clk_put;
 
#3 lore raw

PATCH v4 2/5 ASoC: dwc: Switch to managed clock resource

In reply to Andrew Jackson

From: Andrew Jackson <[email protected]>

Simplify error handling during probe by using managed clock resources.

---
 sound/soc/dwc/designware_i2s.c |    6 ++----
 1 files changed, 2 insertions(+), 4 deletions(-)
sound/soc/dwc/designware_i2s.c +2 -4
index 9573ec7..b3dc535 100644
@@ -407,13 +407,13 @@ static int dw_i2s_probe(struct platform_device *pdev)
 
 	dev->capability = pdata->cap;
 	dev->i2s_clk_cfg = pdata->i2s_clk_cfg;
-	dev->clk = clk_get(&pdev->dev, NULL);
+	dev->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(dev->clk))
 		return  PTR_ERR(dev->clk);
 
 	ret = clk_prepare_enable(dev->clk);
 	if (ret < 0)
-		goto err_clk_put;
+		return ret;
 
 	dev_set_drvdata(&pdev->dev, dev);
 	ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component,
@@ -427,8 +427,6 @@ static int dw_i2s_probe(struct platform_device *pdev)
 
 err_clk_disable:
 	clk_disable(dev->clk);
-err_clk_put:
-	clk_put(dev->clk);
 	return ret;
 }
 
Signature · 1 line
1.7.1
#4 lore raw

Re: [PATCH v4 2/5] ASoC: dwc: Switch to managed clock resource

Quoted 4 lines · Andrew Jackson

From: Andrew Jackson <[email protected]>

Simplify error handling during probe by using managed clock resources.

In my haste to get to the Christmas turkey I missed a clk_put elsewhere. Will fix and resubmit.

Andrew

Quoted 35 lines
---
 sound/soc/dwc/designware_i2s.c |    6 ++----
 1 files changed, 2 insertions(+), 4 deletions(-)
sound/soc/dwc/designware_i2s.c +2 -4
index 9573ec7..b3dc535 100644
@@ -407,13 +407,13 @@ static int dw_i2s_probe(struct platform_device *pdev)
 
 	dev->capability = pdata->cap;
 	dev->i2s_clk_cfg = pdata->i2s_clk_cfg;
-	dev->clk = clk_get(&pdev->dev, NULL);
+	dev->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(dev->clk))
 		return  PTR_ERR(dev->clk);
 
 	ret = clk_prepare_enable(dev->clk);
 	if (ret < 0)
-		goto err_clk_put;
+		return ret;
 
 	dev_set_drvdata(&pdev->dev, dev);
 	ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component,
@@ -427,8 +427,6 @@ static int dw_i2s_probe(struct platform_device *pdev)
 
 err_clk_disable:
 	clk_disable(dev->clk);
-err_clk_put:
-	clk_put(dev->clk);
 	return ret;
 }
 
#5 lore raw

PATCH v4 3/5 ASoC: dwc: Read I2S block configuration from registers

In reply to Andrew Jackson

From: Andrew Jackson <[email protected]>

The I2S block provides component parameter registers which describe how the block is instantiated. Use these registers to extract the block's configuration rather than relying on platform data.

---
 sound/soc/dwc/designware_i2s.c |   96 +++++++++++++++++++++++++++++++++++----
 1 files changed, 86 insertions(+), 10 deletions(-)
sound/soc/dwc/designware_i2s.c +86 -10
index b3dc535..c89b9eb 100644
@@ -54,6 +54,31 @@
 #define I2S_COMP_VERSION	0x01F8
 #define I2S_COMP_TYPE		0x01FC
 
+/*
+ * Component parameter register fields - define the I2S block's
+ * configuration.
+ */
+#define	COMP1_TX_WORDSIZE_3(r)	(((r) & GENMASK(27, 25)) >> 25)
+#define	COMP1_TX_WORDSIZE_2(r)	(((r) & GENMASK(24, 22)) >> 22)
+#define	COMP1_TX_WORDSIZE_1(r)	(((r) & GENMASK(21, 19)) >> 19)
+#define	COMP1_TX_WORDSIZE_0(r)	(((r) & GENMASK(18, 16)) >> 16)
+#define	COMP1_TX_CHANNELS(r)	(((r) & GENMASK(10, 9)) >> 9)
+#define	COMP1_RX_CHANNELS(r)	(((r) & GENMASK(8, 7)) >> 7)
+#define	COMP1_RX_ENABLED(r)	(((r) & BIT(6)) >> 6)
+#define	COMP1_TX_ENABLED(r)	(((r) & BIT(5)) >> 5)
+#define	COMP1_MODE_EN(r)	(((r) & BIT(4)) >> 4)
+#define	COMP1_FIFO_DEPTH_GLOBAL(r)	(((r) & GENMASK(3, 2)) >> 2)
+#define	COMP1_APB_DATA_WIDTH(r)	(((r) & GENMASK(1, 0)) >> 0)
+
+#define	COMP2_RX_WORDSIZE_3(r)	(((r) & GENMASK(12, 10)) >> 10)
+#define	COMP2_RX_WORDSIZE_2(r)	(((r) & GENMASK(9, 7)) >> 7)
+#define	COMP2_RX_WORDSIZE_1(r)	(((r) & GENMASK(5, 3)) >> 3)
+#define	COMP2_RX_WORDSIZE_0(r)	(((r) & GENMASK(2, 0)) >> 0)
+
+/* Number of entries in WORDSIZE and DATA_WIDTH parameter registers */
+#define	COMP_MAX_WORDSIZE	(1 << 3)
+#define	COMP_MAX_DATA_WIDTH	(1 << 2)
+
 #define MAX_CHANNEL_NUM		8
 #define MIN_CHANNEL_NUM		2
 
@@ -335,11 +360,50 @@ static int dw_i2s_resume(struct snd_soc_dai *dai)
 #define dw_i2s_resume	NULL
 #endif
 
-static void dw_configure_dai_by_pd(struct dw_i2s_dev *dev,
+/*
+ * The following tables allow a direct lookup of various parameters
+ * defined in the I2S block's configuration in terms of sound system
+ * parameters.  Each table is sized to the number of entries possible
+ * according to the number of configuration bits describing an I2S
+ * block parameter.
+ */
+
+/* Width of (DMA) bus */
+static const u32 bus_widths[COMP_MAX_DATA_WIDTH] = {
+	DMA_SLAVE_BUSWIDTH_1_BYTE,
+	DMA_SLAVE_BUSWIDTH_2_BYTES,
+	DMA_SLAVE_BUSWIDTH_4_BYTES,
+	DMA_SLAVE_BUSWIDTH_UNDEFINED
+};
+
+/* PCM format to support channel resolution */
+static const u32 formats[COMP_MAX_WORDSIZE] = {
+	SNDRV_PCM_FMTBIT_S16_LE,
+	SNDRV_PCM_FMTBIT_S16_LE,
+	SNDRV_PCM_FMTBIT_S24_LE,
+	SNDRV_PCM_FMTBIT_S24_LE,
+	SNDRV_PCM_FMTBIT_S32_LE,
+	0,
+	0,
+	0
+};
+
+static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev,
 				   struct snd_soc_dai_driver *dw_i2s_dai,
 				   struct resource *res,
 				   const struct i2s_platform_data *pdata)
 {
+	/*
+	 * Read component parameter registers to extract
+	 * the I2S block's configuration.
+	 */
+	u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1);
+	u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2);
+	u32 idx = COMP1_APB_DATA_WIDTH(comp1);
+
+	if (WARN_ON(idx >= ARRAY_SIZE(bus_widths)))
+		return -EINVAL;
+
 	/* Set DMA slaves info */
 
 	dev->play_dma_data.data = pdata->play_dma_data;
@@ -348,26 +412,36 @@ static void dw_configure_dai_by_pd(struct dw_i2s_dev *dev,
 	dev->capture_dma_data.addr = res->start + I2S_RXDMA;
 	dev->play_dma_data.max_burst = 16;
 	dev->capture_dma_data.max_burst = 16;
-	dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
-	dev->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+	dev->play_dma_data.addr_width = bus_widths[idx];
+	dev->capture_dma_data.addr_width = bus_widths[idx];
 	dev->play_dma_data.filter = pdata->filter;
 	dev->capture_dma_data.filter = pdata->filter;
 
-	if (pdata->cap & DWC_I2S_PLAY) {
+	if (COMP1_TX_ENABLED(comp1)) {
 		dev_dbg(dev->dev, " designware: play supported\n");
+		idx = COMP1_TX_WORDSIZE_0(comp1);
+		if (WARN_ON(idx >= ARRAY_SIZE(formats)))
+			return -EINVAL;
 		dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM;
-		dw_i2s_dai->playback.channels_max = pdata->channel;
-		dw_i2s_dai->playback.formats = pdata->snd_fmts;
+		dw_i2s_dai->playback.channels_max =
+				1 << (COMP1_TX_CHANNELS(comp1) + 1);
+		dw_i2s_dai->playback.formats = formats[idx];
 		dw_i2s_dai->playback.rates = pdata->snd_rates;
 	}
 
-	if (pdata->cap & DWC_I2S_RECORD) {
+	if (COMP1_RX_ENABLED(comp1)) {
 		dev_dbg(dev->dev, "designware: record supported\n");
+		idx = COMP2_RX_WORDSIZE_0(comp2);
+		if (WARN_ON(idx >= ARRAY_SIZE(formats)))
+			return -EINVAL;
 		dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM;
-		dw_i2s_dai->capture.channels_max = pdata->channel;
-		dw_i2s_dai->capture.formats = pdata->snd_fmts;
+		dw_i2s_dai->capture.channels_max =
+				1 << (COMP1_RX_CHANNELS(comp1) + 1);
+		dw_i2s_dai->capture.formats = formats[idx];
 		dw_i2s_dai->capture.rates = pdata->snd_rates;
 	}
+
+	return 0;
 }
 
 static int dw_i2s_probe(struct platform_device *pdev)
@@ -403,7 +477,9 @@ static int dw_i2s_probe(struct platform_device *pdev)
 		return PTR_ERR(dev->i2s_base);
 
 	dev->dev = &pdev->dev;
-	dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata);
+	ret = dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata);
+	if (ret < 0)
+		return ret;
 
 	dev->capability = pdata->cap;
 	dev->i2s_clk_cfg = pdata->i2s_clk_cfg;
Signature · 1 line
1.7.1
#6 lore raw

PATCH v4 4/5 ASoC: dwc: Add documentation for I2S DT

In reply to Andrew Jackson

From: Andrew Jackson <[email protected]>

Add documentation for Designware I2S hardware block. The block requires one clock (for audio sampling) and DMA channels for receive and transmit.

---
 .../devicetree/bindings/sound/designware-i2s.txt   |   31 ++++++++++++++++++++
 1 files changed, 31 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/designware-i2s.txt
Documentation/devicetree/bindings/sound/designware-i2s.txt new file +31 -0
new file mode 100644
index 0000000..7bb5424
@@ -0,0 +1,31 @@
+DesignWare I2S controller
+
+Required properties:
+ - compatible : Must be "snps,designware-i2s"
+ - reg : Must contain the I2S core's registers location and length
+ - clocks : Pairs of phandle and specifier referencing the controller's
+   clocks. The controller expects one clock: the clock used as the sampling
+   rate reference clock sample.
+ - clock-names : "i2sclk" for the sample rate reference clock.
+ - dmas: Pairs of phandle and specifier for the DMA channels that are used by
+   the core. The core expects one or two dma channels: one for transmit and
+   one for receive.
+ - dma-names : "tx" for the transmit channel, "rx" for the receive channel.
+
+For more details on the 'dma', 'dma-names', 'clock' and 'clock-names'
+properties please check:
+	* resource-names.txt
+	* clock/clock-bindings.txt
+	* dma/dma.txt
+
+Example:
+
+	soc_i2s: i2s@7ff90000 {
+		compatible = "snps,designware-i2s";
+		reg = <0x0 0x7ff90000 0x0 0x1000>;
+		clocks = <&scpi_i2sclk 0>;
+		clock-names = "i2sclk";
+		#sound-dai-cells = <0>;
+		dmas = <&dma0 5>;
+		dma-names = "tx";
+	};
Signature · 6 lines
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#7 lore raw

PATCH v4 5/5 ASoC: dwc: Add devicetree support for Designware I2S

In reply to Andrew Jackson

From: Andrew Jackson <[email protected]>

Allow the driver to be configured through a device tree rather than platform data.

---
 sound/soc/dwc/Kconfig          |    1 +
 sound/soc/dwc/designware_i2s.c |  193 +++++++++++++++++++++++++++++++---------
 2 files changed, 151 insertions(+), 43 deletions(-)
sound/soc/dwc/Kconfig +1 -0
index e334900..d50e085 100644
@@ -1,6 +1,7 @@
 config SND_DESIGNWARE_I2S
 	tristate "Synopsys I2S Device Driver"
 	depends on CLKDEV_LOOKUP
+	select SND_SOC_GENERIC_DMAENGINE_PCM
 	help
 	 Say Y or M if you want to add support for I2S driver for
 	 Synopsys desigwnware I2S device. The device supports upto
sound/soc/dwc/designware_i2s.c +150 -43

289 lines not on this page · raw message

Signature · 1 line
1.7.1