Loading Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml +1 −18 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ properties: - renesas,r9a07g043-ssi # RZ/G2UL and RZ/Five - renesas,r9a07g044-ssi # RZ/G2{L,LC} - renesas,r9a07g054-ssi # RZ/V2L - renesas,r9a08g045-ssi # RZ/G3S - const: renesas,rz-ssi reg: Loading Loading @@ -57,24 +58,6 @@ properties: dmas: minItems: 1 maxItems: 2 description: The first cell represents a phandle to dmac. The second cell specifies the encoded MID/RID values of the SSI port connected to the DMA client and the slave channel configuration parameters. bits[0:9] - Specifies MID/RID value of a SSI channel as below MID/RID value of SSI rx0 = 0x256 MID/RID value of SSI tx0 = 0x255 MID/RID value of SSI rx1 = 0x25a MID/RID value of SSI tx1 = 0x259 MID/RID value of SSI rt2 = 0x25f MID/RID value of SSI rx3 = 0x262 MID/RID value of SSI tx3 = 0x261 bit[10] - HIEN = 1, Detects a request in response to the rising edge of the signal bit[11] - LVL = 0, Detects based on the edge bits[12:14] - AM = 2, Bus cycle mode bit[15] - TM = 0, Single transfer mode dma-names: oneOf: Loading sound/soc/renesas/rz-ssi.c +138 −88 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ #include <linux/clk.h> #include <linux/dmaengine.h> #include <linux/io.h> #include <linux/iopoll.h> #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/reset.h> Loading Loading @@ -71,7 +72,7 @@ #define PREALLOC_BUFFER (SZ_32K) #define PREALLOC_BUFFER_MAX (SZ_32K) #define SSI_RATES SNDRV_PCM_RATE_8000_48000 /* 8k-44.1kHz */ #define SSI_RATES SNDRV_PCM_RATE_8000_48000 /* 8k-48kHz */ #define SSI_FMTS SNDRV_PCM_FMTBIT_S16_LE #define SSI_CHAN_MIN 2 #define SSI_CHAN_MAX 2 Loading Loading @@ -99,7 +100,6 @@ struct rz_ssi_stream { struct rz_ssi_priv { void __iomem *base; struct platform_device *pdev; struct reset_control *rstc; struct device *dev; struct clk *sfr_clk; Loading Loading @@ -163,16 +163,7 @@ static void rz_ssi_reg_mask_setl(struct rz_ssi_priv *priv, uint reg, writel(val, (priv->base + reg)); } static inline struct snd_soc_dai * rz_ssi_get_dai(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); return snd_soc_rtd_to_cpu(rtd, 0); } static inline bool rz_ssi_stream_is_play(struct rz_ssi_priv *ssi, struct snd_pcm_substream *substream) static inline bool rz_ssi_stream_is_play(struct snd_pcm_substream *substream) { return substream->stream == SNDRV_PCM_STREAM_PLAYBACK; } Loading Loading @@ -244,22 +235,21 @@ static void rz_ssi_stream_init(struct rz_ssi_stream *strm, static void rz_ssi_stream_quit(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) { struct snd_soc_dai *dai = rz_ssi_get_dai(strm->substream); struct device *dev = ssi->dev; rz_ssi_set_substream(strm, NULL); if (strm->oerr_num > 0) dev_info(dai->dev, "overrun = %d\n", strm->oerr_num); dev_info(dev, "overrun = %d\n", strm->oerr_num); if (strm->uerr_num > 0) dev_info(dai->dev, "underrun = %d\n", strm->uerr_num); dev_info(dev, "underrun = %d\n", strm->uerr_num); } static int rz_ssi_clk_setup(struct rz_ssi_priv *ssi, unsigned int rate, unsigned int channels) { static s8 ckdv[16] = { 1, 2, 4, 8, 16, 32, 64, 128, 6, 12, 24, 48, 96, -1, -1, -1 }; static u8 ckdv[] = { 1, 2, 4, 8, 16, 32, 64, 128, 6, 12, 24, 48, 96 }; unsigned int channel_bits = 32; /* System Word Length */ unsigned long bclk_rate = rate * channels * channel_bits; unsigned int div; Loading Loading @@ -318,7 +308,8 @@ static int rz_ssi_clk_setup(struct rz_ssi_priv *ssi, unsigned int rate, static void rz_ssi_set_idle(struct rz_ssi_priv *ssi) { int timeout; u32 tmp; int ret; /* Disable irqs */ rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TUIEN | SSICR_TOIEN | Loading @@ -331,15 +322,9 @@ static void rz_ssi_set_idle(struct rz_ssi_priv *ssi) 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"); ret = readl_poll_timeout_atomic(ssi->base + SSISR, tmp, (tmp & SSISR_IIRQ), 1, 100); if (ret) dev_warn_ratelimited(ssi->dev, "timeout waiting for SSI idle\n"); /* Hold FIFOs in reset */ rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_FIFO_RST); Loading @@ -347,7 +332,7 @@ static void rz_ssi_set_idle(struct rz_ssi_priv *ssi) 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_play = rz_ssi_stream_is_play(strm->substream); bool is_full_duplex; u32 ssicr, ssifcr; Loading Loading @@ -403,6 +388,15 @@ static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) return 0; } static int rz_ssi_swreset(struct rz_ssi_priv *ssi) { u32 tmp; rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_SSIRST); rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_SSIRST, 0); return readl_poll_timeout_atomic(ssi->base + SSIFCR, tmp, !(tmp & SSIFCR_SSIRST), 1, 5); } static int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) { strm->running = 0; Loading @@ -415,8 +409,12 @@ static int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0); /* Cancel all remaining DMA transactions */ if (rz_ssi_is_dma_enabled(ssi)) dmaengine_terminate_async(strm->dma_ch); if (rz_ssi_is_dma_enabled(ssi)) { if (ssi->playback.dma_ch) dmaengine_terminate_async(ssi->playback.dma_ch); if (ssi->capture.dma_ch) dmaengine_terminate_async(ssi->capture.dma_ch); } rz_ssi_set_idle(ssi); Loading Loading @@ -680,7 +678,7 @@ static int rz_ssi_dma_transfer(struct rz_ssi_priv *ssi, */ return 0; dir = rz_ssi_stream_is_play(ssi, substream) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; dir = rz_ssi_stream_is_play(substream) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; /* Always transfer 1 period */ amount = runtime->period_size; Loading Loading @@ -784,6 +782,32 @@ static int rz_ssi_dma_request(struct rz_ssi_priv *ssi, struct device *dev) return -ENODEV; } static int rz_ssi_trigger_resume(struct rz_ssi_priv *ssi) { int ret; if (rz_ssi_is_stream_running(&ssi->playback) || rz_ssi_is_stream_running(&ssi->capture)) return 0; ret = rz_ssi_swreset(ssi); if (ret) return ret; return rz_ssi_clk_setup(ssi, ssi->hw_params_cache.rate, ssi->hw_params_cache.channels); } static void rz_ssi_streams_suspend(struct rz_ssi_priv *ssi) { if (rz_ssi_is_stream_running(&ssi->playback) || rz_ssi_is_stream_running(&ssi->capture)) return; ssi->playback.dma_buffer_pos = 0; ssi->capture.dma_buffer_pos = 0; } static int rz_ssi_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { Loading @@ -792,21 +816,21 @@ static int rz_ssi_dai_trigger(struct snd_pcm_substream *substream, int cmd, int ret = 0, i, num_transfer = 1; switch (cmd) { case SNDRV_PCM_TRIGGER_START: /* Soft Reset */ 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); } case SNDRV_PCM_TRIGGER_RESUME: ret = rz_ssi_trigger_resume(ssi); if (ret) return ret; fallthrough; case SNDRV_PCM_TRIGGER_START: if (cmd == SNDRV_PCM_TRIGGER_START) rz_ssi_stream_init(strm, substream); if (ssi->dma_rt) { bool is_playback; is_playback = rz_ssi_stream_is_play(ssi, substream); is_playback = rz_ssi_stream_is_play(substream); ret = rz_ssi_dma_slave_config(ssi, ssi->playback.dma_ch, is_playback); /* Fallback to pio */ Loading @@ -829,6 +853,12 @@ static int rz_ssi_dai_trigger(struct snd_pcm_substream *substream, int cmd, ret = rz_ssi_start(ssi, strm); break; case SNDRV_PCM_TRIGGER_SUSPEND: rz_ssi_stop(ssi, strm); rz_ssi_streams_suspend(ssi); break; case SNDRV_PCM_TRIGGER_STOP: rz_ssi_stop(ssi, strm); rz_ssi_stream_quit(ssi, strm); Loading Loading @@ -925,6 +955,7 @@ static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min; unsigned int channels = params_channels(params); unsigned int rate = params_rate(params); int ret; if (sample_bits != 16) { dev_err(ssi->dev, "Unsupported sample width: %d\n", Loading @@ -951,6 +982,10 @@ static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream, rz_ssi_cache_hw_params(ssi, rate, channels, strm->sample_width, sample_bits); ret = rz_ssi_swreset(ssi); if (ret) return ret; return rz_ssi_clk_setup(ssi, rate, channels); } Loading @@ -963,7 +998,8 @@ static const struct snd_soc_dai_ops rz_ssi_dai_ops = { static const struct snd_pcm_hardware rz_ssi_pcm_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID, SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_RESUME, .buffer_bytes_max = PREALLOC_BUFFER, .period_bytes_min = 32, .period_bytes_max = 8192, Loading @@ -986,7 +1022,8 @@ static int rz_ssi_pcm_open(struct snd_soc_component *component, static snd_pcm_uframes_t rz_ssi_pcm_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct snd_soc_dai *dai = rz_ssi_get_dai(substream); struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0); struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream); Loading Loading @@ -1031,37 +1068,37 @@ static const struct snd_soc_component_driver rz_ssi_soc_component = { static int rz_ssi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct rz_ssi_priv *ssi; struct clk *audio_clk; struct resource *res; int ret; ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), GFP_KERNEL); ssi = devm_kzalloc(dev, sizeof(*ssi), GFP_KERNEL); if (!ssi) return -ENOMEM; ssi->pdev = pdev; ssi->dev = &pdev->dev; ssi->dev = dev; ssi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(ssi->base)) return PTR_ERR(ssi->base); ssi->phys = res->start; ssi->clk = devm_clk_get(&pdev->dev, "ssi"); ssi->clk = devm_clk_get(dev, "ssi"); if (IS_ERR(ssi->clk)) return PTR_ERR(ssi->clk); ssi->sfr_clk = devm_clk_get(&pdev->dev, "ssi_sfr"); ssi->sfr_clk = devm_clk_get(dev, "ssi_sfr"); if (IS_ERR(ssi->sfr_clk)) return PTR_ERR(ssi->sfr_clk); audio_clk = devm_clk_get(&pdev->dev, "audio_clk1"); audio_clk = devm_clk_get(dev, "audio_clk1"); if (IS_ERR(audio_clk)) return dev_err_probe(&pdev->dev, PTR_ERR(audio_clk), "no audio clk1"); ssi->audio_clk_1 = clk_get_rate(audio_clk); audio_clk = devm_clk_get(&pdev->dev, "audio_clk2"); audio_clk = devm_clk_get(dev, "audio_clk2"); if (IS_ERR(audio_clk)) return dev_err_probe(&pdev->dev, PTR_ERR(audio_clk), "no audio clk2"); Loading @@ -1074,13 +1111,13 @@ static int rz_ssi_probe(struct platform_device *pdev) ssi->audio_mck = ssi->audio_clk_1 ? ssi->audio_clk_1 : ssi->audio_clk_2; /* Detect DMA support */ ret = rz_ssi_dma_request(ssi, &pdev->dev); ret = rz_ssi_dma_request(ssi, dev); if (ret < 0) { dev_warn(&pdev->dev, "DMA not available, using PIO\n"); dev_warn(dev, "DMA not available, using PIO\n"); ssi->playback.transfer = rz_ssi_pio_send; ssi->capture.transfer = rz_ssi_pio_recv; } else { dev_info(&pdev->dev, "DMA enabled"); dev_info(dev, "DMA enabled"); ssi->playback.transfer = rz_ssi_dma_transfer; ssi->capture.transfer = rz_ssi_dma_transfer; } Loading @@ -1089,21 +1126,20 @@ static int rz_ssi_probe(struct platform_device *pdev) ssi->capture.priv = ssi; spin_lock_init(&ssi->lock); dev_set_drvdata(&pdev->dev, ssi); dev_set_drvdata(dev, ssi); /* Error Interrupt */ ssi->irq_int = platform_get_irq_byname(pdev, "int_req"); if (ssi->irq_int < 0) { rz_ssi_release_dma_channels(ssi); return ssi->irq_int; ret = ssi->irq_int; goto err_release_dma_chs; } ret = devm_request_irq(&pdev->dev, ssi->irq_int, &rz_ssi_interrupt, 0, dev_name(&pdev->dev), ssi); ret = devm_request_irq(dev, ssi->irq_int, &rz_ssi_interrupt, 0, dev_name(dev), ssi); if (ret < 0) { rz_ssi_release_dma_channels(ssi); return dev_err_probe(&pdev->dev, ret, "irq request error (int_req)\n"); dev_err_probe(dev, ret, "irq request error (int_req)\n"); goto err_release_dma_chs; } if (!rz_ssi_is_dma_enabled(ssi)) { Loading @@ -1115,11 +1151,11 @@ static int rz_ssi_probe(struct platform_device *pdev) if (ssi->irq_rt < 0) return ssi->irq_rt; ret = devm_request_irq(&pdev->dev, ssi->irq_rt, ret = devm_request_irq(dev, ssi->irq_rt, &rz_ssi_interrupt, 0, dev_name(&pdev->dev), ssi); dev_name(dev), ssi); if (ret < 0) return dev_err_probe(&pdev->dev, ret, return dev_err_probe(dev, ret, "irq request error (dma_rt)\n"); } else { if (ssi->irq_tx < 0) Loading @@ -1128,52 +1164,48 @@ static int rz_ssi_probe(struct platform_device *pdev) if (ssi->irq_rx < 0) return ssi->irq_rx; ret = devm_request_irq(&pdev->dev, ssi->irq_tx, ret = devm_request_irq(dev, ssi->irq_tx, &rz_ssi_interrupt, 0, dev_name(&pdev->dev), ssi); dev_name(dev), ssi); if (ret < 0) return dev_err_probe(&pdev->dev, ret, return dev_err_probe(dev, ret, "irq request error (dma_tx)\n"); ret = devm_request_irq(&pdev->dev, ssi->irq_rx, ret = devm_request_irq(dev, ssi->irq_rx, &rz_ssi_interrupt, 0, dev_name(&pdev->dev), ssi); dev_name(dev), ssi); if (ret < 0) return dev_err_probe(&pdev->dev, ret, return dev_err_probe(dev, ret, "irq request error (dma_rx)\n"); } } ssi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); ssi->rstc = devm_reset_control_get_exclusive(dev, NULL); if (IS_ERR(ssi->rstc)) { ret = PTR_ERR(ssi->rstc); goto err_reset; goto err_release_dma_chs; } reset_control_deassert(ssi->rstc); pm_runtime_enable(&pdev->dev); ret = pm_runtime_resume_and_get(&pdev->dev); /* Default 0 for power saving. Can be overridden via sysfs. */ pm_runtime_set_autosuspend_delay(dev, 0); pm_runtime_use_autosuspend(dev); ret = devm_pm_runtime_enable(dev); if (ret < 0) { dev_err(&pdev->dev, "pm_runtime_resume_and_get failed\n"); goto err_pm; dev_err(dev, "Failed to enable runtime PM!\n"); goto err_release_dma_chs; } ret = devm_snd_soc_register_component(&pdev->dev, &rz_ssi_soc_component, ret = devm_snd_soc_register_component(dev, &rz_ssi_soc_component, rz_ssi_soc_dai, ARRAY_SIZE(rz_ssi_soc_dai)); if (ret < 0) { dev_err(&pdev->dev, "failed to register snd component\n"); goto err_snd_soc; dev_err(dev, "failed to register snd component\n"); goto err_release_dma_chs; } return 0; err_snd_soc: pm_runtime_put(ssi->dev); err_pm: pm_runtime_disable(ssi->dev); reset_control_assert(ssi->rstc); err_reset: err_release_dma_chs: rz_ssi_release_dma_channels(ssi); return ret; Loading @@ -1185,8 +1217,6 @@ static void rz_ssi_remove(struct platform_device *pdev) rz_ssi_release_dma_channels(ssi); pm_runtime_put(ssi->dev); pm_runtime_disable(ssi->dev); reset_control_assert(ssi->rstc); } Loading @@ -1196,10 +1226,30 @@ static const struct of_device_id rz_ssi_of_match[] = { }; MODULE_DEVICE_TABLE(of, rz_ssi_of_match); static int rz_ssi_runtime_suspend(struct device *dev) { struct rz_ssi_priv *ssi = dev_get_drvdata(dev); return reset_control_assert(ssi->rstc); } static int rz_ssi_runtime_resume(struct device *dev) { struct rz_ssi_priv *ssi = dev_get_drvdata(dev); return reset_control_deassert(ssi->rstc); } static const struct dev_pm_ops rz_ssi_pm_ops = { RUNTIME_PM_OPS(rz_ssi_runtime_suspend, rz_ssi_runtime_resume, NULL) SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver rz_ssi_driver = { .driver = { .name = "rz-ssi-pcm-audio", .of_match_table = rz_ssi_of_match, .pm = pm_ptr(&rz_ssi_pm_ops), }, .probe = rz_ssi_probe, .remove = rz_ssi_remove, Loading Loading
Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml +1 −18 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ properties: - renesas,r9a07g043-ssi # RZ/G2UL and RZ/Five - renesas,r9a07g044-ssi # RZ/G2{L,LC} - renesas,r9a07g054-ssi # RZ/V2L - renesas,r9a08g045-ssi # RZ/G3S - const: renesas,rz-ssi reg: Loading Loading @@ -57,24 +58,6 @@ properties: dmas: minItems: 1 maxItems: 2 description: The first cell represents a phandle to dmac. The second cell specifies the encoded MID/RID values of the SSI port connected to the DMA client and the slave channel configuration parameters. bits[0:9] - Specifies MID/RID value of a SSI channel as below MID/RID value of SSI rx0 = 0x256 MID/RID value of SSI tx0 = 0x255 MID/RID value of SSI rx1 = 0x25a MID/RID value of SSI tx1 = 0x259 MID/RID value of SSI rt2 = 0x25f MID/RID value of SSI rx3 = 0x262 MID/RID value of SSI tx3 = 0x261 bit[10] - HIEN = 1, Detects a request in response to the rising edge of the signal bit[11] - LVL = 0, Detects based on the edge bits[12:14] - AM = 2, Bus cycle mode bit[15] - TM = 0, Single transfer mode dma-names: oneOf: Loading
sound/soc/renesas/rz-ssi.c +138 −88 Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ #include <linux/clk.h> #include <linux/dmaengine.h> #include <linux/io.h> #include <linux/iopoll.h> #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/reset.h> Loading Loading @@ -71,7 +72,7 @@ #define PREALLOC_BUFFER (SZ_32K) #define PREALLOC_BUFFER_MAX (SZ_32K) #define SSI_RATES SNDRV_PCM_RATE_8000_48000 /* 8k-44.1kHz */ #define SSI_RATES SNDRV_PCM_RATE_8000_48000 /* 8k-48kHz */ #define SSI_FMTS SNDRV_PCM_FMTBIT_S16_LE #define SSI_CHAN_MIN 2 #define SSI_CHAN_MAX 2 Loading Loading @@ -99,7 +100,6 @@ struct rz_ssi_stream { struct rz_ssi_priv { void __iomem *base; struct platform_device *pdev; struct reset_control *rstc; struct device *dev; struct clk *sfr_clk; Loading Loading @@ -163,16 +163,7 @@ static void rz_ssi_reg_mask_setl(struct rz_ssi_priv *priv, uint reg, writel(val, (priv->base + reg)); } static inline struct snd_soc_dai * rz_ssi_get_dai(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); return snd_soc_rtd_to_cpu(rtd, 0); } static inline bool rz_ssi_stream_is_play(struct rz_ssi_priv *ssi, struct snd_pcm_substream *substream) static inline bool rz_ssi_stream_is_play(struct snd_pcm_substream *substream) { return substream->stream == SNDRV_PCM_STREAM_PLAYBACK; } Loading Loading @@ -244,22 +235,21 @@ static void rz_ssi_stream_init(struct rz_ssi_stream *strm, static void rz_ssi_stream_quit(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) { struct snd_soc_dai *dai = rz_ssi_get_dai(strm->substream); struct device *dev = ssi->dev; rz_ssi_set_substream(strm, NULL); if (strm->oerr_num > 0) dev_info(dai->dev, "overrun = %d\n", strm->oerr_num); dev_info(dev, "overrun = %d\n", strm->oerr_num); if (strm->uerr_num > 0) dev_info(dai->dev, "underrun = %d\n", strm->uerr_num); dev_info(dev, "underrun = %d\n", strm->uerr_num); } static int rz_ssi_clk_setup(struct rz_ssi_priv *ssi, unsigned int rate, unsigned int channels) { static s8 ckdv[16] = { 1, 2, 4, 8, 16, 32, 64, 128, 6, 12, 24, 48, 96, -1, -1, -1 }; static u8 ckdv[] = { 1, 2, 4, 8, 16, 32, 64, 128, 6, 12, 24, 48, 96 }; unsigned int channel_bits = 32; /* System Word Length */ unsigned long bclk_rate = rate * channels * channel_bits; unsigned int div; Loading Loading @@ -318,7 +308,8 @@ static int rz_ssi_clk_setup(struct rz_ssi_priv *ssi, unsigned int rate, static void rz_ssi_set_idle(struct rz_ssi_priv *ssi) { int timeout; u32 tmp; int ret; /* Disable irqs */ rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TUIEN | SSICR_TOIEN | Loading @@ -331,15 +322,9 @@ static void rz_ssi_set_idle(struct rz_ssi_priv *ssi) 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"); ret = readl_poll_timeout_atomic(ssi->base + SSISR, tmp, (tmp & SSISR_IIRQ), 1, 100); if (ret) dev_warn_ratelimited(ssi->dev, "timeout waiting for SSI idle\n"); /* Hold FIFOs in reset */ rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_FIFO_RST); Loading @@ -347,7 +332,7 @@ static void rz_ssi_set_idle(struct rz_ssi_priv *ssi) 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_play = rz_ssi_stream_is_play(strm->substream); bool is_full_duplex; u32 ssicr, ssifcr; Loading Loading @@ -403,6 +388,15 @@ static int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) return 0; } static int rz_ssi_swreset(struct rz_ssi_priv *ssi) { u32 tmp; rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_SSIRST); rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_SSIRST, 0); return readl_poll_timeout_atomic(ssi->base + SSIFCR, tmp, !(tmp & SSIFCR_SSIRST), 1, 5); } static int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) { strm->running = 0; Loading @@ -415,8 +409,12 @@ static int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0); /* Cancel all remaining DMA transactions */ if (rz_ssi_is_dma_enabled(ssi)) dmaengine_terminate_async(strm->dma_ch); if (rz_ssi_is_dma_enabled(ssi)) { if (ssi->playback.dma_ch) dmaengine_terminate_async(ssi->playback.dma_ch); if (ssi->capture.dma_ch) dmaengine_terminate_async(ssi->capture.dma_ch); } rz_ssi_set_idle(ssi); Loading Loading @@ -680,7 +678,7 @@ static int rz_ssi_dma_transfer(struct rz_ssi_priv *ssi, */ return 0; dir = rz_ssi_stream_is_play(ssi, substream) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; dir = rz_ssi_stream_is_play(substream) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; /* Always transfer 1 period */ amount = runtime->period_size; Loading Loading @@ -784,6 +782,32 @@ static int rz_ssi_dma_request(struct rz_ssi_priv *ssi, struct device *dev) return -ENODEV; } static int rz_ssi_trigger_resume(struct rz_ssi_priv *ssi) { int ret; if (rz_ssi_is_stream_running(&ssi->playback) || rz_ssi_is_stream_running(&ssi->capture)) return 0; ret = rz_ssi_swreset(ssi); if (ret) return ret; return rz_ssi_clk_setup(ssi, ssi->hw_params_cache.rate, ssi->hw_params_cache.channels); } static void rz_ssi_streams_suspend(struct rz_ssi_priv *ssi) { if (rz_ssi_is_stream_running(&ssi->playback) || rz_ssi_is_stream_running(&ssi->capture)) return; ssi->playback.dma_buffer_pos = 0; ssi->capture.dma_buffer_pos = 0; } static int rz_ssi_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { Loading @@ -792,21 +816,21 @@ static int rz_ssi_dai_trigger(struct snd_pcm_substream *substream, int cmd, int ret = 0, i, num_transfer = 1; switch (cmd) { case SNDRV_PCM_TRIGGER_START: /* Soft Reset */ 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); } case SNDRV_PCM_TRIGGER_RESUME: ret = rz_ssi_trigger_resume(ssi); if (ret) return ret; fallthrough; case SNDRV_PCM_TRIGGER_START: if (cmd == SNDRV_PCM_TRIGGER_START) rz_ssi_stream_init(strm, substream); if (ssi->dma_rt) { bool is_playback; is_playback = rz_ssi_stream_is_play(ssi, substream); is_playback = rz_ssi_stream_is_play(substream); ret = rz_ssi_dma_slave_config(ssi, ssi->playback.dma_ch, is_playback); /* Fallback to pio */ Loading @@ -829,6 +853,12 @@ static int rz_ssi_dai_trigger(struct snd_pcm_substream *substream, int cmd, ret = rz_ssi_start(ssi, strm); break; case SNDRV_PCM_TRIGGER_SUSPEND: rz_ssi_stop(ssi, strm); rz_ssi_streams_suspend(ssi); break; case SNDRV_PCM_TRIGGER_STOP: rz_ssi_stop(ssi, strm); rz_ssi_stream_quit(ssi, strm); Loading Loading @@ -925,6 +955,7 @@ static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min; unsigned int channels = params_channels(params); unsigned int rate = params_rate(params); int ret; if (sample_bits != 16) { dev_err(ssi->dev, "Unsupported sample width: %d\n", Loading @@ -951,6 +982,10 @@ static int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream, rz_ssi_cache_hw_params(ssi, rate, channels, strm->sample_width, sample_bits); ret = rz_ssi_swreset(ssi); if (ret) return ret; return rz_ssi_clk_setup(ssi, rate, channels); } Loading @@ -963,7 +998,8 @@ static const struct snd_soc_dai_ops rz_ssi_dai_ops = { static const struct snd_pcm_hardware rz_ssi_pcm_hardware = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID, SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_RESUME, .buffer_bytes_max = PREALLOC_BUFFER, .period_bytes_min = 32, .period_bytes_max = 8192, Loading @@ -986,7 +1022,8 @@ static int rz_ssi_pcm_open(struct snd_soc_component *component, static snd_pcm_uframes_t rz_ssi_pcm_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct snd_soc_dai *dai = rz_ssi_get_dai(substream); struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0); struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream); Loading Loading @@ -1031,37 +1068,37 @@ static const struct snd_soc_component_driver rz_ssi_soc_component = { static int rz_ssi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct rz_ssi_priv *ssi; struct clk *audio_clk; struct resource *res; int ret; ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), GFP_KERNEL); ssi = devm_kzalloc(dev, sizeof(*ssi), GFP_KERNEL); if (!ssi) return -ENOMEM; ssi->pdev = pdev; ssi->dev = &pdev->dev; ssi->dev = dev; ssi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(ssi->base)) return PTR_ERR(ssi->base); ssi->phys = res->start; ssi->clk = devm_clk_get(&pdev->dev, "ssi"); ssi->clk = devm_clk_get(dev, "ssi"); if (IS_ERR(ssi->clk)) return PTR_ERR(ssi->clk); ssi->sfr_clk = devm_clk_get(&pdev->dev, "ssi_sfr"); ssi->sfr_clk = devm_clk_get(dev, "ssi_sfr"); if (IS_ERR(ssi->sfr_clk)) return PTR_ERR(ssi->sfr_clk); audio_clk = devm_clk_get(&pdev->dev, "audio_clk1"); audio_clk = devm_clk_get(dev, "audio_clk1"); if (IS_ERR(audio_clk)) return dev_err_probe(&pdev->dev, PTR_ERR(audio_clk), "no audio clk1"); ssi->audio_clk_1 = clk_get_rate(audio_clk); audio_clk = devm_clk_get(&pdev->dev, "audio_clk2"); audio_clk = devm_clk_get(dev, "audio_clk2"); if (IS_ERR(audio_clk)) return dev_err_probe(&pdev->dev, PTR_ERR(audio_clk), "no audio clk2"); Loading @@ -1074,13 +1111,13 @@ static int rz_ssi_probe(struct platform_device *pdev) ssi->audio_mck = ssi->audio_clk_1 ? ssi->audio_clk_1 : ssi->audio_clk_2; /* Detect DMA support */ ret = rz_ssi_dma_request(ssi, &pdev->dev); ret = rz_ssi_dma_request(ssi, dev); if (ret < 0) { dev_warn(&pdev->dev, "DMA not available, using PIO\n"); dev_warn(dev, "DMA not available, using PIO\n"); ssi->playback.transfer = rz_ssi_pio_send; ssi->capture.transfer = rz_ssi_pio_recv; } else { dev_info(&pdev->dev, "DMA enabled"); dev_info(dev, "DMA enabled"); ssi->playback.transfer = rz_ssi_dma_transfer; ssi->capture.transfer = rz_ssi_dma_transfer; } Loading @@ -1089,21 +1126,20 @@ static int rz_ssi_probe(struct platform_device *pdev) ssi->capture.priv = ssi; spin_lock_init(&ssi->lock); dev_set_drvdata(&pdev->dev, ssi); dev_set_drvdata(dev, ssi); /* Error Interrupt */ ssi->irq_int = platform_get_irq_byname(pdev, "int_req"); if (ssi->irq_int < 0) { rz_ssi_release_dma_channels(ssi); return ssi->irq_int; ret = ssi->irq_int; goto err_release_dma_chs; } ret = devm_request_irq(&pdev->dev, ssi->irq_int, &rz_ssi_interrupt, 0, dev_name(&pdev->dev), ssi); ret = devm_request_irq(dev, ssi->irq_int, &rz_ssi_interrupt, 0, dev_name(dev), ssi); if (ret < 0) { rz_ssi_release_dma_channels(ssi); return dev_err_probe(&pdev->dev, ret, "irq request error (int_req)\n"); dev_err_probe(dev, ret, "irq request error (int_req)\n"); goto err_release_dma_chs; } if (!rz_ssi_is_dma_enabled(ssi)) { Loading @@ -1115,11 +1151,11 @@ static int rz_ssi_probe(struct platform_device *pdev) if (ssi->irq_rt < 0) return ssi->irq_rt; ret = devm_request_irq(&pdev->dev, ssi->irq_rt, ret = devm_request_irq(dev, ssi->irq_rt, &rz_ssi_interrupt, 0, dev_name(&pdev->dev), ssi); dev_name(dev), ssi); if (ret < 0) return dev_err_probe(&pdev->dev, ret, return dev_err_probe(dev, ret, "irq request error (dma_rt)\n"); } else { if (ssi->irq_tx < 0) Loading @@ -1128,52 +1164,48 @@ static int rz_ssi_probe(struct platform_device *pdev) if (ssi->irq_rx < 0) return ssi->irq_rx; ret = devm_request_irq(&pdev->dev, ssi->irq_tx, ret = devm_request_irq(dev, ssi->irq_tx, &rz_ssi_interrupt, 0, dev_name(&pdev->dev), ssi); dev_name(dev), ssi); if (ret < 0) return dev_err_probe(&pdev->dev, ret, return dev_err_probe(dev, ret, "irq request error (dma_tx)\n"); ret = devm_request_irq(&pdev->dev, ssi->irq_rx, ret = devm_request_irq(dev, ssi->irq_rx, &rz_ssi_interrupt, 0, dev_name(&pdev->dev), ssi); dev_name(dev), ssi); if (ret < 0) return dev_err_probe(&pdev->dev, ret, return dev_err_probe(dev, ret, "irq request error (dma_rx)\n"); } } ssi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); ssi->rstc = devm_reset_control_get_exclusive(dev, NULL); if (IS_ERR(ssi->rstc)) { ret = PTR_ERR(ssi->rstc); goto err_reset; goto err_release_dma_chs; } reset_control_deassert(ssi->rstc); pm_runtime_enable(&pdev->dev); ret = pm_runtime_resume_and_get(&pdev->dev); /* Default 0 for power saving. Can be overridden via sysfs. */ pm_runtime_set_autosuspend_delay(dev, 0); pm_runtime_use_autosuspend(dev); ret = devm_pm_runtime_enable(dev); if (ret < 0) { dev_err(&pdev->dev, "pm_runtime_resume_and_get failed\n"); goto err_pm; dev_err(dev, "Failed to enable runtime PM!\n"); goto err_release_dma_chs; } ret = devm_snd_soc_register_component(&pdev->dev, &rz_ssi_soc_component, ret = devm_snd_soc_register_component(dev, &rz_ssi_soc_component, rz_ssi_soc_dai, ARRAY_SIZE(rz_ssi_soc_dai)); if (ret < 0) { dev_err(&pdev->dev, "failed to register snd component\n"); goto err_snd_soc; dev_err(dev, "failed to register snd component\n"); goto err_release_dma_chs; } return 0; err_snd_soc: pm_runtime_put(ssi->dev); err_pm: pm_runtime_disable(ssi->dev); reset_control_assert(ssi->rstc); err_reset: err_release_dma_chs: rz_ssi_release_dma_channels(ssi); return ret; Loading @@ -1185,8 +1217,6 @@ static void rz_ssi_remove(struct platform_device *pdev) rz_ssi_release_dma_channels(ssi); pm_runtime_put(ssi->dev); pm_runtime_disable(ssi->dev); reset_control_assert(ssi->rstc); } Loading @@ -1196,10 +1226,30 @@ static const struct of_device_id rz_ssi_of_match[] = { }; MODULE_DEVICE_TABLE(of, rz_ssi_of_match); static int rz_ssi_runtime_suspend(struct device *dev) { struct rz_ssi_priv *ssi = dev_get_drvdata(dev); return reset_control_assert(ssi->rstc); } static int rz_ssi_runtime_resume(struct device *dev) { struct rz_ssi_priv *ssi = dev_get_drvdata(dev); return reset_control_deassert(ssi->rstc); } static const struct dev_pm_ops rz_ssi_pm_ops = { RUNTIME_PM_OPS(rz_ssi_runtime_suspend, rz_ssi_runtime_resume, NULL) SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver rz_ssi_driver = { .driver = { .name = "rz-ssi-pcm-audio", .of_match_table = rz_ssi_of_match, .pm = pm_ptr(&rz_ssi_pm_ops), }, .probe = rz_ssi_probe, .remove = rz_ssi_remove, Loading