mirror of https://gitee.com/openkylin/linux.git
Merge remote-tracking branches 'asoc/topic/pxa' and 'asoc/topic/qcom' into asoc-next
This commit is contained in:
commit
f2d4c127f7
|
@ -52,7 +52,6 @@ static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
|
||||
int freq_out, sspa_mclk, sysclk;
|
||||
int sspa_div;
|
||||
|
||||
if (params_rate(params) > 11025) {
|
||||
freq_out = params_rate(params) * 512;
|
||||
|
@ -63,7 +62,6 @@ static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream,
|
|||
sysclk = params_rate(params) * 512;
|
||||
sspa_mclk = params_rate(params) * 64;
|
||||
}
|
||||
sspa_div = freq_out / sspa_mclk;
|
||||
|
||||
snd_soc_dai_set_sysclk(cpu_dai, MMP_SSPA_CLK_AUDIO, freq_out, 0);
|
||||
snd_soc_dai_set_pll(cpu_dai, MMP_SYSCLK, 0, freq_out, sysclk);
|
||||
|
|
|
@ -11,21 +11,24 @@ config SND_SOC_LPASS_CPU
|
|||
|
||||
config SND_SOC_LPASS_PLATFORM
|
||||
tristate
|
||||
depends on HAS_DMA
|
||||
select REGMAP_MMIO
|
||||
|
||||
config SND_SOC_LPASS_IPQ806X
|
||||
tristate
|
||||
depends on HAS_DMA
|
||||
select SND_SOC_LPASS_CPU
|
||||
select SND_SOC_LPASS_PLATFORM
|
||||
|
||||
config SND_SOC_LPASS_APQ8016
|
||||
tristate
|
||||
depends on HAS_DMA
|
||||
select SND_SOC_LPASS_CPU
|
||||
select SND_SOC_LPASS_PLATFORM
|
||||
|
||||
config SND_SOC_STORM
|
||||
tristate "ASoC I2S support for Storm boards"
|
||||
depends on SND_SOC_QCOM
|
||||
depends on SND_SOC_QCOM && HAS_DMA
|
||||
select SND_SOC_LPASS_IPQ806X
|
||||
select SND_SOC_MAX98357A
|
||||
help
|
||||
|
@ -34,7 +37,7 @@ config SND_SOC_STORM
|
|||
|
||||
config SND_SOC_APQ8016_SBC
|
||||
tristate "SoC Audio support for APQ8016 SBC platforms"
|
||||
depends on SND_SOC_QCOM
|
||||
depends on SND_SOC_QCOM && HAS_DMA
|
||||
select SND_SOC_LPASS_APQ8016
|
||||
help
|
||||
Support for Qualcomm Technologies LPASS audio block in
|
||||
|
|
|
@ -30,6 +30,7 @@ struct apq8016_sbc_data {
|
|||
struct snd_soc_dai_link dai_link[]; /* dynamically allocated */
|
||||
};
|
||||
|
||||
#define MIC_CTRL_TER_WS_SLAVE_SEL BIT(21)
|
||||
#define MIC_CTRL_QUA_WS_SLAVE_SEL_10 BIT(17)
|
||||
#define MIC_CTRL_TLMM_SCLK_EN BIT(1)
|
||||
#define SPKR_CTL_PRI_WS_SLAVE_SEL_11 (BIT(17) | BIT(16))
|
||||
|
@ -53,6 +54,12 @@ static int apq8016_sbc_dai_init(struct snd_soc_pcm_runtime *rtd)
|
|||
MIC_CTRL_TLMM_SCLK_EN,
|
||||
pdata->mic_iomux);
|
||||
break;
|
||||
case MI2S_TERTIARY:
|
||||
writel(readl(pdata->mic_iomux) | MIC_CTRL_TER_WS_SLAVE_SEL |
|
||||
MIC_CTRL_TLMM_SCLK_EN,
|
||||
pdata->mic_iomux);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(card->dev, "unsupported cpu dai configuration\n");
|
||||
|
@ -126,9 +133,6 @@ static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card)
|
|||
}
|
||||
|
||||
link->platform_of_node = link->cpu_of_node;
|
||||
/* For now we only support playback */
|
||||
link->playback_only = true;
|
||||
|
||||
ret = of_property_read_string(np, "link-name", &link->name);
|
||||
if (ret) {
|
||||
dev_err(card->dev, "error getting codec dai_link name\n");
|
||||
|
|
|
@ -133,23 +133,36 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata)
|
||||
static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata,
|
||||
int direction)
|
||||
{
|
||||
struct lpass_variant *v = drvdata->variant;
|
||||
int chan = find_first_zero_bit(&drvdata->rdma_ch_bit_map,
|
||||
int chan = 0;
|
||||
|
||||
if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
chan = find_first_zero_bit(&drvdata->dma_ch_bit_map,
|
||||
v->rdma_channels);
|
||||
|
||||
if (chan >= v->rdma_channels)
|
||||
return -EBUSY;
|
||||
if (chan >= v->rdma_channels)
|
||||
return -EBUSY;
|
||||
} else {
|
||||
chan = find_next_zero_bit(&drvdata->dma_ch_bit_map,
|
||||
v->wrdma_channel_start +
|
||||
v->wrdma_channels,
|
||||
v->wrdma_channel_start);
|
||||
|
||||
set_bit(chan, &drvdata->rdma_ch_bit_map);
|
||||
if (chan >= v->wrdma_channel_start + v->wrdma_channels)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
set_bit(chan, &drvdata->dma_ch_bit_map);
|
||||
|
||||
return chan;
|
||||
}
|
||||
|
||||
static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int chan)
|
||||
{
|
||||
clear_bit(chan, &drvdata->rdma_ch_bit_map);
|
||||
clear_bit(chan, &drvdata->dma_ch_bit_map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -212,7 +225,11 @@ static struct lpass_variant apq8016_data = {
|
|||
.rdma_reg_base = 0x8400,
|
||||
.rdma_reg_stride = 0x1000,
|
||||
.rdma_channels = 2,
|
||||
.rdmactl_audif_start = 1,
|
||||
.dmactl_audif_start = 1,
|
||||
.wrdma_reg_base = 0xB000,
|
||||
.wrdma_reg_stride = 0x1000,
|
||||
.wrdma_channel_start = 5,
|
||||
.wrdma_channels = 2,
|
||||
.dai_driver = apq8016_lpass_cpu_dai_driver,
|
||||
.num_dai = ARRAY_SIZE(apq8016_lpass_cpu_dai_driver),
|
||||
.init = apq8016_lpass_init,
|
||||
|
|
|
@ -120,31 +120,60 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (channels) {
|
||||
case 1:
|
||||
regval |= LPAIF_I2SCTL_SPKMODE_SD0;
|
||||
regval |= LPAIF_I2SCTL_SPKMONO_MONO;
|
||||
break;
|
||||
case 2:
|
||||
regval |= LPAIF_I2SCTL_SPKMODE_SD0;
|
||||
regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
|
||||
break;
|
||||
case 4:
|
||||
regval |= LPAIF_I2SCTL_SPKMODE_QUAD01;
|
||||
regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
|
||||
break;
|
||||
case 6:
|
||||
regval |= LPAIF_I2SCTL_SPKMODE_6CH;
|
||||
regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
|
||||
break;
|
||||
case 8:
|
||||
regval |= LPAIF_I2SCTL_SPKMODE_8CH;
|
||||
regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
|
||||
break;
|
||||
default:
|
||||
dev_err(dai->dev, "%s() invalid channels given: %u\n",
|
||||
__func__, channels);
|
||||
return -EINVAL;
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
switch (channels) {
|
||||
case 1:
|
||||
regval |= LPAIF_I2SCTL_SPKMODE_SD0;
|
||||
regval |= LPAIF_I2SCTL_SPKMONO_MONO;
|
||||
break;
|
||||
case 2:
|
||||
regval |= LPAIF_I2SCTL_SPKMODE_SD0;
|
||||
regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
|
||||
break;
|
||||
case 4:
|
||||
regval |= LPAIF_I2SCTL_SPKMODE_QUAD01;
|
||||
regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
|
||||
break;
|
||||
case 6:
|
||||
regval |= LPAIF_I2SCTL_SPKMODE_6CH;
|
||||
regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
|
||||
break;
|
||||
case 8:
|
||||
regval |= LPAIF_I2SCTL_SPKMODE_8CH;
|
||||
regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
|
||||
break;
|
||||
default:
|
||||
dev_err(dai->dev, "%s() invalid channels given: %u\n",
|
||||
__func__, channels);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
switch (channels) {
|
||||
case 1:
|
||||
regval |= LPAIF_I2SCTL_MICMODE_SD0;
|
||||
regval |= LPAIF_I2SCTL_MICMONO_MONO;
|
||||
break;
|
||||
case 2:
|
||||
regval |= LPAIF_I2SCTL_MICMODE_SD0;
|
||||
regval |= LPAIF_I2SCTL_MICMONO_STEREO;
|
||||
break;
|
||||
case 4:
|
||||
regval |= LPAIF_I2SCTL_MICMODE_QUAD01;
|
||||
regval |= LPAIF_I2SCTL_MICMONO_STEREO;
|
||||
break;
|
||||
case 6:
|
||||
regval |= LPAIF_I2SCTL_MICMODE_6CH;
|
||||
regval |= LPAIF_I2SCTL_MICMONO_STEREO;
|
||||
break;
|
||||
case 8:
|
||||
regval |= LPAIF_I2SCTL_MICMODE_8CH;
|
||||
regval |= LPAIF_I2SCTL_MICMONO_STEREO;
|
||||
break;
|
||||
default:
|
||||
dev_err(dai->dev, "%s() invalid channels given: %u\n",
|
||||
__func__, channels);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
ret = regmap_write(drvdata->lpaif_map,
|
||||
|
@ -188,10 +217,19 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
|
|||
{
|
||||
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
|
||||
int ret;
|
||||
unsigned int val, mask;
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
val = LPAIF_I2SCTL_SPKEN_ENABLE;
|
||||
mask = LPAIF_I2SCTL_SPKEN_MASK;
|
||||
} else {
|
||||
val = LPAIF_I2SCTL_MICEN_ENABLE;
|
||||
mask = LPAIF_I2SCTL_MICEN_MASK;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(drvdata->lpaif_map,
|
||||
LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
|
||||
LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE);
|
||||
mask, val);
|
||||
if (ret)
|
||||
dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
|
||||
__func__, ret);
|
||||
|
@ -204,16 +242,24 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
|
|||
{
|
||||
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
|
||||
int ret = -EINVAL;
|
||||
unsigned int val, mask;
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
val = LPAIF_I2SCTL_SPKEN_ENABLE;
|
||||
mask = LPAIF_I2SCTL_SPKEN_MASK;
|
||||
} else {
|
||||
val = LPAIF_I2SCTL_MICEN_ENABLE;
|
||||
mask = LPAIF_I2SCTL_MICEN_MASK;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(drvdata->lpaif_map,
|
||||
LPAIF_I2SCTL_REG(drvdata->variant,
|
||||
dai->driver->id),
|
||||
LPAIF_I2SCTL_SPKEN_MASK,
|
||||
LPAIF_I2SCTL_SPKEN_ENABLE);
|
||||
mask, val);
|
||||
if (ret)
|
||||
dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
|
||||
__func__, ret);
|
||||
|
@ -221,11 +267,18 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
|
|||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
val = LPAIF_I2SCTL_SPKEN_DISABLE;
|
||||
mask = LPAIF_I2SCTL_SPKEN_MASK;
|
||||
} else {
|
||||
val = LPAIF_I2SCTL_MICEN_DISABLE;
|
||||
mask = LPAIF_I2SCTL_MICEN_MASK;
|
||||
}
|
||||
|
||||
ret = regmap_update_bits(drvdata->lpaif_map,
|
||||
LPAIF_I2SCTL_REG(drvdata->variant,
|
||||
dai->driver->id),
|
||||
LPAIF_I2SCTL_SPKEN_MASK,
|
||||
LPAIF_I2SCTL_SPKEN_DISABLE);
|
||||
mask, val);
|
||||
if (ret)
|
||||
dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
|
||||
__func__, ret);
|
||||
|
@ -294,6 +347,17 @@ static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
|
|||
return true;
|
||||
}
|
||||
|
||||
for (i = 0; i < v->wrdma_channels; ++i) {
|
||||
if (reg == LPAIF_WRDMACTL_REG(v, i + v->wrdma_channel_start))
|
||||
return true;
|
||||
if (reg == LPAIF_WRDMABASE_REG(v, i + v->wrdma_channel_start))
|
||||
return true;
|
||||
if (reg == LPAIF_WRDMABUFF_REG(v, i + v->wrdma_channel_start))
|
||||
return true;
|
||||
if (reg == LPAIF_WRDMAPER_REG(v, i + v->wrdma_channel_start))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -327,6 +391,19 @@ static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
|
|||
return true;
|
||||
}
|
||||
|
||||
for (i = 0; i < v->wrdma_channels; ++i) {
|
||||
if (reg == LPAIF_WRDMACTL_REG(v, i + v->wrdma_channel_start))
|
||||
return true;
|
||||
if (reg == LPAIF_WRDMABASE_REG(v, i + v->wrdma_channel_start))
|
||||
return true;
|
||||
if (reg == LPAIF_WRDMABUFF_REG(v, i + v->wrdma_channel_start))
|
||||
return true;
|
||||
if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start))
|
||||
return true;
|
||||
if (reg == LPAIF_WRDMAPER_REG(v, i + v->wrdma_channel_start))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -344,6 +421,10 @@ static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg)
|
|||
if (reg == LPAIF_RDMACURR_REG(v, i))
|
||||
return true;
|
||||
|
||||
for (i = 0; i < v->wrdma_channels; ++i)
|
||||
if (reg == LPAIF_WRDMACURR_REG(v, i + v->wrdma_channel_start))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -398,8 +479,9 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
|
|||
return PTR_ERR((void const __force *)drvdata->lpaif);
|
||||
}
|
||||
|
||||
lpass_cpu_regmap_config.max_register = LPAIF_RDMAPER_REG(variant,
|
||||
variant->rdma_channels);
|
||||
lpass_cpu_regmap_config.max_register = LPAIF_WRDMAPER_REG(variant,
|
||||
variant->wrdma_channels +
|
||||
variant->wrdma_channel_start);
|
||||
|
||||
drvdata->lpaif_map = devm_regmap_init_mmio(&pdev->dev, drvdata->lpaif,
|
||||
&lpass_cpu_regmap_config);
|
||||
|
|
|
@ -63,9 +63,12 @@ static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = {
|
|||
.ops = &asoc_qcom_lpass_cpu_dai_ops,
|
||||
};
|
||||
|
||||
static int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata)
|
||||
static int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata, int dir)
|
||||
{
|
||||
return IPQ806X_LPAIF_RDMA_CHAN_MI2S;
|
||||
if (dir == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
return IPQ806X_LPAIF_RDMA_CHAN_MI2S;
|
||||
else /* Capture currently not implemented */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int ipq806x_lpass_free_dma_channel(struct lpass_data *drvdata, int chan)
|
||||
|
@ -83,6 +86,10 @@ static struct lpass_variant ipq806x_data = {
|
|||
.rdma_reg_base = 0x6000,
|
||||
.rdma_reg_stride = 0x1000,
|
||||
.rdma_channels = 4,
|
||||
.wrdma_reg_base = 0xB000,
|
||||
.wrdma_reg_stride = 0x1000,
|
||||
.wrdma_channel_start = 5,
|
||||
.wrdma_channels = 4,
|
||||
.dai_driver = &ipq806x_lpass_cpu_dai_driver,
|
||||
.num_dai = 1,
|
||||
.alloc_dma_channel = ipq806x_lpass_alloc_dma_channel,
|
||||
|
|
|
@ -47,6 +47,28 @@
|
|||
#define LPAIF_I2SCTL_SPKMONO_STEREO (0 << LPAIF_I2SCTL_SPKMONO_SHIFT)
|
||||
#define LPAIF_I2SCTL_SPKMONO_MONO (1 << LPAIF_I2SCTL_SPKMONO_SHIFT)
|
||||
|
||||
#define LPAIF_I2SCTL_MICEN_MASK GENMASK(8, 8)
|
||||
#define LPAIF_I2SCTL_MICEN_SHIFT 8
|
||||
#define LPAIF_I2SCTL_MICEN_DISABLE (0 << LPAIF_I2SCTL_MICEN_SHIFT)
|
||||
#define LPAIF_I2SCTL_MICEN_ENABLE (1 << LPAIF_I2SCTL_MICEN_SHIFT)
|
||||
|
||||
#define LPAIF_I2SCTL_MICMODE_MASK GENMASK(7, 4)
|
||||
#define LPAIF_I2SCTL_MICMODE_SHIFT 4
|
||||
#define LPAIF_I2SCTL_MICMODE_NONE (0 << LPAIF_I2SCTL_MICMODE_SHIFT)
|
||||
#define LPAIF_I2SCTL_MICMODE_SD0 (1 << LPAIF_I2SCTL_MICMODE_SHIFT)
|
||||
#define LPAIF_I2SCTL_MICMODE_SD1 (2 << LPAIF_I2SCTL_MICMODE_SHIFT)
|
||||
#define LPAIF_I2SCTL_MICMODE_SD2 (3 << LPAIF_I2SCTL_MICMODE_SHIFT)
|
||||
#define LPAIF_I2SCTL_MICMODE_SD3 (4 << LPAIF_I2SCTL_MICMODE_SHIFT)
|
||||
#define LPAIF_I2SCTL_MICMODE_QUAD01 (5 << LPAIF_I2SCTL_MICMODE_SHIFT)
|
||||
#define LPAIF_I2SCTL_MICMODE_QUAD23 (6 << LPAIF_I2SCTL_MICMODE_SHIFT)
|
||||
#define LPAIF_I2SCTL_MICMODE_6CH (7 << LPAIF_I2SCTL_MICMODE_SHIFT)
|
||||
#define LPAIF_I2SCTL_MICMODE_8CH (8 << LPAIF_I2SCTL_MICMODE_SHIFT)
|
||||
|
||||
#define LPAIF_I2SCTL_MIMONO_MASK GENMASK(3, 3)
|
||||
#define LPAIF_I2SCTL_MICMONO_SHIFT 3
|
||||
#define LPAIF_I2SCTL_MICMONO_STEREO (0 << LPAIF_I2SCTL_MICMONO_SHIFT)
|
||||
#define LPAIF_I2SCTL_MICMONO_MONO (1 << LPAIF_I2SCTL_MICMONO_SHIFT)
|
||||
|
||||
#define LPAIF_I2SCTL_WSSRC_MASK 0x0004
|
||||
#define LPAIF_I2SCTL_WSSRC_SHIFT 2
|
||||
#define LPAIF_I2SCTL_WSSRC_INTERNAL (0 << LPAIF_I2SCTL_WSSRC_SHIFT)
|
||||
|
@ -90,37 +112,65 @@
|
|||
#define LPAIF_RDMAPER_REG(v, chan) LPAIF_RDMA_REG_ADDR(v, 0x10, (chan))
|
||||
#define LPAIF_RDMAPERCNT_REG(v, chan) LPAIF_RDMA_REG_ADDR(v, 0x14, (chan))
|
||||
|
||||
#define LPAIF_RDMACTL_BURSTEN_MASK 0x800
|
||||
#define LPAIF_RDMACTL_BURSTEN_SHIFT 11
|
||||
#define LPAIF_RDMACTL_BURSTEN_SINGLE (0 << LPAIF_RDMACTL_BURSTEN_SHIFT)
|
||||
#define LPAIF_RDMACTL_BURSTEN_INCR4 (1 << LPAIF_RDMACTL_BURSTEN_SHIFT)
|
||||
#define LPAIF_WRDMA_REG_ADDR(v, addr, chan) \
|
||||
(v->wrdma_reg_base + (addr) + \
|
||||
v->wrdma_reg_stride * (chan - v->wrdma_channel_start))
|
||||
|
||||
#define LPAIF_RDMACTL_WPSCNT_MASK 0x700
|
||||
#define LPAIF_RDMACTL_WPSCNT_SHIFT 8
|
||||
#define LPAIF_RDMACTL_WPSCNT_ONE (0 << LPAIF_RDMACTL_WPSCNT_SHIFT)
|
||||
#define LPAIF_RDMACTL_WPSCNT_TWO (1 << LPAIF_RDMACTL_WPSCNT_SHIFT)
|
||||
#define LPAIF_RDMACTL_WPSCNT_THREE (2 << LPAIF_RDMACTL_WPSCNT_SHIFT)
|
||||
#define LPAIF_RDMACTL_WPSCNT_FOUR (3 << LPAIF_RDMACTL_WPSCNT_SHIFT)
|
||||
#define LPAIF_RDMACTL_WPSCNT_SIX (5 << LPAIF_RDMACTL_WPSCNT_SHIFT)
|
||||
#define LPAIF_RDMACTL_WPSCNT_EIGHT (7 << LPAIF_RDMACTL_WPSCNT_SHIFT)
|
||||
#define LPAIF_WRDMACTL_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x00, (chan))
|
||||
#define LPAIF_WRDMABASE_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x04, (chan))
|
||||
#define LPAIF_WRDMABUFF_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x08, (chan))
|
||||
#define LPAIF_WRDMACURR_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x0C, (chan))
|
||||
#define LPAIF_WRDMAPER_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x10, (chan))
|
||||
#define LPAIF_WRDMAPERCNT_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x14, (chan))
|
||||
|
||||
#define LPAIF_RDMACTL_AUDINTF_MASK 0x0F0
|
||||
#define LPAIF_RDMACTL_AUDINTF_SHIFT 4
|
||||
#define __LPAIF_DMA_REG(v, chan, dir, reg) \
|
||||
(dir == SNDRV_PCM_STREAM_PLAYBACK) ? \
|
||||
LPAIF_RDMA##reg##_REG(v, chan) : \
|
||||
LPAIF_WRDMA##reg##_REG(v, chan)
|
||||
|
||||
#define LPAIF_RDMACTL_FIFOWM_MASK 0x00E
|
||||
#define LPAIF_RDMACTL_FIFOWM_SHIFT 1
|
||||
#define LPAIF_RDMACTL_FIFOWM_1 (0 << LPAIF_RDMACTL_FIFOWM_SHIFT)
|
||||
#define LPAIF_RDMACTL_FIFOWM_2 (1 << LPAIF_RDMACTL_FIFOWM_SHIFT)
|
||||
#define LPAIF_RDMACTL_FIFOWM_3 (2 << LPAIF_RDMACTL_FIFOWM_SHIFT)
|
||||
#define LPAIF_RDMACTL_FIFOWM_4 (3 << LPAIF_RDMACTL_FIFOWM_SHIFT)
|
||||
#define LPAIF_RDMACTL_FIFOWM_5 (4 << LPAIF_RDMACTL_FIFOWM_SHIFT)
|
||||
#define LPAIF_RDMACTL_FIFOWM_6 (5 << LPAIF_RDMACTL_FIFOWM_SHIFT)
|
||||
#define LPAIF_RDMACTL_FIFOWM_7 (6 << LPAIF_RDMACTL_FIFOWM_SHIFT)
|
||||
#define LPAIF_RDMACTL_FIFOWM_8 (7 << LPAIF_RDMACTL_FIFOWM_SHIFT)
|
||||
#define LPAIF_DMACTL_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, CTL)
|
||||
#define LPAIF_DMABASE_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, BASE)
|
||||
#define LPAIF_DMABUFF_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, BUFF)
|
||||
#define LPAIF_DMACURR_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, CURR)
|
||||
#define LPAIF_DMAPER_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, PER)
|
||||
#define LPAIF_DMAPERCNT_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, PERCNT)
|
||||
|
||||
#define LPAIF_RDMACTL_ENABLE_MASK 0x1
|
||||
#define LPAIF_RDMACTL_ENABLE_SHIFT 0
|
||||
#define LPAIF_RDMACTL_ENABLE_OFF (0 << LPAIF_RDMACTL_ENABLE_SHIFT)
|
||||
#define LPAIF_RDMACTL_ENABLE_ON (1 << LPAIF_RDMACTL_ENABLE_SHIFT)
|
||||
#define LPAIF_DMACTL_BURSTEN_MASK 0x800
|
||||
#define LPAIF_DMACTL_BURSTEN_SHIFT 11
|
||||
#define LPAIF_DMACTL_BURSTEN_SINGLE (0 << LPAIF_DMACTL_BURSTEN_SHIFT)
|
||||
#define LPAIF_DMACTL_BURSTEN_INCR4 (1 << LPAIF_DMACTL_BURSTEN_SHIFT)
|
||||
|
||||
#define LPAIF_DMACTL_WPSCNT_MASK 0x700
|
||||
#define LPAIF_DMACTL_WPSCNT_SHIFT 8
|
||||
#define LPAIF_DMACTL_WPSCNT_ONE (0 << LPAIF_DMACTL_WPSCNT_SHIFT)
|
||||
#define LPAIF_DMACTL_WPSCNT_TWO (1 << LPAIF_DMACTL_WPSCNT_SHIFT)
|
||||
#define LPAIF_DMACTL_WPSCNT_THREE (2 << LPAIF_DMACTL_WPSCNT_SHIFT)
|
||||
#define LPAIF_DMACTL_WPSCNT_FOUR (3 << LPAIF_DMACTL_WPSCNT_SHIFT)
|
||||
#define LPAIF_DMACTL_WPSCNT_SIX (5 << LPAIF_DMACTL_WPSCNT_SHIFT)
|
||||
#define LPAIF_DMACTL_WPSCNT_EIGHT (7 << LPAIF_DMACTL_WPSCNT_SHIFT)
|
||||
|
||||
#define LPAIF_DMACTL_AUDINTF_MASK 0x0F0
|
||||
#define LPAIF_DMACTL_AUDINTF_SHIFT 4
|
||||
#define LPAIF_DMACTL_AUDINTF(id) (id << LPAIF_DMACTL_AUDINTF_SHIFT)
|
||||
|
||||
#define LPAIF_DMACTL_FIFOWM_MASK 0x00E
|
||||
#define LPAIF_DMACTL_FIFOWM_SHIFT 1
|
||||
#define LPAIF_DMACTL_FIFOWM_1 (0 << LPAIF_DMACTL_FIFOWM_SHIFT)
|
||||
#define LPAIF_DMACTL_FIFOWM_2 (1 << LPAIF_DMACTL_FIFOWM_SHIFT)
|
||||
#define LPAIF_DMACTL_FIFOWM_3 (2 << LPAIF_DMACTL_FIFOWM_SHIFT)
|
||||
#define LPAIF_DMACTL_FIFOWM_4 (3 << LPAIF_DMACTL_FIFOWM_SHIFT)
|
||||
#define LPAIF_DMACTL_FIFOWM_5 (4 << LPAIF_DMACTL_FIFOWM_SHIFT)
|
||||
#define LPAIF_DMACTL_FIFOWM_6 (5 << LPAIF_DMACTL_FIFOWM_SHIFT)
|
||||
#define LPAIF_DMACTL_FIFOWM_7 (6 << LPAIF_DMACTL_FIFOWM_SHIFT)
|
||||
#define LPAIF_DMACTL_FIFOWM_8 (7 << LPAIF_DMACTL_FIFOWM_SHIFT)
|
||||
|
||||
#define LPAIF_DMACTL_ENABLE_MASK 0x1
|
||||
#define LPAIF_DMACTL_ENABLE_SHIFT 0
|
||||
#define LPAIF_DMACTL_ENABLE_OFF (0 << LPAIF_DMACTL_ENABLE_SHIFT)
|
||||
#define LPAIF_DMACTL_ENABLE_ON (1 << LPAIF_DMACTL_ENABLE_SHIFT)
|
||||
|
||||
#define LPAIF_DMACTL_DYNCLK_MASK BIT(12)
|
||||
#define LPAIF_DMACTL_DYNCLK_SHIFT 12
|
||||
#define LPAIF_DMACTL_DYNCLK_OFF (0 << LPAIF_DMACTL_DYNCLK_SHIFT)
|
||||
#define LPAIF_DMACTL_DYNCLK_ON (1 << LPAIF_DMACTL_DYNCLK_SHIFT)
|
||||
#endif /* __LPASS_LPAIF_REG_H__ */
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
struct lpass_pcm_data {
|
||||
int rdma_ch;
|
||||
int wrdma_ch;
|
||||
int i2s_port;
|
||||
};
|
||||
|
||||
|
@ -90,8 +91,14 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
|
|||
snd_pcm_format_t format = params_format(params);
|
||||
unsigned int channels = params_channels(params);
|
||||
unsigned int regval;
|
||||
int ch, dir = substream->stream;
|
||||
int bitwidth;
|
||||
int ret, rdma_port = pcm_data->i2s_port + v->rdmactl_audif_start;
|
||||
int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start;
|
||||
|
||||
if (dir == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
ch = pcm_data->rdma_ch;
|
||||
else
|
||||
ch = pcm_data->wrdma_ch;
|
||||
|
||||
bitwidth = snd_pcm_format_width(format);
|
||||
if (bitwidth < 0) {
|
||||
|
@ -100,25 +107,25 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
|
|||
return bitwidth;
|
||||
}
|
||||
|
||||
regval = LPAIF_RDMACTL_BURSTEN_INCR4 |
|
||||
LPAIF_RDMACTL_AUDINTF(rdma_port) |
|
||||
LPAIF_RDMACTL_FIFOWM_8;
|
||||
regval = LPAIF_DMACTL_BURSTEN_INCR4 |
|
||||
LPAIF_DMACTL_AUDINTF(dma_port) |
|
||||
LPAIF_DMACTL_FIFOWM_8;
|
||||
|
||||
switch (bitwidth) {
|
||||
case 16:
|
||||
switch (channels) {
|
||||
case 1:
|
||||
case 2:
|
||||
regval |= LPAIF_RDMACTL_WPSCNT_ONE;
|
||||
regval |= LPAIF_DMACTL_WPSCNT_ONE;
|
||||
break;
|
||||
case 4:
|
||||
regval |= LPAIF_RDMACTL_WPSCNT_TWO;
|
||||
regval |= LPAIF_DMACTL_WPSCNT_TWO;
|
||||
break;
|
||||
case 6:
|
||||
regval |= LPAIF_RDMACTL_WPSCNT_THREE;
|
||||
regval |= LPAIF_DMACTL_WPSCNT_THREE;
|
||||
break;
|
||||
case 8:
|
||||
regval |= LPAIF_RDMACTL_WPSCNT_FOUR;
|
||||
regval |= LPAIF_DMACTL_WPSCNT_FOUR;
|
||||
break;
|
||||
default:
|
||||
dev_err(soc_runtime->dev, "%s() invalid PCM config given: bw=%d, ch=%u\n",
|
||||
|
@ -130,19 +137,19 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
|
|||
case 32:
|
||||
switch (channels) {
|
||||
case 1:
|
||||
regval |= LPAIF_RDMACTL_WPSCNT_ONE;
|
||||
regval |= LPAIF_DMACTL_WPSCNT_ONE;
|
||||
break;
|
||||
case 2:
|
||||
regval |= LPAIF_RDMACTL_WPSCNT_TWO;
|
||||
regval |= LPAIF_DMACTL_WPSCNT_TWO;
|
||||
break;
|
||||
case 4:
|
||||
regval |= LPAIF_RDMACTL_WPSCNT_FOUR;
|
||||
regval |= LPAIF_DMACTL_WPSCNT_FOUR;
|
||||
break;
|
||||
case 6:
|
||||
regval |= LPAIF_RDMACTL_WPSCNT_SIX;
|
||||
regval |= LPAIF_DMACTL_WPSCNT_SIX;
|
||||
break;
|
||||
case 8:
|
||||
regval |= LPAIF_RDMACTL_WPSCNT_EIGHT;
|
||||
regval |= LPAIF_DMACTL_WPSCNT_EIGHT;
|
||||
break;
|
||||
default:
|
||||
dev_err(soc_runtime->dev, "%s() invalid PCM config given: bw=%d, ch=%u\n",
|
||||
|
@ -157,7 +164,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
|
|||
}
|
||||
|
||||
ret = regmap_write(drvdata->lpaif_map,
|
||||
LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch), regval);
|
||||
LPAIF_DMACTL_REG(v, ch, dir), regval);
|
||||
if (ret) {
|
||||
dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
|
||||
__func__, ret);
|
||||
|
@ -174,10 +181,15 @@ static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
|
|||
struct lpass_data *drvdata =
|
||||
snd_soc_platform_get_drvdata(soc_runtime->platform);
|
||||
struct lpass_variant *v = drvdata->variant;
|
||||
unsigned int reg;
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(drvdata->lpaif_map,
|
||||
LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch), 0);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
reg = LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch);
|
||||
else
|
||||
reg = LPAIF_WRDMACTL_REG(v, pcm_data->wrdma_ch);
|
||||
|
||||
ret = regmap_write(drvdata->lpaif_map, reg, 0);
|
||||
if (ret)
|
||||
dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
|
||||
__func__, ret);
|
||||
|
@ -193,10 +205,15 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
|
|||
struct lpass_data *drvdata =
|
||||
snd_soc_platform_get_drvdata(soc_runtime->platform);
|
||||
struct lpass_variant *v = drvdata->variant;
|
||||
int ret, ch = pcm_data->rdma_ch;
|
||||
int ret, ch, dir = substream->stream;
|
||||
|
||||
if (dir == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
ch = pcm_data->rdma_ch;
|
||||
else
|
||||
ch = pcm_data->wrdma_ch;
|
||||
|
||||
ret = regmap_write(drvdata->lpaif_map,
|
||||
LPAIF_RDMABASE_REG(v, ch),
|
||||
LPAIF_DMABASE_REG(v, ch, dir),
|
||||
runtime->dma_addr);
|
||||
if (ret) {
|
||||
dev_err(soc_runtime->dev, "%s() error writing to rdmabase reg: %d\n",
|
||||
|
@ -205,7 +222,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
|
|||
}
|
||||
|
||||
ret = regmap_write(drvdata->lpaif_map,
|
||||
LPAIF_RDMABUFF_REG(v, ch),
|
||||
LPAIF_DMABUFF_REG(v, ch, dir),
|
||||
(snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);
|
||||
if (ret) {
|
||||
dev_err(soc_runtime->dev, "%s() error writing to rdmabuff reg: %d\n",
|
||||
|
@ -214,7 +231,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
|
|||
}
|
||||
|
||||
ret = regmap_write(drvdata->lpaif_map,
|
||||
LPAIF_RDMAPER_REG(v, ch),
|
||||
LPAIF_DMAPER_REG(v, ch, dir),
|
||||
(snd_pcm_lib_period_bytes(substream) >> 2) - 1);
|
||||
if (ret) {
|
||||
dev_err(soc_runtime->dev, "%s() error writing to rdmaper reg: %d\n",
|
||||
|
@ -223,8 +240,8 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
|
|||
}
|
||||
|
||||
ret = regmap_update_bits(drvdata->lpaif_map,
|
||||
LPAIF_RDMACTL_REG(v, ch),
|
||||
LPAIF_RDMACTL_ENABLE_MASK, LPAIF_RDMACTL_ENABLE_ON);
|
||||
LPAIF_DMACTL_REG(v, ch, dir),
|
||||
LPAIF_DMACTL_ENABLE_MASK, LPAIF_DMACTL_ENABLE_ON);
|
||||
if (ret) {
|
||||
dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
|
||||
__func__, ret);
|
||||
|
@ -242,7 +259,12 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
|
|||
struct lpass_data *drvdata =
|
||||
snd_soc_platform_get_drvdata(soc_runtime->platform);
|
||||
struct lpass_variant *v = drvdata->variant;
|
||||
int ret, ch = pcm_data->rdma_ch;
|
||||
int ret, ch, dir = substream->stream;
|
||||
|
||||
if (dir == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
ch = pcm_data->rdma_ch;
|
||||
else
|
||||
ch = pcm_data->wrdma_ch;
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
|
@ -269,9 +291,9 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
|
|||
}
|
||||
|
||||
ret = regmap_update_bits(drvdata->lpaif_map,
|
||||
LPAIF_RDMACTL_REG(v, ch),
|
||||
LPAIF_RDMACTL_ENABLE_MASK,
|
||||
LPAIF_RDMACTL_ENABLE_ON);
|
||||
LPAIF_DMACTL_REG(v, ch, dir),
|
||||
LPAIF_DMACTL_ENABLE_MASK,
|
||||
LPAIF_DMACTL_ENABLE_ON);
|
||||
if (ret) {
|
||||
dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
|
||||
__func__, ret);
|
||||
|
@ -282,9 +304,9 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
|
|||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
ret = regmap_update_bits(drvdata->lpaif_map,
|
||||
LPAIF_RDMACTL_REG(v, ch),
|
||||
LPAIF_RDMACTL_ENABLE_MASK,
|
||||
LPAIF_RDMACTL_ENABLE_OFF);
|
||||
LPAIF_DMACTL_REG(v, ch, dir),
|
||||
LPAIF_DMACTL_ENABLE_MASK,
|
||||
LPAIF_DMACTL_ENABLE_OFF);
|
||||
if (ret) {
|
||||
dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
|
||||
__func__, ret);
|
||||
|
@ -314,10 +336,15 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
|
|||
snd_soc_platform_get_drvdata(soc_runtime->platform);
|
||||
struct lpass_variant *v = drvdata->variant;
|
||||
unsigned int base_addr, curr_addr;
|
||||
int ret, ch = pcm_data->rdma_ch;
|
||||
int ret, ch, dir = substream->stream;
|
||||
|
||||
if (dir == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
ch = pcm_data->rdma_ch;
|
||||
else
|
||||
ch = pcm_data->wrdma_ch;
|
||||
|
||||
ret = regmap_read(drvdata->lpaif_map,
|
||||
LPAIF_RDMABASE_REG(v, ch), &base_addr);
|
||||
LPAIF_DMABASE_REG(v, ch, dir), &base_addr);
|
||||
if (ret) {
|
||||
dev_err(soc_runtime->dev, "%s() error reading from rdmabase reg: %d\n",
|
||||
__func__, ret);
|
||||
|
@ -325,7 +352,7 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
|
|||
}
|
||||
|
||||
ret = regmap_read(drvdata->lpaif_map,
|
||||
LPAIF_RDMACURR_REG(v, ch), &curr_addr);
|
||||
LPAIF_DMACURR_REG(v, ch, dir), &curr_addr);
|
||||
if (ret) {
|
||||
dev_err(soc_runtime->dev, "%s() error reading from rdmacurr reg: %d\n",
|
||||
__func__, ret);
|
||||
|
@ -439,101 +466,124 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_pcm_runtime *rt)
|
||||
{
|
||||
struct snd_dma_buffer *buf = &substream->dma_buffer;
|
||||
size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
|
||||
|
||||
buf->dev.type = SNDRV_DMA_TYPE_DEV;
|
||||
buf->dev.dev = rt->platform->dev;
|
||||
buf->private_data = NULL;
|
||||
buf->area = dma_alloc_coherent(rt->platform->dev, size, &buf->addr,
|
||||
GFP_KERNEL);
|
||||
if (!buf->area) {
|
||||
dev_err(rt->platform->dev, "%s: Could not allocate DMA buffer\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
buf->bytes = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lpass_platform_free_buffer(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_pcm_runtime *rt)
|
||||
{
|
||||
struct snd_dma_buffer *buf = &substream->dma_buffer;
|
||||
|
||||
if (buf->area) {
|
||||
dma_free_coherent(rt->dev, buf->bytes, buf->area,
|
||||
buf->addr);
|
||||
}
|
||||
buf->area = NULL;
|
||||
}
|
||||
|
||||
static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
|
||||
{
|
||||
struct snd_pcm *pcm = soc_runtime->pcm;
|
||||
struct snd_pcm_substream *substream =
|
||||
pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
|
||||
struct snd_pcm_substream *psubstream, *csubstream;
|
||||
struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
|
||||
struct lpass_data *drvdata =
|
||||
snd_soc_platform_get_drvdata(soc_runtime->platform);
|
||||
struct lpass_variant *v = drvdata->variant;
|
||||
int ret;
|
||||
struct lpass_pcm_data *data;
|
||||
size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
|
||||
|
||||
data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
if (v->alloc_dma_channel)
|
||||
data->rdma_ch = v->alloc_dma_channel(drvdata);
|
||||
|
||||
if (IS_ERR_VALUE(data->rdma_ch))
|
||||
return data->rdma_ch;
|
||||
|
||||
drvdata->substream[data->rdma_ch] = substream;
|
||||
data->i2s_port = cpu_dai->driver->id;
|
||||
|
||||
snd_soc_pcm_set_drvdata(soc_runtime, data);
|
||||
|
||||
ret = lpass_platform_alloc_buffer(substream, soc_runtime);
|
||||
if (ret)
|
||||
return ret;
|
||||
psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
|
||||
if (psubstream) {
|
||||
if (v->alloc_dma_channel)
|
||||
data->rdma_ch = v->alloc_dma_channel(drvdata,
|
||||
SNDRV_PCM_STREAM_PLAYBACK);
|
||||
|
||||
ret = regmap_write(drvdata->lpaif_map,
|
||||
if (IS_ERR_VALUE(data->rdma_ch))
|
||||
return data->rdma_ch;
|
||||
|
||||
drvdata->substream[data->rdma_ch] = psubstream;
|
||||
|
||||
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
|
||||
soc_runtime->platform->dev,
|
||||
size, &psubstream->dma_buffer);
|
||||
if (ret)
|
||||
goto playback_alloc_err;
|
||||
|
||||
ret = regmap_write(drvdata->lpaif_map,
|
||||
LPAIF_RDMACTL_REG(v, data->rdma_ch), 0);
|
||||
if (ret) {
|
||||
dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
|
||||
if (ret) {
|
||||
dev_err(soc_runtime->dev,
|
||||
"%s() error writing to rdmactl reg: %d\n",
|
||||
__func__, ret);
|
||||
goto err_buf;
|
||||
goto capture_alloc_err;
|
||||
}
|
||||
}
|
||||
|
||||
csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
|
||||
if (csubstream) {
|
||||
if (v->alloc_dma_channel)
|
||||
data->wrdma_ch = v->alloc_dma_channel(drvdata,
|
||||
SNDRV_PCM_STREAM_CAPTURE);
|
||||
|
||||
if (IS_ERR_VALUE(data->wrdma_ch))
|
||||
goto capture_alloc_err;
|
||||
|
||||
drvdata->substream[data->wrdma_ch] = csubstream;
|
||||
|
||||
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
|
||||
soc_runtime->platform->dev,
|
||||
size, &csubstream->dma_buffer);
|
||||
if (ret)
|
||||
goto capture_alloc_err;
|
||||
|
||||
ret = regmap_write(drvdata->lpaif_map,
|
||||
LPAIF_WRDMACTL_REG(v, data->wrdma_ch), 0);
|
||||
if (ret) {
|
||||
dev_err(soc_runtime->dev,
|
||||
"%s() error writing to wrdmactl reg: %d\n",
|
||||
__func__, ret);
|
||||
goto capture_reg_err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_buf:
|
||||
lpass_platform_free_buffer(substream, soc_runtime);
|
||||
capture_reg_err:
|
||||
if (csubstream)
|
||||
snd_dma_free_pages(&csubstream->dma_buffer);
|
||||
|
||||
capture_alloc_err:
|
||||
if (psubstream)
|
||||
snd_dma_free_pages(&psubstream->dma_buffer);
|
||||
|
||||
playback_alloc_err:
|
||||
dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void lpass_platform_pcm_free(struct snd_pcm *pcm)
|
||||
{
|
||||
struct snd_pcm_substream *substream =
|
||||
pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
|
||||
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
|
||||
struct lpass_data *drvdata =
|
||||
snd_soc_platform_get_drvdata(soc_runtime->platform);
|
||||
struct lpass_pcm_data *data = snd_soc_pcm_get_drvdata(soc_runtime);
|
||||
struct lpass_variant *v = drvdata->variant;
|
||||
struct snd_soc_pcm_runtime *rt;
|
||||
struct lpass_data *drvdata;
|
||||
struct lpass_pcm_data *data;
|
||||
struct lpass_variant *v;
|
||||
struct snd_pcm_substream *substream;
|
||||
int ch, i;
|
||||
|
||||
drvdata->substream[data->rdma_ch] = NULL;
|
||||
for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) {
|
||||
substream = pcm->streams[i].substream;
|
||||
if (substream) {
|
||||
rt = substream->private_data;
|
||||
data = snd_soc_pcm_get_drvdata(rt);
|
||||
drvdata = snd_soc_platform_get_drvdata(rt->platform);
|
||||
|
||||
if (v->free_dma_channel)
|
||||
v->free_dma_channel(drvdata, data->rdma_ch);
|
||||
ch = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
? data->rdma_ch
|
||||
: data->wrdma_ch;
|
||||
v = drvdata->variant;
|
||||
drvdata->substream[ch] = NULL;
|
||||
if (v->free_dma_channel)
|
||||
v->free_dma_channel(drvdata, ch);
|
||||
|
||||
lpass_platform_free_buffer(substream, soc_runtime);
|
||||
snd_dma_free_pages(&substream->dma_buffer);
|
||||
substream->dma_buffer.area = NULL;
|
||||
substream->dma_buffer.addr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct snd_soc_platform_driver lpass_platform_driver = {
|
||||
|
|
|
@ -50,7 +50,7 @@ struct lpass_data {
|
|||
struct lpass_variant *variant;
|
||||
|
||||
/* bit map to keep track of static channel allocations */
|
||||
unsigned long rdma_ch_bit_map;
|
||||
unsigned long dma_ch_bit_map;
|
||||
|
||||
/* used it for handling interrupt per dma channel */
|
||||
struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS];
|
||||
|
@ -71,16 +71,20 @@ struct lpass_variant {
|
|||
u32 rdma_reg_base;
|
||||
u32 rdma_reg_stride;
|
||||
u32 rdma_channels;
|
||||
u32 wrdma_reg_base;
|
||||
u32 wrdma_reg_stride;
|
||||
u32 wrdma_channels;
|
||||
|
||||
/**
|
||||
* on SOCs like APQ8016 the channel control bits start
|
||||
* at different offset to ipq806x
|
||||
**/
|
||||
u32 rdmactl_audif_start;
|
||||
u32 dmactl_audif_start;
|
||||
u32 wrdma_channel_start;
|
||||
/* SOC specific intialization like clocks */
|
||||
int (*init)(struct platform_device *pdev);
|
||||
int (*exit)(struct platform_device *pdev);
|
||||
int (*alloc_dma_channel)(struct lpass_data *data);
|
||||
int (*alloc_dma_channel)(struct lpass_data *data, int direction);
|
||||
int (*free_dma_channel)(struct lpass_data *data, int ch);
|
||||
|
||||
/* SOC specific dais */
|
||||
|
|
Loading…
Reference in New Issue