~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/qcom/lpass-platform.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
  4  *
  5  * lpass-platform.c -- ALSA SoC platform driver for QTi LPASS
  6  */
  7 
  8 #include <dt-bindings/sound/qcom,lpass.h>
  9 #include <linux/dma-mapping.h>
 10 #include <linux/export.h>
 11 #include <linux/kernel.h>
 12 #include <linux/module.h>
 13 #include <linux/platform_device.h>
 14 #include <sound/pcm_params.h>
 15 #include <linux/regmap.h>
 16 #include <sound/soc.h>
 17 #include "lpass-lpaif-reg.h"
 18 #include "lpass.h"
 19 
 20 #define DRV_NAME "lpass-platform"
 21 
 22 #define LPASS_PLATFORM_BUFFER_SIZE      (24 *  2 * 1024)
 23 #define LPASS_PLATFORM_PERIODS          2
 24 #define LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE (8 * 1024)
 25 #define LPASS_VA_CDC_DMA_LPM_BUFF_SIZE (12 * 1024)
 26 #define LPASS_CDC_DMA_REGISTER_FIELDS_MAX 15
 27 
 28 static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
 29         .info                   =       SNDRV_PCM_INFO_MMAP |
 30                                         SNDRV_PCM_INFO_MMAP_VALID |
 31                                         SNDRV_PCM_INFO_INTERLEAVED |
 32                                         SNDRV_PCM_INFO_PAUSE |
 33                                         SNDRV_PCM_INFO_RESUME,
 34         .formats                =       SNDRV_PCM_FMTBIT_S16 |
 35                                         SNDRV_PCM_FMTBIT_S24 |
 36                                         SNDRV_PCM_FMTBIT_S32,
 37         .rates                  =       SNDRV_PCM_RATE_8000_192000,
 38         .rate_min               =       8000,
 39         .rate_max               =       192000,
 40         .channels_min           =       1,
 41         .channels_max           =       8,
 42         .buffer_bytes_max       =       LPASS_PLATFORM_BUFFER_SIZE,
 43         .period_bytes_max       =       LPASS_PLATFORM_BUFFER_SIZE /
 44                                                 LPASS_PLATFORM_PERIODS,
 45         .period_bytes_min       =       LPASS_PLATFORM_BUFFER_SIZE /
 46                                                 LPASS_PLATFORM_PERIODS,
 47         .periods_min            =       LPASS_PLATFORM_PERIODS,
 48         .periods_max            =       LPASS_PLATFORM_PERIODS,
 49         .fifo_size              =       0,
 50 };
 51 
 52 static const struct snd_pcm_hardware lpass_platform_rxtx_hardware = {
 53         .info                   =       SNDRV_PCM_INFO_MMAP |
 54                                         SNDRV_PCM_INFO_MMAP_VALID |
 55                                         SNDRV_PCM_INFO_INTERLEAVED |
 56                                         SNDRV_PCM_INFO_PAUSE |
 57                                         SNDRV_PCM_INFO_RESUME,
 58         .formats                =       SNDRV_PCM_FMTBIT_S16 |
 59                                         SNDRV_PCM_FMTBIT_S24 |
 60                                         SNDRV_PCM_FMTBIT_S32,
 61         .rates                  =       SNDRV_PCM_RATE_8000_192000,
 62         .rate_min               =       8000,
 63         .rate_max               =       192000,
 64         .channels_min           =       1,
 65         .channels_max           =       8,
 66         .buffer_bytes_max       =       LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE,
 67         .period_bytes_max       =       LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE /
 68                                                 LPASS_PLATFORM_PERIODS,
 69         .period_bytes_min       =       LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE /
 70                                                 LPASS_PLATFORM_PERIODS,
 71         .periods_min            =       LPASS_PLATFORM_PERIODS,
 72         .periods_max            =       LPASS_PLATFORM_PERIODS,
 73         .fifo_size              =       0,
 74 };
 75 
 76 static const struct snd_pcm_hardware lpass_platform_va_hardware = {
 77         .info                   =       SNDRV_PCM_INFO_MMAP |
 78                                         SNDRV_PCM_INFO_MMAP_VALID |
 79                                         SNDRV_PCM_INFO_INTERLEAVED |
 80                                         SNDRV_PCM_INFO_PAUSE |
 81                                         SNDRV_PCM_INFO_RESUME,
 82         .formats                =       SNDRV_PCM_FMTBIT_S16 |
 83                                         SNDRV_PCM_FMTBIT_S24 |
 84                                         SNDRV_PCM_FMTBIT_S32,
 85         .rates                  =       SNDRV_PCM_RATE_8000_192000,
 86         .rate_min               =       8000,
 87         .rate_max               =       192000,
 88         .channels_min           =       1,
 89         .channels_max           =       8,
 90         .buffer_bytes_max       =       LPASS_VA_CDC_DMA_LPM_BUFF_SIZE,
 91         .period_bytes_max       =       LPASS_VA_CDC_DMA_LPM_BUFF_SIZE /
 92                                                 LPASS_PLATFORM_PERIODS,
 93         .period_bytes_min       =       LPASS_VA_CDC_DMA_LPM_BUFF_SIZE /
 94                                                 LPASS_PLATFORM_PERIODS,
 95         .periods_min            =       LPASS_PLATFORM_PERIODS,
 96         .periods_max            =       LPASS_PLATFORM_PERIODS,
 97         .fifo_size              =       0,
 98 };
 99 
