162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// Renesas RZ/G2L ASoC Serial Sound Interface (SSIF-2) Driver 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright (C) 2021 Renesas Electronics Corp. 662306a36Sopenharmony_ci// Copyright (C) 2019 Chris Brandt. 762306a36Sopenharmony_ci// 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/clk.h> 1062306a36Sopenharmony_ci#include <linux/dmaengine.h> 1162306a36Sopenharmony_ci#include <linux/io.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/of_device.h> 1462306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1562306a36Sopenharmony_ci#include <linux/reset.h> 1662306a36Sopenharmony_ci#include <sound/soc.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* REGISTER OFFSET */ 1962306a36Sopenharmony_ci#define SSICR 0x000 2062306a36Sopenharmony_ci#define SSISR 0x004 2162306a36Sopenharmony_ci#define SSIFCR 0x010 2262306a36Sopenharmony_ci#define SSIFSR 0x014 2362306a36Sopenharmony_ci#define SSIFTDR 0x018 2462306a36Sopenharmony_ci#define SSIFRDR 0x01c 2562306a36Sopenharmony_ci#define SSIOFR 0x020 2662306a36Sopenharmony_ci#define SSISCR 0x024 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* SSI REGISTER BITS */ 2962306a36Sopenharmony_ci#define SSICR_DWL(x) (((x) & 0x7) << 19) 3062306a36Sopenharmony_ci#define SSICR_SWL(x) (((x) & 0x7) << 16) 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define SSICR_CKS BIT(30) 3362306a36Sopenharmony_ci#define SSICR_TUIEN BIT(29) 3462306a36Sopenharmony_ci#define SSICR_TOIEN BIT(28) 3562306a36Sopenharmony_ci#define SSICR_RUIEN BIT(27) 3662306a36Sopenharmony_ci#define SSICR_ROIEN BIT(26) 3762306a36Sopenharmony_ci#define SSICR_MST BIT(14) 3862306a36Sopenharmony_ci#define SSICR_BCKP BIT(13) 3962306a36Sopenharmony_ci#define SSICR_LRCKP BIT(12) 4062306a36Sopenharmony_ci#define SSICR_CKDV(x) (((x) & 0xf) << 4) 4162306a36Sopenharmony_ci#define SSICR_TEN BIT(1) 4262306a36Sopenharmony_ci#define SSICR_REN BIT(0) 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define SSISR_TUIRQ BIT(29) 4562306a36Sopenharmony_ci#define SSISR_TOIRQ BIT(28) 4662306a36Sopenharmony_ci#define SSISR_RUIRQ BIT(27) 4762306a36Sopenharmony_ci#define SSISR_ROIRQ BIT(26) 4862306a36Sopenharmony_ci#define SSISR_IIRQ BIT(25) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define SSIFCR_AUCKE BIT(31) 5162306a36Sopenharmony_ci#define SSIFCR_SSIRST BIT(16) 5262306a36Sopenharmony_ci#define SSIFCR_TIE BIT(3) 5362306a36Sopenharmony_ci#define SSIFCR_RIE BIT(2) 5462306a36Sopenharmony_ci#define SSIFCR_TFRST BIT(1) 5562306a36Sopenharmony_ci#define SSIFCR_RFRST BIT(0) 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define SSIFSR_TDC_MASK 0x3f 5862306a36Sopenharmony_ci#define SSIFSR_TDC_SHIFT 24 5962306a36Sopenharmony_ci#define SSIFSR_RDC_MASK 0x3f 6062306a36Sopenharmony_ci#define SSIFSR_RDC_SHIFT 8 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci#define SSIFSR_TDE BIT(16) 6362306a36Sopenharmony_ci#define SSIFSR_RDF BIT(0) 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define SSIOFR_LRCONT BIT(8) 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#define SSISCR_TDES(x) (((x) & 0x1f) << 8) 6862306a36Sopenharmony_ci#define SSISCR_RDFS(x) (((x) & 0x1f) << 0) 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* Pre allocated buffers sizes */ 7162306a36Sopenharmony_ci#define PREALLOC_BUFFER (SZ_32K) 7262306a36Sopenharmony_ci#define PREALLOC_BUFFER_MAX (SZ_32K) 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci#define SSI_RATES SNDRV_PCM_RATE_8000_48000 /* 8k-44.1kHz */ 7562306a36Sopenharmony_ci#define SSI_FMTS SNDRV_PCM_FMTBIT_S16_LE 7662306a36Sopenharmony_ci#define SSI_CHAN_MIN 2 7762306a36Sopenharmony_ci#define SSI_CHAN_MAX 2 7862306a36Sopenharmony_ci#define SSI_FIFO_DEPTH 32 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistruct rz_ssi_priv; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistruct rz_ssi_stream { 8362306a36Sopenharmony_ci struct rz_ssi_priv *priv; 8462306a36Sopenharmony_ci struct snd_pcm_substream *substream; 8562306a36Sopenharmony_ci int fifo_sample_size; /* sample capacity of SSI FIFO */ 8662306a36Sopenharmony_ci int dma_buffer_pos; /* The address for the next DMA descriptor */ 8762306a36Sopenharmony_ci int period_counter; /* for keeping track of periods transferred */ 8862306a36Sopenharmony_ci int sample_width; 8962306a36Sopenharmony_ci int buffer_pos; /* current frame position in the buffer */ 9062306a36Sopenharmony_ci int running; /* 0=stopped, 1=running */ 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci int uerr_num; 9362306a36Sopenharmony_ci int oerr_num; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci struct dma_chan *dma_ch; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci int (*transfer)(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm); 9862306a36Sopenharmony_ci}; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistruct rz_ssi_priv { 10162306a36Sopenharmony_ci void __iomem *base; 10262306a36Sopenharmony_ci struct platform_device *pdev; 10362306a36Sopenharmony_ci struct reset_control *rstc; 10462306a36Sopenharmony_ci struct device *dev; 10562306a36Sopenharmony_ci struct clk *sfr_clk; 10662306a36Sopenharmony_ci struct clk *clk; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci phys_addr_t phys; 10962306a36Sopenharmony_ci int irq_int; 11062306a36Sopenharmony_ci int irq_tx; 11162306a36Sopenharmony_ci int irq_rx; 11262306a36Sopenharmony_ci int irq_rt; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci spinlock_t lock; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* 11762306a36Sopenharmony_ci * The SSI supports full-duplex transmission and reception. 11862306a36Sopenharmony_ci * However, if an error occurs, channel reset (both transmission 11962306a36Sopenharmony_ci * and reception reset) is required. 12062306a36Sopenharmony_ci * So it is better to use as half-duplex (playing and recording 12162306a36Sopenharmony_ci * should be done on separate channels). 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_ci struct rz_ssi_stream playback; 12462306a36Sopenharmony_ci struct rz_ssi_stream capture; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* clock */ 12762306a36Sopenharmony_ci unsigned long audio_mck; 12862306a36Sopenharmony_ci unsigned long audio_clk_1; 12962306a36Sopenharmony_ci unsigned long audio_clk_2; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci bool lrckp_fsync_fall; /* LR clock polarity (SSICR.LRCKP) */ 13262306a36Sopenharmony_ci bool bckp_rise; /* Bit clock polarity (SSICR.BCKP) */ 13362306a36Sopenharmony_ci bool dma_rt; 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic void rz_ssi_dma_complete(void *data); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic void rz_ssi_reg_writel(struct rz_ssi_priv *priv, uint reg, u32 data) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci writel(data, (priv->base + reg)); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic u32 rz_ssi_reg_readl(struct rz_ssi_priv *priv, uint reg) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci return readl(priv->base + reg); 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic void rz_ssi_reg_mask_setl(struct rz_ssi_priv *priv, uint reg, 14962306a36Sopenharmony_ci u32 bclr, u32 bset) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci u32 val; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci val = readl(priv->base + reg); 15462306a36Sopenharmony_ci val = (val & ~bclr) | bset; 15562306a36Sopenharmony_ci writel(val, (priv->base + reg)); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic inline struct snd_soc_dai * 15962306a36Sopenharmony_cirz_ssi_get_dai(struct snd_pcm_substream *substream) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci return asoc_rtd_to_cpu(rtd, 0); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic inline bool rz_ssi_stream_is_play(struct rz_ssi_priv *ssi, 16762306a36Sopenharmony_ci struct snd_pcm_substream *substream) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci return substream->stream == SNDRV_PCM_STREAM_PLAYBACK; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic inline struct rz_ssi_stream * 17362306a36Sopenharmony_cirz_ssi_stream_get(struct rz_ssi_priv *ssi, struct snd_pcm_substream *substream) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci struct rz_ssi_stream *stream = &ssi->playback; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) 17862306a36Sopenharmony_ci stream = &ssi->capture; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci return stream; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic inline bool rz_ssi_is_dma_enabled(struct rz_ssi_priv *ssi) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci return (ssi->playback.dma_ch && (ssi->dma_rt || ssi->capture.dma_ch)); 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic void rz_ssi_set_substream(struct rz_ssi_stream *strm, 18962306a36Sopenharmony_ci struct snd_pcm_substream *substream) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci struct rz_ssi_priv *ssi = strm->priv; 19262306a36Sopenharmony_ci unsigned long flags; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci spin_lock_irqsave(&ssi->lock, flags); 19562306a36Sopenharmony_ci strm->substream = substream; 19662306a36Sopenharmony_ci spin_unlock_irqrestore(&ssi->lock, flags); 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic bool rz_ssi_stream_is_valid(struct rz_ssi_priv *ssi, 20062306a36Sopenharmony_ci struct rz_ssi_stream *strm) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci unsigned long flags; 20362306a36Sopenharmony_ci bool ret; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci spin_lock_irqsave(&ssi->lock, flags); 20662306a36Sopenharmony_ci ret = strm->substream && strm->substream->runtime; 20762306a36Sopenharmony_ci spin_unlock_irqrestore(&ssi->lock, flags); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci return ret; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic void rz_ssi_stream_init(struct rz_ssi_stream *strm, 21362306a36Sopenharmony_ci struct snd_pcm_substream *substream) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci rz_ssi_set_substream(strm, substream); 21862306a36Sopenharmony_ci strm->sample_width = samples_to_bytes(runtime, 1); 21962306a36Sopenharmony_ci strm->dma_buffer_pos = 0; 22062306a36Sopenharmony_ci strm->period_counter = 0; 22162306a36Sopenharmony_ci strm->buffer_pos = 0; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci strm->oerr_num = 0; 22462306a36Sopenharmony_ci strm->uerr_num = 0; 22562306a36Sopenharmony_ci strm->running = 0; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* fifo init */ 22862306a36Sopenharmony_ci strm->fifo_sample_size = SSI_FIFO_DEPTH; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic void rz_ssi_stream_quit(struct rz_ssi_priv *ssi, 23262306a36Sopenharmony_ci struct rz_ssi_stream *strm) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct snd_soc_dai *dai = rz_ssi_get_dai(strm->substream); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci rz_ssi_set_substream(strm, NULL); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (strm->oerr_num > 0) 23962306a36Sopenharmony_ci dev_info(dai->dev, "overrun = %d\n", strm->oerr_num); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (strm->uerr_num > 0) 24262306a36Sopenharmony_ci dev_info(dai->dev, "underrun = %d\n", strm->uerr_num); 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic int rz_ssi_clk_setup(struct rz_ssi_priv *ssi, unsigned int rate, 24662306a36Sopenharmony_ci unsigned int channels) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci static s8 ckdv[16] = { 1, 2, 4, 8, 16, 32, 64, 128, 24962306a36Sopenharmony_ci 6, 12, 24, 48, 96, -1, -1, -1 }; 25062306a36Sopenharmony_ci unsigned int channel_bits = 32; /* System Word Length */ 25162306a36Sopenharmony_ci unsigned long bclk_rate = rate * channels * channel_bits; 25262306a36Sopenharmony_ci unsigned int div; 25362306a36Sopenharmony_ci unsigned int i; 25462306a36Sopenharmony_ci u32 ssicr = 0; 25562306a36Sopenharmony_ci u32 clk_ckdv; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /* Clear AUCKE so we can set MST */ 25862306a36Sopenharmony_ci rz_ssi_reg_writel(ssi, SSIFCR, 0); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* Continue to output LRCK pin even when idle */ 26162306a36Sopenharmony_ci rz_ssi_reg_writel(ssi, SSIOFR, SSIOFR_LRCONT); 26262306a36Sopenharmony_ci if (ssi->audio_clk_1 && ssi->audio_clk_2) { 26362306a36Sopenharmony_ci if (ssi->audio_clk_1 % bclk_rate) 26462306a36Sopenharmony_ci ssi->audio_mck = ssi->audio_clk_2; 26562306a36Sopenharmony_ci else 26662306a36Sopenharmony_ci ssi->audio_mck = ssi->audio_clk_1; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci /* Clock setting */ 27062306a36Sopenharmony_ci ssicr |= SSICR_MST; 27162306a36Sopenharmony_ci if (ssi->audio_mck == ssi->audio_clk_1) 27262306a36Sopenharmony_ci ssicr |= SSICR_CKS; 27362306a36Sopenharmony_ci if (ssi->bckp_rise) 27462306a36Sopenharmony_ci ssicr |= SSICR_BCKP; 27562306a36Sopenharmony_ci if (ssi->lrckp_fsync_fall) 27662306a36Sopenharmony_ci ssicr |= SSICR_LRCKP; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* Determine the clock divider */ 27962306a36Sopenharmony_ci clk_ckdv = 0; 28062306a36Sopenharmony_ci div = ssi->audio_mck / bclk_rate; 28162306a36Sopenharmony_ci /* try to find an match */ 28262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ckdv); i++) { 28362306a36Sopenharmony_ci if (ckdv[i] == div) { 28462306a36Sopenharmony_ci clk_ckdv = i; 28562306a36Sopenharmony_ci break; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (i == ARRAY_SIZE(ckdv)) { 29062306a36Sopenharmony_ci dev_err(ssi->dev, "Rate not divisible by audio clock source\n"); 29162306a36Sopenharmony_ci return -EINVAL; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci /* 29562306a36Sopenharmony_ci * DWL: Data Word Length = 16 bits 29662306a36Sopenharmony_ci * SWL: System Word Length = 32 bits 29762306a36Sopenharmony_ci */ 29862306a36Sopenharmony_ci ssicr |= SSICR_CKDV(clk_ckdv); 29962306a36Sopenharmony_ci ssicr |= SSICR_DWL(1) | SSICR_SWL(3); 30062306a36Sopenharmony_ci rz_ssi_reg_writel(ssi, SSICR, ssicr); 30162306a36Sopenharmony_ci rz_ssi_reg_writel(ssi, SSIFCR, 30262306a36Sopenharmony_ci (SSIFCR_AUCKE | SSIFCR_TFRST | SSIFCR_RFRST)); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci return 0; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic int rz_ssi_start(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci bool is_play = rz_ssi_stream_is_play(ssi, strm->substream); 31062306a36Sopenharmony_ci u32 ssicr, ssifcr; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci ssicr = rz_ssi_reg_readl(ssi, SSICR); 31362306a36Sopenharmony_ci ssifcr = rz_ssi_reg_readl(ssi, SSIFCR) & ~0xF; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* FIFO interrupt thresholds */ 31662306a36Sopenharmony_ci if (rz_ssi_is_dma_enabled(ssi)) 31762306a36Sopenharmony_ci rz_ssi_reg_writel(ssi, SSISCR, 0); 31862306a36Sopenharmony_ci else 31962306a36Sopenharmony_ci rz_ssi_reg_writel(ssi, SSISCR, 32062306a36Sopenharmony_ci SSISCR_TDES(strm->fifo_sample_size / 2 - 1) | 32162306a36Sopenharmony_ci SSISCR_RDFS(0)); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* enable IRQ */ 32462306a36Sopenharmony_ci if (is_play) { 32562306a36Sopenharmony_ci ssicr |= SSICR_TUIEN | SSICR_TOIEN; 32662306a36Sopenharmony_ci ssifcr |= SSIFCR_TIE | SSIFCR_RFRST; 32762306a36Sopenharmony_ci } else { 32862306a36Sopenharmony_ci ssicr |= SSICR_RUIEN | SSICR_ROIEN; 32962306a36Sopenharmony_ci ssifcr |= SSIFCR_RIE | SSIFCR_TFRST; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci rz_ssi_reg_writel(ssi, SSICR, ssicr); 33362306a36Sopenharmony_ci rz_ssi_reg_writel(ssi, SSIFCR, ssifcr); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* Clear all error flags */ 33662306a36Sopenharmony_ci rz_ssi_reg_mask_setl(ssi, SSISR, 33762306a36Sopenharmony_ci (SSISR_TOIRQ | SSISR_TUIRQ | SSISR_ROIRQ | 33862306a36Sopenharmony_ci SSISR_RUIRQ), 0); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci strm->running = 1; 34162306a36Sopenharmony_ci ssicr |= is_play ? SSICR_TEN : SSICR_REN; 34262306a36Sopenharmony_ci rz_ssi_reg_writel(ssi, SSICR, ssicr); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return 0; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci int timeout; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci strm->running = 0; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci /* Disable TX/RX */ 35462306a36Sopenharmony_ci rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* Cancel all remaining DMA transactions */ 35762306a36Sopenharmony_ci if (rz_ssi_is_dma_enabled(ssi)) 35862306a36Sopenharmony_ci dmaengine_terminate_async(strm->dma_ch); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* Disable irqs */ 36162306a36Sopenharmony_ci rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TUIEN | SSICR_TOIEN | 36262306a36Sopenharmony_ci SSICR_RUIEN | SSICR_ROIEN, 0); 36362306a36Sopenharmony_ci rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_TIE | SSIFCR_RIE, 0); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* Clear all error flags */ 36662306a36Sopenharmony_ci rz_ssi_reg_mask_setl(ssi, SSISR, 36762306a36Sopenharmony_ci (SSISR_TOIRQ | SSISR_TUIRQ | SSISR_ROIRQ | 36862306a36Sopenharmony_ci SSISR_RUIRQ), 0); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* Wait for idle */ 37162306a36Sopenharmony_ci timeout = 100; 37262306a36Sopenharmony_ci while (--timeout) { 37362306a36Sopenharmony_ci if (rz_ssi_reg_readl(ssi, SSISR) & SSISR_IIRQ) 37462306a36Sopenharmony_ci break; 37562306a36Sopenharmony_ci udelay(1); 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci if (!timeout) 37962306a36Sopenharmony_ci dev_info(ssi->dev, "timeout waiting for SSI idle\n"); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci /* Hold FIFOs in reset */ 38262306a36Sopenharmony_ci rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, 38362306a36Sopenharmony_ci SSIFCR_TFRST | SSIFCR_RFRST); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci return 0; 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic void rz_ssi_pointer_update(struct rz_ssi_stream *strm, int frames) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci struct snd_pcm_substream *substream = strm->substream; 39162306a36Sopenharmony_ci struct snd_pcm_runtime *runtime; 39262306a36Sopenharmony_ci int current_period; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (!strm->running || !substream || !substream->runtime) 39562306a36Sopenharmony_ci return; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci runtime = substream->runtime; 39862306a36Sopenharmony_ci strm->buffer_pos += frames; 39962306a36Sopenharmony_ci WARN_ON(strm->buffer_pos > runtime->buffer_size); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci /* ring buffer */ 40262306a36Sopenharmony_ci if (strm->buffer_pos == runtime->buffer_size) 40362306a36Sopenharmony_ci strm->buffer_pos = 0; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci current_period = strm->buffer_pos / runtime->period_size; 40662306a36Sopenharmony_ci if (strm->period_counter != current_period) { 40762306a36Sopenharmony_ci snd_pcm_period_elapsed(strm->substream); 40862306a36Sopenharmony_ci strm->period_counter = current_period; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic int rz_ssi_pio_recv(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci struct snd_pcm_substream *substream = strm->substream; 41562306a36Sopenharmony_ci struct snd_pcm_runtime *runtime; 41662306a36Sopenharmony_ci u16 *buf; 41762306a36Sopenharmony_ci int fifo_samples; 41862306a36Sopenharmony_ci int frames_left; 41962306a36Sopenharmony_ci int samples; 42062306a36Sopenharmony_ci int i; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (!rz_ssi_stream_is_valid(ssi, strm)) 42362306a36Sopenharmony_ci return -EINVAL; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci runtime = substream->runtime; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci do { 42862306a36Sopenharmony_ci /* frames left in this period */ 42962306a36Sopenharmony_ci frames_left = runtime->period_size - 43062306a36Sopenharmony_ci (strm->buffer_pos % runtime->period_size); 43162306a36Sopenharmony_ci if (!frames_left) 43262306a36Sopenharmony_ci frames_left = runtime->period_size; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci /* Samples in RX FIFO */ 43562306a36Sopenharmony_ci fifo_samples = (rz_ssi_reg_readl(ssi, SSIFSR) >> 43662306a36Sopenharmony_ci SSIFSR_RDC_SHIFT) & SSIFSR_RDC_MASK; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* Only read full frames at a time */ 43962306a36Sopenharmony_ci samples = 0; 44062306a36Sopenharmony_ci while (frames_left && (fifo_samples >= runtime->channels)) { 44162306a36Sopenharmony_ci samples += runtime->channels; 44262306a36Sopenharmony_ci fifo_samples -= runtime->channels; 44362306a36Sopenharmony_ci frames_left--; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* not enough samples yet */ 44762306a36Sopenharmony_ci if (!samples) 44862306a36Sopenharmony_ci break; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci /* calculate new buffer index */ 45162306a36Sopenharmony_ci buf = (u16 *)runtime->dma_area; 45262306a36Sopenharmony_ci buf += strm->buffer_pos * runtime->channels; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci /* Note, only supports 16-bit samples */ 45562306a36Sopenharmony_ci for (i = 0; i < samples; i++) 45662306a36Sopenharmony_ci *buf++ = (u16)(rz_ssi_reg_readl(ssi, SSIFRDR) >> 16); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0); 45962306a36Sopenharmony_ci rz_ssi_pointer_update(strm, samples / runtime->channels); 46062306a36Sopenharmony_ci } while (!frames_left && fifo_samples >= runtime->channels); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci return 0; 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic int rz_ssi_pio_send(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci struct snd_pcm_substream *substream = strm->substream; 46862306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 46962306a36Sopenharmony_ci int sample_space; 47062306a36Sopenharmony_ci int samples = 0; 47162306a36Sopenharmony_ci int frames_left; 47262306a36Sopenharmony_ci int i; 47362306a36Sopenharmony_ci u32 ssifsr; 47462306a36Sopenharmony_ci u16 *buf; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if (!rz_ssi_stream_is_valid(ssi, strm)) 47762306a36Sopenharmony_ci return -EINVAL; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* frames left in this period */ 48062306a36Sopenharmony_ci frames_left = runtime->period_size - (strm->buffer_pos % 48162306a36Sopenharmony_ci runtime->period_size); 48262306a36Sopenharmony_ci if (frames_left == 0) 48362306a36Sopenharmony_ci frames_left = runtime->period_size; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci sample_space = strm->fifo_sample_size; 48662306a36Sopenharmony_ci ssifsr = rz_ssi_reg_readl(ssi, SSIFSR); 48762306a36Sopenharmony_ci sample_space -= (ssifsr >> SSIFSR_TDC_SHIFT) & SSIFSR_TDC_MASK; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci /* Only add full frames at a time */ 49062306a36Sopenharmony_ci while (frames_left && (sample_space >= runtime->channels)) { 49162306a36Sopenharmony_ci samples += runtime->channels; 49262306a36Sopenharmony_ci sample_space -= runtime->channels; 49362306a36Sopenharmony_ci frames_left--; 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci /* no space to send anything right now */ 49762306a36Sopenharmony_ci if (samples == 0) 49862306a36Sopenharmony_ci return 0; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci /* calculate new buffer index */ 50162306a36Sopenharmony_ci buf = (u16 *)(runtime->dma_area); 50262306a36Sopenharmony_ci buf += strm->buffer_pos * runtime->channels; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci /* Note, only supports 16-bit samples */ 50562306a36Sopenharmony_ci for (i = 0; i < samples; i++) 50662306a36Sopenharmony_ci rz_ssi_reg_writel(ssi, SSIFTDR, ((u32)(*buf++) << 16)); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_TDE, 0); 50962306a36Sopenharmony_ci rz_ssi_pointer_update(strm, samples / runtime->channels); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci return 0; 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cistatic irqreturn_t rz_ssi_interrupt(int irq, void *data) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci struct rz_ssi_stream *strm = NULL; 51762306a36Sopenharmony_ci struct rz_ssi_priv *ssi = data; 51862306a36Sopenharmony_ci u32 ssisr = rz_ssi_reg_readl(ssi, SSISR); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci if (ssi->playback.substream) 52162306a36Sopenharmony_ci strm = &ssi->playback; 52262306a36Sopenharmony_ci else if (ssi->capture.substream) 52362306a36Sopenharmony_ci strm = &ssi->capture; 52462306a36Sopenharmony_ci else 52562306a36Sopenharmony_ci return IRQ_HANDLED; /* Left over TX/RX interrupt */ 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci if (irq == ssi->irq_int) { /* error or idle */ 52862306a36Sopenharmony_ci if (ssisr & SSISR_TUIRQ) 52962306a36Sopenharmony_ci strm->uerr_num++; 53062306a36Sopenharmony_ci if (ssisr & SSISR_TOIRQ) 53162306a36Sopenharmony_ci strm->oerr_num++; 53262306a36Sopenharmony_ci if (ssisr & SSISR_RUIRQ) 53362306a36Sopenharmony_ci strm->uerr_num++; 53462306a36Sopenharmony_ci if (ssisr & SSISR_ROIRQ) 53562306a36Sopenharmony_ci strm->oerr_num++; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci if (ssisr & (SSISR_TUIRQ | SSISR_TOIRQ | SSISR_RUIRQ | 53862306a36Sopenharmony_ci SSISR_ROIRQ)) { 53962306a36Sopenharmony_ci /* Error handling */ 54062306a36Sopenharmony_ci /* You must reset (stop/restart) after each interrupt */ 54162306a36Sopenharmony_ci rz_ssi_stop(ssi, strm); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci /* Clear all flags */ 54462306a36Sopenharmony_ci rz_ssi_reg_mask_setl(ssi, SSISR, SSISR_TOIRQ | 54562306a36Sopenharmony_ci SSISR_TUIRQ | SSISR_ROIRQ | 54662306a36Sopenharmony_ci SSISR_RUIRQ, 0); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci /* Add/remove more data */ 54962306a36Sopenharmony_ci strm->transfer(ssi, strm); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci /* Resume */ 55262306a36Sopenharmony_ci rz_ssi_start(ssi, strm); 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (!strm->running) 55762306a36Sopenharmony_ci return IRQ_HANDLED; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* tx data empty */ 56062306a36Sopenharmony_ci if (irq == ssi->irq_tx) 56162306a36Sopenharmony_ci strm->transfer(ssi, &ssi->playback); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci /* rx data full */ 56462306a36Sopenharmony_ci if (irq == ssi->irq_rx) { 56562306a36Sopenharmony_ci strm->transfer(ssi, &ssi->capture); 56662306a36Sopenharmony_ci rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0); 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (irq == ssi->irq_rt) { 57062306a36Sopenharmony_ci struct snd_pcm_substream *substream = strm->substream; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci if (rz_ssi_stream_is_play(ssi, substream)) { 57362306a36Sopenharmony_ci strm->transfer(ssi, &ssi->playback); 57462306a36Sopenharmony_ci } else { 57562306a36Sopenharmony_ci strm->transfer(ssi, &ssi->capture); 57662306a36Sopenharmony_ci rz_ssi_reg_mask_setl(ssi, SSIFSR, SSIFSR_RDF, 0); 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci return IRQ_HANDLED; 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_cistatic int rz_ssi_dma_slave_config(struct rz_ssi_priv *ssi, 58462306a36Sopenharmony_ci struct dma_chan *dma_ch, bool is_play) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci struct dma_slave_config cfg; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci memset(&cfg, 0, sizeof(cfg)); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; 59162306a36Sopenharmony_ci cfg.dst_addr = ssi->phys + SSIFTDR; 59262306a36Sopenharmony_ci cfg.src_addr = ssi->phys + SSIFRDR; 59362306a36Sopenharmony_ci cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 59462306a36Sopenharmony_ci cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci return dmaengine_slave_config(dma_ch, &cfg); 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_cistatic int rz_ssi_dma_transfer(struct rz_ssi_priv *ssi, 60062306a36Sopenharmony_ci struct rz_ssi_stream *strm) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci struct snd_pcm_substream *substream = strm->substream; 60362306a36Sopenharmony_ci struct dma_async_tx_descriptor *desc; 60462306a36Sopenharmony_ci struct snd_pcm_runtime *runtime; 60562306a36Sopenharmony_ci enum dma_transfer_direction dir; 60662306a36Sopenharmony_ci u32 dma_paddr, dma_size; 60762306a36Sopenharmony_ci int amount; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci if (!rz_ssi_stream_is_valid(ssi, strm)) 61062306a36Sopenharmony_ci return -EINVAL; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci runtime = substream->runtime; 61362306a36Sopenharmony_ci if (runtime->state == SNDRV_PCM_STATE_DRAINING) 61462306a36Sopenharmony_ci /* 61562306a36Sopenharmony_ci * Stream is ending, so do not queue up any more DMA 61662306a36Sopenharmony_ci * transfers otherwise we play partial sound clips 61762306a36Sopenharmony_ci * because we can't shut off the DMA quick enough. 61862306a36Sopenharmony_ci */ 61962306a36Sopenharmony_ci return 0; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci dir = rz_ssi_stream_is_play(ssi, substream) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci /* Always transfer 1 period */ 62462306a36Sopenharmony_ci amount = runtime->period_size; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci /* DMA physical address and size */ 62762306a36Sopenharmony_ci dma_paddr = runtime->dma_addr + frames_to_bytes(runtime, 62862306a36Sopenharmony_ci strm->dma_buffer_pos); 62962306a36Sopenharmony_ci dma_size = frames_to_bytes(runtime, amount); 63062306a36Sopenharmony_ci desc = dmaengine_prep_slave_single(strm->dma_ch, dma_paddr, dma_size, 63162306a36Sopenharmony_ci dir, 63262306a36Sopenharmony_ci DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 63362306a36Sopenharmony_ci if (!desc) { 63462306a36Sopenharmony_ci dev_err(ssi->dev, "dmaengine_prep_slave_single() fail\n"); 63562306a36Sopenharmony_ci return -ENOMEM; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci desc->callback = rz_ssi_dma_complete; 63962306a36Sopenharmony_ci desc->callback_param = strm; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci if (dmaengine_submit(desc) < 0) { 64262306a36Sopenharmony_ci dev_err(ssi->dev, "dmaengine_submit() fail\n"); 64362306a36Sopenharmony_ci return -EIO; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci /* Update DMA pointer */ 64762306a36Sopenharmony_ci strm->dma_buffer_pos += amount; 64862306a36Sopenharmony_ci if (strm->dma_buffer_pos >= runtime->buffer_size) 64962306a36Sopenharmony_ci strm->dma_buffer_pos = 0; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci /* Start DMA */ 65262306a36Sopenharmony_ci dma_async_issue_pending(strm->dma_ch); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci return 0; 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cistatic void rz_ssi_dma_complete(void *data) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci struct rz_ssi_stream *strm = (struct rz_ssi_stream *)data; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci if (!strm->running || !strm->substream || !strm->substream->runtime) 66262306a36Sopenharmony_ci return; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci /* Note that next DMA transaction has probably already started */ 66562306a36Sopenharmony_ci rz_ssi_pointer_update(strm, strm->substream->runtime->period_size); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* Queue up another DMA transaction */ 66862306a36Sopenharmony_ci rz_ssi_dma_transfer(strm->priv, strm); 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistatic void rz_ssi_release_dma_channels(struct rz_ssi_priv *ssi) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci if (ssi->playback.dma_ch) { 67462306a36Sopenharmony_ci dma_release_channel(ssi->playback.dma_ch); 67562306a36Sopenharmony_ci ssi->playback.dma_ch = NULL; 67662306a36Sopenharmony_ci if (ssi->dma_rt) 67762306a36Sopenharmony_ci ssi->dma_rt = false; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (ssi->capture.dma_ch) { 68162306a36Sopenharmony_ci dma_release_channel(ssi->capture.dma_ch); 68262306a36Sopenharmony_ci ssi->capture.dma_ch = NULL; 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic int rz_ssi_dma_request(struct rz_ssi_priv *ssi, struct device *dev) 68762306a36Sopenharmony_ci{ 68862306a36Sopenharmony_ci ssi->playback.dma_ch = dma_request_chan(dev, "tx"); 68962306a36Sopenharmony_ci if (IS_ERR(ssi->playback.dma_ch)) 69062306a36Sopenharmony_ci ssi->playback.dma_ch = NULL; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci ssi->capture.dma_ch = dma_request_chan(dev, "rx"); 69362306a36Sopenharmony_ci if (IS_ERR(ssi->capture.dma_ch)) 69462306a36Sopenharmony_ci ssi->capture.dma_ch = NULL; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci if (!ssi->playback.dma_ch && !ssi->capture.dma_ch) { 69762306a36Sopenharmony_ci ssi->playback.dma_ch = dma_request_chan(dev, "rt"); 69862306a36Sopenharmony_ci if (IS_ERR(ssi->playback.dma_ch)) { 69962306a36Sopenharmony_ci ssi->playback.dma_ch = NULL; 70062306a36Sopenharmony_ci goto no_dma; 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci ssi->dma_rt = true; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (!rz_ssi_is_dma_enabled(ssi)) 70762306a36Sopenharmony_ci goto no_dma; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci if (ssi->playback.dma_ch && 71062306a36Sopenharmony_ci (rz_ssi_dma_slave_config(ssi, ssi->playback.dma_ch, true) < 0)) 71162306a36Sopenharmony_ci goto no_dma; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci if (ssi->capture.dma_ch && 71462306a36Sopenharmony_ci (rz_ssi_dma_slave_config(ssi, ssi->capture.dma_ch, false) < 0)) 71562306a36Sopenharmony_ci goto no_dma; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci return 0; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_cino_dma: 72062306a36Sopenharmony_ci rz_ssi_release_dma_channels(ssi); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci return -ENODEV; 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_cistatic int rz_ssi_dai_trigger(struct snd_pcm_substream *substream, int cmd, 72662306a36Sopenharmony_ci struct snd_soc_dai *dai) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); 72962306a36Sopenharmony_ci struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream); 73062306a36Sopenharmony_ci int ret = 0, i, num_transfer = 1; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci switch (cmd) { 73362306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 73462306a36Sopenharmony_ci /* Soft Reset */ 73562306a36Sopenharmony_ci rz_ssi_reg_mask_setl(ssi, SSIFCR, 0, SSIFCR_SSIRST); 73662306a36Sopenharmony_ci rz_ssi_reg_mask_setl(ssi, SSIFCR, SSIFCR_SSIRST, 0); 73762306a36Sopenharmony_ci udelay(5); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci rz_ssi_stream_init(strm, substream); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci if (ssi->dma_rt) { 74262306a36Sopenharmony_ci bool is_playback; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci is_playback = rz_ssi_stream_is_play(ssi, substream); 74562306a36Sopenharmony_ci ret = rz_ssi_dma_slave_config(ssi, ssi->playback.dma_ch, 74662306a36Sopenharmony_ci is_playback); 74762306a36Sopenharmony_ci /* Fallback to pio */ 74862306a36Sopenharmony_ci if (ret < 0) { 74962306a36Sopenharmony_ci ssi->playback.transfer = rz_ssi_pio_send; 75062306a36Sopenharmony_ci ssi->capture.transfer = rz_ssi_pio_recv; 75162306a36Sopenharmony_ci rz_ssi_release_dma_channels(ssi); 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci /* For DMA, queue up multiple DMA descriptors */ 75662306a36Sopenharmony_ci if (rz_ssi_is_dma_enabled(ssi)) 75762306a36Sopenharmony_ci num_transfer = 4; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci for (i = 0; i < num_transfer; i++) { 76062306a36Sopenharmony_ci ret = strm->transfer(ssi, strm); 76162306a36Sopenharmony_ci if (ret) 76262306a36Sopenharmony_ci goto done; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci ret = rz_ssi_start(ssi, strm); 76662306a36Sopenharmony_ci break; 76762306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 76862306a36Sopenharmony_ci rz_ssi_stop(ssi, strm); 76962306a36Sopenharmony_ci rz_ssi_stream_quit(ssi, strm); 77062306a36Sopenharmony_ci break; 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cidone: 77462306a36Sopenharmony_ci return ret; 77562306a36Sopenharmony_ci} 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_cistatic int rz_ssi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 78262306a36Sopenharmony_ci case SND_SOC_DAIFMT_BP_FP: 78362306a36Sopenharmony_ci break; 78462306a36Sopenharmony_ci default: 78562306a36Sopenharmony_ci dev_err(ssi->dev, "Codec should be clk and frame consumer\n"); 78662306a36Sopenharmony_ci return -EINVAL; 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci /* 79062306a36Sopenharmony_ci * set clock polarity 79162306a36Sopenharmony_ci * 79262306a36Sopenharmony_ci * "normal" BCLK = Signal is available at rising edge of BCLK 79362306a36Sopenharmony_ci * "normal" FSYNC = (I2S) Left ch starts with falling FSYNC edge 79462306a36Sopenharmony_ci */ 79562306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 79662306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 79762306a36Sopenharmony_ci ssi->bckp_rise = false; 79862306a36Sopenharmony_ci ssi->lrckp_fsync_fall = false; 79962306a36Sopenharmony_ci break; 80062306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_IF: 80162306a36Sopenharmony_ci ssi->bckp_rise = false; 80262306a36Sopenharmony_ci ssi->lrckp_fsync_fall = true; 80362306a36Sopenharmony_ci break; 80462306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 80562306a36Sopenharmony_ci ssi->bckp_rise = true; 80662306a36Sopenharmony_ci ssi->lrckp_fsync_fall = false; 80762306a36Sopenharmony_ci break; 80862306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_IF: 80962306a36Sopenharmony_ci ssi->bckp_rise = true; 81062306a36Sopenharmony_ci ssi->lrckp_fsync_fall = true; 81162306a36Sopenharmony_ci break; 81262306a36Sopenharmony_ci default: 81362306a36Sopenharmony_ci return -EINVAL; 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci /* only i2s support */ 81762306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 81862306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 81962306a36Sopenharmony_ci break; 82062306a36Sopenharmony_ci default: 82162306a36Sopenharmony_ci dev_err(ssi->dev, "Only I2S mode is supported.\n"); 82262306a36Sopenharmony_ci return -EINVAL; 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci return 0; 82662306a36Sopenharmony_ci} 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_cistatic int rz_ssi_dai_hw_params(struct snd_pcm_substream *substream, 82962306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 83062306a36Sopenharmony_ci struct snd_soc_dai *dai) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); 83362306a36Sopenharmony_ci unsigned int sample_bits = hw_param_interval(params, 83462306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min; 83562306a36Sopenharmony_ci unsigned int channels = params_channels(params); 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci if (sample_bits != 16) { 83862306a36Sopenharmony_ci dev_err(ssi->dev, "Unsupported sample width: %d\n", 83962306a36Sopenharmony_ci sample_bits); 84062306a36Sopenharmony_ci return -EINVAL; 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci if (channels != 2) { 84462306a36Sopenharmony_ci dev_err(ssi->dev, "Number of channels not matched: %d\n", 84562306a36Sopenharmony_ci channels); 84662306a36Sopenharmony_ci return -EINVAL; 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci return rz_ssi_clk_setup(ssi, params_rate(params), 85062306a36Sopenharmony_ci params_channels(params)); 85162306a36Sopenharmony_ci} 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_cistatic const struct snd_soc_dai_ops rz_ssi_dai_ops = { 85462306a36Sopenharmony_ci .trigger = rz_ssi_dai_trigger, 85562306a36Sopenharmony_ci .set_fmt = rz_ssi_dai_set_fmt, 85662306a36Sopenharmony_ci .hw_params = rz_ssi_dai_hw_params, 85762306a36Sopenharmony_ci}; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_cistatic const struct snd_pcm_hardware rz_ssi_pcm_hardware = { 86062306a36Sopenharmony_ci .info = SNDRV_PCM_INFO_INTERLEAVED | 86162306a36Sopenharmony_ci SNDRV_PCM_INFO_MMAP | 86262306a36Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID, 86362306a36Sopenharmony_ci .buffer_bytes_max = PREALLOC_BUFFER, 86462306a36Sopenharmony_ci .period_bytes_min = 32, 86562306a36Sopenharmony_ci .period_bytes_max = 8192, 86662306a36Sopenharmony_ci .channels_min = SSI_CHAN_MIN, 86762306a36Sopenharmony_ci .channels_max = SSI_CHAN_MAX, 86862306a36Sopenharmony_ci .periods_min = 1, 86962306a36Sopenharmony_ci .periods_max = 32, 87062306a36Sopenharmony_ci .fifo_size = 32 * 2, 87162306a36Sopenharmony_ci}; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_cistatic int rz_ssi_pcm_open(struct snd_soc_component *component, 87462306a36Sopenharmony_ci struct snd_pcm_substream *substream) 87562306a36Sopenharmony_ci{ 87662306a36Sopenharmony_ci snd_soc_set_runtime_hwparams(substream, &rz_ssi_pcm_hardware); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci return snd_pcm_hw_constraint_integer(substream->runtime, 87962306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIODS); 88062306a36Sopenharmony_ci} 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_cistatic snd_pcm_uframes_t rz_ssi_pcm_pointer(struct snd_soc_component *component, 88362306a36Sopenharmony_ci struct snd_pcm_substream *substream) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci struct snd_soc_dai *dai = rz_ssi_get_dai(substream); 88662306a36Sopenharmony_ci struct rz_ssi_priv *ssi = snd_soc_dai_get_drvdata(dai); 88762306a36Sopenharmony_ci struct rz_ssi_stream *strm = rz_ssi_stream_get(ssi, substream); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci return strm->buffer_pos; 89062306a36Sopenharmony_ci} 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_cistatic int rz_ssi_pcm_new(struct snd_soc_component *component, 89362306a36Sopenharmony_ci struct snd_soc_pcm_runtime *rtd) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, 89662306a36Sopenharmony_ci rtd->card->snd_card->dev, 89762306a36Sopenharmony_ci PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); 89862306a36Sopenharmony_ci return 0; 89962306a36Sopenharmony_ci} 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_cistatic struct snd_soc_dai_driver rz_ssi_soc_dai[] = { 90262306a36Sopenharmony_ci { 90362306a36Sopenharmony_ci .name = "rz-ssi-dai", 90462306a36Sopenharmony_ci .playback = { 90562306a36Sopenharmony_ci .rates = SSI_RATES, 90662306a36Sopenharmony_ci .formats = SSI_FMTS, 90762306a36Sopenharmony_ci .channels_min = SSI_CHAN_MIN, 90862306a36Sopenharmony_ci .channels_max = SSI_CHAN_MAX, 90962306a36Sopenharmony_ci }, 91062306a36Sopenharmony_ci .capture = { 91162306a36Sopenharmony_ci .rates = SSI_RATES, 91262306a36Sopenharmony_ci .formats = SSI_FMTS, 91362306a36Sopenharmony_ci .channels_min = SSI_CHAN_MIN, 91462306a36Sopenharmony_ci .channels_max = SSI_CHAN_MAX, 91562306a36Sopenharmony_ci }, 91662306a36Sopenharmony_ci .ops = &rz_ssi_dai_ops, 91762306a36Sopenharmony_ci }, 91862306a36Sopenharmony_ci}; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_cistatic const struct snd_soc_component_driver rz_ssi_soc_component = { 92162306a36Sopenharmony_ci .name = "rz-ssi", 92262306a36Sopenharmony_ci .open = rz_ssi_pcm_open, 92362306a36Sopenharmony_ci .pointer = rz_ssi_pcm_pointer, 92462306a36Sopenharmony_ci .pcm_construct = rz_ssi_pcm_new, 92562306a36Sopenharmony_ci .legacy_dai_naming = 1, 92662306a36Sopenharmony_ci}; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_cistatic int rz_ssi_probe(struct platform_device *pdev) 92962306a36Sopenharmony_ci{ 93062306a36Sopenharmony_ci struct rz_ssi_priv *ssi; 93162306a36Sopenharmony_ci struct clk *audio_clk; 93262306a36Sopenharmony_ci struct resource *res; 93362306a36Sopenharmony_ci int ret; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), GFP_KERNEL); 93662306a36Sopenharmony_ci if (!ssi) 93762306a36Sopenharmony_ci return -ENOMEM; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci ssi->pdev = pdev; 94062306a36Sopenharmony_ci ssi->dev = &pdev->dev; 94162306a36Sopenharmony_ci ssi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 94262306a36Sopenharmony_ci if (IS_ERR(ssi->base)) 94362306a36Sopenharmony_ci return PTR_ERR(ssi->base); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci ssi->phys = res->start; 94662306a36Sopenharmony_ci ssi->clk = devm_clk_get(&pdev->dev, "ssi"); 94762306a36Sopenharmony_ci if (IS_ERR(ssi->clk)) 94862306a36Sopenharmony_ci return PTR_ERR(ssi->clk); 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci ssi->sfr_clk = devm_clk_get(&pdev->dev, "ssi_sfr"); 95162306a36Sopenharmony_ci if (IS_ERR(ssi->sfr_clk)) 95262306a36Sopenharmony_ci return PTR_ERR(ssi->sfr_clk); 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci audio_clk = devm_clk_get(&pdev->dev, "audio_clk1"); 95562306a36Sopenharmony_ci if (IS_ERR(audio_clk)) 95662306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(audio_clk), 95762306a36Sopenharmony_ci "no audio clk1"); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci ssi->audio_clk_1 = clk_get_rate(audio_clk); 96062306a36Sopenharmony_ci audio_clk = devm_clk_get(&pdev->dev, "audio_clk2"); 96162306a36Sopenharmony_ci if (IS_ERR(audio_clk)) 96262306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(audio_clk), 96362306a36Sopenharmony_ci "no audio clk2"); 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci ssi->audio_clk_2 = clk_get_rate(audio_clk); 96662306a36Sopenharmony_ci if (!(ssi->audio_clk_1 || ssi->audio_clk_2)) 96762306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, -EINVAL, 96862306a36Sopenharmony_ci "no audio clk1 or audio clk2"); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci ssi->audio_mck = ssi->audio_clk_1 ? ssi->audio_clk_1 : ssi->audio_clk_2; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci /* Detect DMA support */ 97362306a36Sopenharmony_ci ret = rz_ssi_dma_request(ssi, &pdev->dev); 97462306a36Sopenharmony_ci if (ret < 0) { 97562306a36Sopenharmony_ci dev_warn(&pdev->dev, "DMA not available, using PIO\n"); 97662306a36Sopenharmony_ci ssi->playback.transfer = rz_ssi_pio_send; 97762306a36Sopenharmony_ci ssi->capture.transfer = rz_ssi_pio_recv; 97862306a36Sopenharmony_ci } else { 97962306a36Sopenharmony_ci dev_info(&pdev->dev, "DMA enabled"); 98062306a36Sopenharmony_ci ssi->playback.transfer = rz_ssi_dma_transfer; 98162306a36Sopenharmony_ci ssi->capture.transfer = rz_ssi_dma_transfer; 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci ssi->playback.priv = ssi; 98562306a36Sopenharmony_ci ssi->capture.priv = ssi; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci spin_lock_init(&ssi->lock); 98862306a36Sopenharmony_ci dev_set_drvdata(&pdev->dev, ssi); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci /* Error Interrupt */ 99162306a36Sopenharmony_ci ssi->irq_int = platform_get_irq_byname(pdev, "int_req"); 99262306a36Sopenharmony_ci if (ssi->irq_int < 0) { 99362306a36Sopenharmony_ci rz_ssi_release_dma_channels(ssi); 99462306a36Sopenharmony_ci return ssi->irq_int; 99562306a36Sopenharmony_ci } 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, ssi->irq_int, &rz_ssi_interrupt, 99862306a36Sopenharmony_ci 0, dev_name(&pdev->dev), ssi); 99962306a36Sopenharmony_ci if (ret < 0) { 100062306a36Sopenharmony_ci rz_ssi_release_dma_channels(ssi); 100162306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, ret, 100262306a36Sopenharmony_ci "irq request error (int_req)\n"); 100362306a36Sopenharmony_ci } 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci if (!rz_ssi_is_dma_enabled(ssi)) { 100662306a36Sopenharmony_ci /* Tx and Rx interrupts (pio only) */ 100762306a36Sopenharmony_ci ssi->irq_tx = platform_get_irq_byname(pdev, "dma_tx"); 100862306a36Sopenharmony_ci ssi->irq_rx = platform_get_irq_byname(pdev, "dma_rx"); 100962306a36Sopenharmony_ci if (ssi->irq_tx == -ENXIO && ssi->irq_rx == -ENXIO) { 101062306a36Sopenharmony_ci ssi->irq_rt = platform_get_irq_byname(pdev, "dma_rt"); 101162306a36Sopenharmony_ci if (ssi->irq_rt < 0) 101262306a36Sopenharmony_ci return ssi->irq_rt; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, ssi->irq_rt, 101562306a36Sopenharmony_ci &rz_ssi_interrupt, 0, 101662306a36Sopenharmony_ci dev_name(&pdev->dev), ssi); 101762306a36Sopenharmony_ci if (ret < 0) 101862306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, ret, 101962306a36Sopenharmony_ci "irq request error (dma_rt)\n"); 102062306a36Sopenharmony_ci } else { 102162306a36Sopenharmony_ci if (ssi->irq_tx < 0) 102262306a36Sopenharmony_ci return ssi->irq_tx; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci if (ssi->irq_rx < 0) 102562306a36Sopenharmony_ci return ssi->irq_rx; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, ssi->irq_tx, 102862306a36Sopenharmony_ci &rz_ssi_interrupt, 0, 102962306a36Sopenharmony_ci dev_name(&pdev->dev), ssi); 103062306a36Sopenharmony_ci if (ret < 0) 103162306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, ret, 103262306a36Sopenharmony_ci "irq request error (dma_tx)\n"); 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, ssi->irq_rx, 103562306a36Sopenharmony_ci &rz_ssi_interrupt, 0, 103662306a36Sopenharmony_ci dev_name(&pdev->dev), ssi); 103762306a36Sopenharmony_ci if (ret < 0) 103862306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, ret, 103962306a36Sopenharmony_ci "irq request error (dma_rx)\n"); 104062306a36Sopenharmony_ci } 104162306a36Sopenharmony_ci } 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci ssi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); 104462306a36Sopenharmony_ci if (IS_ERR(ssi->rstc)) { 104562306a36Sopenharmony_ci ret = PTR_ERR(ssi->rstc); 104662306a36Sopenharmony_ci goto err_reset; 104762306a36Sopenharmony_ci } 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci reset_control_deassert(ssi->rstc); 105062306a36Sopenharmony_ci pm_runtime_enable(&pdev->dev); 105162306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(&pdev->dev); 105262306a36Sopenharmony_ci if (ret < 0) { 105362306a36Sopenharmony_ci dev_err(&pdev->dev, "pm_runtime_resume_and_get failed\n"); 105462306a36Sopenharmony_ci goto err_pm; 105562306a36Sopenharmony_ci } 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, &rz_ssi_soc_component, 105862306a36Sopenharmony_ci rz_ssi_soc_dai, 105962306a36Sopenharmony_ci ARRAY_SIZE(rz_ssi_soc_dai)); 106062306a36Sopenharmony_ci if (ret < 0) { 106162306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to register snd component\n"); 106262306a36Sopenharmony_ci goto err_snd_soc; 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci return 0; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_cierr_snd_soc: 106862306a36Sopenharmony_ci pm_runtime_put(ssi->dev); 106962306a36Sopenharmony_cierr_pm: 107062306a36Sopenharmony_ci pm_runtime_disable(ssi->dev); 107162306a36Sopenharmony_ci reset_control_assert(ssi->rstc); 107262306a36Sopenharmony_cierr_reset: 107362306a36Sopenharmony_ci rz_ssi_release_dma_channels(ssi); 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci return ret; 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_cistatic void rz_ssi_remove(struct platform_device *pdev) 107962306a36Sopenharmony_ci{ 108062306a36Sopenharmony_ci struct rz_ssi_priv *ssi = dev_get_drvdata(&pdev->dev); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci rz_ssi_release_dma_channels(ssi); 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci pm_runtime_put(ssi->dev); 108562306a36Sopenharmony_ci pm_runtime_disable(ssi->dev); 108662306a36Sopenharmony_ci reset_control_assert(ssi->rstc); 108762306a36Sopenharmony_ci} 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_cistatic const struct of_device_id rz_ssi_of_match[] = { 109062306a36Sopenharmony_ci { .compatible = "renesas,rz-ssi", }, 109162306a36Sopenharmony_ci {/* Sentinel */}, 109262306a36Sopenharmony_ci}; 109362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rz_ssi_of_match); 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_cistatic struct platform_driver rz_ssi_driver = { 109662306a36Sopenharmony_ci .driver = { 109762306a36Sopenharmony_ci .name = "rz-ssi-pcm-audio", 109862306a36Sopenharmony_ci .of_match_table = rz_ssi_of_match, 109962306a36Sopenharmony_ci }, 110062306a36Sopenharmony_ci .probe = rz_ssi_probe, 110162306a36Sopenharmony_ci .remove_new = rz_ssi_remove, 110262306a36Sopenharmony_ci}; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_cimodule_platform_driver(rz_ssi_driver); 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 110762306a36Sopenharmony_ciMODULE_DESCRIPTION("Renesas RZ/G2L ASoC Serial Sound Interface Driver"); 110862306a36Sopenharmony_ciMODULE_AUTHOR("Biju Das <biju.das.jz@bp.renesas.com>"); 1109