summaryrefslogtreecommitdiff
path: root/sound/soc/sh
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sh')
-rw-r--r--sound/soc/sh/Kconfig1
-rw-r--r--sound/soc/sh/fsi.c2
-rw-r--r--sound/soc/sh/hac.c2
-rw-r--r--sound/soc/sh/rcar/adg.c4
-rw-r--r--sound/soc/sh/rcar/core.c19
-rw-r--r--sound/soc/sh/rcar/dma.c75
-rw-r--r--sound/soc/sh/rcar/rsnd.h10
-rw-r--r--sound/soc/sh/rcar/ssi.c2
-rw-r--r--sound/soc/sh/rz-ssi.c259
-rw-r--r--sound/soc/sh/siu_dai.c2
10 files changed, 198 insertions, 178 deletions
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index 7bddfd5e38d6..426632996a0a 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -41,6 +41,7 @@ config SND_SOC_RCAR
depends on COMMON_CLK
depends on OF
select SND_SIMPLE_CARD_UTILS
+ select SND_DMAENGINE_PCM
select REGMAP_MMIO
help
This option enables R-Car SRU/SCU/SSIU/SSI sound support
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 087e379aa3bc..221ce91f1950 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -2107,7 +2107,7 @@ static struct platform_driver fsi_driver = {
.of_match_table = fsi_of_match,
},
.probe = fsi_probe,
- .remove_new = fsi_remove,
+ .remove = fsi_remove,
.id_table = fsi_id_table,
};
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c
index cc200f45826c..db618c09d1e0 100644
--- a/sound/soc/sh/hac.c
+++ b/sound/soc/sh/hac.c
@@ -334,7 +334,7 @@ static struct platform_driver hac_pcm_driver = {
},
.probe = hac_soc_platform_probe,
- .remove_new = hac_soc_platform_remove,
+ .remove = hac_soc_platform_remove,
};
module_platform_driver(hac_pcm_driver);
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index afd69c6eb654..0f190abf00e7 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -262,7 +262,7 @@ int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
int id = rsnd_mod_id(src_mod);
int shift = (id % 2) ? 16 : 0;
- rsnd_mod_confirm_src(src_mod);
+ rsnd_mod_make_sure(src_mod, RSND_MOD_SRC);
rsnd_adg_get_timesel_ratio(priv, io,
in_rate, out_rate,
@@ -291,7 +291,7 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
int shift = (id % 4) * 8;
u32 mask = 0xFF << shift;
- rsnd_mod_confirm_ssi(ssi_mod);
+ rsnd_mod_make_sure(ssi_mod, RSND_MOD_SSI);
val = val << shift;
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 63b3c8bf0fde..9784718a2b6f 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -660,23 +660,6 @@ static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai)
return rsnd_rdai_get(priv, dai->id);
}
-/*
- * rsnd_soc_dai functions
- */
-void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io)
-{
- struct snd_pcm_substream *substream = io->substream;
-
- /*
- * this function should be called...
- *
- * - if rsnd_dai_pointer_update() returns true
- * - without spin lock
- */
-
- snd_pcm_period_elapsed(substream);
-}
-
static void rsnd_dai_stream_init(struct rsnd_dai_stream *io,
struct snd_pcm_substream *substream)
{
@@ -2104,7 +2087,7 @@ static struct platform_driver rsnd_driver = {
.of_match_table = rsnd_of_match,
},
.probe = rsnd_probe,
- .remove_new = rsnd_remove,
+ .remove = rsnd_remove,
};
module_platform_driver(rsnd_driver);
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c
index 7b499eee5080..2342bbb6fe92 100644
--- a/sound/soc/sh/rcar/dma.c
+++ b/sound/soc/sh/rcar/dma.c
@@ -7,6 +7,7 @@
#include <linux/delay.h>
#include <linux/of_dma.h>
+#include <sound/dmaengine_pcm.h>
#include "rsnd.h"
/*
@@ -22,8 +23,6 @@
struct rsnd_dmaen {
struct dma_chan *chan;
- dma_cookie_t cookie;
- unsigned int dma_len;
};
struct rsnd_dmapp {
@@ -66,20 +65,6 @@ static struct rsnd_mod mem = {
/*
* Audio DMAC
*/
-static void __rsnd_dmaen_complete(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io)
-{
- if (rsnd_io_is_working(io))
- rsnd_dai_period_elapsed(io);
-}
-
-static void rsnd_dmaen_complete(void *data)
-{
- struct rsnd_mod *mod = data;
-
- rsnd_mod_interrupt(mod, __rsnd_dmaen_complete);
-}
-
static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io,
struct rsnd_mod *mod_from,
struct rsnd_mod *mod_to)
@@ -98,13 +83,7 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct rsnd_priv *priv)
{
- struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
- struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
-
- if (dmaen->chan)
- dmaengine_terminate_async(dmaen->chan);
-
- return 0;
+ return snd_dmaengine_pcm_trigger(io->substream, SNDRV_PCM_TRIGGER_STOP);
}
static int rsnd_dmaen_cleanup(struct rsnd_mod *mod,
@@ -120,7 +99,7 @@ static int rsnd_dmaen_cleanup(struct rsnd_mod *mod,
* Let's call it under prepare
*/
if (dmaen->chan)
- dma_release_channel(dmaen->chan);
+ snd_dmaengine_pcm_close_release_chan(io->substream);
dmaen->chan = NULL;
@@ -153,7 +132,7 @@ static int rsnd_dmaen_prepare(struct rsnd_mod *mod,
return -EIO;
}
- return 0;
+ return snd_dmaengine_pcm_open(io->substream, dmaen->chan);
}
static int rsnd_dmaen_start(struct rsnd_mod *mod,
@@ -162,12 +141,9 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
{
struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
- struct snd_pcm_substream *substream = io->substream;
struct device *dev = rsnd_priv_to_dev(priv);
- struct dma_async_tx_descriptor *desc;
struct dma_slave_config cfg = {};
enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
- int is_play = rsnd_io_is_play(io);
int ret;
/*
@@ -195,7 +171,7 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
}
}
- cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
+ cfg.direction = snd_pcm_substream_to_dma_direction(io->substream);
cfg.src_addr = dma->src_addr;
cfg.dst_addr = dma->dst_addr;
cfg.src_addr_width = buswidth;
@@ -209,32 +185,7 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod,
if (ret < 0)
return ret;
- desc = dmaengine_prep_dma_cyclic(dmaen->chan,
- substream->runtime->dma_addr,
- snd_pcm_lib_buffer_bytes(substream),
- snd_pcm_lib_period_bytes(substream),
- is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-
- if (!desc) {
- dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
- return -EIO;
- }
-
- desc->callback = rsnd_dmaen_complete;
- desc->callback_param = rsnd_mod_get(dma);
-
- dmaen->dma_len = snd_pcm_lib_buffer_bytes(substream);
-
- dmaen->cookie = dmaengine_submit(desc);
- if (dmaen->cookie < 0) {
- dev_err(dev, "dmaengine_submit() fail\n");
- return -EIO;
- }
-
- dma_async_issue_pending(dmaen->chan);
-
- return 0;
+ return snd_dmaengine_pcm_trigger(io->substream, SNDRV_PCM_TRIGGER_START);
}
struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, char *name,
@@ -307,19 +258,7 @@ static int rsnd_dmaen_pointer(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
snd_pcm_uframes_t *pointer)
{
- struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
- struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
- struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
- struct dma_tx_state state;
- enum dma_status status;
- unsigned int pos = 0;
-
- status = dmaengine_tx_status(dmaen->chan, dmaen->cookie, &state);
- if (status == DMA_IN_PROGRESS || status == DMA_PAUSED) {
- if (state.residue > 0 && state.residue <= dmaen->dma_len)
- pos = dmaen->dma_len - state.residue;
- }
- *pointer = bytes_to_frames(runtime, pos);
+ *pointer = snd_dmaengine_pcm_pointer(io->substream);
return 0;
}
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index ff294aa2d640..3c164d8e3b16 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -576,7 +576,6 @@ int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai,
#define rsnd_rdai_width_get(rdai) \
rsnd_rdai_width_ctrl(rdai, 0)
int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width);
-void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io);
int rsnd_dai_connect(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
enum rsnd_mod_type type);
@@ -871,15 +870,6 @@ void rsnd_cmd_remove(struct rsnd_priv *priv);
int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id);
void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type);
-#ifdef DEBUG
-#define rsnd_mod_confirm_ssi(mssi) rsnd_mod_make_sure(mssi, RSND_MOD_SSI)
-#define rsnd_mod_confirm_src(msrc) rsnd_mod_make_sure(msrc, RSND_MOD_SRC)
-#define rsnd_mod_confirm_dvc(mdvc) rsnd_mod_make_sure(mdvc, RSND_MOD_DVC)
-#else
-#define rsnd_mod_confirm_ssi(mssi)
-#define rsnd_mod_confirm_src(msrc)
-#define rsnd_mod_confirm_dvc(mdvc)
-#endif
/*
* If you don't need interrupt status debug message,
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 8d2a86383ae0..b3d4e8ae07ef 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -706,7 +706,7 @@ rsnd_ssi_interrupt_out:
spin_unlock(&priv->lock);
if (elapsed)
- rsnd_dai_period_elapsed(io);
+ snd_pcm_period_elapsed(io->substream);
if (stop)
snd_pcm_stop_xrun(io->substream);
diff --git a/sound/soc/sh/rz-ssi.c b/sound/soc/sh/rz-ssi.c
index 9d103646973a..040ce0431fd2 100644
--- a/sound/soc/sh/rz-ssi.c
+++ b/sound/soc/sh/rz-ssi.c
@@ -52,6 +52,7 @@
#define SSIFCR_RIE BIT(2)
#define SSIFCR_TFRST BIT(1)
#define SSIFCR_RFRST BIT(0)
+#define SSIFCR_FIFO_RST (SSIFCR_TFRST | SSIFCR_RFRST)
#define SSIFSR_TDC_MASK 0x3f
#define SSIFSR_TDC_SHIFT 24
@@ -130,6 +131,14 @@ struct rz_ssi_priv {
bool lrckp_fsync_fall; /* LR clock polarity (SSICR.LRCKP) */
bool bckp_rise; /* Bit clock polarity (SSICR.BCKP) */
bool dma_rt;
+
+ /* Full duplex communication support */
+ struct {
+ unsigned int rate;
+ unsigned int channels;
+ unsigned int sample_width;
+ unsigned int sample_bits;
+ } hw_params_cache;
};
static void rz_ssi_dma_complete(void *data);
@@ -208,6 +217,11 @@ static bool rz_ssi_stream_is_valid(struct rz_ssi_priv *ssi,
return ret;
}
+static inline bool rz_ssi_is_stream_running(struct rz_ssi_stream *strm)
+{
+ return strm->substream && strm->running;
+}
+
static void rz_ssi_stream_init(struct rz_ssi_stream *strm,
struct snd_pcm_substream *substream)
{
@@ -303,13 +317,53 @@ static int rz_ssi_clk_setup(struct rz_ssi_priv *ssi, unsigned int rate,
return 0;
}
+static void rz_ssi_set_idle(struct rz_ssi_priv *ssi)
+{
+ int timeout;
+
+ /* Disable irqs */
+ rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TUIEN | SSICR_TOIEN |
+ SSICR_RUIEN | SSICR_ROIEN, 0);
+ rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_TIE | SSIFCR_RIE, 0);
+
+ /* Clear all error flags */
+ rz_ssi_reg_mask_setl(ssi, SSISR,
+ (SSISR_TOIRQ | SSISR_TUIRQ | SSISR_ROIRQ |
+ SSISR_RUIRQ), 0);
+
+ /* Wait for idle */
+ timeout = 100;
+ while (--timeout) {
+ if (rz_ssi_reg_readl(ssi, SSISR) & SSISR_IIRQ)
+ break;
+ udelay(1);
+ }
+
+ if (!timeout)
+ dev_info(ssi->dev, "timeout waiting for SSI idle\n");
+
+ /* Hold FIFOs in reset */
+ rz_ssi_reg_mask_setl(ssi, SSIFCR, 0,
+ SSIFCR_TFRST | SSIFCR_RFRST);
+}
+
static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
{
bool is_play = rz_ssi_stream_is_play(ssi, strm->substream);
+ bool is_full_duplex;
u32 ssicr, ssifcr;
+ is_full_duplex = rz_ssi_is_stream_running(&ssi->playback) ||
+ rz_ssi_is_stream_running(&ssi->capture);
ssicr = rz_ssi_reg_readl(ssi, SSICR);
- ssifcr = rz_ssi_reg_readl(ssi, SSIFCR) & ~0xF;
+ ssifcr = rz_ssi_reg_readl(ssi, SSIFCR);
+ if (!is_full_duplex) {
+ ssifcr &= ~0xF;
+ } else {
+ rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0);
+ rz_ssi_set_idle(ssi);
+ ssifcr &= ~SSIFCR_FIFO_RST;
+ }
/* FIFO interrupt thresholds */
if (rz_ssi_is_dma_enabled(ssi))
@@ -322,10 +376,14 @@ static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
/* enable IRQ */
if (is_play) {
ssicr |= SSICR_TUIEN | SSICR_TOIEN;
- ssifcr |= SSIFCR_TIE | SSIFCR_RFRST;
+ ssifcr |= SSIFCR_TIE;
+ if (!is_full_duplex)
+ ssifcr |= SSIFCR_RFRST;
} else {
ssicr |= SSICR_RUIEN | SSICR_ROIEN;
- ssifcr |= SSIFCR_RIE | SSIFCR_TFRST;
+ ssifcr |= SSIFCR_RIE;
+ if (!is_full_duplex)
+ ssifcr |= SSIFCR_TFRST;
}
rz_ssi_reg_writel(ssi, SSICR, ssicr);
@@ -337,7 +395,11 @@ static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
SSISR_RUIRQ), 0);
strm->running = 1;
- ssicr |= is_play ? SSICR_TEN : SSICR_REN;
+ if (is_full_duplex)
+ ssicr |= SSICR_TEN | SSICR_REN;
+ else
+ ssicr |= is_play ? SSICR_TEN : SSICR_REN;
+
rz_ssi_reg_writel(ssi, SSICR, ssicr);
return 0;
@@ -345,10 +407,12 @@ static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
static int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
{
- int timeout;
-
strm->running = 0;
+ if (rz_ssi_is_stream_running(&ssi->playback) ||
+ rz_ssi_is_stream_running(&ssi->capture))
+ return 0;
+
/* Disable TX/RX */
rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0);
@@ -356,30 +420,7 @@ static int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
if (rz_ssi_is_dma_enabled(ssi))
dmaengine_terminate_async(strm->dma_ch);
- /* Disable irqs */
- rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TUIEN | SSICR_TOIEN |
- SSICR_RUIEN | SSICR_ROIEN, 0);
- rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_TIE | SSIFCR_RIE, 0);
-
- /* Clear all error flags */
- rz_ssi_reg_mask_setl(ssi, SSISR,
- (SSISR_TOIRQ | SSISR_TUIRQ | SSISR_ROIRQ |
- SSISR_RUIRQ), 0);
-
- /* Wait for idle */
- timeout = 100;
- while (--timeout) {
- if (rz_ssi_reg_readl(ssi, SSISR) & SSISR_IIRQ)
- break;
- udelay(1);
- }
-
- if (!timeout)
- dev_info(ssi->dev, "timeout waiting for SSI idle\n");
-
- /* Hold FIFOs in reset */
- rz_ssi_reg_mask_setl(ssi, SSIFCR, 0,
- SSIFCR_TFRST | SSIFCR_RFRST);
+ rz_ssi_set_idle(ssi);
return 0;
}
@@ -512,66 +553,90 @@ static int rz_ssi_pio_send(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
static irqreturn_t rz_ssi_interrupt(int irq, void *data)
{
- struct rz_ssi_stream *strm = NULL;
+ struct rz_ssi_stream *strm_playback = NULL;
+ struct rz_ssi_stream *strm_capture = NULL;
struct rz_ssi_priv *ssi = data;
u32 ssisr = rz_ssi_reg_readl(ssi, SSISR);
if (ssi->playback.substream)
- strm = &ssi->playback;
- else if (ssi->capture.substream)
- strm = &ssi->capture;
- else
+ strm_playback = &ssi->playback;
+ if (ssi->capture.substream)
+ strm_capture = &ssi->capture;
+
+ if (!strm_playback && !strm_capture)
return IRQ_HANDLED; /* Left over TX/RX interrupt */
if (irq == ssi->irq_int) { /* error or idle */
- if (ssisr & SSISR_TUIRQ)
- strm->uerr_num++;
- if (ssisr & SSISR_TOIRQ)
- strm->oerr_num++;
- if (ssisr & SSISR_RUIRQ)
- strm->uerr_num++;
- if (ssisr & SSISR_ROIRQ)
- strm->oerr_num++;
-
- if (ssisr & (SSISR_TUIRQ | SSISR_TOIRQ | SSISR_RUIRQ |
- SSISR_ROIRQ)) {
- /* Error handling */
- /* You must reset (stop/restart) after each interrupt */
- rz_ssi_stop(ssi, strm);
-
- /* Clear all flags */
- rz_ssi_reg_mask_setl(ssi, SSISR, SSISR_TOIRQ |
- SSISR_TUIRQ | SSISR_ROIRQ |
- SSISR_RUIRQ, 0);
-
- /* Add/remove more data */
- strm->transfer(ssi, strm);
-
- /* Resume */
- rz_ssi_start(ssi, strm);
+ bool is_stopped = false;
+ int i, count;
+
+ if (rz_ssi_is_dma_enabled(ssi))
+ count = 4;
+ else
+ count = 1;
+
+ if (ssisr & (SSISR_RUIRQ | SSISR_ROIRQ | SSISR_TUIRQ | SSISR_TOIRQ))
+ is_stopped = true;
+
+ if (ssi->capture.substream && is_stopped) {
+ if (ssisr & SSISR_RUIRQ)
+ strm_capture->uerr_num++;
+ if (ssisr & SSISR_ROIRQ)
+ strm_capture->oerr_num++;
+
+ rz_ssi_stop(ssi, strm_capture);
}
+
+ if (ssi->playback.substream && is_stopped) {
+ if (ssisr & SSISR_TUIRQ)
+ strm_playback->uerr_num++;
+ if (ssisr & SSISR_TOIRQ)
+ strm_playback->oerr_num++;
+
+ rz_ssi_stop(ssi, strm_playback);
+ }
+
+ /* Clear all flags */
+ rz_ssi_reg_mask_setl(ssi, SSISR, SSISR_TOIRQ | SSISR_TUIRQ |
+ SSISR_ROIRQ | SSISR_RUIRQ, 0);
+
+ /* Add/remove more data */
+ if (ssi->capture.substream && is_stopped) {
+ for (i = 0; i < count; i++)
+ strm_capture->transfer(ssi, strm_capture);
+ }
+
+ if (ssi->playback.substream && is_stopped) {
+ for (i = 0; i < count; i++)
+ strm_playback->transfer(ssi, strm_playback);
+ }
+
+ /* Resume */
+ if (ssi->playback.substream && is_stopped)
+ rz_ssi_start(ssi, &ssi->playback);
+ if (ssi->capture.substream && is_stopped)
+ rz_ssi_start(ssi, &ssi->capture);
}
- if (!strm->running)
+ if (!rz_ssi_is_stream_running(&ssi->playback) &&
+ !rz_ssi_is_stream_running(&ssi->capture))
return IRQ_HANDLED;
/* tx data empty */
- if (irq == ssi->irq_tx)
- strm->transfer(ssi, &ssi->playback);
+ if (irq == ssi->irq_tx && rz_ssi_is_stream_running(&ssi->playback))
+ strm_playback->transfer(ssi, &ssi->playback);
/* rx data full */
- if (irq == ssi->irq_rx) {
- strm->transfer(ssi, &ssi->capture);
+ if (irq == ssi->irq_rx && rz_ssi_is_stream_running(&ssi->capture)) {
+ strm_capture->transfer(ssi, &ssi->capture);
rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0);
}
if (irq == ssi->irq_rt) {
- struct snd_pcm_substream *substream = strm->substream;
-
- if (rz_ssi_stream_is_play(ssi, substream)) {
- strm->transfer(ssi, &ssi->playback);
+ if (ssi->playback.substream) {
+ strm_playback->transfer(ssi, &ssi->playback);
} else {
- strm->transfer(ssi, &ssi->capture);
+ strm_capture->transfer(ssi, &ssi->capture);
rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0);
}
}
@@ -731,9 +796,12 @@ static int rz_ssi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
/* Soft Reset */
- rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_SSIRST);
- rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_SSIRST, 0);
- udelay(5);
+ if (!rz_ssi_is_stream_running(&ssi->playback) &&
+ !rz_ssi_is_stream_running(&ssi->capture)) {
+ rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_SSIRST);
+ rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_SSIRST, 0);
+ udelay(5);
+ }
rz_ssi_stream_init(strm, substream);
@@ -824,14 +892,41 @@ static int rz_ssi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
+static bool rz_ssi_is_valid_hw_params(struct rz_ssi_priv *ssi, unsigned int rate,
+ unsigned int channels,
+ unsigned int sample_width,
+ unsigned int sample_bits)
+{
+ if (ssi->hw_params_cache.rate != rate ||
+ ssi->hw_params_cache.channels != channels ||
+ ssi->hw_params_cache.sample_width != sample_width ||
+ ssi->hw_params_cache.sample_bits != sample_bits)
+ return false;
+
+ return true;
+}
+
+static void rz_ssi_cache_hw_params(struct rz_ssi_priv *ssi, unsigned int rate,
+ unsigned int channels,
+ unsigned int sample_width,
+ unsigned int sample_bits)
+{
+ ssi->hw_params_cache.rate = rate;
+ ssi->hw_params_cache.channels = channels;
+ ssi->hw_params_cache.sample_width = sample_width;
+ ssi->hw_params_cache.sample_bits = sample_bits;
+}
+
static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai);
+ struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream);
unsigned int sample_bits = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min;
unsigned int channels = params_channels(params);
+ unsigned int rate = params_rate(params);
if (sample_bits != 16) {
dev_err(ssi->dev, "Unsupported sample width: %d\n",
@@ -845,8 +940,20 @@ static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- return rz_ssi_clk_setup(ssi, params_rate(params),
- params_channels(params));
+ if (rz_ssi_is_stream_running(&ssi->playback) ||
+ rz_ssi_is_stream_running(&ssi->capture)) {
+ if (rz_ssi_is_valid_hw_params(ssi, rate, channels,
+ strm->sample_width, sample_bits))
+ return 0;
+
+ dev_err(ssi->dev, "Full duplex needs same HW params\n");
+ return -EINVAL;
+ }
+
+ rz_ssi_cache_hw_params(ssi, rate, channels, strm->sample_width,
+ sample_bits);
+
+ return rz_ssi_clk_setup(ssi, rate, channels);
}
static const struct snd_soc_dai_ops rz_ssi_dai_ops = {
@@ -1097,7 +1204,7 @@ static struct platform_driver rz_ssi_driver = {
.of_match_table = rz_ssi_of_match,
},
.probe = rz_ssi_probe,
- .remove_new = rz_ssi_remove,
+ .remove = rz_ssi_remove,
};
module_platform_driver(rz_ssi_driver);
diff --git a/sound/soc/sh/siu_dai.c b/sound/soc/sh/siu_dai.c
index d0b5c543fd2f..7e771a164a80 100644
--- a/sound/soc/sh/siu_dai.c
+++ b/sound/soc/sh/siu_dai.c
@@ -788,7 +788,7 @@ static struct platform_driver siu_driver = {
.name = "siu-pcm-audio",
},
.probe = siu_probe,
- .remove_new = siu_remove,
+ .remove = siu_remove,
};
module_platform_driver(siu_driver);