Lines Matching +full:burst +full:- +full:wrap

1 // SPDX-License-Identifier: GPL-2.0-only
3 * rt5677-spi.c -- RT5677 ALSA SoC audio codec driver
30 #include "rt5677-spi.h"
39 * DataPhase word size of 16-bit commands is 2 bytes.
40 * DataPhase word size of 32-bit commands is 4 bytes.
41 * DataPhase word size of burst commands is 8 bytes.
42 * The DSP CPU is little-endian.
54 #define RT5677_MIC_BUF_BYTES ((u32)(RT5677_BUF_BYTES_TOTAL - \
66 size_t dma_offset; /* zero-based offset into runtime->dma_area */
68 u32 mic_read_offset; /* zero-based offset into DSP's mic buffer */
87 /* The DAI name "rt5677-dsp-cpu-dai" is not used. The actual DAI name
88 * registered with ASoC is the name of the device "spi-RT5677AA:00",
91 .name = "rt5677-dsp-cpu-dai",
123 cancel_delayed_work_sync(&rt5677_dsp->copy_work); in rt5677_spi_pcm_close()
124 rt5677->set_dsp_vad(codec_component, false); in rt5677_spi_pcm_close()
136 mutex_lock(&rt5677_dsp->dma_lock); in rt5677_spi_hw_params()
137 rt5677_dsp->substream = substream; in rt5677_spi_hw_params()
138 mutex_unlock(&rt5677_dsp->dma_lock); in rt5677_spi_hw_params()
150 mutex_lock(&rt5677_dsp->dma_lock); in rt5677_spi_hw_free()
151 rt5677_dsp->substream = NULL; in rt5677_spi_hw_free()
152 mutex_unlock(&rt5677_dsp->dma_lock); in rt5677_spi_hw_free()
169 rt5677->set_dsp_vad(rt5677_component, true); in rt5677_spi_prepare()
170 rt5677_dsp->dma_offset = 0; in rt5677_spi_prepare()
171 rt5677_dsp->avail_bytes = 0; in rt5677_spi_prepare()
179 struct snd_pcm_runtime *runtime = substream->runtime; in rt5677_spi_pcm_pointer()
183 return bytes_to_frames(runtime, rt5677_dsp->dma_offset); in rt5677_spi_pcm_pointer()
197 /* Adjust the offset so that it's zero-based */ in rt5677_spi_mic_write_offset()
198 *mic_write_offset = *mic_write_offset - sizeof(u32); in rt5677_spi_mic_write_offset()
199 return *mic_write_offset < RT5677_MIC_BUF_BYTES ? 0 : -EFAULT; in rt5677_spi_mic_write_offset()
204 * dma_area of the pcm runtime. The receiving buffer may wrap around.
214 struct snd_pcm_runtime *runtime = rt5677_dsp->substream->runtime; in rt5677_spi_copy_block()
219 if (begin > end || runtime->dma_bytes < 2 * bytes_per_frame) { in rt5677_spi_copy_block()
220 dev_err(rt5677_dsp->dev, in rt5677_spi_copy_block()
222 begin, end, runtime->dma_bytes); in rt5677_spi_copy_block()
223 return -EINVAL; in rt5677_spi_copy_block()
231 * last "receiving buffer size - one frame" bytes are copied. in rt5677_spi_copy_block()
233 if (end - begin > runtime->dma_bytes - bytes_per_frame) in rt5677_spi_copy_block()
234 begin = end - (runtime->dma_bytes - bytes_per_frame); in rt5677_spi_copy_block()
237 first_chunk_len = end - begin; in rt5677_spi_copy_block()
239 if (rt5677_dsp->dma_offset + first_chunk_len > runtime->dma_bytes) { in rt5677_spi_copy_block()
242 first_chunk_len = runtime->dma_bytes - rt5677_dsp->dma_offset; in rt5677_spi_copy_block()
243 second_chunk_len -= first_chunk_len; in rt5677_spi_copy_block()
248 runtime->dma_area + rt5677_dsp->dma_offset, in rt5677_spi_copy_block()
252 rt5677_dsp->dma_offset += first_chunk_len; in rt5677_spi_copy_block()
253 if (rt5677_dsp->dma_offset == runtime->dma_bytes) in rt5677_spi_copy_block()
254 rt5677_dsp->dma_offset = 0; in rt5677_spi_copy_block()
259 begin + first_chunk_len, runtime->dma_area, in rt5677_spi_copy_block()
262 rt5677_dsp->dma_offset = second_chunk_len; in rt5677_spi_copy_block()
270 * wrap around. mic_read_offset is updated after successful copy.
283 target = rt5677_dsp->mic_read_offset + amount; in rt5677_spi_copy()
285 ret |= rt5677_spi_copy_block(rt5677_dsp, rt5677_dsp->mic_read_offset, in rt5677_spi_copy()
289 /* Wrap around, copy the second chunk */ in rt5677_spi_copy()
290 target -= RT5677_MIC_BUF_BYTES; in rt5677_spi_copy()
295 rt5677_dsp->mic_read_offset = target; in rt5677_spi_copy()
313 /* Ensure runtime->dma_area buffer does not go away while copying. */ in rt5677_spi_copy_work()
314 mutex_lock(&rt5677_dsp->dma_lock); in rt5677_spi_copy_work()
315 if (!rt5677_dsp->substream) { in rt5677_spi_copy_work()
316 dev_err(rt5677_dsp->dev, "No pcm substream\n"); in rt5677_spi_copy_work()
320 runtime = rt5677_dsp->substream->runtime; in rt5677_spi_copy_work()
323 dev_err(rt5677_dsp->dev, "No mic_write_offset\n"); in rt5677_spi_copy_work()
331 if (rt5677_dsp->new_hotword) { in rt5677_spi_copy_work()
332 rt5677_dsp->new_hotword = false; in rt5677_spi_copy_work()
335 rt5677_dsp->mic_read_offset = RT5677_MIC_BUF_BYTES - in rt5677_spi_copy_work()
336 (RT5677_MIC_BUF_FIRST_READ_SIZE - in rt5677_spi_copy_work()
339 rt5677_dsp->mic_read_offset = mic_write_offset - in rt5677_spi_copy_work()
344 if (rt5677_dsp->mic_read_offset <= mic_write_offset) in rt5677_spi_copy_work()
345 new_bytes = mic_write_offset - rt5677_dsp->mic_read_offset; in rt5677_spi_copy_work()
348 - rt5677_dsp->mic_read_offset; in rt5677_spi_copy_work()
351 period_bytes = snd_pcm_lib_period_bytes(rt5677_dsp->substream); in rt5677_spi_copy_work()
354 - rt5677_dsp->avail_bytes); in rt5677_spi_copy_work()
357 dev_err(rt5677_dsp->dev, "Copy failed %d\n", ret); in rt5677_spi_copy_work()
360 rt5677_dsp->avail_bytes += copy_bytes; in rt5677_spi_copy_work()
361 if (rt5677_dsp->avail_bytes >= period_bytes) { in rt5677_spi_copy_work()
362 snd_pcm_period_elapsed(rt5677_dsp->substream); in rt5677_spi_copy_work()
363 rt5677_dsp->avail_bytes = 0; in rt5677_spi_copy_work()
365 new_bytes -= copy_bytes; in rt5677_spi_copy_work()
368 delay = bytes_to_frames(runtime, period_bytes) / (runtime->rate / 1000); in rt5677_spi_copy_work()
369 schedule_delayed_work(&rt5677_dsp->copy_work, msecs_to_jiffies(delay)); in rt5677_spi_copy_work()
371 mutex_unlock(&rt5677_dsp->dma_lock); in rt5677_spi_copy_work()
377 snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_VMALLOC, in rt5677_spi_pcm_new()
386 rt5677_dsp = devm_kzalloc(component->dev, sizeof(*rt5677_dsp), in rt5677_spi_pcm_probe()
389 return -ENOMEM; in rt5677_spi_pcm_probe()
390 rt5677_dsp->dev = &g_spi->dev; in rt5677_spi_pcm_probe()
391 mutex_init(&rt5677_dsp->dma_lock); in rt5677_spi_pcm_probe()
392 INIT_DELAYED_WORK(&rt5677_dsp->copy_work, rt5677_spi_copy_work); in rt5677_spi_pcm_probe()
448 *len = (((remain - 1) >> 3) + 1) << 3; in rt5677_spi_select_cmd()
464 si = w + word_size - i - 1; in rt5677_spi_reverse()
470 /* Read DSP address space using SPI. addr and len have to be 4-byte aligned. */
484 return -ENODEV; in rt5677_spi_read()
487 dev_err(&g_spi->dev, "Bad read align 0x%x(%zu)\n", addr, len); in rt5677_spi_read()
488 return -EACCES; in rt5677_spi_read()
501 len - offset, &t[1].len); in rt5677_spi_read()
516 rt5677_spi_reverse(cb + offset, len - offset, body, t[1].len); in rt5677_spi_read()
522 /* Write DSP address space using SPI. addr has to be 4-byte aligned.
523 * If len is not 4-byte aligned, then extra zeros are written at the end
539 return -ENODEV; in rt5677_spi_write()
542 dev_err(&g_spi->dev, "Bad write align 0x%x(%zu)\n", addr, len); in rt5677_spi_write()
543 return -EACCES; in rt5677_spi_write()
553 len - offset, &t.len); in rt5677_spi_write()
563 rt5677_spi_reverse(body, t.len, cb + offset, len - offset); in rt5677_spi_write()
577 return rt5677_spi_write(addr, fw->data, fw->size); in rt5677_spi_write_firmware()
588 rt5677_dsp = dev_get_drvdata(&g_spi->dev); in rt5677_spi_hotword_detected()
590 dev_err(&g_spi->dev, "Can't get rt5677_dsp\n"); in rt5677_spi_hotword_detected()
594 mutex_lock(&rt5677_dsp->dma_lock); in rt5677_spi_hotword_detected()
595 dev_info(rt5677_dsp->dev, "Hotword detected\n"); in rt5677_spi_hotword_detected()
596 rt5677_dsp->new_hotword = true; in rt5677_spi_hotword_detected()
597 mutex_unlock(&rt5677_dsp->dma_lock); in rt5677_spi_hotword_detected()
599 schedule_delayed_work(&rt5677_dsp->copy_work, 0); in rt5677_spi_hotword_detected()
609 ret = devm_snd_soc_register_component(&spi->dev, in rt5677_spi_probe()
613 dev_err(&spi->dev, "Failed to register component.\n"); in rt5677_spi_probe()