19b4fe0f1SSrinivas Kandagatla // SPDX-License-Identifier: GPL-2.0 29b4fe0f1SSrinivas Kandagatla // Copyright (c) 2021, Linaro Limited 39b4fe0f1SSrinivas Kandagatla 49b4fe0f1SSrinivas Kandagatla #include <linux/init.h> 59b4fe0f1SSrinivas Kandagatla #include <linux/err.h> 69b4fe0f1SSrinivas Kandagatla #include <linux/module.h> 79b4fe0f1SSrinivas Kandagatla #include <linux/platform_device.h> 89b4fe0f1SSrinivas Kandagatla #include <linux/slab.h> 99b4fe0f1SSrinivas Kandagatla #include <sound/soc.h> 109b4fe0f1SSrinivas Kandagatla #include <sound/soc-dapm.h> 119b4fe0f1SSrinivas Kandagatla #include <sound/pcm.h> 129b4fe0f1SSrinivas Kandagatla #include <asm/dma.h> 139b4fe0f1SSrinivas Kandagatla #include <linux/dma-mapping.h> 149b4fe0f1SSrinivas Kandagatla #include <linux/of_device.h> 159b4fe0f1SSrinivas Kandagatla #include <sound/pcm_params.h> 169b4fe0f1SSrinivas Kandagatla #include "q6apm.h" 179b4fe0f1SSrinivas Kandagatla 189b4fe0f1SSrinivas Kandagatla #define DRV_NAME "q6apm-dai" 199b4fe0f1SSrinivas Kandagatla 209b4fe0f1SSrinivas Kandagatla #define PLAYBACK_MIN_NUM_PERIODS 2 219b4fe0f1SSrinivas Kandagatla #define PLAYBACK_MAX_NUM_PERIODS 8 229b4fe0f1SSrinivas Kandagatla #define PLAYBACK_MAX_PERIOD_SIZE 65536 239b4fe0f1SSrinivas Kandagatla #define PLAYBACK_MIN_PERIOD_SIZE 128 249b4fe0f1SSrinivas Kandagatla #define CAPTURE_MIN_NUM_PERIODS 2 259b4fe0f1SSrinivas Kandagatla #define CAPTURE_MAX_NUM_PERIODS 8 269b4fe0f1SSrinivas Kandagatla #define CAPTURE_MAX_PERIOD_SIZE 4096 279b4fe0f1SSrinivas Kandagatla #define CAPTURE_MIN_PERIOD_SIZE 320 289b4fe0f1SSrinivas Kandagatla #define BUFFER_BYTES_MAX (PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE) 299b4fe0f1SSrinivas Kandagatla #define BUFFER_BYTES_MIN (PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE) 309b4fe0f1SSrinivas Kandagatla #define SID_MASK_DEFAULT 0xF 319b4fe0f1SSrinivas Kandagatla 329b4fe0f1SSrinivas Kandagatla enum stream_state { 339b4fe0f1SSrinivas Kandagatla Q6APM_STREAM_IDLE = 0, 349b4fe0f1SSrinivas Kandagatla Q6APM_STREAM_STOPPED, 359b4fe0f1SSrinivas Kandagatla Q6APM_STREAM_RUNNING, 369b4fe0f1SSrinivas Kandagatla }; 379b4fe0f1SSrinivas Kandagatla 389b4fe0f1SSrinivas Kandagatla struct q6apm_dai_rtd { 399b4fe0f1SSrinivas Kandagatla struct snd_pcm_substream *substream; 409b4fe0f1SSrinivas Kandagatla struct snd_compr_stream *cstream; 419b4fe0f1SSrinivas Kandagatla struct snd_compr_params codec_param; 429b4fe0f1SSrinivas Kandagatla struct snd_dma_buffer dma_buffer; 439b4fe0f1SSrinivas Kandagatla phys_addr_t phys; 449b4fe0f1SSrinivas Kandagatla unsigned int pcm_size; 459b4fe0f1SSrinivas Kandagatla unsigned int pcm_count; 469b4fe0f1SSrinivas Kandagatla unsigned int pos; /* Buffer position */ 479b4fe0f1SSrinivas Kandagatla unsigned int periods; 489b4fe0f1SSrinivas Kandagatla unsigned int bytes_sent; 499b4fe0f1SSrinivas Kandagatla unsigned int bytes_received; 509b4fe0f1SSrinivas Kandagatla unsigned int copied_total; 519b4fe0f1SSrinivas Kandagatla uint16_t bits_per_sample; 529b4fe0f1SSrinivas Kandagatla uint16_t source; /* Encoding source bit mask */ 539b4fe0f1SSrinivas Kandagatla uint16_t session_id; 549b4fe0f1SSrinivas Kandagatla enum stream_state state; 559b4fe0f1SSrinivas Kandagatla struct q6apm_graph *graph; 569b4fe0f1SSrinivas Kandagatla }; 579b4fe0f1SSrinivas Kandagatla 589b4fe0f1SSrinivas Kandagatla struct q6apm_dai_data { 599b4fe0f1SSrinivas Kandagatla long long sid; 609b4fe0f1SSrinivas Kandagatla }; 619b4fe0f1SSrinivas Kandagatla 629b4fe0f1SSrinivas Kandagatla static struct snd_pcm_hardware q6apm_dai_hardware_capture = { 639b4fe0f1SSrinivas Kandagatla .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER | 649b4fe0f1SSrinivas Kandagatla SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | 659b4fe0f1SSrinivas Kandagatla SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), 669b4fe0f1SSrinivas Kandagatla .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), 679b4fe0f1SSrinivas Kandagatla .rates = SNDRV_PCM_RATE_8000_48000, 689b4fe0f1SSrinivas Kandagatla .rate_min = 8000, 699b4fe0f1SSrinivas Kandagatla .rate_max = 48000, 709b4fe0f1SSrinivas Kandagatla .channels_min = 2, 719b4fe0f1SSrinivas Kandagatla .channels_max = 4, 729b4fe0f1SSrinivas Kandagatla .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE, 739b4fe0f1SSrinivas Kandagatla .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE, 749b4fe0f1SSrinivas Kandagatla .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE, 759b4fe0f1SSrinivas Kandagatla .periods_min = CAPTURE_MIN_NUM_PERIODS, 769b4fe0f1SSrinivas Kandagatla .periods_max = CAPTURE_MAX_NUM_PERIODS, 779b4fe0f1SSrinivas Kandagatla .fifo_size = 0, 789b4fe0f1SSrinivas Kandagatla }; 799b4fe0f1SSrinivas Kandagatla 809b4fe0f1SSrinivas Kandagatla static struct snd_pcm_hardware q6apm_dai_hardware_playback = { 819b4fe0f1SSrinivas Kandagatla .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER | 829b4fe0f1SSrinivas Kandagatla SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | 839b4fe0f1SSrinivas Kandagatla SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), 849b4fe0f1SSrinivas Kandagatla .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE), 859b4fe0f1SSrinivas Kandagatla .rates = SNDRV_PCM_RATE_8000_192000, 869b4fe0f1SSrinivas Kandagatla .rate_min = 8000, 879b4fe0f1SSrinivas Kandagatla .rate_max = 192000, 889b4fe0f1SSrinivas Kandagatla .channels_min = 2, 899b4fe0f1SSrinivas Kandagatla .channels_max = 8, 909b4fe0f1SSrinivas Kandagatla .buffer_bytes_max = (PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE), 919b4fe0f1SSrinivas Kandagatla .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE, 929b4fe0f1SSrinivas Kandagatla .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE, 939b4fe0f1SSrinivas Kandagatla .periods_min = PLAYBACK_MIN_NUM_PERIODS, 949b4fe0f1SSrinivas Kandagatla .periods_max = PLAYBACK_MAX_NUM_PERIODS, 959b4fe0f1SSrinivas Kandagatla .fifo_size = 0, 969b4fe0f1SSrinivas Kandagatla }; 979b4fe0f1SSrinivas Kandagatla 989b4fe0f1SSrinivas Kandagatla static void event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, void *priv) 999b4fe0f1SSrinivas Kandagatla { 1009b4fe0f1SSrinivas Kandagatla struct q6apm_dai_rtd *prtd = priv; 1019b4fe0f1SSrinivas Kandagatla struct snd_pcm_substream *substream = prtd->substream; 1029b4fe0f1SSrinivas Kandagatla 1039b4fe0f1SSrinivas Kandagatla switch (opcode) { 1049b4fe0f1SSrinivas Kandagatla case APM_CLIENT_EVENT_CMD_EOS_DONE: 1059b4fe0f1SSrinivas Kandagatla prtd->state = Q6APM_STREAM_STOPPED; 1069b4fe0f1SSrinivas Kandagatla break; 1079b4fe0f1SSrinivas Kandagatla case APM_CLIENT_EVENT_DATA_WRITE_DONE: 1089b4fe0f1SSrinivas Kandagatla prtd->pos += prtd->pcm_count; 1099b4fe0f1SSrinivas Kandagatla snd_pcm_period_elapsed(substream); 1109b4fe0f1SSrinivas Kandagatla if (prtd->state == Q6APM_STREAM_RUNNING) 1119b4fe0f1SSrinivas Kandagatla q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, 0); 1129b4fe0f1SSrinivas Kandagatla 1139b4fe0f1SSrinivas Kandagatla break; 1149b4fe0f1SSrinivas Kandagatla case APM_CLIENT_EVENT_DATA_READ_DONE: 1159b4fe0f1SSrinivas Kandagatla prtd->pos += prtd->pcm_count; 1169b4fe0f1SSrinivas Kandagatla snd_pcm_period_elapsed(substream); 1179b4fe0f1SSrinivas Kandagatla if (prtd->state == Q6APM_STREAM_RUNNING) 1189b4fe0f1SSrinivas Kandagatla q6apm_read(prtd->graph); 1199b4fe0f1SSrinivas Kandagatla 1209b4fe0f1SSrinivas Kandagatla break; 1219b4fe0f1SSrinivas Kandagatla default: 1229b4fe0f1SSrinivas Kandagatla break; 1239b4fe0f1SSrinivas Kandagatla } 1249b4fe0f1SSrinivas Kandagatla } 1259b4fe0f1SSrinivas Kandagatla 1269b4fe0f1SSrinivas Kandagatla static int q6apm_dai_prepare(struct snd_soc_component *component, 1279b4fe0f1SSrinivas Kandagatla struct snd_pcm_substream *substream) 1289b4fe0f1SSrinivas Kandagatla { 1299b4fe0f1SSrinivas Kandagatla struct snd_pcm_runtime *runtime = substream->runtime; 1309b4fe0f1SSrinivas Kandagatla struct q6apm_dai_rtd *prtd = runtime->private_data; 1319b4fe0f1SSrinivas Kandagatla struct audioreach_module_config cfg; 1329b4fe0f1SSrinivas Kandagatla struct device *dev = component->dev; 1339b4fe0f1SSrinivas Kandagatla struct q6apm_dai_data *pdata; 1349b4fe0f1SSrinivas Kandagatla int ret; 1359b4fe0f1SSrinivas Kandagatla 1369b4fe0f1SSrinivas Kandagatla pdata = snd_soc_component_get_drvdata(component); 1379b4fe0f1SSrinivas Kandagatla if (!pdata) 1389b4fe0f1SSrinivas Kandagatla return -EINVAL; 1399b4fe0f1SSrinivas Kandagatla 1409b4fe0f1SSrinivas Kandagatla if (!prtd || !prtd->graph) { 1419b4fe0f1SSrinivas Kandagatla dev_err(dev, "%s: private data null or audio client freed\n", __func__); 1429b4fe0f1SSrinivas Kandagatla return -EINVAL; 1439b4fe0f1SSrinivas Kandagatla } 1449b4fe0f1SSrinivas Kandagatla 1459b4fe0f1SSrinivas Kandagatla cfg.direction = substream->stream; 1469b4fe0f1SSrinivas Kandagatla cfg.sample_rate = runtime->rate; 1479b4fe0f1SSrinivas Kandagatla cfg.num_channels = runtime->channels; 1489b4fe0f1SSrinivas Kandagatla cfg.bit_width = prtd->bits_per_sample; 1499b4fe0f1SSrinivas Kandagatla 150*58136d93SSrinivas Kandagatla if (prtd->state) { 151*58136d93SSrinivas Kandagatla /* clear the previous setup if any */ 152*58136d93SSrinivas Kandagatla q6apm_graph_stop(prtd->graph); 153*58136d93SSrinivas Kandagatla q6apm_unmap_memory_regions(prtd->graph, substream->stream); 154*58136d93SSrinivas Kandagatla } 155*58136d93SSrinivas Kandagatla 1569b4fe0f1SSrinivas Kandagatla prtd->pcm_count = snd_pcm_lib_period_bytes(substream); 1579b4fe0f1SSrinivas Kandagatla prtd->pos = 0; 1589b4fe0f1SSrinivas Kandagatla /* rate and channels are sent to audio driver */ 1599b4fe0f1SSrinivas Kandagatla ret = q6apm_graph_media_format_shmem(prtd->graph, &cfg); 1609b4fe0f1SSrinivas Kandagatla if (ret < 0) { 1619b4fe0f1SSrinivas Kandagatla dev_err(dev, "%s: q6apm_open_write failed\n", __func__); 1629b4fe0f1SSrinivas Kandagatla return ret; 1639b4fe0f1SSrinivas Kandagatla } 1649b4fe0f1SSrinivas Kandagatla 1659b4fe0f1SSrinivas Kandagatla ret = q6apm_graph_media_format_pcm(prtd->graph, &cfg); 1669b4fe0f1SSrinivas Kandagatla if (ret < 0) 1679b4fe0f1SSrinivas Kandagatla dev_err(dev, "%s: CMD Format block failed\n", __func__); 1689b4fe0f1SSrinivas Kandagatla 1699b4fe0f1SSrinivas Kandagatla ret = q6apm_map_memory_regions(prtd->graph, substream->stream, prtd->phys, 1709b4fe0f1SSrinivas Kandagatla (prtd->pcm_size / prtd->periods), prtd->periods); 1719b4fe0f1SSrinivas Kandagatla 1729b4fe0f1SSrinivas Kandagatla if (ret < 0) { 1739b4fe0f1SSrinivas Kandagatla dev_err(dev, "Audio Start: Buffer Allocation failed rc = %d\n", ret); 1749b4fe0f1SSrinivas Kandagatla return -ENOMEM; 1759b4fe0f1SSrinivas Kandagatla } 1769b4fe0f1SSrinivas Kandagatla 1779b4fe0f1SSrinivas Kandagatla ret = q6apm_graph_prepare(prtd->graph); 1789b4fe0f1SSrinivas Kandagatla if (ret) { 1799b4fe0f1SSrinivas Kandagatla dev_err(dev, "Failed to prepare Graph %d\n", ret); 1809b4fe0f1SSrinivas Kandagatla return ret; 1819b4fe0f1SSrinivas Kandagatla } 1829b4fe0f1SSrinivas Kandagatla 1839b4fe0f1SSrinivas Kandagatla ret = q6apm_graph_start(prtd->graph); 1849b4fe0f1SSrinivas Kandagatla if (ret) { 1859b4fe0f1SSrinivas Kandagatla dev_err(dev, "Failed to Start Graph %d\n", ret); 1869b4fe0f1SSrinivas Kandagatla return ret; 1879b4fe0f1SSrinivas Kandagatla } 1889b4fe0f1SSrinivas Kandagatla 1899b4fe0f1SSrinivas Kandagatla if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 1909b4fe0f1SSrinivas Kandagatla int i; 1919b4fe0f1SSrinivas Kandagatla /* Queue the buffers for Capture ONLY after graph is started */ 1929b4fe0f1SSrinivas Kandagatla for (i = 0; i < runtime->periods; i++) 1939b4fe0f1SSrinivas Kandagatla q6apm_read(prtd->graph); 1949b4fe0f1SSrinivas Kandagatla 1959b4fe0f1SSrinivas Kandagatla } 1969b4fe0f1SSrinivas Kandagatla 1979b4fe0f1SSrinivas Kandagatla /* Now that graph as been prepared and started update the internal state accordingly */ 1989b4fe0f1SSrinivas Kandagatla prtd->state = Q6APM_STREAM_RUNNING; 1999b4fe0f1SSrinivas Kandagatla 2009b4fe0f1SSrinivas Kandagatla return 0; 2019b4fe0f1SSrinivas Kandagatla } 2029b4fe0f1SSrinivas Kandagatla 2039b4fe0f1SSrinivas Kandagatla static int q6apm_dai_trigger(struct snd_soc_component *component, 2049b4fe0f1SSrinivas Kandagatla struct snd_pcm_substream *substream, int cmd) 2059b4fe0f1SSrinivas Kandagatla { 2069b4fe0f1SSrinivas Kandagatla struct snd_pcm_runtime *runtime = substream->runtime; 2079b4fe0f1SSrinivas Kandagatla struct q6apm_dai_rtd *prtd = runtime->private_data; 2089b4fe0f1SSrinivas Kandagatla int ret = 0; 2099b4fe0f1SSrinivas Kandagatla 2109b4fe0f1SSrinivas Kandagatla switch (cmd) { 2119b4fe0f1SSrinivas Kandagatla case SNDRV_PCM_TRIGGER_START: 2129b4fe0f1SSrinivas Kandagatla case SNDRV_PCM_TRIGGER_RESUME: 2139b4fe0f1SSrinivas Kandagatla case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 2149b4fe0f1SSrinivas Kandagatla /* start writing buffers for playback only as we already queued capture buffers */ 2159b4fe0f1SSrinivas Kandagatla if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 2169b4fe0f1SSrinivas Kandagatla ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, 0); 2179b4fe0f1SSrinivas Kandagatla break; 2189b4fe0f1SSrinivas Kandagatla case SNDRV_PCM_TRIGGER_STOP: 2199b4fe0f1SSrinivas Kandagatla /* TODO support be handled via SoftPause Module */ 2209b4fe0f1SSrinivas Kandagatla prtd->state = Q6APM_STREAM_STOPPED; 2219b4fe0f1SSrinivas Kandagatla break; 2229b4fe0f1SSrinivas Kandagatla case SNDRV_PCM_TRIGGER_SUSPEND: 2239b4fe0f1SSrinivas Kandagatla case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 2249b4fe0f1SSrinivas Kandagatla break; 2259b4fe0f1SSrinivas Kandagatla default: 2269b4fe0f1SSrinivas Kandagatla ret = -EINVAL; 2279b4fe0f1SSrinivas Kandagatla break; 2289b4fe0f1SSrinivas Kandagatla } 2299b4fe0f1SSrinivas Kandagatla 2309b4fe0f1SSrinivas Kandagatla return ret; 2319b4fe0f1SSrinivas Kandagatla } 2329b4fe0f1SSrinivas Kandagatla 2339b4fe0f1SSrinivas Kandagatla static int q6apm_dai_open(struct snd_soc_component *component, 2349b4fe0f1SSrinivas Kandagatla struct snd_pcm_substream *substream) 2359b4fe0f1SSrinivas Kandagatla { 2369b4fe0f1SSrinivas Kandagatla struct snd_pcm_runtime *runtime = substream->runtime; 2379b4fe0f1SSrinivas Kandagatla struct snd_soc_pcm_runtime *soc_prtd = substream->private_data; 2389b4fe0f1SSrinivas Kandagatla struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_prtd, 0); 2399b4fe0f1SSrinivas Kandagatla struct device *dev = component->dev; 2409b4fe0f1SSrinivas Kandagatla struct q6apm_dai_data *pdata; 2419b4fe0f1SSrinivas Kandagatla struct q6apm_dai_rtd *prtd; 2429b4fe0f1SSrinivas Kandagatla int graph_id, ret; 2439b4fe0f1SSrinivas Kandagatla 2449b4fe0f1SSrinivas Kandagatla graph_id = cpu_dai->driver->id; 2459b4fe0f1SSrinivas Kandagatla 2469b4fe0f1SSrinivas Kandagatla pdata = snd_soc_component_get_drvdata(component); 2479b4fe0f1SSrinivas Kandagatla if (!pdata) { 2489b4fe0f1SSrinivas Kandagatla dev_err(dev, "Drv data not found ..\n"); 2499b4fe0f1SSrinivas Kandagatla return -EINVAL; 2509b4fe0f1SSrinivas Kandagatla } 2519b4fe0f1SSrinivas Kandagatla 2529b4fe0f1SSrinivas Kandagatla prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); 2539b4fe0f1SSrinivas Kandagatla if (prtd == NULL) 2549b4fe0f1SSrinivas Kandagatla return -ENOMEM; 2559b4fe0f1SSrinivas Kandagatla 2569b4fe0f1SSrinivas Kandagatla prtd->substream = substream; 2579b4fe0f1SSrinivas Kandagatla prtd->graph = q6apm_graph_open(dev, (q6apm_cb)event_handler, prtd, graph_id); 2589b4fe0f1SSrinivas Kandagatla if (IS_ERR(prtd->graph)) { 2599b4fe0f1SSrinivas Kandagatla dev_err(dev, "%s: Could not allocate memory\n", __func__); 2609b4fe0f1SSrinivas Kandagatla ret = PTR_ERR(prtd->graph); 2619b4fe0f1SSrinivas Kandagatla goto err; 2629b4fe0f1SSrinivas Kandagatla } 2639b4fe0f1SSrinivas Kandagatla 2649b4fe0f1SSrinivas Kandagatla if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 2659b4fe0f1SSrinivas Kandagatla runtime->hw = q6apm_dai_hardware_playback; 2669b4fe0f1SSrinivas Kandagatla else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 2679b4fe0f1SSrinivas Kandagatla runtime->hw = q6apm_dai_hardware_capture; 2689b4fe0f1SSrinivas Kandagatla 2699b4fe0f1SSrinivas Kandagatla /* Ensure that buffer size is a multiple of period size */ 2709b4fe0f1SSrinivas Kandagatla ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 2719b4fe0f1SSrinivas Kandagatla if (ret < 0) { 2729b4fe0f1SSrinivas Kandagatla dev_err(dev, "snd_pcm_hw_constraint_integer failed\n"); 2739b4fe0f1SSrinivas Kandagatla goto err; 2749b4fe0f1SSrinivas Kandagatla } 2759b4fe0f1SSrinivas Kandagatla 2769b4fe0f1SSrinivas Kandagatla if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 2779b4fe0f1SSrinivas Kandagatla ret = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 2789b4fe0f1SSrinivas Kandagatla BUFFER_BYTES_MIN, BUFFER_BYTES_MAX); 2799b4fe0f1SSrinivas Kandagatla if (ret < 0) { 2809b4fe0f1SSrinivas Kandagatla dev_err(dev, "constraint for buffer bytes min max ret = %d\n", ret); 2819b4fe0f1SSrinivas Kandagatla goto err; 2829b4fe0f1SSrinivas Kandagatla } 2839b4fe0f1SSrinivas Kandagatla } 2849b4fe0f1SSrinivas Kandagatla 2859b4fe0f1SSrinivas Kandagatla ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); 2869b4fe0f1SSrinivas Kandagatla if (ret < 0) { 2879b4fe0f1SSrinivas Kandagatla dev_err(dev, "constraint for period bytes step ret = %d\n", ret); 2889b4fe0f1SSrinivas Kandagatla goto err; 2899b4fe0f1SSrinivas Kandagatla } 2909b4fe0f1SSrinivas Kandagatla 2919b4fe0f1SSrinivas Kandagatla ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); 2929b4fe0f1SSrinivas Kandagatla if (ret < 0) { 2939b4fe0f1SSrinivas Kandagatla dev_err(dev, "constraint for buffer bytes step ret = %d\n", ret); 2949b4fe0f1SSrinivas Kandagatla goto err; 2959b4fe0f1SSrinivas Kandagatla } 2969b4fe0f1SSrinivas Kandagatla 2979b4fe0f1SSrinivas Kandagatla runtime->private_data = prtd; 2989b4fe0f1SSrinivas Kandagatla runtime->dma_bytes = BUFFER_BYTES_MAX; 2999b4fe0f1SSrinivas Kandagatla if (pdata->sid < 0) 3009b4fe0f1SSrinivas Kandagatla prtd->phys = substream->dma_buffer.addr; 3019b4fe0f1SSrinivas Kandagatla else 3029b4fe0f1SSrinivas Kandagatla prtd->phys = substream->dma_buffer.addr | (pdata->sid << 32); 3039b4fe0f1SSrinivas Kandagatla 3049b4fe0f1SSrinivas Kandagatla return 0; 3059b4fe0f1SSrinivas Kandagatla err: 3069b4fe0f1SSrinivas Kandagatla kfree(prtd); 3079b4fe0f1SSrinivas Kandagatla 3089b4fe0f1SSrinivas Kandagatla return ret; 3099b4fe0f1SSrinivas Kandagatla } 3109b4fe0f1SSrinivas Kandagatla 3119b4fe0f1SSrinivas Kandagatla static int q6apm_dai_close(struct snd_soc_component *component, 3129b4fe0f1SSrinivas Kandagatla struct snd_pcm_substream *substream) 3139b4fe0f1SSrinivas Kandagatla { 3149b4fe0f1SSrinivas Kandagatla struct snd_pcm_runtime *runtime = substream->runtime; 3159b4fe0f1SSrinivas Kandagatla struct q6apm_dai_rtd *prtd = runtime->private_data; 3169b4fe0f1SSrinivas Kandagatla 3178f2e5c65SSrinivas Kandagatla if (prtd->state) { /* only stop graph that is started */ 3189b4fe0f1SSrinivas Kandagatla q6apm_graph_stop(prtd->graph); 3199b4fe0f1SSrinivas Kandagatla q6apm_unmap_memory_regions(prtd->graph, substream->stream); 3208f2e5c65SSrinivas Kandagatla } 3218f2e5c65SSrinivas Kandagatla 3229b4fe0f1SSrinivas Kandagatla q6apm_graph_close(prtd->graph); 3239b4fe0f1SSrinivas Kandagatla prtd->graph = NULL; 3249b4fe0f1SSrinivas Kandagatla kfree(prtd); 3259b4fe0f1SSrinivas Kandagatla runtime->private_data = NULL; 3269b4fe0f1SSrinivas Kandagatla 3279b4fe0f1SSrinivas Kandagatla return 0; 3289b4fe0f1SSrinivas Kandagatla } 3299b4fe0f1SSrinivas Kandagatla 3309b4fe0f1SSrinivas Kandagatla static snd_pcm_uframes_t q6apm_dai_pointer(struct snd_soc_component *component, 3319b4fe0f1SSrinivas Kandagatla struct snd_pcm_substream *substream) 3329b4fe0f1SSrinivas Kandagatla { 3339b4fe0f1SSrinivas Kandagatla struct snd_pcm_runtime *runtime = substream->runtime; 3349b4fe0f1SSrinivas Kandagatla struct q6apm_dai_rtd *prtd = runtime->private_data; 3359b4fe0f1SSrinivas Kandagatla 3369b4fe0f1SSrinivas Kandagatla if (prtd->pos == prtd->pcm_size) 3379b4fe0f1SSrinivas Kandagatla prtd->pos = 0; 3389b4fe0f1SSrinivas Kandagatla 3399b4fe0f1SSrinivas Kandagatla return bytes_to_frames(runtime, prtd->pos); 3409b4fe0f1SSrinivas Kandagatla } 3419b4fe0f1SSrinivas Kandagatla 3429b4fe0f1SSrinivas Kandagatla static int q6apm_dai_hw_params(struct snd_soc_component *component, 3439b4fe0f1SSrinivas Kandagatla struct snd_pcm_substream *substream, 3449b4fe0f1SSrinivas Kandagatla struct snd_pcm_hw_params *params) 3459b4fe0f1SSrinivas Kandagatla { 3469b4fe0f1SSrinivas Kandagatla struct snd_pcm_runtime *runtime = substream->runtime; 3479b4fe0f1SSrinivas Kandagatla struct q6apm_dai_rtd *prtd = runtime->private_data; 3489b4fe0f1SSrinivas Kandagatla 3499b4fe0f1SSrinivas Kandagatla prtd->pcm_size = params_buffer_bytes(params); 3509b4fe0f1SSrinivas Kandagatla prtd->periods = params_periods(params); 3519b4fe0f1SSrinivas Kandagatla 3529b4fe0f1SSrinivas Kandagatla switch (params_format(params)) { 3539b4fe0f1SSrinivas Kandagatla case SNDRV_PCM_FORMAT_S16_LE: 3549b4fe0f1SSrinivas Kandagatla prtd->bits_per_sample = 16; 3559b4fe0f1SSrinivas Kandagatla break; 3569b4fe0f1SSrinivas Kandagatla case SNDRV_PCM_FORMAT_S24_LE: 3579b4fe0f1SSrinivas Kandagatla prtd->bits_per_sample = 24; 3589b4fe0f1SSrinivas Kandagatla break; 3599b4fe0f1SSrinivas Kandagatla default: 3609b4fe0f1SSrinivas Kandagatla return -EINVAL; 3619b4fe0f1SSrinivas Kandagatla } 3629b4fe0f1SSrinivas Kandagatla 3639b4fe0f1SSrinivas Kandagatla return 0; 3649b4fe0f1SSrinivas Kandagatla } 3659b4fe0f1SSrinivas Kandagatla 3669b4fe0f1SSrinivas Kandagatla static int q6apm_dai_pcm_new(struct snd_soc_component *component, struct snd_soc_pcm_runtime *rtd) 3679b4fe0f1SSrinivas Kandagatla { 3689b4fe0f1SSrinivas Kandagatla int size = BUFFER_BYTES_MAX; 3699b4fe0f1SSrinivas Kandagatla 3709b4fe0f1SSrinivas Kandagatla return snd_pcm_set_fixed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, component->dev, size); 3719b4fe0f1SSrinivas Kandagatla } 3729b4fe0f1SSrinivas Kandagatla 3739b4fe0f1SSrinivas Kandagatla static const struct snd_soc_component_driver q6apm_fe_dai_component = { 3749b4fe0f1SSrinivas Kandagatla .name = DRV_NAME, 3759b4fe0f1SSrinivas Kandagatla .open = q6apm_dai_open, 3769b4fe0f1SSrinivas Kandagatla .close = q6apm_dai_close, 3779b4fe0f1SSrinivas Kandagatla .prepare = q6apm_dai_prepare, 3789b4fe0f1SSrinivas Kandagatla .pcm_construct = q6apm_dai_pcm_new, 3799b4fe0f1SSrinivas Kandagatla .hw_params = q6apm_dai_hw_params, 3809b4fe0f1SSrinivas Kandagatla .pointer = q6apm_dai_pointer, 3819b4fe0f1SSrinivas Kandagatla .trigger = q6apm_dai_trigger, 3829b4fe0f1SSrinivas Kandagatla }; 3839b4fe0f1SSrinivas Kandagatla 3849b4fe0f1SSrinivas Kandagatla static int q6apm_dai_probe(struct platform_device *pdev) 3859b4fe0f1SSrinivas Kandagatla { 3869b4fe0f1SSrinivas Kandagatla struct device *dev = &pdev->dev; 3879b4fe0f1SSrinivas Kandagatla struct device_node *node = dev->of_node; 3889b4fe0f1SSrinivas Kandagatla struct q6apm_dai_data *pdata; 3899b4fe0f1SSrinivas Kandagatla struct of_phandle_args args; 3909b4fe0f1SSrinivas Kandagatla int rc; 3919b4fe0f1SSrinivas Kandagatla 3929b4fe0f1SSrinivas Kandagatla pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 3939b4fe0f1SSrinivas Kandagatla if (!pdata) 3949b4fe0f1SSrinivas Kandagatla return -ENOMEM; 3959b4fe0f1SSrinivas Kandagatla 3969b4fe0f1SSrinivas Kandagatla rc = of_parse_phandle_with_fixed_args(node, "iommus", 1, 0, &args); 3979b4fe0f1SSrinivas Kandagatla if (rc < 0) 3989b4fe0f1SSrinivas Kandagatla pdata->sid = -1; 3999b4fe0f1SSrinivas Kandagatla else 4009b4fe0f1SSrinivas Kandagatla pdata->sid = args.args[0] & SID_MASK_DEFAULT; 4019b4fe0f1SSrinivas Kandagatla 4029b4fe0f1SSrinivas Kandagatla dev_set_drvdata(dev, pdata); 4039b4fe0f1SSrinivas Kandagatla 4049b4fe0f1SSrinivas Kandagatla return devm_snd_soc_register_component(dev, &q6apm_fe_dai_component, NULL, 0); 4059b4fe0f1SSrinivas Kandagatla } 4069b4fe0f1SSrinivas Kandagatla 4079b4fe0f1SSrinivas Kandagatla #ifdef CONFIG_OF 4089b4fe0f1SSrinivas Kandagatla static const struct of_device_id q6apm_dai_device_id[] = { 4099b4fe0f1SSrinivas Kandagatla { .compatible = "qcom,q6apm-dais" }, 4109b4fe0f1SSrinivas Kandagatla {}, 4119b4fe0f1SSrinivas Kandagatla }; 4129b4fe0f1SSrinivas Kandagatla MODULE_DEVICE_TABLE(of, q6apm_dai_device_id); 4139b4fe0f1SSrinivas Kandagatla #endif 4149b4fe0f1SSrinivas Kandagatla 4159b4fe0f1SSrinivas Kandagatla static struct platform_driver q6apm_dai_platform_driver = { 4169b4fe0f1SSrinivas Kandagatla .driver = { 4179b4fe0f1SSrinivas Kandagatla .name = "q6apm-dai", 4189b4fe0f1SSrinivas Kandagatla .of_match_table = of_match_ptr(q6apm_dai_device_id), 4199b4fe0f1SSrinivas Kandagatla }, 4209b4fe0f1SSrinivas Kandagatla .probe = q6apm_dai_probe, 4219b4fe0f1SSrinivas Kandagatla }; 4229b4fe0f1SSrinivas Kandagatla module_platform_driver(q6apm_dai_platform_driver); 4239b4fe0f1SSrinivas Kandagatla 4249b4fe0f1SSrinivas Kandagatla MODULE_DESCRIPTION("Q6APM dai driver"); 4259b4fe0f1SSrinivas Kandagatla MODULE_LICENSE("GPL"); 426