Skip to content

Commit

Permalink
soundwire: cdns: Add stream routines
Browse files Browse the repository at this point in the history
Add support for Cadence stream initialization and implement
stream APIs.

Signed-off-by: Sanyog Kale <[email protected]>
Signed-off-by: Shreyas NC <[email protected]>
Signed-off-by: Vinod Koul <[email protected]>
  • Loading branch information
vinodkoul committed May 11, 2018
1 parent 07abeff commit 5d6b3c8
Show file tree
Hide file tree
Showing 2 changed files with 238 additions and 0 deletions.
195 changes: 195 additions & 0 deletions drivers/soundwire/cadence_master.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -985,5 +987,198 @@ 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);

/**
* cdns_find_pdi() - Find a free PDI
*
* @cdns: Cadence instance
* @num: Number of PDIs
* @pdi: PDI instances
*
* Find and return a free PDI for a given PDI array
*/
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);

/**
* cdns_get_num_pdi() - Get number of PDIs required
*
* @cdns: Cadence instance
* @pdi: PDI to be used
* @num: Number of PDIs
* @ch_count: Channel count
*/
static int cdns_get_num_pdi(struct sdw_cdns *cdns,
struct sdw_cdns_pdi *pdi,
unsigned int num, u32 ch_count)
{
int i, pdis = 0;

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_num_pdi(cdns, stream->in, stream->num_in, ch);
else
pdis = cdns_get_num_pdi(cdns, stream->out, stream->num_out, ch);

/* check if we found PDI, else find in bi-directional */
if (!pdis)
pdis = cdns_get_num_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");
43 changes: 43 additions & 0 deletions drivers/soundwire/cadence_master.h
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -90,6 +91,26 @@ struct sdw_cdns_stream_config {
unsigned int pdm_out;
};

/**
* 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
Expand Down Expand Up @@ -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);

Expand All @@ -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 */

0 comments on commit 5d6b3c8

Please sign in to comment.