100 static int lpass_platform_alloc_rxtx_dmactl_fields(struct device *dev,
101                                          struct regmap *map)
102 {
103         struct lpass_data *drvdata = dev_get_drvdata(dev);
104         const struct lpass_variant *v = drvdata->variant;
105         struct lpaif_dmactl *rd_dmactl, *wr_dmactl;
106         int rval;
107 
108         rd_dmactl = devm_kzalloc(dev, sizeof(*rd_dmactl), GFP_KERNEL);
109         if (!rd_dmactl)
110                 return -ENOMEM;
111 
112         wr_dmactl = devm_kzalloc(dev, sizeof(*wr_dmactl), GFP_KERNEL);
113         if (!wr_dmactl)
114                 return -ENOMEM;
115 
116         drvdata->rxtx_rd_dmactl = rd_dmactl;
117         drvdata->rxtx_wr_dmactl = wr_dmactl;
118 
119         rval = devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->intf,
120                                             &v->rxtx_rdma_intf, LPASS_CDC_DMA_REGISTER_FIELDS_MAX);
121         if (rval)
122                 return rval;
123 
124         return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
125                                             &v->rxtx_wrdma_intf, LPASS_CDC_DMA_REGISTER_FIELDS_MAX);
126 }
127 
128 static int lpass_platform_alloc_va_dmactl_fields(struct device *dev,
129                                          struct regmap *map)
130 {
131         struct lpass_data *drvdata = dev_get_drvdata(dev);
132         const struct lpass_variant *v = drvdata->variant;
133         struct lpaif_dmactl *wr_dmactl;
134 
135         wr_dmactl = devm_kzalloc(dev, sizeof(*wr_dmactl), GFP_KERNEL);
136         if (!wr_dmactl)
137                 return -ENOMEM;
138 
139         drvdata->va_wr_dmactl = wr_dmactl;
140         return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
141                                             &v->va_wrdma_intf, LPASS_CDC_DMA_REGISTER_FIELDS_MAX);
142 }
143 
144 
145 static int lpass_platform_alloc_dmactl_fields(struct device *dev,
146                                          struct regmap *map)
147 {
148         struct lpass_data *drvdata = dev_get_drvdata(dev);
149         const struct lpass_variant *v = drvdata->variant;
150         struct lpaif_dmactl *rd_dmactl, *wr_dmactl;
151         int rval;
152 
153         drvdata->rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
154                                           GFP_KERNEL);
155         if (drvdata->rd_dmactl == NULL)
156                 return -ENOMEM;
157 
158         drvdata->wr_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
159                                           GFP_KERNEL);
160         if (drvdata->wr_dmactl == NULL)
161                 return -ENOMEM;
162 
163         rd_dmactl = drvdata->rd_dmactl;
164         wr_dmactl = drvdata->wr_dmactl;
165 
166         rval = devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->intf,
167                                             &v->rdma_intf, 6);
168         if (rval)
169                 return rval;
170 
171         return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
172                                             &v->wrdma_intf, 6);
173 }
174 
175 static int lpass_platform_alloc_hdmidmactl_fields(struct device *dev,
176                                          struct regmap *map)
177 {
178         struct lpass_data *drvdata = dev_get_drvdata(dev);
179         const struct lpass_variant *v = drvdata->variant;
180         struct lpaif_dmactl *rd_dmactl;
181 
182         rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl), GFP_KERNEL);
183         if (rd_dmactl == NULL)
184                 return -ENOMEM;
185 
186         drvdata->hdmi_rd_dmactl = rd_dmactl;
187 
188         return devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->bursten,
189                                             &v->hdmi_rdma_bursten, 8);
190 }
191 
192 static int lpass_platform_pcmops_open(struct snd_soc_component *component,
193                                       struct snd_pcm_substream *substream)
194 {
195         struct snd_pcm_runtime *runtime = substream->runtime;
196         struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
197         struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
198         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
199         const struct lpass_variant *v = drvdata->variant;
200         int ret, dma_ch, dir = substream->stream;
201         struct lpass_pcm_data *data;
202         struct regmap *map;
203         unsigned int dai_id = cpu_dai->driver->id;
204 
205         component->id = dai_id;
206         data = kzalloc(sizeof(*data), GFP_KERNEL);
207         if (!data)
208                 return -ENOMEM;
209 
210         data->i2s_port = cpu_dai->driver->id;
211         runtime->private_data = data;
212 
213         if (v->alloc_dma_channel)
214                 dma_ch = v->alloc_dma_channel(drvdata, dir, dai_id);
215         else
216                 dma_ch = 0;
217 
218         if (dma_ch < 0) {
219                 kfree(data);
220                 return dma_ch;
221         }
222 
223         switch (dai_id) {
224         case MI2S_PRIMARY ... MI2S_QUINARY:
225                 map = drvdata->lpaif_map;
226                 drvdata->substream[dma_ch] = substream;
227                 break;
228         case LPASS_DP_RX:
229                 map = drvdata->hdmiif_map;
230                 drvdata->hdmi_substream[dma_ch] = substream;
231                 break;
232         case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
233         case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
234                 map = drvdata->rxtx_lpaif_map;
235                 drvdata->rxtx_substream[dma_ch] = substream;
236                 break;
237         case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
238                 map = drvdata->va_lpaif_map;
239                 drvdata->va_substream[dma_ch] = substream;
240                 break;
241         default:
242                 break;
243         }
244 
245         data->dma_ch = dma_ch;
246         switch (dai_id) {
247         case MI2S_PRIMARY ... MI2S_QUINARY:
248         case LPASS_DP_RX:
249                 ret = regmap_write(map, LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0);
250                 if (ret) {
251                         kfree(data);
252                         dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n", ret);
253                         return ret;
254                 }
255                 snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
256                 runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
257                 break;
258         case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
259         case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
260                 snd_soc_set_runtime_hwparams(substream, &lpass_platform_rxtx_hardware);
261                 runtime->dma_bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
262                 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
263                 break;
264         case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
265                 snd_soc_set_runtime_hwparams(substream, &lpass_platform_va_hardware);
266                 runtime->dma_bytes = lpass_platform_va_hardware.buffer_bytes_max;
267                 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
268                 break;
269         default:
270                 break;
271         }
272         ret = snd_pcm_hw_constraint_integer(runtime,
273                         SNDRV_PCM_HW_PARAM_PERIODS);
274         if (ret < 0) {
275                 kfree(data);
276                 dev_err(soc_runtime->dev, "setting constraints failed: %d\n",
277                         ret);
278                 return -EINVAL;
279         }
280 
281         return 0;
282 }
283 
284 static int lpass_platform_pcmops_close(struct snd_soc_component *component,
285                                        struct snd_pcm_substream *substream)
286 {
287         struct snd_pcm_runtime *runtime = substream->runtime;
288         struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
289         struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
290         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
291         const struct lpass_variant *v = drvdata->variant;
292         struct lpass_pcm_data *data;
293         unsigned int dai_id = cpu_dai->driver->id;
294 
295         data = runtime->private_data;
296 
297         switch (dai_id) {
298         case MI2S_PRIMARY ... MI2S_QUINARY:
299                 drvdata->substream[data->dma_ch] = NULL;
300                 break;
301         case LPASS_DP_RX:
302                 drvdata->hdmi_substream[data->dma_ch] = NULL;
303                 break;
304         case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
305         case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
306                 drvdata->rxtx_substream[data->dma_ch] = NULL;
307                 break;
308         case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
309                 drvdata->va_substream[data->dma_ch] = NULL;
310                 break;
311         default:
312                 break;
313         }
314 
315         if (v->free_dma_channel)
316                 v->free_dma_channel(drvdata, data->dma_ch, dai_id);
317 
318         kfree(data);
319         return 0;
320 }
321 
322 static struct lpaif_dmactl *__lpass_get_dmactl_handle(const struct snd_pcm_substream *substream,
323                                      struct snd_soc_component *component)
324 {
325         struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
326         struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
327         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
328         struct lpaif_dmactl *dmactl = NULL;
329 
330         switch (cpu_dai->driver->id) {
331         case MI2S_PRIMARY ... MI2S_QUINARY:
332                 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
333                         dmactl = drvdata->rd_dmactl;
334                 else
335                         dmactl = drvdata->wr_dmactl;
336                 break;
337         case LPASS_DP_RX:
338                 dmactl = drvdata->hdmi_rd_dmactl;
339                 break;
340         case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
341                 dmactl = drvdata->rxtx_rd_dmactl;
342                 break;
343         case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
344                 dmactl = drvdata->rxtx_wr_dmactl;
345                 break;
346         case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
347                 dmactl = drvdata->va_wr_dmactl;
348                 break;
349         }
350 
351         return dmactl;
352 }
353 
354 static int __lpass_get_id(const struct snd_pcm_substream *substream,
355                                      struct snd_soc_component *component)
356 {
357         struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
358         struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
359         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
360         struct snd_pcm_runtime *rt = substream->runtime;
361         struct lpass_pcm_data *pcm_data = rt->private_data;
362         const struct lpass_variant *v = drvdata->variant;
363         int id;
364 
365         switch (cpu_dai->driver->id) {
366         case MI2S_PRIMARY ... MI2S_QUINARY:
367                 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
368                         id = pcm_data->dma_ch;
369                 else
370                         id = pcm_data->dma_ch - v->wrdma_channel_start;
371                 break;
372         case LPASS_DP_RX:
373                 id = pcm_data->dma_ch;
374                 break;
375         case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
376                 id = pcm_data->dma_ch;
377                 break;
378         case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
379                 id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start;
380                 break;
381         case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
382                 id = pcm_data->dma_ch - v->va_wrdma_channel_start;
383                 break;
384         }
385 
386         return id;
387 }
388 
389 static struct regmap *__lpass_get_regmap_handle(const struct snd_pcm_substream *substream,
390                                      struct snd_soc_component *component)
391 {
392         struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
393         struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
394         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
395         struct regmap *map = NULL;
396 
397         switch (cpu_dai->driver->id) {
398         case MI2S_PRIMARY ... MI2S_QUINARY:
399                 map = drvdata->lpaif_map;
400                 break;
401         case LPASS_DP_RX:
402                 map = drvdata->hdmiif_map;
403                 break;
404         case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
405         case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
406                 map = drvdata->rxtx_lpaif_map;
407                 break;
408         case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
409                 map = drvdata->va_lpaif_map;
410                 break;
411         }
412 
413         return map;
414 }
415 
416 static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
417                                            struct snd_pcm_substream *substream,
418                                            struct snd_pcm_hw_params *params)
419 {
420         struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
421         struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
422         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
423         struct snd_pcm_runtime *rt = substream->runtime;
424         struct lpass_pcm_data *pcm_data = rt->private_data;
425         const struct lpass_variant *v = drvdata->variant;
426         snd_pcm_format_t format = params_format(params);
427         unsigned int channels = params_channels(params);
428         unsigned int regval;
429         struct lpaif_dmactl *dmactl;
430         int id;
431         int bitwidth;
432         int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start;
433         unsigned int dai_id = cpu_dai->driver->id;
434 
435         dmactl = __lpass_get_dmactl_handle(substream, component);
436         id = __lpass_get_id(substream, component);
437 
438         bitwidth = snd_pcm_format_width(format);
439         if (bitwidth < 0) {
440                 dev_err(soc_runtime->dev, "invalid bit width given: %d\n",
441                                 bitwidth);
442                 return bitwidth;
443         }
444 
445         ret = regmap_fields_write(dmactl->bursten, id, LPAIF_DMACTL_BURSTEN_INCR4);
446         if (ret) {
447                 dev_err(soc_runtime->dev, "error updating bursten field: %d\n", ret);
448                 return ret;
449         }
450 
451         ret = regmap_fields_write(dmactl->fifowm, id, LPAIF_DMACTL_FIFOWM_8);
452         if (ret) {
453                 dev_err(soc_runtime->dev, "error updating fifowm field: %d\n", ret);
454                 return ret;
455         }
456 
457         switch (dai_id) {
458         case LPASS_DP_RX:
459                 ret = regmap_fields_write(dmactl->burst8, id,
460                                                         LPAIF_DMACTL_BURSTEN_INCR4);
461                 if (ret) {
462                         dev_err(soc_runtime->dev, "error updating burst8en field: %d\n", ret);
463                         return ret;
464                 }
465                 ret = regmap_fields_write(dmactl->burst16, id,
466                                                         LPAIF_DMACTL_BURSTEN_INCR4);
467                 if (ret) {
468                         dev_err(soc_runtime->dev, "error updating burst16en field: %d\n", ret);
469                         return ret;
470                 }
471                 ret = regmap_fields_write(dmactl->dynburst, id,
472                                                         LPAIF_DMACTL_BURSTEN_INCR4);
473                 if (ret) {
474                         dev_err(soc_runtime->dev, "error updating dynbursten field: %d\n", ret);
475                         return ret;
476                 }
477                 break;
478         case MI2S_PRIMARY:
479         case MI2S_SECONDARY:
480         case MI2S_TERTIARY:
481         case MI2S_QUATERNARY:
482         case MI2S_QUINARY:
483                 ret = regmap_fields_write(dmactl->intf, id,
484                                                 LPAIF_DMACTL_AUDINTF(dma_port));
485                 if (ret) {
486                         dev_err(soc_runtime->dev, "error updating audio interface field: %d\n",
487                                         ret);
488                         return ret;
489                 }
490 
491                 break;
492         case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
493         case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
494         case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX0:
495                 break;
496         default:
497                 dev_err(soc_runtime->dev, "%s: invalid  interface: %d\n", __func__, dai_id);
498                 break;
499         }
500         switch (bitwidth) {
501         case 16:
502                 switch (channels) {
503                 case 1:
504                 case 2:
505                         regval = LPAIF_DMACTL_WPSCNT_ONE;
506                         break;
507                 case 4:
508                         regval = LPAIF_DMACTL_WPSCNT_TWO;
509                         break;
510                 case 6:
511                         regval = LPAIF_DMACTL_WPSCNT_THREE;
512                         break;
513                 case 8:
514                         regval = LPAIF_DMACTL_WPSCNT_FOUR;
515                         break;
516                 default:
517                         dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n",
518                                 bitwidth, channels);
519                         return -EINVAL;
520                 }
521                 break;
522         case 24:
523         case 32:
524                 switch (channels) {
525                 case 1:
526                         regval = LPAIF_DMACTL_WPSCNT_ONE;
527                         break;
528                 case 2:
529                         regval = (dai_id == LPASS_DP_RX ?
530                         LPAIF_DMACTL_WPSCNT_ONE :
531                         LPAIF_DMACTL_WPSCNT_TWO);
532                         break;
533                 case 4:
534                         regval = (dai_id == LPASS_DP_RX ?
535                         LPAIF_DMACTL_WPSCNT_TWO :
536                         LPAIF_DMACTL_WPSCNT_FOUR);
537                         break;
538                 case 6:
539                         regval = (dai_id == LPASS_DP_RX ?
540                         LPAIF_DMACTL_WPSCNT_THREE :
541                         LPAIF_DMACTL_WPSCNT_SIX);
542                         break;
543                 case 8:
544                         regval = (dai_id == LPASS_DP_RX ?
545                         LPAIF_DMACTL_WPSCNT_FOUR :
546                         LPAIF_DMACTL_WPSCNT_EIGHT);
547                         break;
548                 default:
549                         dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n",
550                                 bitwidth, channels);
551                         return -EINVAL;
552                 }
553                 break;
554         default:
555                 dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n",
556                         bitwidth, channels);
557                 return -EINVAL;
558         }
559 
560         ret = regmap_fields_write(dmactl->wpscnt, id, regval);
561         if (ret) {
562                 dev_err(soc_runtime->dev, "error writing to dmactl reg: %d\n",
563                         ret);
564                 return ret;
565         }
566 
567         return 0;
568 }
569 
570 static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component,
571                                          struct snd_pcm_substream *substream)
572 {
573         struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
574         struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
575         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
576         struct snd_pcm_runtime *rt = substream->runtime;
577         struct lpass_pcm_data *pcm_data = rt->private_data;
578         const struct lpass_variant *v = drvdata->variant;
579         unsigned int reg;
580         int ret;
581         struct regmap *map;
582         unsigned int dai_id = cpu_dai->driver->id;
583 
584         if (is_cdc_dma_port(dai_id))
585                 return 0;
586         map = __lpass_get_regmap_handle(substream, component);
587 
588         reg = LPAIF_DMACTL_REG(v, pcm_data->dma_ch, substream->stream, dai_id);
589         ret = regmap_write(map, reg, 0);
590         if (ret)
591                 dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
592                         ret);
593 
594         return ret;
595 }
596 
597 static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
598                                          struct snd_pcm_substream *substream)
599 {
600         struct snd_pcm_runtime *runtime = substream->runtime;
601         struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
602         struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
603         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
604         struct snd_pcm_runtime *rt = substream->runtime;
605         struct lpass_pcm_data *pcm_data = rt->private_data;
606         const struct lpass_variant *v = drvdata->variant;
607         struct lpaif_dmactl *dmactl;
608         struct regmap *map;
609         int ret, id, ch, dir = substream->stream;
610         unsigned int dai_id = cpu_dai->driver->id;
611 
612         ch = pcm_data->dma_ch;
613 
614         dmactl = __lpass_get_dmactl_handle(substream, component);
615         id = __lpass_get_id(substream, component);
616         map = __lpass_get_regmap_handle(substream, component);
617 
618         ret = regmap_write(map, LPAIF_DMABASE_REG(v, ch, dir, dai_id),
619                                 runtime->dma_addr);
620         if (ret) {
621                 dev_err(soc_runtime->dev, "error writing to rdmabase reg: %d\n",
622                         ret);
623                 return ret;
624         }
625 
626         ret = regmap_write(map, LPAIF_DMABUFF_REG(v, ch, dir, dai_id),
627                         (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);
628         if (ret) {
629                 dev_err(soc_runtime->dev, "error writing to rdmabuff reg: %d\n",
630                         ret);
631                 return ret;
632         }
633 
634         ret = regmap_write(map, LPAIF_DMAPER_REG(v, ch, dir, dai_id),
635                         (snd_pcm_lib_period_bytes(substream) >> 2) - 1);
636         if (ret) {
637                 dev_err(soc_runtime->dev, "error writing to rdmaper reg: %d\n",
638                         ret);
639                 return ret;
640         }
641 
642         if (is_cdc_dma_port(dai_id)) {
643                 ret = regmap_fields_write(dmactl->fifowm, id, LPAIF_DMACTL_FIFOWM_8);
644                 if (ret) {
645                         dev_err(soc_runtime->dev, "error writing fifowm field to dmactl reg: %d, id: %d\n",
646                                 ret, id);
647                         return ret;
648                 }
649         }
650         ret = regmap_fields_write(dmactl->enable, id, LPAIF_DMACTL_ENABLE_ON);
651         if (ret) {
652                 dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
653                         ret);
654                 return ret;
655         }
656 
657         return 0;
658 }
659 
660 static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
661                                          struct snd_pcm_substream *substream,
662                                          int cmd)
663 {
664         struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
665         struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
666         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
667         struct snd_pcm_runtime *rt = substream->runtime;
668         struct lpass_pcm_data *pcm_data = rt->private_data;
669         const struct lpass_variant *v = drvdata->variant;
670         struct lpaif_dmactl *dmactl;
671         struct regmap *map;
672         int ret, ch, id;
673         unsigned int reg_irqclr = 0, val_irqclr = 0;
674         unsigned int  reg_irqen = 0, val_irqen = 0, val_mask = 0;
675         unsigned int dai_id = cpu_dai->driver->id;
676 
677         ch = pcm_data->dma_ch;
678         dmactl = __lpass_get_dmactl_handle(substream, component);
679         id = __lpass_get_id(substream, component);
680         map = __lpass_get_regmap_handle(substream, component);
681 
682         switch (cmd) {
683         case SNDRV_PCM_TRIGGER_START:
684         case SNDRV_PCM_TRIGGER_RESUME:
685         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
686                 ret = regmap_fields_write(dmactl->enable, id,
687                                                  LPAIF_DMACTL_ENABLE_ON);
688                 if (ret) {
689                         dev_err(soc_runtime->dev,
690                                 "error writing to rdmactl reg: %d\n", ret);
691                         return ret;
692                 }
693                 switch (dai_id) {
694                 case LPASS_DP_RX:
695                         ret = regmap_fields_write(dmactl->dyncclk, id,
696                                          LPAIF_DMACTL_DYNCLK_ON);
697                         if (ret) {
698                                 dev_err(soc_runtime->dev,
699                                         "error writing to rdmactl reg: %d\n", ret);
700                                 return ret;
701                         }
702                         reg_irqclr = LPASS_HDMITX_APP_IRQCLEAR_REG(v);
703                         val_irqclr = (LPAIF_IRQ_ALL(ch) |
704                                         LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
705                                         LPAIF_IRQ_HDMI_METADONE |
706                                         LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
707 
708                         reg_irqen = LPASS_HDMITX_APP_IRQEN_REG(v);
709                         val_mask = (LPAIF_IRQ_ALL(ch) |
710                                         LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
711                                         LPAIF_IRQ_HDMI_METADONE |
712                                         LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
713                         val_irqen = (LPAIF_IRQ_ALL(ch) |
714                                         LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
715                                         LPAIF_IRQ_HDMI_METADONE |
716                                         LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
717                         break;
718                 case MI2S_PRIMARY:
719                 case MI2S_SECONDARY:
720                 case MI2S_TERTIARY:
721                 case MI2S_QUATERNARY:
722                 case MI2S_QUINARY:
723                         reg_irqclr = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
724                         val_irqclr = LPAIF_IRQ_ALL(ch);
725 
726 
727                         reg_irqen = LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
728                         val_mask = LPAIF_IRQ_ALL(ch);
729                         val_irqen = LPAIF_IRQ_ALL(ch);
730                         break;
731                 case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
732                 case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
733                         ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_ON);
734                         if (ret) {
735                                 dev_err(soc_runtime->dev,
736                                         "error writing to rdmactl reg field: %d\n", ret);
737                                 return ret;
738                         }
739                         reg_irqclr = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
740                         val_irqclr = LPAIF_IRQ_ALL(ch);
741 
742                         reg_irqen = LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
743                         val_mask = LPAIF_IRQ_ALL(ch);
744                         val_irqen = LPAIF_IRQ_ALL(ch);
745                         break;
746                 case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
747                         ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_ON);
748                         if (ret) {
749                                 dev_err(soc_runtime->dev,
750                                         "error writing to rdmactl reg field: %d\n", ret);
751                                 return ret;
752                         }
753                         reg_irqclr = LPAIF_VA_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
754                         val_irqclr = LPAIF_IRQ_ALL(ch);
755 
756                         reg_irqen = LPAIF_VA_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
757                         val_mask = LPAIF_IRQ_ALL(ch);
758                         val_irqen = LPAIF_IRQ_ALL(ch);
759                         break;
760                 default:
761                         dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);
762                         return -EINVAL;
763                 }
764 
765                 ret = regmap_write_bits(map, reg_irqclr, val_irqclr, val_irqclr);
766                 if (ret) {
767                         dev_err(soc_runtime->dev, "error writing to irqclear reg: %d\n", ret);
768                         return ret;
769                 }
770                 ret = regmap_update_bits(map, reg_irqen, val_mask, val_irqen);
771                 if (ret) {
772                         dev_err(soc_runtime->dev, "error writing to irqen reg: %d\n", ret);
773                         return ret;
774                 }
775                 break;
776         case SNDRV_PCM_TRIGGER_STOP:
777         case SNDRV_PCM_TRIGGER_SUSPEND:
778         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
779                 ret = regmap_fields_write(dmactl->enable, id,
780                                          LPAIF_DMACTL_ENABLE_OFF);
781                 if (ret) {
782                         dev_err(soc_runtime->dev,
783                                 "error writing to rdmactl reg: %d\n", ret);
784                         return ret;
785                 }
786                 switch (dai_id) {
787                 case LPASS_DP_RX:
788                         ret = regmap_fields_write(dmactl->dyncclk, id,
789                                          LPAIF_DMACTL_DYNCLK_OFF);
790                         if (ret) {
791                                 dev_err(soc_runtime->dev,
792                                         "error writing to rdmactl reg: %d\n", ret);
793                                 return ret;
794                         }
795                         reg_irqen = LPASS_HDMITX_APP_IRQEN_REG(v);
796                         val_mask = (LPAIF_IRQ_ALL(ch) |
797                                         LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
798                                         LPAIF_IRQ_HDMI_METADONE |
799                                         LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
800                         val_irqen = 0;
801                         break;
802                 case MI2S_PRIMARY:
803                 case MI2S_SECONDARY:
804                 case MI2S_TERTIARY:
805                 case MI2S_QUATERNARY:
806                 case MI2S_QUINARY:
807                         reg_irqen = LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
808                         val_mask = LPAIF_IRQ_ALL(ch);
809                         val_irqen = 0;
810                         break;
811                 case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
812                 case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
813                         ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_OFF);
814                         if (ret) {
815                                 dev_err(soc_runtime->dev,
816                                         "error writing to rdmactl reg field: %d\n", ret);
817                                 return ret;
818                         }
819 
820                         reg_irqclr = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
821                         val_irqclr = LPAIF_IRQ_ALL(ch);
822 
823                         reg_irqen = LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
824                         val_mask = LPAIF_IRQ_ALL(ch);
825                         val_irqen = LPAIF_IRQ_ALL(ch);
826                         break;
827                 case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
828                         ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_OFF);
829                         if (ret) {
830                                 dev_err(soc_runtime->dev,
831                                         "error writing to rdmactl reg field: %d\n", ret);
832                                 return ret;
833                         }
834 
835                         reg_irqclr = LPAIF_VA_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
836                         val_irqclr = LPAIF_IRQ_ALL(ch);
837 
838                         reg_irqen = LPAIF_VA_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
839                         val_mask = LPAIF_IRQ_ALL(ch);
840                         val_irqen = LPAIF_IRQ_ALL(ch);
841                         break;
842                 default:
843                         dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);
844                         return -EINVAL;
845                 }
846 
847                 ret = regmap_update_bits(map, reg_irqen, val_mask, val_irqen);
848                 if (ret) {
849                         dev_err(soc_runtime->dev,
850                                 "error writing to irqen reg: %d\n", ret);
851                         return ret;
852                 }
853                 break;
854         }
855 
856         return 0;
857 }
858 
859 static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
860                 struct snd_soc_component *component,
861                 struct snd_pcm_substream *substream)
862 {
863         struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
864         struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
865         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
866         struct snd_pcm_runtime *rt = substream->runtime;
867         struct lpass_pcm_data *pcm_data = rt->private_data;
868         const struct lpass_variant *v = drvdata->variant;
869         unsigned int base_addr, curr_addr;
870         int ret, ch, dir = substream->stream;
871         struct regmap *map;
872         unsigned int dai_id = cpu_dai->driver->id;
873 
874         map = __lpass_get_regmap_handle(substream, component);
875         ch = pcm_data->dma_ch;
876 
877         ret = regmap_read(map,
878                         LPAIF_DMABASE_REG(v, ch, dir, dai_id), &base_addr);
879         if (ret) {
880                 dev_err(soc_runtime->dev,
881                         "error reading from rdmabase reg: %d\n", ret);
882                 return ret;
883         }
884 
885         ret = regmap_read(map,
886                         LPAIF_DMACURR_REG(v, ch, dir, dai_id), &curr_addr);
887         if (ret) {
888                 dev_err(soc_runtime->dev,
889                         "error reading from rdmacurr reg: %d\n", ret);
890                 return ret;
891         }
892 
893         return bytes_to_frames(substream->runtime, curr_addr - base_addr);
894 }
895 
896 static int lpass_platform_cdc_dma_mmap(struct snd_pcm_substream *substream,
897                                        struct vm_area_struct *vma)
898 {
899         struct snd_pcm_runtime *runtime = substream->runtime;
900         unsigned long size, offset;
901 
902         vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
903         size = vma->vm_end - vma->vm_start;
904         offset = vma->vm_pgoff << PAGE_SHIFT;
905         return io_remap_pfn_range(vma, vma->vm_start,
906                         (runtime->dma_addr + offset) >> PAGE_SHIFT,
907                         size, vma->vm_page_prot);
908 
909 }
910 
911 static int lpass_platform_pcmops_mmap(struct snd_soc_component *component,
912                                       struct snd_pcm_substream *substream,
913                                       struct vm_area_struct *vma)
914 {
915         struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
916         struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
917         unsigned int dai_id = cpu_dai->driver->id;
918 
919         if (is_cdc_dma_port(dai_id))
920                 return lpass_platform_cdc_dma_mmap(substream, vma);
921 
922         return snd_pcm_lib_default_mmap(substream, vma);
923 }
924 
925 static irqreturn_t lpass_dma_interrupt_handler(
926                         struct snd_pcm_substream *substream,
927                         struct lpass_data *drvdata,
928                         int chan, u32 interrupts)
929 {
930         struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
931         struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
932         const struct lpass_variant *v = drvdata->variant;
933         irqreturn_t ret = IRQ_NONE;
934         int rv;
935         unsigned int reg, val, mask;
936         struct regmap *map;
937         unsigned int dai_id = cpu_dai->driver->id;
938 
939         mask = LPAIF_IRQ_ALL(chan);
940         switch (dai_id) {
941         case LPASS_DP_RX:
942                 map = drvdata->hdmiif_map;
943                 reg = LPASS_HDMITX_APP_IRQCLEAR_REG(v);
944                 val = (LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(chan) |
945                 LPAIF_IRQ_HDMI_METADONE |
946                 LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(chan));
947         break;
948         case MI2S_PRIMARY:
949         case MI2S_SECONDARY:
950         case MI2S_TERTIARY:
951         case MI2S_QUATERNARY:
952         case MI2S_QUINARY:
953                 map = drvdata->lpaif_map;
954                 reg = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
955                 val = 0;
956         break;
957         case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
958         case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
959                 map = drvdata->rxtx_lpaif_map;
960                 reg = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
961                 val = 0;
962         break;
963         case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
964                 map = drvdata->va_lpaif_map;
965                 reg = LPAIF_VA_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
966                 val = 0;
967         break;
968         default:
969         dev_err(soc_runtime->dev, "%s: invalid  %d interface\n", __func__, dai_id);
970         return -EINVAL;
971         }
972         if (interrupts & LPAIF_IRQ_PER(chan)) {
973                 rv = regmap_write_bits(map, reg, mask, (LPAIF_IRQ_PER(chan) | val));
974                 if (rv) {
975                         dev_err(soc_runtime->dev,
976                                 "error writing to irqclear reg: %d\n", rv);
977                         return IRQ_NONE;
978                 }
979                 snd_pcm_period_elapsed(substream);
980                 ret = IRQ_HANDLED;
981         }
982 
983         if (interrupts & LPAIF_IRQ_XRUN(chan)) {
984                 rv = regmap_write_bits(map, reg, mask, (LPAIF_IRQ_XRUN(chan) | val));
985                 if (rv) {
986                         dev_err(soc_runtime->dev,
987                                 "error writing to irqclear reg: %d\n", rv);
988                         return IRQ_NONE;
989                 }
990                 dev_warn_ratelimited(soc_runtime->dev, "xrun warning\n");
991 
992                 snd_pcm_stop_xrun(substream);
993                 ret = IRQ_HANDLED;
994         }
995 
996         if (interrupts & LPAIF_IRQ_ERR(chan)) {
997                 rv = regmap_write_bits(map, reg, mask, (LPAIF_IRQ_ERR(chan) | val));
998                 if (rv) {
999                         dev_err(soc_runtime->dev,
1000                                 "error writing to irqclear reg: %d\n", rv);
1001                         return IRQ_NONE;
1002                 }
1003                 dev_err(soc_runtime->dev, "bus access error\n");
1004                 snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
1005                 ret = IRQ_HANDLED;
1006         }
1007 
1008         if (interrupts & val) {
1009                 rv = regmap_write(map, reg, val);
1010                 if (rv) {
1011                         dev_err(soc_runtime->dev,
1012                         "error writing to irqclear reg: %d\n", rv);
1013                         return IRQ_NONE;
1014                 }
1015                 ret = IRQ_HANDLED;
1016         }
1017 
1018         return ret;
1019 }
1020 
1021 static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
1022 {
1023         struct lpass_data *drvdata = data;
1024         const struct lpass_variant *v = drvdata->variant;
1025         unsigned int irqs;
1026         int rv, chan;
1027 
1028         rv = regmap_read(drvdata->lpaif_map,
1029                         LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
1030         if (rv) {
1031                 pr_err("error reading from irqstat reg: %d\n", rv);
1032                 return IRQ_NONE;
1033         }
1034 
1035         /* Handle per channel interrupts */
1036         for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++) {
1037                 if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan]) {
1038                         rv = lpass_dma_interrupt_handler(
1039                                                 drvdata->substream[chan],
1040                                                 drvdata, chan, irqs);
1041                         if (rv != IRQ_HANDLED)
1042                                 return rv;
1043                 }
1044         }
1045 
1046         return IRQ_HANDLED;
1047 }
1048 
1049 static irqreturn_t lpass_platform_hdmiif_irq(int irq, void *data)
1050 {
1051         struct lpass_data *drvdata = data;
1052         const struct lpass_variant *v = drvdata->variant;
1053         unsigned int irqs;
1054         int rv, chan;
1055 
1056         rv = regmap_read(drvdata->hdmiif_map,
1057                         LPASS_HDMITX_APP_IRQSTAT_REG(v), &irqs);
1058         if (rv) {
1059                 pr_err("error reading from irqstat reg: %d\n", rv);
1060                 return IRQ_NONE;
1061         }
1062 
1063         /* Handle per channel interrupts */
1064         for (chan = 0; chan < LPASS_MAX_HDMI_DMA_CHANNELS; chan++) {
1065                 if (irqs & (LPAIF_IRQ_ALL(chan) | LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(chan) |
1066                                 LPAIF_IRQ_HDMI_METADONE |
1067                                 LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(chan))
1068                         && drvdata->hdmi_substream[chan]) {
1069                         rv = lpass_dma_interrupt_handler(
1070                                                 drvdata->hdmi_substream[chan],
1071                                                 drvdata, chan, irqs);
1072                         if (rv != IRQ_HANDLED)
1073                                 return rv;
1074                 }
1075         }
1076         return IRQ_HANDLED;
1077 }
1078 
1079 static irqreturn_t lpass_platform_rxtxif_irq(int irq, void *data)
1080 {
1081         struct lpass_data *drvdata = data;
1082         const struct lpass_variant *v = drvdata->variant;
1083         unsigned int irqs;
1084         irqreturn_t rv;
1085         int chan;
1086 
1087         rv = regmap_read(drvdata->rxtx_lpaif_map,
1088                         LPAIF_RXTX_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
1089 
1090         /* Handle per channel interrupts */
1091         for (chan = 0; chan < LPASS_MAX_CDC_DMA_CHANNELS; chan++) {
1092                 if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->rxtx_substream[chan]) {
1093                         rv = lpass_dma_interrupt_handler(
1094                                                 drvdata->rxtx_substream[chan],
1095                                                 drvdata, chan, irqs);
1096                         if (rv != IRQ_HANDLED)
1097                                 return rv;
1098                 }
1099         }
1100 
1101         return IRQ_HANDLED;
1102 }
1103 
1104 static irqreturn_t lpass_platform_vaif_irq(int irq, void *data)
1105 {
1106         struct lpass_data *drvdata = data;
1107         const struct lpass_variant *v = drvdata->variant;
1108         unsigned int irqs;
1109         irqreturn_t rv;
1110         int chan;
1111 
1112         rv = regmap_read(drvdata->va_lpaif_map,
1113                         LPAIF_VA_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
1114 
1115         /* Handle per channel interrupts */
1116         for (chan = 0; chan < LPASS_MAX_VA_CDC_DMA_CHANNELS; chan++) {
1117                 if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->va_substream[chan]) {
1118                         rv = lpass_dma_interrupt_handler(
1119                                                 drvdata->va_substream[chan],
1120                                                 drvdata, chan, irqs);
1121                         if (rv != IRQ_HANDLED)
1122                                 return rv;
1123                 }
1124         }
1125         return IRQ_HANDLED;
1126 }
1127 
1128 static int lpass_platform_prealloc_cdc_dma_buffer(struct snd_soc_component *component,
1129                                                   struct snd_pcm *pcm, int dai_id)
1130 {
1131         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
1132         struct snd_pcm_substream *substream;
1133         struct snd_dma_buffer *buf;
1134 
1135         if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
1136                 substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
1137         else
1138                 substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
1139 
1140         buf = &substream->dma_buffer;
1141         buf->dev.dev = pcm->card->dev;
1142         buf->private_data = NULL;
1143 
1144         /* Assign Codec DMA buffer pointers */
1145         buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS;
1146 
1147         switch (dai_id) {
1148         case LPASS_CDC_DMA_RX0 ... LPASS_CDC_DMA_RX9:
1149                 buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
1150                 buf->addr = drvdata->rxtx_cdc_dma_lpm_buf;
1151                 break;
1152         case LPASS_CDC_DMA_TX0 ... LPASS_CDC_DMA_TX8:
1153                 buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
1154                 buf->addr = drvdata->rxtx_cdc_dma_lpm_buf + LPASS_RXTX_CDC_DMA_LPM_BUFF_SIZE;
1155                 break;
1156         case LPASS_CDC_DMA_VA_TX0 ... LPASS_CDC_DMA_VA_TX8:
1157                 buf->bytes = lpass_platform_va_hardware.buffer_bytes_max;
1158                 buf->addr = drvdata->va_cdc_dma_lpm_buf;
1159                 break;
1160         default:
1161                 break;
1162         }
1163 
1164         buf->area = (unsigned char * __force)memremap(buf->addr, buf->bytes, MEMREMAP_WC);
1165 
1166         return 0;
1167 }
1168 
1169 static int lpass_platform_pcm_new(struct snd_soc_component *component,
1170                                   struct snd_soc_pcm_runtime *soc_runtime)
1171 {
1172         struct snd_pcm *pcm = soc_runtime->pcm;
1173         struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
1174         unsigned int dai_id = cpu_dai->driver->id;
1175 
1176         size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
1177 
1178         /*
1179          * Lpass codec dma can access only lpass lpm hardware memory.
1180          * ioremap is for HLOS to access hardware memory.
1181          */
1182         if (is_cdc_dma_port(dai_id))
1183                 return lpass_platform_prealloc_cdc_dma_buffer(component, pcm, dai_id);
1184 
1185         return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_NONCOHERENT,
1186                                             component->dev, size);
1187 }
1188 
1189 static int lpass_platform_pcmops_suspend(struct snd_soc_component *component)
1190 {
1191         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
1192         struct regmap *map;
1193         unsigned int dai_id = component->id;
1194 
1195         if (dai_id == LPASS_DP_RX)
1196                 map = drvdata->hdmiif_map;
1197         else
1198                 map = drvdata->lpaif_map;
1199 
1200         regcache_cache_only(map, true);
1201         regcache_mark_dirty(map);
1202 
1203         return 0;
1204 }
1205 
1206 static int lpass_platform_pcmops_resume(struct snd_soc_component *component)
1207 {
1208         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
1209         struct regmap *map;
1210         unsigned int dai_id = component->id;
1211 
1212         if (dai_id == LPASS_DP_RX)
1213                 map = drvdata->hdmiif_map;
1214         else
1215                 map = drvdata->lpaif_map;
1216 
1217         regcache_cache_only(map, false);
1218         return regcache_sync(map);
1219 }
1220 
1221 static int lpass_platform_copy(struct snd_soc_component *component,
1222                                struct snd_pcm_substream *substream, int channel,
1223                                unsigned long pos, struct iov_iter *buf,
1224                                unsigned long bytes)
1225 {
1226         struct snd_pcm_runtime *rt = substream->runtime;
1227         unsigned int dai_id = component->id;
1228         int ret = 0;
1229 
1230         void __iomem *dma_buf = (void __iomem *) (rt->dma_area + pos +
1231                                 channel * (rt->dma_bytes / rt->channels));
1232 
1233         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1234                 if (is_cdc_dma_port(dai_id)) {
1235                         ret = copy_from_iter_toio(dma_buf, buf, bytes);
1236                 } else {
1237                         if (copy_from_iter((void __force *)dma_buf, bytes, buf) != bytes)
1238                                 ret = -EFAULT;
1239                 }
1240         } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
1241                 if (is_cdc_dma_port(dai_id)) {
1242                         ret = copy_to_iter_fromio(buf, dma_buf, bytes);
1243                 } else {
1244                         if (copy_to_iter((void __force *)dma_buf, bytes, buf) != bytes)
1245                                 ret = -EFAULT;
1246                 }
1247         }
1248 
1249         return ret;
1250 }
1251 
1252 static const struct snd_soc_component_driver lpass_component_driver = {
1253         .name           = DRV_NAME,
1254         .open           = lpass_platform_pcmops_open,
1255         .close          = lpass_platform_pcmops_close,
1256         .hw_params      = lpass_platform_pcmops_hw_params,
1257         .hw_free        = lpass_platform_pcmops_hw_free,
1258         .prepare        = lpass_platform_pcmops_prepare,
1259         .trigger        = lpass_platform_pcmops_trigger,
1260         .pointer        = lpass_platform_pcmops_pointer,
1261         .mmap           = lpass_platform_pcmops_mmap,
1262         .pcm_construct  = lpass_platform_pcm_new,
1263         .suspend                = lpass_platform_pcmops_suspend,
1264         .resume                 = lpass_platform_pcmops_resume,
1265         .copy           = lpass_platform_copy,
1266 
1267 };
1268 
1269 int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
1270 {
1271         struct lpass_data *drvdata = platform_get_drvdata(pdev);
1272         const struct lpass_variant *v = drvdata->variant;
1273         int ret;
1274 
1275         drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
1276         if (drvdata->lpaif_irq < 0)
1277                 return -ENODEV;
1278 
1279         /* ensure audio hardware is disabled */
1280         ret = regmap_write(drvdata->lpaif_map,
1281                         LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
1282         if (ret) {
1283                 dev_err(&pdev->dev, "error writing to irqen reg: %d\n", ret);
1284                 return ret;
1285         }
1286 
1287         ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,
1288                         lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
1289                         "lpass-irq-lpaif", drvdata);
1290         if (ret) {
1291                 dev_err(&pdev->dev, "irq request failed: %d\n", ret);
1292                 return ret;
1293         }
1294 
1295         ret = lpass_platform_alloc_dmactl_fields(&pdev->dev,
1296                                                  drvdata->lpaif_map);
1297         if (ret) {
1298                 dev_err(&pdev->dev,
1299                         "error initializing dmactl fields: %d\n", ret);
1300                 return ret;
1301         }
1302 
1303         if (drvdata->codec_dma_enable) {
1304                 ret = regmap_write(drvdata->rxtx_lpaif_map,
1305                         LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0x0);
1306                 if (ret) {
1307                         dev_err(&pdev->dev, "error writing to rxtx irqen reg: %d\n", ret);
1308                         return ret;
1309                 }
1310                 ret = regmap_write(drvdata->va_lpaif_map,
1311                         LPAIF_VA_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0x0);
1312                 if (ret) {
1313                         dev_err(&pdev->dev, "error writing to rxtx irqen reg: %d\n", ret);
1314                         return ret;
1315                 }
1316                 drvdata->rxtxif_irq = platform_get_irq_byname(pdev, "lpass-irq-rxtxif");
1317                 if (drvdata->rxtxif_irq < 0)
1318                         return -ENODEV;
1319 
1320                 ret = devm_request_irq(&pdev->dev, drvdata->rxtxif_irq,
1321                                 lpass_platform_rxtxif_irq, 0, "lpass-irq-rxtxif", drvdata);
1322                 if (ret) {
1323                         dev_err(&pdev->dev, "rxtx irq request failed: %d\n", ret);
1324                         return ret;
1325                 }
1326 
1327                 ret = lpass_platform_alloc_rxtx_dmactl_fields(&pdev->dev,
1328                                                  drvdata->rxtx_lpaif_map);
1329                 if (ret) {
1330                         dev_err(&pdev->dev,
1331                                 "error initializing rxtx dmactl fields: %d\n", ret);
1332                         return ret;
1333                 }
1334 
1335                 drvdata->vaif_irq = platform_get_irq_byname(pdev, "lpass-irq-vaif");
1336                 if (drvdata->vaif_irq < 0)
1337                         return -ENODEV;
1338 
1339                 ret = devm_request_irq(&pdev->dev, drvdata->vaif_irq,
1340                                 lpass_platform_vaif_irq, 0, "lpass-irq-vaif", drvdata);
1341                 if (ret) {
1342                         dev_err(&pdev->dev, "va irq request failed: %d\n", ret);
1343                         return ret;
1344                 }
1345 
1346                 ret = lpass_platform_alloc_va_dmactl_fields(&pdev->dev,
1347                                                  drvdata->va_lpaif_map);
1348                 if (ret) {
1349                         dev_err(&pdev->dev,
1350                                 "error initializing va dmactl fields: %d\n", ret);
1351                         return ret;
1352                 }
1353         }
1354 
1355         if (drvdata->hdmi_port_enable) {
1356                 drvdata->hdmiif_irq = platform_get_irq_byname(pdev, "lpass-irq-hdmi");
1357                 if (drvdata->hdmiif_irq < 0)
1358                         return -ENODEV;
1359 
1360                 ret = devm_request_irq(&pdev->dev, drvdata->hdmiif_irq,
1361                                 lpass_platform_hdmiif_irq, 0, "lpass-irq-hdmi", drvdata);
1362                 if (ret) {
1363                         dev_err(&pdev->dev, "irq hdmi request failed: %d\n", ret);
1364                         return ret;
1365                 }
1366                 ret = regmap_write(drvdata->hdmiif_map,
1367                                 LPASS_HDMITX_APP_IRQEN_REG(v), 0);
1368                 if (ret) {
1369                         dev_err(&pdev->dev, "error writing to hdmi irqen reg: %d\n", ret);
1370                         return ret;
1371                 }
1372 
1373                 ret = lpass_platform_alloc_hdmidmactl_fields(&pdev->dev,
1374                                                          drvdata->hdmiif_map);
1375                 if (ret) {
1376                         dev_err(&pdev->dev,
1377                                 "error initializing hdmidmactl fields: %d\n", ret);
1378                         return ret;
1379                 }
1380         }
1381         return devm_snd_soc_register_component(&pdev->dev,
1382                         &lpass_component_driver, NULL, 0);
1383 }
1384 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register);
1385 
1386 MODULE_DESCRIPTION("QTi LPASS Platform Driver");
1387 MODULE_LICENSE("GPL");
1388 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php