diff options
Diffstat (limited to 'sound/soc/sh/rcar')
-rw-r--r-- | sound/soc/sh/rcar/adg.c | 6 | ||||
-rw-r--r-- | sound/soc/sh/rcar/core.c | 147 | ||||
-rw-r--r-- | sound/soc/sh/rcar/dma.c | 104 | ||||
-rw-r--r-- | sound/soc/sh/rcar/rsnd.h | 15 | ||||
-rw-r--r-- | sound/soc/sh/rcar/ssi.c | 161 | ||||
-rw-r--r-- | sound/soc/sh/rcar/ssiu.c | 5 |
6 files changed, 188 insertions, 250 deletions
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 8ddb08714faa..4672688cac32 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -222,7 +222,7 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, NULL, &val, NULL); val = val << shift; - mask = 0xffff << shift; + mask = 0x0f1f << shift; rsnd_mod_bset(adg_mod, CMDOUT_TIMSEL, mask, val); @@ -250,7 +250,7 @@ int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod, in = in << shift; out = out << shift; - mask = 0xffff << shift; + mask = 0x0f1f << shift; switch (id / 2) { case 0: @@ -380,7 +380,7 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) ckr = 0x80000000; } - rsnd_mod_bset(adg_mod, BRGCKR, 0x80FF0000, adg->ckr | ckr); + rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr | ckr); rsnd_mod_write(adg_mod, BRRA, adg->rbga); rsnd_mod_write(adg_mod, BRRB, adg->rbgb); diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index c70eb2097816..64d5ecb86528 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -197,16 +197,27 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io) return 0; } -int rsnd_runtime_channel_original(struct rsnd_dai_stream *io) +int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io, + struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - return runtime->channels; + /* + * params will be added when refine + * see + * __rsnd_soc_hw_rule_rate() + * __rsnd_soc_hw_rule_channels() + */ + if (params) + return params_channels(params); + else + return runtime->channels; } -int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io) +int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, + struct snd_pcm_hw_params *params) { - int chan = rsnd_runtime_channel_original(io); + int chan = rsnd_runtime_channel_original_with_params(io, params); struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io); if (ctu_mod) { @@ -219,12 +230,13 @@ int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io) return chan; } -int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io) +int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, + struct snd_pcm_hw_params *params) { struct rsnd_dai *rdai = rsnd_io_to_rdai(io); int chan = rsnd_io_is_play(io) ? - rsnd_runtime_channel_after_ctu(io) : - rsnd_runtime_channel_original(io); + rsnd_runtime_channel_after_ctu_with_params(io, params) : + rsnd_runtime_channel_original_with_params(io, params); /* Use Multi SSI */ if (rsnd_runtime_is_ssi_multi(io)) @@ -262,10 +274,10 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct device *dev = rsnd_priv_to_dev(priv); - switch (runtime->sample_bits) { + switch (snd_pcm_format_width(runtime->format)) { case 16: return 8 << 16; - case 32: + case 24: return 0 << 16; } @@ -282,11 +294,12 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); struct rsnd_mod *target; struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - u32 val = 0x76543210; - u32 mask = ~0; /* - * *Hardware* L/R and *Software* L/R are inverted. + * *Hardware* L/R and *Software* L/R are inverted for 16bit data. + * 31..16 15...0 + * HW: [L ch] [R ch] + * SW: [R ch] [L ch] * We need to care about inversion timing to control * Playback/Capture correctly. * The point is [DVC] needs *Hardware* L/R, [MEM] needs *Software* L/R @@ -313,27 +326,13 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) target = cmd ? cmd : ssiu; } - mask <<= runtime->channels * 4; - val = val & mask; - - switch (runtime->sample_bits) { - case 16: - val |= 0x67452301 & ~mask; - break; - case 32: - val |= 0x76543210 & ~mask; - break; - } - - /* - * exchange channeles on SRC if possible, - * otherwise, R/L volume settings on DVC - * changes inverted channels - */ - if (mod == target) - return val; - else + /* Non target mod or 24bit data needs normal DALIGN */ + if ((snd_pcm_format_width(runtime->format) != 16) || + (mod != target)) return 0x76543210; + /* Target mod needs inverted DALIGN when 16bit */ + else + return 0x67452301; } u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod) @@ -363,12 +362,8 @@ u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod) * HW 24bit data is located as 0x******00 * */ - switch (runtime->sample_bits) { - case 16: + if (snd_pcm_format_width(runtime->format) == 16) return 0; - case 32: - break; - } for (i = 0; i < ARRAY_SIZE(playback_mods); i++) { tmod = rsnd_io_to_mod(io, mods[i]); @@ -616,8 +611,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: - rsnd_dai_stream_init(io, substream); - ret = rsnd_dai_call(init, io, priv); if (ret < 0) goto dai_trigger_end; @@ -639,7 +632,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, ret |= rsnd_dai_call(quit, io, priv); - rsnd_dai_stream_quit(io); break; default: ret = -EINVAL; @@ -784,8 +776,9 @@ static int rsnd_soc_hw_rule(struct rsnd_priv *priv, return snd_interval_refine(iv, &p); } -static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) +static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule, + int is_play) { struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); @@ -793,25 +786,37 @@ static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_soc_dai *dai = rule->private; struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; /* * possible sampling rate limitation is same as * 2ch if it supports multi ssi + * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init()) */ ic = *ic_; - if (1 < rsnd_rdai_ssi_lane_get(rdai)) { - ic.min = 2; - ic.max = 2; - } + ic.min = + ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); return rsnd_soc_hw_rule(priv, rsnd_soc_hw_rate_list, ARRAY_SIZE(rsnd_soc_hw_rate_list), &ic, ir); } +static int rsnd_soc_hw_rule_rate_playback(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + return __rsnd_soc_hw_rule_rate(params, rule, 1); +} + +static int rsnd_soc_hw_rule_rate_capture(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + return __rsnd_soc_hw_rule_rate(params, rule, 0); +} -static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, - struct snd_pcm_hw_rule *rule) +static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule, + int is_play) { struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); @@ -819,22 +824,34 @@ static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, struct snd_soc_dai *dai = rule->private; struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; /* * possible sampling rate limitation is same as * 2ch if it supports multi ssi + * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init()) */ ic = *ic_; - if (1 < rsnd_rdai_ssi_lane_get(rdai)) { - ic.min = 2; - ic.max = 2; - } + ic.min = + ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); return rsnd_soc_hw_rule(priv, rsnd_soc_hw_channels_list, ARRAY_SIZE(rsnd_soc_hw_channels_list), ir, &ic); } +static int rsnd_soc_hw_rule_channels_playback(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + return __rsnd_soc_hw_rule_channels(params, rule, 1); +} + +static int rsnd_soc_hw_rule_channels_capture(struct snd_pcm_hw_params *params, + struct snd_pcm_hw_rule *rule) +{ + return __rsnd_soc_hw_rule_channels(params, rule, 0); +} + static const struct snd_pcm_hardware rsnd_pcm_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | @@ -859,6 +876,8 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, int ret; int i; + rsnd_dai_stream_init(io, substream); + /* * Channel Limitation * It depends on Platform design @@ -886,11 +905,17 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, * It depends on Clock Master Mode */ if (rsnd_rdai_is_clk_master(rdai)) { + int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - rsnd_soc_hw_rule_rate, dai, + is_play ? rsnd_soc_hw_rule_rate_playback : + rsnd_soc_hw_rule_rate_capture, + dai, SNDRV_PCM_HW_PARAM_CHANNELS, -1); snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - rsnd_soc_hw_rule_channels, dai, + is_play ? rsnd_soc_hw_rule_channels_playback : + rsnd_soc_hw_rule_channels_capture, + dai, SNDRV_PCM_HW_PARAM_RATE, -1); } @@ -915,6 +940,8 @@ static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, * call rsnd_dai_call without spinlock */ rsnd_dai_call(nolock_stop, io, priv); + + rsnd_dai_stream_quit(io); } static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { @@ -990,7 +1017,7 @@ of_node_compatible: static void __rsnd_dai_probe(struct rsnd_priv *priv, struct device_node *dai_np, - int dai_i, int is_graph) + int dai_i) { struct device_node *playback, *capture; struct rsnd_dai_stream *io_playback; @@ -1089,13 +1116,13 @@ static int rsnd_dai_probe(struct rsnd_priv *priv) dai_i = 0; if (is_graph) { for_each_endpoint_of_node(dai_node, dai_np) { - __rsnd_dai_probe(priv, dai_np, dai_i, is_graph); + __rsnd_dai_probe(priv, dai_np, dai_i); rsnd_ssi_parse_hdmi_connection(priv, dai_np, dai_i); dai_i++; } } else { for_each_child_of_node(dai_node, dai_np) - __rsnd_dai_probe(priv, dai_np, dai_i++, is_graph); + __rsnd_dai_probe(priv, dai_np, dai_i++); } return 0; @@ -1332,8 +1359,8 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd) return snd_pcm_lib_preallocate_pages_for_all( rtd->pcm, - SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), + SNDRV_DMA_TYPE_DEV, + rtd->card->snd_card->dev, PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); } @@ -1496,6 +1523,8 @@ static int rsnd_remove(struct platform_device *pdev) }; int ret = 0, i; + snd_soc_disconnect_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); for_each_rsnd_dai(rdai, priv, i) { diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index fd557abfe390..41de23417c4a 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -26,10 +26,7 @@ struct rsnd_dmaen { struct dma_chan *chan; dma_cookie_t cookie; - dma_addr_t dma_buf; unsigned int dma_len; - unsigned int dma_period; - unsigned int dma_cnt; }; struct rsnd_dmapp { @@ -71,69 +68,10 @@ static struct rsnd_mod mem = { /* * Audio DMAC */ -#define rsnd_dmaen_sync(dmaen, io, i) __rsnd_dmaen_sync(dmaen, io, i, 1) -#define rsnd_dmaen_unsync(dmaen, io, i) __rsnd_dmaen_sync(dmaen, io, i, 0) -static void __rsnd_dmaen_sync(struct rsnd_dmaen *dmaen, struct rsnd_dai_stream *io, - int i, int sync) -{ - struct device *dev = dmaen->chan->device->dev; - enum dma_data_direction dir; - int is_play = rsnd_io_is_play(io); - dma_addr_t buf; - int len, max; - size_t period; - - len = dmaen->dma_len; - period = dmaen->dma_period; - max = len / period; - i = i % max; - buf = dmaen->dma_buf + (period * i); - - dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; - - if (sync) - dma_sync_single_for_device(dev, buf, period, dir); - else - dma_sync_single_for_cpu(dev, buf, period, dir); -} - static void __rsnd_dmaen_complete(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - bool elapsed = false; - unsigned long flags; - - /* - * Renesas sound Gen1 needs 1 DMAC, - * Gen2 needs 2 DMAC. - * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri. - * But, Audio-DMAC-peri-peri doesn't have interrupt, - * and this driver is assuming that here. - */ - spin_lock_irqsave(&priv->lock, flags); - - if (rsnd_io_is_working(io)) { - rsnd_dmaen_unsync(dmaen, io, dmaen->dma_cnt); - - /* - * Next period is already started. - * Let's sync Next Next period - * see - * rsnd_dmaen_start() - */ - rsnd_dmaen_sync(dmaen, io, dmaen->dma_cnt + 2); - - elapsed = true; - - dmaen->dma_cnt++; - } - - spin_unlock_irqrestore(&priv->lock, flags); - - if (elapsed) + if (rsnd_io_is_working(io)) rsnd_dai_period_elapsed(io); } @@ -165,14 +103,8 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod, struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - if (dmaen->chan) { - int is_play = rsnd_io_is_play(io); - + if (dmaen->chan) dmaengine_terminate_all(dmaen->chan); - dma_unmap_single(dmaen->chan->device->dev, - dmaen->dma_buf, dmaen->dma_len, - is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - } return 0; } @@ -237,11 +169,7 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, struct device *dev = rsnd_priv_to_dev(priv); struct dma_async_tx_descriptor *desc; struct dma_slave_config cfg = {}; - dma_addr_t buf; - size_t len; - size_t period; int is_play = rsnd_io_is_play(io); - int i; int ret; cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; @@ -258,19 +186,10 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, if (ret < 0) return ret; - len = snd_pcm_lib_buffer_bytes(substream); - period = snd_pcm_lib_period_bytes(substream); - buf = dma_map_single(dmaen->chan->device->dev, - substream->runtime->dma_area, - len, - is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - if (dma_mapping_error(dmaen->chan->device->dev, buf)) { - dev_err(dev, "dma map failed\n"); - return -EIO; - } - desc = dmaengine_prep_dma_cyclic(dmaen->chan, - buf, len, period, + 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); @@ -282,18 +201,7 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, desc->callback = rsnd_dmaen_complete; desc->callback_param = rsnd_mod_get(dma); - dmaen->dma_buf = buf; - dmaen->dma_len = len; - dmaen->dma_period = period; - dmaen->dma_cnt = 0; - - /* - * synchronize this and next period - * see - * __rsnd_dmaen_complete() - */ - for (i = 0; i < 2; i++) - rsnd_dmaen_sync(dmaen, io, i); + dmaen->dma_len = snd_pcm_lib_buffer_bytes(substream); dmaen->cookie = dmaengine_submit(desc); if (dmaen->cookie < 0) { diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 57cd2bc773c2..ad6523595b0a 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -399,9 +399,18 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai, struct device_node *playback, struct device_node *capture); -int rsnd_runtime_channel_original(struct rsnd_dai_stream *io); -int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io); -int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io); +#define rsnd_runtime_channel_original(io) \ + rsnd_runtime_channel_original_with_params(io, NULL) +int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io, + struct snd_pcm_hw_params *params); +#define rsnd_runtime_channel_after_ctu(io) \ + rsnd_runtime_channel_after_ctu_with_params(io, NULL) +int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, + struct snd_pcm_hw_params *params); +#define rsnd_runtime_channel_for_ssi(io) \ + rsnd_runtime_channel_for_ssi_with_params(io, NULL) +int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, + struct snd_pcm_hw_params *params); int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io); int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io); diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index fece1e5f582f..97a9db892a8f 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -79,8 +79,8 @@ struct rsnd_ssi { int irq; unsigned int usrcnt; + /* for PIO */ int byte_pos; - int period_pos; int byte_per_period; int next_period_byte; }; @@ -371,11 +371,11 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, if (rsnd_io_is_play(io)) cr_own |= TRMD; - switch (runtime->sample_bits) { + switch (snd_pcm_format_width(runtime->format)) { case 16: cr_own |= DWL_16; break; - case 32: + case 24: cr_own |= DWL_24; break; } @@ -414,59 +414,6 @@ static void rsnd_ssi_register_setup(struct rsnd_mod *mod) ssi->cr_en); } -static void rsnd_ssi_pointer_init(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - - ssi->byte_pos = 0; - ssi->period_pos = 0; - ssi->byte_per_period = runtime->period_size * - runtime->channels * - samples_to_bytes(runtime, 1); - ssi->next_period_byte = ssi->byte_per_period; -} - -static int rsnd_ssi_pointer_offset(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - int additional) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - int pos = ssi->byte_pos + additional; - - pos %= (runtime->periods * ssi->byte_per_period); - - return pos; -} - -static bool rsnd_ssi_pointer_update(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - int byte) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - - ssi->byte_pos += byte; - - if (ssi->byte_pos >= ssi->next_period_byte) { - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - - ssi->period_pos++; - ssi->next_period_byte += ssi->byte_per_period; - - if (ssi->period_pos >= runtime->periods) { - ssi->byte_pos = 0; - ssi->period_pos = 0; - ssi->next_period_byte = ssi->byte_per_period; - } - - return true; - } - - return false; -} - /* * SSI mod common functions */ @@ -480,8 +427,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, if (!rsnd_ssi_is_run_mods(mod, io)) return 0; - rsnd_ssi_pointer_init(mod, io); - ssi->usrcnt++; rsnd_mod_power_on(mod); @@ -652,6 +597,8 @@ static int rsnd_ssi_irq(struct rsnd_mod *mod, return 0; } +static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod, + struct rsnd_dai_stream *io); static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { @@ -670,30 +617,8 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, status = rsnd_ssi_status_get(mod); /* PIO only */ - if (!is_dma && (status & DIRQ)) { - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - u32 *buf = (u32 *)(runtime->dma_area + - rsnd_ssi_pointer_offset(mod, io, 0)); - int shift = 0; - - switch (runtime->sample_bits) { - case 32: - shift = 8; - break; - } - - /* - * 8/16/32 data can be assesse to TDR/RDR register - * directly as 32bit data - * see rsnd_ssi_init() - */ - if (rsnd_io_is_play(io)) - rsnd_mod_write(mod, SSITDR, (*buf) << shift); - else - *buf = (rsnd_mod_read(mod, SSIRDR) >> shift); - - elapsed = rsnd_ssi_pointer_update(mod, io, sizeof(*buf)); - } + if (!is_dma && (status & DIRQ)) + elapsed = rsnd_ssi_pio_interrupt(mod, io); /* DMA only */ if (is_dma && (status & (UIRQ | OIRQ))) @@ -831,14 +756,78 @@ static int rsnd_ssi_common_remove(struct rsnd_mod *mod, return 0; } -static int rsnd_ssi_pointer(struct rsnd_mod *mod, +/* + * SSI PIO functions + */ +static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod, + struct rsnd_dai_stream *io) +{ + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + u32 *buf = (u32 *)(runtime->dma_area + ssi->byte_pos); + int shift = 0; + int byte_pos; + bool elapsed = false; + + if (snd_pcm_format_width(runtime->format) == 24) + shift = 8; + + /* + * 8/16/32 data can be assesse to TDR/RDR register + * directly as 32bit data + * see rsnd_ssi_init() + */ + if (rsnd_io_is_play(io)) + rsnd_mod_write(mod, SSITDR, (*buf) << shift); + else + *buf = (rsnd_mod_read(mod, SSIRDR) >> shift); + + byte_pos = ssi->byte_pos + sizeof(*buf); + + if (byte_pos >= ssi->next_period_byte) { + int period_pos = byte_pos / ssi->byte_per_period; + + if (period_pos >= runtime->periods) { + byte_pos = 0; + period_pos = 0; + } + + ssi->next_period_byte = (period_pos + 1) * ssi->byte_per_period; + + elapsed = true; + } + + WRITE_ONCE(ssi->byte_pos, byte_pos); + + return elapsed; +} + +static int rsnd_ssi_pio_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + + if (!rsnd_ssi_is_parent(mod, io)) { + ssi->byte_pos = 0; + ssi->byte_per_period = runtime->period_size * + runtime->channels * + samples_to_bytes(runtime, 1); + ssi->next_period_byte = ssi->byte_per_period; + } + + return rsnd_ssi_init(mod, io, priv); +} + +static int rsnd_ssi_pio_pointer(struct rsnd_mod *mod, struct rsnd_dai_stream *io, snd_pcm_uframes_t *pointer) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - *pointer = bytes_to_frames(runtime, ssi->byte_pos); + *pointer = bytes_to_frames(runtime, READ_ONCE(ssi->byte_pos)); return 0; } @@ -847,12 +836,12 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = { .name = SSI_NAME, .probe = rsnd_ssi_common_probe, .remove = rsnd_ssi_common_remove, - .init = rsnd_ssi_init, + .init = rsnd_ssi_pio_init, .quit = rsnd_ssi_quit, .start = rsnd_ssi_start, .stop = rsnd_ssi_stop, .irq = rsnd_ssi_irq, - .pointer= rsnd_ssi_pointer, + .pointer = rsnd_ssi_pio_pointer, .pcm_new = rsnd_ssi_pcm_new, .hw_params = rsnd_ssi_hw_params, }; diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 4d948757d300..6ff8a36c2c82 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -125,6 +125,7 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, { int hdmi = rsnd_ssi_hdmi_port(io); int ret; + u32 mode = 0; ret = rsnd_ssiu_init(mod, io, priv); if (ret < 0) @@ -136,9 +137,11 @@ static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, * see * rsnd_ssi_config_init() */ - rsnd_mod_write(mod, SSI_MODE, 0x1); + mode = 0x1; } + rsnd_mod_write(mod, SSI_MODE, mode); + if (rsnd_ssi_use_busif(io)) { rsnd_mod_write(mod, SSI_BUSIF_ADINR, rsnd_get_adinr_bit(mod, io) | |