Commit 12229b7e authored by Venkata Prasad Potturu's avatar Venkata Prasad Potturu Committed by Mark Brown

ASoC: amd: acp: Add TDM support for acp i2s stream

Add callback and code changes to enable ACP I2S controller in TDM
mode. Add new fields in acp_stream and acp_dev_data struct to configure
tdm related registers for ACP i2s controllers.
Signed-off-by: default avatarVenkata Prasad Potturu <venkataprasad.potturu@amd.com>
Link: https://lore.kernel.org/r/20220810132913.1181247-3-venkataprasad.potturu@amd.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 7929985c
...@@ -25,6 +25,65 @@ ...@@ -25,6 +25,65 @@
#define DRV_NAME "acp_i2s_playcap" #define DRV_NAME "acp_i2s_playcap"
static int acp_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
unsigned int fmt)
{
struct acp_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai);
int mode;
mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
switch (mode) {
case SND_SOC_DAIFMT_I2S:
adata->tdm_mode = TDM_DISABLE;
break;
case SND_SOC_DAIFMT_DSP_A:
adata->tdm_mode = TDM_ENABLE;
break;
default:
return -EINVAL;
}
return 0;
}
static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mask,
int slots, int slot_width)
{
struct device *dev = dai->component->dev;
struct acp_dev_data *adata = snd_soc_dai_get_drvdata(dai);
struct acp_stream *stream;
int slot_len;
switch (slot_width) {
case SLOT_WIDTH_8:
slot_len = 8;
break;
case SLOT_WIDTH_16:
slot_len = 16;
break;
case SLOT_WIDTH_24:
slot_len = 24;
break;
case SLOT_WIDTH_32:
slot_len = 0;
break;
default:
dev_err(dev, "Unsupported bitdepth %d\n", slot_width);
return -EINVAL;
}
spin_lock_irq(&adata->acp_lock);
list_for_each_entry(stream, &adata->stream_list, list) {
if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK)
adata->tdm_tx_fmt[stream->dai_id - 1] =
FRM_LEN | (slots << 15) | (slot_len << 18);
else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE)
adata->tdm_rx_fmt[stream->dai_id - 1] =
FRM_LEN | (slots << 15) | (slot_len << 18);
}
spin_unlock_irq(&adata->acp_lock);
return 0;
}
static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
...@@ -33,7 +92,7 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ ...@@ -33,7 +92,7 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
struct acp_resource *rsrc; struct acp_resource *rsrc;
u32 val; u32 val;
u32 xfer_resolution; u32 xfer_resolution;
u32 reg_val; u32 reg_val, fmt_reg, tdm_fmt;
u32 lrclk_div_val, bclk_div_val; u32 lrclk_div_val, bclk_div_val;
adata = snd_soc_dai_get_drvdata(dai); adata = snd_soc_dai_get_drvdata(dai);
...@@ -62,12 +121,15 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ ...@@ -62,12 +121,15 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
switch (dai->driver->id) { switch (dai->driver->id) {
case I2S_BT_INSTANCE: case I2S_BT_INSTANCE:
reg_val = ACP_BTTDM_ITER; reg_val = ACP_BTTDM_ITER;
fmt_reg = ACP_BTTDM_TXFRMT;
break; break;
case I2S_SP_INSTANCE: case I2S_SP_INSTANCE:
reg_val = ACP_I2STDM_ITER; reg_val = ACP_I2STDM_ITER;
fmt_reg = ACP_I2STDM_TXFRMT;
break; break;
case I2S_HS_INSTANCE: case I2S_HS_INSTANCE:
reg_val = ACP_HSTDM_ITER; reg_val = ACP_HSTDM_ITER;
fmt_reg = ACP_HSTDM_TXFRMT;
break; break;
default: default:
dev_err(dev, "Invalid dai id %x\n", dai->driver->id); dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
...@@ -77,12 +139,15 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ ...@@ -77,12 +139,15 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
switch (dai->driver->id) { switch (dai->driver->id) {
case I2S_BT_INSTANCE: case I2S_BT_INSTANCE:
reg_val = ACP_BTTDM_IRER; reg_val = ACP_BTTDM_IRER;
fmt_reg = ACP_BTTDM_RXFRMT;
break; break;
case I2S_SP_INSTANCE: case I2S_SP_INSTANCE:
reg_val = ACP_I2STDM_IRER; reg_val = ACP_I2STDM_IRER;
fmt_reg = ACP_I2STDM_RXFRMT;
break; break;
case I2S_HS_INSTANCE: case I2S_HS_INSTANCE:
reg_val = ACP_HSTDM_IRER; reg_val = ACP_HSTDM_IRER;
fmt_reg = ACP_HSTDM_RXFRMT;
break; break;
default: default:
dev_err(dev, "Invalid dai id %x\n", dai->driver->id); dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
...@@ -95,6 +160,16 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ ...@@ -95,6 +160,16 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
val = val | (xfer_resolution << 3); val = val | (xfer_resolution << 3);
writel(val, adata->acp_base + reg_val); writel(val, adata->acp_base + reg_val);
if (adata->tdm_mode) {
val = readl(adata->acp_base + reg_val);
writel(val | BIT(1), adata->acp_base + reg_val);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
tdm_fmt = adata->tdm_tx_fmt[dai->driver->id - 1];
else
tdm_fmt = adata->tdm_rx_fmt[dai->driver->id - 1];
writel(tdm_fmt, adata->acp_base + fmt_reg);
}
if (rsrc->soc_mclk) { if (rsrc->soc_mclk) {
switch (params_format(params)) { switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE: case SNDRV_PCM_FORMAT_S16_LE:
...@@ -443,6 +518,7 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d ...@@ -443,6 +518,7 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d
stream->id = dai->driver->id + dir; stream->id = dai->driver->id + dir;
stream->dai_id = dai->driver->id; stream->dai_id = dai->driver->id;
stream->irq_bit = irq_bit; stream->irq_bit = irq_bit;
stream->dir = substream->stream;
return 0; return 0;
} }
...@@ -452,6 +528,8 @@ const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = { ...@@ -452,6 +528,8 @@ const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
.hw_params = acp_i2s_hwparams, .hw_params = acp_i2s_hwparams,
.prepare = acp_i2s_prepare, .prepare = acp_i2s_prepare,
.trigger = acp_i2s_trigger, .trigger = acp_i2s_trigger,
.set_fmt = acp_i2s_set_fmt,
.set_tdm_slot = acp_i2s_set_tdm_slot,
}; };
EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON); EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, SND_SOC_ACP_COMMON);
......
...@@ -84,6 +84,14 @@ ...@@ -84,6 +84,14 @@
#define ACP_MAX_STREAM 8 #define ACP_MAX_STREAM 8
#define TDM_ENABLE 1
#define TDM_DISABLE 0
#define SLOT_WIDTH_8 0x8
#define SLOT_WIDTH_16 0x10
#define SLOT_WIDTH_24 0x18
#define SLOT_WIDTH_32 0x20
struct acp_chip_info { struct acp_chip_info {
char *name; /* Platform name */ char *name; /* Platform name */
unsigned int acp_rev; /* ACP Revision id */ unsigned int acp_rev; /* ACP Revision id */
...@@ -96,6 +104,7 @@ struct acp_stream { ...@@ -96,6 +104,7 @@ struct acp_stream {
int irq_bit; int irq_bit;
int dai_id; int dai_id;
int id; int id;
int dir;
u64 bytescount; u64 bytescount;
u32 reg_offset; u32 reg_offset;
u32 pte_offset; u32 pte_offset;
...@@ -120,6 +129,7 @@ struct acp_dev_data { ...@@ -120,6 +129,7 @@ struct acp_dev_data {
void __iomem *acp_base; void __iomem *acp_base;
unsigned int i2s_irq; unsigned int i2s_irq;
bool tdm_mode;
/* SOC specific dais */ /* SOC specific dais */
struct snd_soc_dai_driver *dai_driver; struct snd_soc_dai_driver *dai_driver;
int num_dai; int num_dai;
...@@ -134,6 +144,8 @@ struct acp_dev_data { ...@@ -134,6 +144,8 @@ struct acp_dev_data {
u32 lrclk_div; u32 lrclk_div;
struct acp_resource *rsrc; struct acp_resource *rsrc;
u32 tdm_tx_fmt[3];
u32 tdm_rx_fmt[3];
}; };
union acp_i2stdm_mstrclkgen { union acp_i2stdm_mstrclkgen {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment