diff options
Diffstat (limited to 'sound/soc/qcom/qdsp6')
-rw-r--r-- | sound/soc/qcom/qdsp6/q6apm-dai.c | 22 | ||||
-rw-r--r-- | sound/soc/qcom/qdsp6/q6apm-lpass-dais.c | 5 | ||||
-rw-r--r-- | sound/soc/qcom/qdsp6/q6apm.c | 14 | ||||
-rw-r--r-- | sound/soc/qcom/qdsp6/q6apm.h | 2 | ||||
-rw-r--r-- | sound/soc/qcom/qdsp6/q6prm.c | 4 |
5 files changed, 44 insertions, 3 deletions
diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c index ee59ef36b85a..7f02f5b2c33f 100644 --- a/sound/soc/qcom/qdsp6/q6apm-dai.c +++ b/sound/soc/qcom/qdsp6/q6apm-dai.c @@ -8,6 +8,7 @@ #include <linux/slab.h> #include <sound/soc.h> #include <sound/soc-dapm.h> +#include <linux/spinlock.h> #include <sound/pcm.h> #include <asm/dma.h> #include <linux/dma-mapping.h> @@ -53,6 +54,7 @@ struct q6apm_dai_rtd { uint16_t session_id; enum stream_state state; struct q6apm_graph *graph; + spinlock_t lock; }; struct q6apm_dai_data { @@ -62,7 +64,8 @@ struct q6apm_dai_data { static struct snd_pcm_hardware q6apm_dai_hardware_capture = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_BATCH), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), .rates = SNDRV_PCM_RATE_8000_48000, .rate_min = 8000, @@ -80,7 +83,8 @@ static struct snd_pcm_hardware q6apm_dai_hardware_capture = { static struct snd_pcm_hardware q6apm_dai_hardware_playback = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_BATCH), .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), .rates = SNDRV_PCM_RATE_8000_192000, .rate_min = 8000, @@ -99,20 +103,25 @@ static void event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, vo { struct q6apm_dai_rtd *prtd = priv; struct snd_pcm_substream *substream = prtd->substream; + unsigned long flags; switch (opcode) { case APM_CLIENT_EVENT_CMD_EOS_DONE: prtd->state = Q6APM_STREAM_STOPPED; break; case APM_CLIENT_EVENT_DATA_WRITE_DONE: + spin_lock_irqsave(&prtd->lock, flags); prtd->pos += prtd->pcm_count; + spin_unlock_irqrestore(&prtd->lock, flags); snd_pcm_period_elapsed(substream); if (prtd->state == Q6APM_STREAM_RUNNING) q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, 0); break; case APM_CLIENT_EVENT_DATA_READ_DONE: + spin_lock_irqsave(&prtd->lock, flags); prtd->pos += prtd->pcm_count; + spin_unlock_irqrestore(&prtd->lock, flags); snd_pcm_period_elapsed(substream); if (prtd->state == Q6APM_STREAM_RUNNING) q6apm_read(prtd->graph); @@ -253,6 +262,7 @@ static int q6apm_dai_open(struct snd_soc_component *component, if (prtd == NULL) return -ENOMEM; + spin_lock_init(&prtd->lock); prtd->substream = substream; prtd->graph = q6apm_graph_open(dev, (q6apm_cb)event_handler, prtd, graph_id); if (IS_ERR(prtd->graph)) { @@ -332,11 +342,17 @@ static snd_pcm_uframes_t q6apm_dai_pointer(struct snd_soc_component *component, { struct snd_pcm_runtime *runtime = substream->runtime; struct q6apm_dai_rtd *prtd = runtime->private_data; + snd_pcm_uframes_t ptr; + unsigned long flags; + spin_lock_irqsave(&prtd->lock, flags); if (prtd->pos == prtd->pcm_size) prtd->pos = 0; - return bytes_to_frames(runtime, prtd->pos); + ptr = bytes_to_frames(runtime, prtd->pos); + spin_unlock_irqrestore(&prtd->lock, flags); + + return ptr; } static int q6apm_dai_hw_params(struct snd_soc_component *component, diff --git a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c index ce9e5646d8f3..23d23bc6fbaa 100644 --- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c +++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c @@ -127,6 +127,11 @@ static int q6apm_lpass_dai_prepare(struct snd_pcm_substream *substream, struct s int graph_id = dai->id; int rc; + if (dai_data->is_port_started[dai->id]) { + q6apm_graph_stop(dai_data->graph[dai->id]); + dai_data->is_port_started[dai->id] = false; + } + /** * It is recommend to load DSP with source graph first and then sink * graph, so sequence for playback and capture will be different diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c index 5beb898f28f5..994c9e823a88 100644 --- a/sound/soc/qcom/qdsp6/q6apm.c +++ b/sound/soc/qcom/qdsp6/q6apm.c @@ -27,6 +27,8 @@ struct apm_graph_mgmt_cmd { #define APM_GRAPH_MGMT_PSIZE(p, n) ALIGN(struct_size(p, sub_graph_id_list, n), 8) +struct q6apm *g_apm; + int q6apm_send_cmd_sync(struct q6apm *apm, struct gpr_pkt *pkt, uint32_t rsp_opcode) { gpr_device_t *gdev = apm->gdev; @@ -143,6 +145,7 @@ static void q6apm_put_audioreach_graph(struct kref *ref) kfree(graph); } + static int q6apm_get_apm_state(struct q6apm *apm) { struct gpr_pkt *pkt; @@ -158,6 +161,15 @@ static int q6apm_get_apm_state(struct q6apm *apm) return apm->state; } +bool q6apm_is_adsp_ready(void) +{ + if (g_apm) + return q6apm_get_apm_state(g_apm); + + return false; +} +EXPORT_SYMBOL_GPL(q6apm_is_adsp_ready); + static struct audioreach_module *__q6apm_find_module_by_mid(struct q6apm *apm, struct audioreach_graph_info *info, uint32_t mid) @@ -658,6 +670,8 @@ static int apm_probe(gpr_device_t *gdev) idr_init(&apm->modules_idr); + g_apm = apm; + q6apm_get_apm_state(apm); ret = devm_snd_soc_register_component(dev, &q6apm_audio_component, NULL, 0); diff --git a/sound/soc/qcom/qdsp6/q6apm.h b/sound/soc/qcom/qdsp6/q6apm.h index 273f97812741..7005be9b63e3 100644 --- a/sound/soc/qcom/qdsp6/q6apm.h +++ b/sound/soc/qcom/qdsp6/q6apm.h @@ -145,4 +145,6 @@ struct audioreach_module *q6apm_find_module_by_mid(struct q6apm_graph *graph, void q6apm_set_fe_dai_ops(struct snd_soc_dai_driver *dai_drv); int q6apm_graph_get_rx_shmem_module_iid(struct q6apm_graph *graph); +bool q6apm_is_adsp_ready(void); + #endif /* __APM_GRAPH_ */ diff --git a/sound/soc/qcom/qdsp6/q6prm.c b/sound/soc/qcom/qdsp6/q6prm.c index 8aa1a213bfb7..3aa63aac4a68 100644 --- a/sound/soc/qcom/qdsp6/q6prm.c +++ b/sound/soc/qcom/qdsp6/q6prm.c @@ -12,6 +12,7 @@ #include <linux/soc/qcom/apr.h> #include <dt-bindings/soc/qcom,gpr.h> #include <dt-bindings/sound/qcom,q6dsp-lpass-ports.h> +#include "q6apm.h" #include "q6prm.h" #include "audioreach.h" @@ -226,6 +227,9 @@ static int prm_probe(gpr_device_t *gdev) init_waitqueue_head(&cc->wait); dev_set_drvdata(dev, cc); + if (!q6apm_is_adsp_ready()) + return -EPROBE_DEFER; + return devm_of_platform_populate(dev); } |