diff mbox

[v2,11/13] soundwire: cdns: Add stream routines

Message ID 1522946904-2089-12-git-send-email-vinod.koul@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Vinod Koul April 5, 2018, 4:48 p.m. UTC
Add support for Cadence stream initialization and implement
stream APIs.

Signed-off-by: Sanyog Kale <sanyog.r.kale@intel.com>
Signed-off-by: Shreyas NC <shreyas.nc@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
---
 drivers/soundwire/cadence_master.c | 180 +++++++++++++++++++++++++++++++++++++
 drivers/soundwire/cadence_master.h |  43 +++++++++
 2 files changed, 223 insertions(+)

Comments

Pierre-Louis Bossart April 6, 2018, 12:29 a.m. UTC | #1
On 4/5/18 11:48 AM, Vinod Koul wrote:
> Add support for Cadence stream initialization and implement
> stream APIs.
> 
> Signed-off-by: Sanyog Kale <sanyog.r.kale@intel.com>
> Signed-off-by: Shreyas NC <shreyas.nc@intel.com>
> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
> ---
>   drivers/soundwire/cadence_master.c | 180 +++++++++++++++++++++++++++++++++++++
>   drivers/soundwire/cadence_master.h |  43 +++++++++
>   2 files changed, 223 insertions(+)
> 
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index 89a4ae86d36a..9400327c9fe2 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -13,6 +13,8 @@
>   #include <linux/mod_devicetable.h>
>   #include <linux/soundwire/sdw_registers.h>
>   #include <linux/soundwire/sdw.h>
> +#include <sound/pcm_params.h>
> +#include <sound/soc.h>
>   #include "bus.h"
>   #include "cadence_master.h"
>   
> @@ -998,5 +1000,183 @@ int sdw_cdns_probe(struct sdw_cdns *cdns)
>   }
>   EXPORT_SYMBOL(sdw_cdns_probe);
>   
> +int cdns_set_sdw_stream(struct snd_soc_dai *dai,
> +		void *stream, bool pcm, int direction)
> +{
> +	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
> +	struct sdw_cdns_dma_data *dma;
> +
> +	dma = kzalloc(sizeof(*dma), GFP_KERNEL);
> +	if (!dma)
> +		return -ENOMEM;
> +
> +	if (pcm)
> +		dma->stream_type = SDW_STREAM_PCM;
> +	else
> +		dma->stream_type = SDW_STREAM_PDM;
> +
> +	dma->bus = &cdns->bus;
> +	dma->link_id = cdns->instance;
> +
> +	dma->stream = stream;
> +
> +	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
> +		dai->playback_dma_data = dma;
> +	else
> +		dai->capture_dma_data = dma;
> +
> +	return 0;
> +
> +}
> +EXPORT_SYMBOL(cdns_set_sdw_stream);
> +
> +static struct sdw_cdns_pdi *cdns_find_pdi(struct sdw_cdns *cdns,
> +		unsigned int num, struct sdw_cdns_pdi *pdi)
> +{
> +	int i;
> +
> +	for (i = 0; i < num; i++) {
> +		if (pdi[i].assigned == true)
> +			continue;
> +		pdi[i].assigned = true;
> +		return &pdi[i];
> +	}
> +
> +	return NULL;
> +}
> +
> +/**
> + * sdw_cdns_config_stream: Configure a stream
> + *
> + * @cdns: Cadence instance
> + * @port: Cadence data port
> + * @ch: Channel count
> + * @dir: Data direction
> + * @pdi: PDI to be used
> + */
> +void sdw_cdns_config_stream(struct sdw_cdns *cdns,
> +				struct sdw_cdns_port *port,
> +				u32 ch, u32 dir, struct sdw_cdns_pdi *pdi)
> +{
> +	u32 offset, val = 0;
> +
> +	if (dir == SDW_DATA_DIR_RX)
> +		val = CDNS_PORTCTRL_DIRN;
> +
> +	offset = CDNS_PORTCTRL + port->num * CDNS_PORT_OFFSET;
> +	cdns_updatel(cdns, offset, CDNS_PORTCTRL_DIRN, val);
> +
> +	val = port->num;
> +	val |= ((1 << ch) - 1) << SDW_REG_SHIFT(CDNS_PDI_CONFIG_CHANNEL);
> +	cdns_writel(cdns, CDNS_PDI_CONFIG(pdi->num), val);
> +}
> +EXPORT_SYMBOL(sdw_cdns_config_stream);
> +
> +static int cdns_get_pdi(struct sdw_cdns *cdns,
> +		struct sdw_cdns_pdi *pdi,
> +		unsigned int num, u32 ch)
> +{
> +	int i, pdis = 0;
> +	u32 ch_count = ch;

redundant variable without added value...

> +
> +	for (i = 0; i < num; i++) {
> +		if (pdi[i].assigned == true)
> +			continue;
> +
> +		if (pdi[i].ch_count < ch_count)
> +			ch_count -= pdi[i].ch_count;
> +		else
> +			ch_count = 0;
> +
> +		pdis++;
> +
> +		if (!ch_count)
> +			break;
> +	}
> +
> +	if (ch_count)
> +		return 0;
> +
> +	return pdis;
> +}
> +
> +/**
> + * sdw_cdns_get_stream: Get stream information
> + *
> + * @cdns: Cadence instance
> + * @stream: Stream to be allocated
> + * @ch: Channel count
> + * @dir: Data direction
> + */
> +int sdw_cdns_get_stream(struct sdw_cdns *cdns,
> +			struct sdw_cdns_streams *stream,
> +			u32 ch, u32 dir)
> +{
> +	int pdis = 0;
> +
> +	if (dir == SDW_DATA_DIR_RX)
> +		pdis = cdns_get_pdi(cdns, stream->in, stream->num_in, ch);
> +	else
> +		pdis = cdns_get_pdi(cdns, stream->out, stream->num_out, ch);
> +
> +	/* check if we found PDI, else find in bi-directional */
> +	if (!pdis)
> +		pdis = cdns_get_pdi(cdns, stream->bd, stream->num_bd, ch);
> +
> +	return pdis;
> +}
> +EXPORT_SYMBOL(sdw_cdns_get_stream);
> +
> +/**
> + * sdw_cdns_alloc_stream: Allocate a stream
> + *
> + * @cdns: Cadence instance
> + * @stream: Stream to be allocated
> + * @port: Cadence data port
> + * @ch: Channel count
> + * @dir: Data direction
> + */
> +int sdw_cdns_alloc_stream(struct sdw_cdns *cdns,
> +			struct sdw_cdns_streams *stream,
> +			struct sdw_cdns_port *port, u32 ch, u32 dir)
> +{
> +	struct sdw_cdns_pdi *pdi = NULL;
> +
> +	if (dir == SDW_DATA_DIR_RX)
> +		pdi = cdns_find_pdi(cdns, stream->num_in, stream->in);
> +	else
> +		pdi = cdns_find_pdi(cdns, stream->num_out, stream->out);
> +
> +	/* check if we found a PDI, else find in bi-directional */
> +	if (!pdi)
> +		pdi = cdns_find_pdi(cdns, stream->num_bd, stream->bd);
> +
> +	if (!pdi)
> +		return -EIO;
> +
> +	port->pdi = pdi;
> +	pdi->l_ch_num = 0;
> +	pdi->h_ch_num = ch - 1;
> +	pdi->dir = dir;
> +	pdi->ch_count = ch;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(sdw_cdns_alloc_stream);

can you clarify the difference between _get_pdi and _find_pdi and 
alloc_stream/get_stream.

It's pretty confusing.

> +
> +void sdw_cdns_shutdown(struct snd_pcm_substream *substream,
> +					struct snd_soc_dai *dai)
> +{
> +	struct sdw_cdns_dma_data *dma;
> +
> +	dma = snd_soc_dai_get_dma_data(dai, substream);
> +	if (!dma)
> +		return;
> +
> +	snd_soc_dai_set_dma_data(dai, substream, NULL);
> +	kfree(dma);
> +}
> +EXPORT_SYMBOL(sdw_cdns_shutdown);
> +
>   MODULE_LICENSE("Dual BSD/GPL");
>   MODULE_DESCRIPTION("Cadence Soundwire Library");
> diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h
> index 98a17f57918f..eb902b19c5a4 100644
> --- a/drivers/soundwire/cadence_master.h
> +++ b/drivers/soundwire/cadence_master.h
> @@ -1,5 +1,6 @@
>   // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
>   // Copyright(c) 2015-17 Intel Corporation.
> +#include <sound/soc.h>
>   
>   #ifndef __SDW_CADENCE_H
>   #define __SDW_CADENCE_H
> @@ -91,6 +92,26 @@ struct sdw_cdns_stream_config {
>   };
>   
>   /**
> + * struct sdw_cdns_dma_data: Cadence DMA data
> + *
> + * @name: SoundWire stream name
> + * @nr_ports: Number of ports
> + * @port: Ports
> + * @bus: Bus handle
> + * @stream_type: Stream type
> + * @link_id: Master link id
> + */
> +struct sdw_cdns_dma_data {
> +	char *name;
> +	struct sdw_stream_runtime *stream;
> +	int nr_ports;
> +	struct sdw_cdns_port **port;
> +	struct sdw_bus *bus;
> +	enum sdw_stream_type stream_type;
> +	int link_id;
> +};
> +
> +/**
>    * struct sdw_cdns - Cadence driver context
>    * @dev: Linux device
>    * @bus: Bus handle
> @@ -142,6 +163,25 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
>   			struct sdw_cdns_stream_config config);
>   int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns);
>   
> +int sdw_cdns_get_stream(struct sdw_cdns *cdns,
> +			struct sdw_cdns_streams *stream,
> +			u32 ch, u32 dir);
> +int sdw_cdns_alloc_stream(struct sdw_cdns *cdns,
> +			struct sdw_cdns_streams *stream,
> +			struct sdw_cdns_port *port, u32 ch, u32 dir);
> +void sdw_cdns_config_stream(struct sdw_cdns *cdns, struct sdw_cdns_port *port,
> +			u32 ch, u32 dir, struct sdw_cdns_pdi *pdi);
> +
> +void sdw_cdns_shutdown(struct snd_pcm_substream *substream,
> +				struct snd_soc_dai *dai);
> +int sdw_cdns_pcm_set_stream(struct snd_soc_dai *dai,
> +				void *stream, int direction);
> +int sdw_cdns_pdm_set_stream(struct snd_soc_dai *dai,
> +				void *stream, int direction);
> +
> +enum sdw_command_response
> +cdns_reset_page_addr(struct sdw_bus *bus, unsigned int dev_num);
> +
>   enum sdw_command_response
>   cdns_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg);
>   
> @@ -153,4 +193,7 @@ enum sdw_command_response
>   cdns_reset_page_addr(struct sdw_bus *bus, unsigned int dev_num);
>   
>   int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params);
> +
> +int cdns_set_sdw_stream(struct snd_soc_dai *dai,
> +		void *stream, bool pcm, int direction);
>   #endif /* __SDW_CADENCE_H */
>
Vinod Koul April 6, 2018, 8:57 a.m. UTC | #2
On Thu, Apr 05, 2018 at 07:29:11PM -0500, Pierre-Louis Bossart wrote:
> On 4/5/18 11:48 AM, Vinod Koul wrote:

> >+static int cdns_get_pdi(struct sdw_cdns *cdns,
> >+		struct sdw_cdns_pdi *pdi,
> >+		unsigned int num, u32 ch)
> >+{
> >+	int i, pdis = 0;
> >+	u32 ch_count = ch;
> 
> redundant variable without added value...

ok will remove

> >+EXPORT_SYMBOL(sdw_cdns_alloc_stream);
> 
> can you clarify the difference between _get_pdi and _find_pdi and
> alloc_stream/get_stream.
> 
> It's pretty confusing.

Okay will add few notes and try to rename the functions.
diff mbox

Patch

diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index 89a4ae86d36a..9400327c9fe2 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -13,6 +13,8 @@ 
 #include <linux/mod_devicetable.h>
 #include <linux/soundwire/sdw_registers.h>
 #include <linux/soundwire/sdw.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
 #include "bus.h"
 #include "cadence_master.h"
 
@@ -998,5 +1000,183 @@  int sdw_cdns_probe(struct sdw_cdns *cdns)
 }
 EXPORT_SYMBOL(sdw_cdns_probe);
 
+int cdns_set_sdw_stream(struct snd_soc_dai *dai,
+		void *stream, bool pcm, int direction)
+{
+	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
+	struct sdw_cdns_dma_data *dma;
+
+	dma = kzalloc(sizeof(*dma), GFP_KERNEL);
+	if (!dma)
+		return -ENOMEM;
+
+	if (pcm)
+		dma->stream_type = SDW_STREAM_PCM;
+	else
+		dma->stream_type = SDW_STREAM_PDM;
+
+	dma->bus = &cdns->bus;
+	dma->link_id = cdns->instance;
+
+	dma->stream = stream;
+
+	if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+		dai->playback_dma_data = dma;
+	else
+		dai->capture_dma_data = dma;
+
+	return 0;
+
+}
+EXPORT_SYMBOL(cdns_set_sdw_stream);
+
+static struct sdw_cdns_pdi *cdns_find_pdi(struct sdw_cdns *cdns,
+		unsigned int num, struct sdw_cdns_pdi *pdi)
+{
+	int i;
+
+	for (i = 0; i < num; i++) {
+		if (pdi[i].assigned == true)
+			continue;
+		pdi[i].assigned = true;
+		return &pdi[i];
+	}
+
+	return NULL;
+}
+
+/**
+ * sdw_cdns_config_stream: Configure a stream
+ *
+ * @cdns: Cadence instance
+ * @port: Cadence data port
+ * @ch: Channel count
+ * @dir: Data direction
+ * @pdi: PDI to be used
+ */
+void sdw_cdns_config_stream(struct sdw_cdns *cdns,
+				struct sdw_cdns_port *port,
+				u32 ch, u32 dir, struct sdw_cdns_pdi *pdi)
+{
+	u32 offset, val = 0;
+
+	if (dir == SDW_DATA_DIR_RX)
+		val = CDNS_PORTCTRL_DIRN;
+
+	offset = CDNS_PORTCTRL + port->num * CDNS_PORT_OFFSET;
+	cdns_updatel(cdns, offset, CDNS_PORTCTRL_DIRN, val);
+
+	val = port->num;
+	val |= ((1 << ch) - 1) << SDW_REG_SHIFT(CDNS_PDI_CONFIG_CHANNEL);
+	cdns_writel(cdns, CDNS_PDI_CONFIG(pdi->num), val);
+}
+EXPORT_SYMBOL(sdw_cdns_config_stream);
+
+static int cdns_get_pdi(struct sdw_cdns *cdns,
+		struct sdw_cdns_pdi *pdi,
+		unsigned int num, u32 ch)
+{
+	int i, pdis = 0;
+	u32 ch_count = ch;
+
+	for (i = 0; i < num; i++) {
+		if (pdi[i].assigned == true)
+			continue;
+
+		if (pdi[i].ch_count < ch_count)
+			ch_count -= pdi[i].ch_count;
+		else
+			ch_count = 0;
+
+		pdis++;
+
+		if (!ch_count)
+			break;
+	}
+
+	if (ch_count)
+		return 0;
+
+	return pdis;
+}
+
+/**
+ * sdw_cdns_get_stream: Get stream information
+ *
+ * @cdns: Cadence instance
+ * @stream: Stream to be allocated
+ * @ch: Channel count
+ * @dir: Data direction
+ */
+int sdw_cdns_get_stream(struct sdw_cdns *cdns,
+			struct sdw_cdns_streams *stream,
+			u32 ch, u32 dir)
+{
+	int pdis = 0;
+
+	if (dir == SDW_DATA_DIR_RX)
+		pdis = cdns_get_pdi(cdns, stream->in, stream->num_in, ch);
+	else
+		pdis = cdns_get_pdi(cdns, stream->out, stream->num_out, ch);
+
+	/* check if we found PDI, else find in bi-directional */
+	if (!pdis)
+		pdis = cdns_get_pdi(cdns, stream->bd, stream->num_bd, ch);
+
+	return pdis;
+}
+EXPORT_SYMBOL(sdw_cdns_get_stream);
+
+/**
+ * sdw_cdns_alloc_stream: Allocate a stream
+ *
+ * @cdns: Cadence instance
+ * @stream: Stream to be allocated
+ * @port: Cadence data port
+ * @ch: Channel count
+ * @dir: Data direction
+ */
+int sdw_cdns_alloc_stream(struct sdw_cdns *cdns,
+			struct sdw_cdns_streams *stream,
+			struct sdw_cdns_port *port, u32 ch, u32 dir)
+{
+	struct sdw_cdns_pdi *pdi = NULL;
+
+	if (dir == SDW_DATA_DIR_RX)
+		pdi = cdns_find_pdi(cdns, stream->num_in, stream->in);
+	else
+		pdi = cdns_find_pdi(cdns, stream->num_out, stream->out);
+
+	/* check if we found a PDI, else find in bi-directional */
+	if (!pdi)
+		pdi = cdns_find_pdi(cdns, stream->num_bd, stream->bd);
+
+	if (!pdi)
+		return -EIO;
+
+	port->pdi = pdi;
+	pdi->l_ch_num = 0;
+	pdi->h_ch_num = ch - 1;
+	pdi->dir = dir;
+	pdi->ch_count = ch;
+
+	return 0;
+}
+EXPORT_SYMBOL(sdw_cdns_alloc_stream);
+
+void sdw_cdns_shutdown(struct snd_pcm_substream *substream,
+					struct snd_soc_dai *dai)
+{
+	struct sdw_cdns_dma_data *dma;
+
+	dma = snd_soc_dai_get_dma_data(dai, substream);
+	if (!dma)
+		return;
+
+	snd_soc_dai_set_dma_data(dai, substream, NULL);
+	kfree(dma);
+}
+EXPORT_SYMBOL(sdw_cdns_shutdown);
+
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_DESCRIPTION("Cadence Soundwire Library");
diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h
index 98a17f57918f..eb902b19c5a4 100644
--- a/drivers/soundwire/cadence_master.h
+++ b/drivers/soundwire/cadence_master.h
@@ -1,5 +1,6 @@ 
 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
 // Copyright(c) 2015-17 Intel Corporation.
+#include <sound/soc.h>
 
 #ifndef __SDW_CADENCE_H
 #define __SDW_CADENCE_H
@@ -91,6 +92,26 @@  struct sdw_cdns_stream_config {
 };
 
 /**
+ * struct sdw_cdns_dma_data: Cadence DMA data
+ *
+ * @name: SoundWire stream name
+ * @nr_ports: Number of ports
+ * @port: Ports
+ * @bus: Bus handle
+ * @stream_type: Stream type
+ * @link_id: Master link id
+ */
+struct sdw_cdns_dma_data {
+	char *name;
+	struct sdw_stream_runtime *stream;
+	int nr_ports;
+	struct sdw_cdns_port **port;
+	struct sdw_bus *bus;
+	enum sdw_stream_type stream_type;
+	int link_id;
+};
+
+/**
  * struct sdw_cdns - Cadence driver context
  * @dev: Linux device
  * @bus: Bus handle
@@ -142,6 +163,25 @@  int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
 			struct sdw_cdns_stream_config config);
 int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns);
 
+int sdw_cdns_get_stream(struct sdw_cdns *cdns,
+			struct sdw_cdns_streams *stream,
+			u32 ch, u32 dir);
+int sdw_cdns_alloc_stream(struct sdw_cdns *cdns,
+			struct sdw_cdns_streams *stream,
+			struct sdw_cdns_port *port, u32 ch, u32 dir);
+void sdw_cdns_config_stream(struct sdw_cdns *cdns, struct sdw_cdns_port *port,
+			u32 ch, u32 dir, struct sdw_cdns_pdi *pdi);
+
+void sdw_cdns_shutdown(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai);
+int sdw_cdns_pcm_set_stream(struct snd_soc_dai *dai,
+				void *stream, int direction);
+int sdw_cdns_pdm_set_stream(struct snd_soc_dai *dai,
+				void *stream, int direction);
+
+enum sdw_command_response
+cdns_reset_page_addr(struct sdw_bus *bus, unsigned int dev_num);
+
 enum sdw_command_response
 cdns_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg);
 
@@ -153,4 +193,7 @@  enum sdw_command_response
 cdns_reset_page_addr(struct sdw_bus *bus, unsigned int dev_num);
 
 int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params);
+
+int cdns_set_sdw_stream(struct snd_soc_dai *dai,
+		void *stream, bool pcm, int direction);
 #endif /* __SDW_CADENCE_H */