summaryrefslogtreecommitdiffstats
path: root/sound/soc/qcom
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/qcom')
-rw-r--r--sound/soc/qcom/Kconfig22
-rw-r--r--sound/soc/qcom/common.c22
-rw-r--r--sound/soc/qcom/lpass-platform.c74
-rw-r--r--sound/soc/qcom/qdsp6/q6asm-dai.c107
-rw-r--r--sound/soc/qcom/qdsp6/q6asm.c55
-rw-r--r--sound/soc/qcom/qdsp6/q6asm.h15
-rw-r--r--sound/soc/qcom/qdsp6/q6routing.c14
-rw-r--r--sound/soc/qcom/sdm845.c88
8 files changed, 286 insertions, 111 deletions
diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 8e3e86619b35..6530d2462a9e 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -3,8 +3,8 @@ config SND_SOC_QCOM
tristate "ASoC support for QCOM platforms"
depends on ARCH_QCOM || COMPILE_TEST
help
- Say Y or M if you want to add support to use audio devices
- in Qualcomm Technologies SOC-based platforms.
+ Say Y or M if you want to add support to use audio devices
+ in Qualcomm Technologies SOC-based platforms.
config SND_SOC_LPASS_CPU
tristate
@@ -30,17 +30,17 @@ config SND_SOC_STORM
select SND_SOC_LPASS_IPQ806X
select SND_SOC_MAX98357A
help
- Say Y or M if you want add support for SoC audio on the
- Qualcomm Technologies IPQ806X-based Storm board.
+ Say Y or M if you want add support for SoC audio on the
+ Qualcomm Technologies IPQ806X-based Storm board.
config SND_SOC_APQ8016_SBC
tristate "SoC Audio support for APQ8016 SBC platforms"
depends on SND_SOC_QCOM
select SND_SOC_LPASS_APQ8016
help
- Support for Qualcomm Technologies LPASS audio block in
- APQ8016 SOC-based systems.
- Say Y if you want to use audio devices on MI2S.
+ Support for Qualcomm Technologies LPASS audio block in
+ APQ8016 SOC-based systems.
+ Say Y if you want to use audio devices on MI2S.
config SND_SOC_QCOM_COMMON
tristate
@@ -93,13 +93,13 @@ config SND_SOC_MSM8996
select SND_SOC_QDSP6
select SND_SOC_QCOM_COMMON
help
- Support for Qualcomm Technologies LPASS audio block in
- APQ8096 SoC-based systems.
- Say Y if you want to use audio device on this SoCs
+ Support for Qualcomm Technologies LPASS audio block in
+ APQ8096 SoC-based systems.
+ Say Y if you want to use audio device on this SoCs
config SND_SOC_SDM845
tristate "SoC Machine driver for SDM845 boards"
- depends on QCOM_APR && MFD_CROS_EC && I2C
+ depends on QCOM_APR && CROS_EC && I2C
select SND_SOC_QDSP6
select SND_SOC_QCOM_COMMON
select SND_SOC_RT5663
diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
index 2c7348ddbbb3..6c20bdd850f3 100644
--- a/sound/soc/qcom/common.c
+++ b/sound/soc/qcom/common.c
@@ -53,12 +53,18 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
link->num_cpus = 1;
link->num_platforms = 1;
+ ret = of_property_read_string(np, "link-name", &link->name);
+ if (ret) {
+ dev_err(card->dev, "error getting codec dai_link name\n");
+ goto err;
+ }
+
cpu = of_get_child_by_name(np, "cpu");
platform = of_get_child_by_name(np, "platform");
codec = of_get_child_by_name(np, "codec");
if (!cpu) {
- dev_err(dev, "Can't find cpu DT node\n");
+ dev_err(dev, "%s: Can't find cpu DT node\n", link->name);
ret = -EINVAL;
goto err;
}
@@ -66,7 +72,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
ret = of_parse_phandle_with_args(cpu, "sound-dai",
"#sound-dai-cells", 0, &args);
if (ret) {
- dev_err(card->dev, "error getting cpu phandle\n");
+ dev_err(card->dev, "%s: error getting cpu phandle\n", link->name);
goto err;
}
link->cpus->of_node = args.np;
@@ -74,7 +80,7 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
ret = snd_soc_of_get_dai_name(cpu, &link->cpus->dai_name);
if (ret) {
- dev_err(card->dev, "error getting cpu dai name\n");
+ dev_err(card->dev, "%s: error getting cpu dai name\n", link->name);
goto err;
}
@@ -83,14 +89,14 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
"sound-dai",
0);
if (!link->platforms->of_node) {
- dev_err(card->dev, "platform dai not found\n");
+ dev_err(card->dev, "%s: platform dai not found\n", link->name);
ret = -EINVAL;
goto err;
}
ret = snd_soc_of_get_dai_link_codecs(dev, codec, link);
if (ret < 0) {
- dev_err(card->dev, "codec dai not found\n");
+ dev_err(card->dev, "%s: codec dai not found\n", link->name);
goto err;
}
link->no_pcm = 1;
@@ -110,12 +116,6 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
}
link->ignore_suspend = 1;
- ret = of_property_read_string(np, "link-name", &link->name);
- if (ret) {
- dev_err(card->dev, "error getting codec dai_link name\n");
- goto err;
- }
-
link->nonatomic = 1;
link->dpcm_playback = 1;
link->dpcm_capture = 1;
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index cf7a299f4547..b05091c283b7 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -50,12 +50,12 @@ static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
.fifo_size = 0,
};
-static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)
+static int lpass_platform_pcmops_open(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
- struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
struct lpass_variant *v = drvdata->variant;
int ret, dma_ch, dir = substream->stream;
@@ -105,11 +105,10 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream)
return 0;
}
-static int lpass_platform_pcmops_close(struct snd_pcm_substream *substream)
+static int lpass_platform_pcmops_close(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
struct lpass_variant *v = drvdata->variant;
struct lpass_pcm_data *data;
@@ -122,11 +121,11 @@ static int lpass_platform_pcmops_close(struct snd_pcm_substream *substream)
return 0;
}
-static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
+static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
struct snd_pcm_runtime *rt = substream->runtime;
struct lpass_pcm_data *pcm_data = rt->private_data;
@@ -216,10 +215,10 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
+static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
struct snd_pcm_runtime *rt = substream->runtime;
struct lpass_pcm_data *pcm_data = rt->private_data;
@@ -236,11 +235,11 @@ static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
return ret;
}
-static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
+static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
struct snd_pcm_runtime *rt = substream->runtime;
struct lpass_pcm_data *pcm_data = rt->private_data;
@@ -288,11 +287,11 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
return 0;
}
-static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
- int cmd)
+static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream,
+ int cmd)
{
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
struct snd_pcm_runtime *rt = substream->runtime;
struct lpass_pcm_data *pcm_data = rt->private_data;
@@ -363,10 +362,10 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
}
static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
+ struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
- struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
struct snd_pcm_runtime *rt = substream->runtime;
struct lpass_pcm_data *pcm_data = rt->private_data;
@@ -395,8 +394,9 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
return bytes_to_frames(substream->runtime, curr_addr - base_addr);
}
-static int lpass_platform_pcmops_mmap(struct snd_pcm_substream *substream,
- struct vm_area_struct *vma)
+static int lpass_platform_pcmops_mmap(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -405,18 +405,6 @@ static int lpass_platform_pcmops_mmap(struct snd_pcm_substream *substream,
runtime->dma_bytes);
}
-static const struct snd_pcm_ops lpass_platform_pcm_ops = {
- .open = lpass_platform_pcmops_open,
- .close = lpass_platform_pcmops_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = lpass_platform_pcmops_hw_params,
- .hw_free = lpass_platform_pcmops_hw_free,
- .prepare = lpass_platform_pcmops_prepare,
- .trigger = lpass_platform_pcmops_trigger,
- .pointer = lpass_platform_pcmops_pointer,
- .mmap = lpass_platform_pcmops_mmap,
-};
-
static irqreturn_t lpass_dma_interrupt_handler(
struct snd_pcm_substream *substream,
struct lpass_data *drvdata,
@@ -499,11 +487,11 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
+static int lpass_platform_pcm_new(struct snd_soc_component *component,
+ struct snd_soc_pcm_runtime *soc_runtime)
{
struct snd_pcm *pcm = soc_runtime->pcm;
struct snd_pcm_substream *psubstream, *csubstream;
- struct snd_soc_component *component = snd_soc_rtdcom_lookup(soc_runtime, DRV_NAME);
int ret = -EINVAL;
size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
@@ -535,7 +523,8 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
return 0;
}
-static void lpass_platform_pcm_free(struct snd_pcm *pcm)
+static void lpass_platform_pcm_free(struct snd_soc_component *component,
+ struct snd_pcm *pcm)
{
struct snd_pcm_substream *substream;
int i;
@@ -552,9 +541,17 @@ static void lpass_platform_pcm_free(struct snd_pcm *pcm)
static const struct snd_soc_component_driver lpass_component_driver = {
.name = DRV_NAME,
- .pcm_new = lpass_platform_pcm_new,
- .pcm_free = lpass_platform_pcm_free,
- .ops = &lpass_platform_pcm_ops,
+ .open = lpass_platform_pcmops_open,
+ .close = lpass_platform_pcmops_close,
+ .hw_params = lpass_platform_pcmops_hw_params,
+ .hw_free = lpass_platform_pcmops_hw_free,
+ .prepare = lpass_platform_pcmops_prepare,
+ .trigger = lpass_platform_pcmops_trigger,
+ .pointer = lpass_platform_pcmops_pointer,
+ .mmap = lpass_platform_pcmops_mmap,
+ .pcm_construct = lpass_platform_pcm_new,
+ .pcm_destruct = lpass_platform_pcm_free,
+
};
int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
@@ -564,11 +561,8 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
int ret;
drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
- if (drvdata->lpaif_irq < 0) {
- dev_err(&pdev->dev, "error getting irq handle: %d\n",
- drvdata->lpaif_irq);
+ if (drvdata->lpaif_irq < 0)
return -ENODEV;
- }
/* ensure audio hardware is disabled */
ret = regmap_write(drvdata->lpaif_map,
diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index 548eb4fa2da6..c0d422d0ab94 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -72,7 +72,7 @@ struct q6asm_dai_data {
long long int sid;
};
-static struct snd_pcm_hardware q6asm_dai_hardware_capture = {
+static const struct snd_pcm_hardware q6asm_dai_hardware_capture = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
@@ -206,16 +206,16 @@ static void event_handler(uint32_t opcode, uint32_t token,
}
}
-static int q6asm_dai_prepare(struct snd_pcm_substream *substream)
+static int q6asm_dai_prepare(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
struct q6asm_dai_rtd *prtd = runtime->private_data;
- struct snd_soc_component *c = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
struct q6asm_dai_data *pdata;
int ret, i;
- pdata = snd_soc_component_get_drvdata(c);
+ pdata = snd_soc_component_get_drvdata(component);
if (!pdata)
return -EINVAL;
@@ -294,7 +294,8 @@ static int q6asm_dai_prepare(struct snd_pcm_substream *substream)
return 0;
}
-static int q6asm_dai_trigger(struct snd_pcm_substream *substream, int cmd)
+static int q6asm_dai_trigger(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream, int cmd)
{
int ret = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -322,21 +323,21 @@ static int q6asm_dai_trigger(struct snd_pcm_substream *substream, int cmd)
return ret;
}
-static int q6asm_dai_open(struct snd_pcm_substream *substream)
+static int q6asm_dai_open(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
struct snd_soc_dai *cpu_dai = soc_prtd->cpu_dai;
- struct snd_soc_component *c = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
struct q6asm_dai_rtd *prtd;
struct q6asm_dai_data *pdata;
- struct device *dev = c->dev;
+ struct device *dev = component->dev;
int ret = 0;
int stream_id;
stream_id = cpu_dai->driver->id;
- pdata = snd_soc_component_get_drvdata(c);
+ pdata = snd_soc_component_get_drvdata(component);
if (!pdata) {
pr_err("Drv data not found ..\n");
return -EINVAL;
@@ -414,7 +415,8 @@ static int q6asm_dai_open(struct snd_pcm_substream *substream)
return 0;
}
-static int q6asm_dai_close(struct snd_pcm_substream *substream)
+static int q6asm_dai_close(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
@@ -435,7 +437,8 @@ static int q6asm_dai_close(struct snd_pcm_substream *substream)
return 0;
}
-static snd_pcm_uframes_t q6asm_dai_pointer(struct snd_pcm_substream *substream)
+static snd_pcm_uframes_t q6asm_dai_pointer(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -447,22 +450,21 @@ static snd_pcm_uframes_t q6asm_dai_pointer(struct snd_pcm_substream *substream)
return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
}
-static int q6asm_dai_mmap(struct snd_pcm_substream *substream,
- struct vm_area_struct *vma)
+static int q6asm_dai_mmap(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
{
-
struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
- struct snd_soc_component *c = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
- struct device *dev = c->dev;
+ struct device *dev = component->dev;
return dma_mmap_coherent(dev, vma,
runtime->dma_area, runtime->dma_addr,
runtime->dma_bytes);
}
-static int q6asm_dai_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
+static int q6asm_dai_hw_params(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct q6asm_dai_rtd *prtd = runtime->private_data;
@@ -482,17 +484,6 @@ static int q6asm_dai_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static struct snd_pcm_ops q6asm_dai_ops = {
- .open = q6asm_dai_open,
- .hw_params = q6asm_dai_hw_params,
- .close = q6asm_dai_close,
- .ioctl = snd_pcm_lib_ioctl,
- .prepare = q6asm_dai_prepare,
- .trigger = q6asm_dai_trigger,
- .pointer = q6asm_dai_pointer,
- .mmap = q6asm_dai_mmap,
-};
-
static void compress_event_handler(uint32_t opcode, uint32_t token,
uint32_t *payload, void *priv)
{
@@ -635,8 +626,14 @@ static int q6asm_dai_compr_set_params(struct snd_compr_stream *stream,
struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
int dir = stream->direction;
struct q6asm_dai_data *pdata;
+ struct q6asm_flac_cfg flac_cfg;
struct device *dev = c->dev;
int ret;
+ union snd_codec_options *codec_options;
+ struct snd_dec_flac *flac;
+
+ codec_options = &(prtd->codec_param.codec.options);
+
memcpy(&prtd->codec_param, params, sizeof(*params));
@@ -673,6 +670,32 @@ static int q6asm_dai_compr_set_params(struct snd_compr_stream *stream,
return ret;
}
+ switch (params->codec.id) {
+ case SND_AUDIOCODEC_FLAC:
+
+ memset(&flac_cfg, 0x0, sizeof(struct q6asm_flac_cfg));
+ flac = &codec_options->flac_d;
+
+ flac_cfg.ch_cfg = params->codec.ch_in;
+ flac_cfg.sample_rate = params->codec.sample_rate;
+ flac_cfg.stream_info_present = 1;
+ flac_cfg.sample_size = flac->sample_size;
+ flac_cfg.min_blk_size = flac->min_blk_size;
+ flac_cfg.max_blk_size = flac->max_blk_size;
+ flac_cfg.max_frame_size = flac->max_frame_size;
+ flac_cfg.min_frame_size = flac->min_frame_size;
+
+ ret = q6asm_stream_media_format_block_flac(prtd->audio_client,
+ &flac_cfg);
+ if (ret < 0) {
+ dev_err(dev, "FLAC CMD Format block failed:%d\n", ret);
+ return -EIO;
+ }
+ break;
+ default:
+ break;
+ }
+
ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys,
(prtd->pcm_size / prtd->periods),
prtd->periods);
@@ -768,8 +791,9 @@ static int q6asm_dai_compr_get_caps(struct snd_compr_stream *stream,
caps->max_fragment_size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE;
caps->min_fragments = COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
caps->max_fragments = COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
- caps->num_codecs = 1;
+ caps->num_codecs = 2;
caps->codecs[0] = SND_AUDIOCODEC_MP3;
+ caps->codecs[1] = SND_AUDIOCODEC_FLAC;
return 0;
}
@@ -800,15 +824,15 @@ static struct snd_compr_ops q6asm_dai_compr_ops = {
.ack = q6asm_dai_compr_ack,
};
-static int q6asm_dai_pcm_new(struct snd_soc_pcm_runtime *rtd)
+static int q6asm_dai_pcm_new(struct snd_soc_component *component,
+ struct snd_soc_pcm_runtime *rtd)
{
struct snd_pcm_substream *psubstream, *csubstream;
- struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
struct snd_pcm *pcm = rtd->pcm;
struct device *dev;
int size, ret;
- dev = c->dev;
+ dev = component->dev;
size = q6asm_dai_hardware_playback.buffer_bytes_max;
psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
if (psubstream) {
@@ -835,7 +859,8 @@ static int q6asm_dai_pcm_new(struct snd_soc_pcm_runtime *rtd)
return 0;
}
-static void q6asm_dai_pcm_free(struct snd_pcm *pcm)
+static void q6asm_dai_pcm_free(struct snd_soc_component *component,
+ struct snd_pcm *pcm)
{
struct snd_pcm_substream *substream;
int i;
@@ -852,9 +877,15 @@ static void q6asm_dai_pcm_free(struct snd_pcm *pcm)
static const struct snd_soc_component_driver q6asm_fe_dai_component = {
.name = DRV_NAME,
- .ops = &q6asm_dai_ops,
- .pcm_new = q6asm_dai_pcm_new,
- .pcm_free = q6asm_dai_pcm_free,
+ .open = q6asm_dai_open,
+ .hw_params = q6asm_dai_hw_params,
+ .close = q6asm_dai_close,
+ .prepare = q6asm_dai_prepare,
+ .trigger = q6asm_dai_trigger,
+ .pointer = q6asm_dai_pointer,
+ .mmap = q6asm_dai_mmap,
+ .pcm_construct = q6asm_dai_pcm_new,
+ .pcm_destruct = q6asm_dai_pcm_free,
.compr_ops = &q6asm_dai_compr_ops,
};
diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
index e8141a33a55e..36e0eab13a98 100644
--- a/sound/soc/qcom/qdsp6/q6asm.c
+++ b/sound/soc/qcom/qdsp6/q6asm.c
@@ -38,6 +38,7 @@
#define ASM_SESSION_CMD_RUN_V2 0x00010DAA
#define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2 0x00010DA5
#define ASM_MEDIA_FMT_MP3 0x00010BE9
+#define ASM_MEDIA_FMT_FLAC 0x00010C16
#define ASM_DATA_CMD_WRITE_V2 0x00010DAB
#define ASM_DATA_CMD_READ_V2 0x00010DAC
#define ASM_SESSION_CMD_SUSPEND 0x00010DEC
@@ -89,6 +90,20 @@ struct asm_multi_channel_pcm_fmt_blk_v2 {
u8 channel_mapping[PCM_MAX_NUM_CHANNEL];
} __packed;
+struct asm_flac_fmt_blk_v2 {
+ struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
+ u16 is_stream_info_present;
+ u16 num_channels;
+ u16 min_blk_size;
+ u16 max_blk_size;
+ u16 md5_sum[8];
+ u32 sample_rate;
+ u32 min_frame_size;
+ u32 max_frame_size;
+ u16 sample_size;
+ u16 reserved;
+} __packed;
+
struct asm_stream_cmd_set_encdec_param {
u32 param_id;
u32 param_size;
@@ -876,6 +891,9 @@ int q6asm_open_write(struct audio_client *ac, uint32_t format,
case FORMAT_LINEAR_PCM:
open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
break;
+ case SND_AUDIOCODEC_FLAC:
+ open->dec_fmt_id = ASM_MEDIA_FMT_FLAC;
+ break;
default:
dev_err(ac->dev, "Invalid format 0x%x\n", format);
rc = -EINVAL;
@@ -1021,6 +1039,42 @@ err:
}
EXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm);
+
+int q6asm_stream_media_format_block_flac(struct audio_client *ac,
+ struct q6asm_flac_cfg *cfg)
+{
+ struct asm_flac_fmt_blk_v2 *fmt;
+ struct apr_pkt *pkt;
+ void *p;
+ int rc, pkt_size;
+
+ pkt_size = APR_HDR_SIZE + sizeof(*fmt);
+ p = kzalloc(pkt_size, GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ pkt = p;
+ fmt = p + APR_HDR_SIZE;
+
+ q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id);
+
+ pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk);
+ fmt->is_stream_info_present = cfg->stream_info_present;
+ fmt->num_channels = cfg->ch_cfg;
+ fmt->min_blk_size = cfg->min_blk_size;
+ fmt->max_blk_size = cfg->max_blk_size;
+ fmt->sample_rate = cfg->sample_rate;
+ fmt->min_frame_size = cfg->min_frame_size;
+ fmt->max_frame_size = cfg->max_frame_size;
+ fmt->sample_size = cfg->sample_size;
+
+ rc = q6asm_ac_send_cmd_sync(ac, pkt);
+ kfree(pkt);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(q6asm_stream_media_format_block_flac);
/**
* q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture
*
@@ -1075,6 +1129,7 @@ err:
}
EXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support);
+
/**
* q6asm_read() - read data of period size from audio client
*
diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h
index 9f5fb573e4a0..6764f55f7078 100644
--- a/sound/soc/qcom/qdsp6/q6asm.h
+++ b/sound/soc/qcom/qdsp6/q6asm.h
@@ -32,6 +32,19 @@ enum {
#define NO_TIMESTAMP 0xFF00
#define FORMAT_LINEAR_PCM 0x0000
+struct q6asm_flac_cfg {
+ u32 sample_rate;
+ u32 ext_sample_rate;
+ u32 min_frame_size;
+ u32 max_frame_size;
+ u16 stream_info_present;
+ u16 min_blk_size;
+ u16 max_blk_size;
+ u16 ch_cfg;
+ u16 sample_size;
+ u16 md5_sum;
+};
+
typedef void (*q6asm_cb) (uint32_t opcode, uint32_t token,
void *payload, void *priv);
struct audio_client;
@@ -54,6 +67,8 @@ int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
uint32_t rate, uint32_t channels,
u8 channel_map[PCM_MAX_NUM_CHANNEL],
uint16_t bits_per_sample);
+int q6asm_stream_media_format_block_flac(struct audio_client *ac,
+ struct q6asm_flac_cfg *cfg);
int q6asm_run(struct audio_client *ac, uint32_t flags, uint32_t msw_ts,
uint32_t lsw_ts);
int q6asm_run_nowait(struct audio_client *ac, uint32_t flags, uint32_t msw_ts,
diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c
index ddcd9978cf57..20724102e85a 100644
--- a/sound/soc/qcom/qdsp6/q6routing.c
+++ b/sound/soc/qcom/qdsp6/q6routing.c
@@ -939,12 +939,12 @@ static const struct snd_soc_dapm_route intercon[] = {
};
-static int routing_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
+static int routing_hw_params(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
- struct msm_routing_data *data = dev_get_drvdata(c->dev);
+ struct msm_routing_data *data = dev_get_drvdata(component->dev);
unsigned int be_id = rtd->cpu_dai->id;
struct session_data *session;
int path_type;
@@ -980,10 +980,6 @@ static int routing_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static struct snd_pcm_ops q6pcm_routing_ops = {
- .hw_params = routing_hw_params,
-};
-
static int msm_routing_probe(struct snd_soc_component *c)
{
int i;
@@ -997,9 +993,9 @@ static int msm_routing_probe(struct snd_soc_component *c)
}
static const struct snd_soc_component_driver msm_soc_routing_component = {
- .ops = &q6pcm_routing_ops,
.probe = msm_routing_probe,
.name = DRV_NAME,
+ .hw_params = routing_hw_params,
.dapm_widgets = msm_qdsp6_widgets,
.num_dapm_widgets = ARRAY_SIZE(msm_qdsp6_widgets),
.dapm_routes = intercon,
diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c
index 882f52ed8231..3b5547a27aad 100644
--- a/sound/soc/qcom/sdm845.c
+++ b/sound/soc/qcom/sdm845.c
@@ -24,6 +24,9 @@
#define RIGHT_SPK_TDM_TX_MASK 0xC0
#define SPK_TDM_RX_MASK 0x03
#define NUM_TDM_SLOTS 8
+#define SLIM_MAX_TX_PORTS 16
+#define SLIM_MAX_RX_PORTS 16
+#define WCD934X_DEFAULT_MCLK_RATE 9600000
struct sdm845_snd_data {
struct snd_soc_jack jack;
@@ -36,6 +39,39 @@ struct sdm845_snd_data {
static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
+static int sdm845_slim_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
+ int ret = 0, i;
+
+ for (i = 0 ; i < dai_link->num_codecs; i++) {
+ ret = snd_soc_dai_get_channel_map(rtd->codec_dais[i],
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+
+ if (ret != 0 && ret != -ENOTSUPP) {
+ pr_err("failed to get codec chan map, err:%d\n", ret);
+ return ret;
+ } else if (ret == -ENOTSUPP) {
+ /* Ignore unsupported */
+ continue;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
+ rx_ch_cnt, rx_ch);
+ else
+ ret = snd_soc_dai_set_channel_map(cpu_dai, tx_ch_cnt,
+ tx_ch, 0, NULL);
+ }
+
+ return 0;
+}
+
static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -151,6 +187,11 @@ static int sdm845_snd_hw_params(struct snd_pcm_substream *substream,
case QUATERNARY_TDM_TX_0:
ret = sdm845_tdm_snd_hw_params(substream, params);
break;
+ case SLIMBUS_0_RX...SLIMBUS_6_TX:
+ ret = sdm845_slim_snd_hw_params(substream, params);
+ break;
+ case QUATERNARY_MI2S_RX:
+ break;
default:
pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
break;
@@ -173,7 +214,20 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct sdm845_snd_data *pdata = snd_soc_card_get_drvdata(card);
struct snd_jack *jack;
- int rval;
+ struct snd_soc_dai_link *dai_link = rtd->dai_link;
+ /*
+ * Codec SLIMBUS configuration
+ * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13
+ * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
+ * TX14, TX15, TX16
+ */
+ unsigned int rx_ch[SLIM_MAX_RX_PORTS] = {144, 145, 146, 147, 148, 149,
+ 150, 151, 152, 153, 154, 155, 156};
+ unsigned int tx_ch[SLIM_MAX_TX_PORTS] = {128, 129, 130, 131, 132, 133,
+ 134, 135, 136, 137, 138, 139,
+ 140, 141, 142, 143};
+ int rval, i;
+
if (!pdata->jack_setup) {
rval = snd_soc_card_jack_new(card, "Headset Jack",
@@ -211,6 +265,21 @@ static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd)
return rval;
}
break;
+ case SLIMBUS_0_RX...SLIMBUS_6_TX:
+ for (i = 0 ; i < dai_link->num_codecs; i++) {
+ rval = snd_soc_dai_set_channel_map(rtd->codec_dais[i],
+ ARRAY_SIZE(tx_ch),
+ tx_ch,
+ ARRAY_SIZE(rx_ch),
+ rx_ch);
+ if (rval != 0 && rval != -ENOTSUPP)
+ return rval;
+
+ snd_soc_dai_set_sysclk(rtd->codec_dais[i], 0,
+ WCD934X_DEFAULT_MCLK_RATE,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ }
+ break;
default:
break;
}
@@ -257,6 +326,14 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream)
snd_soc_dai_set_fmt(cpu_dai, fmt);
snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
break;
+ case QUATERNARY_MI2S_RX:
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT,
+ MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+ snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS);
+
+
+ break;
case QUATERNARY_TDM_RX_0:
case QUATERNARY_TDM_TX_0:
@@ -294,6 +371,8 @@ static int sdm845_snd_startup(struct snd_pcm_substream *substream)
}
}
break;
+ case SLIMBUS_0_RX...SLIMBUS_6_TX:
+ break;
default:
pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
@@ -319,7 +398,7 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream)
snd_soc_dai_set_sysclk(cpu_dai,
Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
0, SNDRV_PCM_STREAM_PLAYBACK);
- };
+ }
break;
case SECONDARY_MI2S_TX:
@@ -338,6 +417,9 @@ static void sdm845_snd_shutdown(struct snd_pcm_substream *substream)
0, SNDRV_PCM_STREAM_PLAYBACK);
}
break;
+ case SLIMBUS_0_RX...SLIMBUS_6_TX:
+ case QUATERNARY_MI2S_RX:
+ break;
default:
pr_err("%s: invalid dai id 0x%x\n", __func__, cpu_dai->id);
@@ -451,6 +533,8 @@ static int sdm845_snd_platform_remove(struct platform_device *pdev)
static const struct of_device_id sdm845_snd_device_id[] = {
{ .compatible = "qcom,sdm845-sndcard" },
+ { .compatible = "qcom,db845c-sndcard" },
+ { .compatible = "lenovo,yoga-c630-sndcard" },
{},
};
MODULE_DEVICE_TABLE(of, sdm845_snd_device_id);
OpenPOWER on IntegriCloud