Merge tag 'for-5.15-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
[sfrench/cifs-2.6.git] / sound / soc / qcom / lpass-platform.c
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 <linux/dma-mapping.h>
9 #include <linux/export.h>
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <sound/pcm_params.h>
14 #include <linux/regmap.h>
15 #include <sound/soc.h>
16 #include "lpass-lpaif-reg.h"
17 #include "lpass.h"
18
19 #define DRV_NAME "lpass-platform"
20
21 struct lpass_pcm_data {
22         int dma_ch;
23         int i2s_port;
24 };
25
26 #define LPASS_PLATFORM_BUFFER_SIZE      (24 *  2 * 1024)
27 #define LPASS_PLATFORM_PERIODS          2
28
29 static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
30         .info                   =       SNDRV_PCM_INFO_MMAP |
31                                         SNDRV_PCM_INFO_MMAP_VALID |
32                                         SNDRV_PCM_INFO_INTERLEAVED |
33                                         SNDRV_PCM_INFO_PAUSE |
34                                         SNDRV_PCM_INFO_RESUME,
35         .formats                =       SNDRV_PCM_FMTBIT_S16 |
36                                         SNDRV_PCM_FMTBIT_S24 |
37                                         SNDRV_PCM_FMTBIT_S32,
38         .rates                  =       SNDRV_PCM_RATE_8000_192000,
39         .rate_min               =       8000,
40         .rate_max               =       192000,
41         .channels_min           =       1,
42         .channels_max           =       8,
43         .buffer_bytes_max       =       LPASS_PLATFORM_BUFFER_SIZE,
44         .period_bytes_max       =       LPASS_PLATFORM_BUFFER_SIZE /
45                                                 LPASS_PLATFORM_PERIODS,
46         .period_bytes_min       =       LPASS_PLATFORM_BUFFER_SIZE /
47                                                 LPASS_PLATFORM_PERIODS,
48         .periods_min            =       LPASS_PLATFORM_PERIODS,
49         .periods_max            =       LPASS_PLATFORM_PERIODS,
50         .fifo_size              =       0,
51 };
52
53 static int lpass_platform_alloc_dmactl_fields(struct device *dev,
54                                          struct regmap *map)
55 {
56         struct lpass_data *drvdata = dev_get_drvdata(dev);
57         struct lpass_variant *v = drvdata->variant;
58         struct lpaif_dmactl *rd_dmactl, *wr_dmactl;
59         int rval;
60
61         drvdata->rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
62                                           GFP_KERNEL);
63         if (drvdata->rd_dmactl == NULL)
64                 return -ENOMEM;
65
66         drvdata->wr_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
67                                           GFP_KERNEL);
68         if (drvdata->wr_dmactl == NULL)
69                 return -ENOMEM;
70
71         rd_dmactl = drvdata->rd_dmactl;
72         wr_dmactl = drvdata->wr_dmactl;
73
74         rval = devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->intf,
75                                             &v->rdma_intf, 6);
76         if (rval)
77                 return rval;
78
79         return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
80                                             &v->wrdma_intf, 6);
81 }
82
83 static int lpass_platform_alloc_hdmidmactl_fields(struct device *dev,
84                                          struct regmap *map)
85 {
86         struct lpass_data *drvdata = dev_get_drvdata(dev);
87         struct lpass_variant *v = drvdata->variant;
88         struct lpaif_dmactl *rd_dmactl;
89
90         rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl), GFP_KERNEL);
91         if (rd_dmactl == NULL)
92                 return -ENOMEM;
93
94         drvdata->hdmi_rd_dmactl = rd_dmactl;
95
96         return devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->bursten,
97                                             &v->hdmi_rdma_bursten, 8);
98 }
99
100 static int lpass_platform_pcmops_open(struct snd_soc_component *component,
101                                       struct snd_pcm_substream *substream)
102 {
103         struct snd_pcm_runtime *runtime = substream->runtime;
104         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
105         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
106         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
107         struct lpass_variant *v = drvdata->variant;
108         int ret, dma_ch, dir = substream->stream;
109         struct lpass_pcm_data *data;
110         struct regmap *map;
111         unsigned int dai_id = cpu_dai->driver->id;
112
113         component->id = dai_id;
114         data = kzalloc(sizeof(*data), GFP_KERNEL);
115         if (!data)
116                 return -ENOMEM;
117
118         data->i2s_port = cpu_dai->driver->id;
119         runtime->private_data = data;
120
121         if (v->alloc_dma_channel)
122                 dma_ch = v->alloc_dma_channel(drvdata, dir, dai_id);
123         else
124                 dma_ch = 0;
125
126         if (dma_ch < 0) {
127                 kfree(data);
128                 return dma_ch;
129         }
130
131         if (cpu_dai->driver->id == LPASS_DP_RX) {
132                 map = drvdata->hdmiif_map;
133                 drvdata->hdmi_substream[dma_ch] = substream;
134         } else {
135                 map = drvdata->lpaif_map;
136                 drvdata->substream[dma_ch] = substream;
137         }
138         data->dma_ch = dma_ch;
139         ret = regmap_write(map,
140                         LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0);
141         if (ret) {
142                 dev_err(soc_runtime->dev,
143                         "error writing to rdmactl reg: %d\n", ret);
144                 return ret;
145         }
146         snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
147
148         runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
149
150         ret = snd_pcm_hw_constraint_integer(runtime,
151                         SNDRV_PCM_HW_PARAM_PERIODS);
152         if (ret < 0) {
153                 kfree(data);
154                 dev_err(soc_runtime->dev, "setting constraints failed: %d\n",
155                         ret);
156                 return -EINVAL;
157         }
158
159         return 0;
160 }
161
162 static int lpass_platform_pcmops_close(struct snd_soc_component *component,
163                                        struct snd_pcm_substream *substream)
164 {
165         struct snd_pcm_runtime *runtime = substream->runtime;
166         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
167         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
168         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
169         struct lpass_variant *v = drvdata->variant;
170         struct lpass_pcm_data *data;
171         unsigned int dai_id = cpu_dai->driver->id;
172
173         data = runtime->private_data;
174         if (dai_id == LPASS_DP_RX)
175                 drvdata->hdmi_substream[data->dma_ch] = NULL;
176         else
177                 drvdata->substream[data->dma_ch] = NULL;
178         if (v->free_dma_channel)
179                 v->free_dma_channel(drvdata, data->dma_ch, dai_id);
180
181         kfree(data);
182         return 0;
183 }
184
185 static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
186                                            struct snd_pcm_substream *substream,
187                                            struct snd_pcm_hw_params *params)
188 {
189         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
190         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
191         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
192         struct snd_pcm_runtime *rt = substream->runtime;
193         struct lpass_pcm_data *pcm_data = rt->private_data;
194         struct lpass_variant *v = drvdata->variant;
195         snd_pcm_format_t format = params_format(params);
196         unsigned int channels = params_channels(params);
197         unsigned int regval;
198         struct lpaif_dmactl *dmactl;
199         int id, dir = substream->stream;
200         int bitwidth;
201         int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start;
202         unsigned int dai_id = cpu_dai->driver->id;
203
204         if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
205                 id = pcm_data->dma_ch;
206                 if (dai_id == LPASS_DP_RX)
207                         dmactl = drvdata->hdmi_rd_dmactl;
208                 else
209                         dmactl = drvdata->rd_dmactl;
210
211         } else {
212                 dmactl = drvdata->wr_dmactl;
213                 id = pcm_data->dma_ch - v->wrdma_channel_start;
214         }
215
216         bitwidth = snd_pcm_format_width(format);
217         if (bitwidth < 0) {
218                 dev_err(soc_runtime->dev, "invalid bit width given: %d\n",
219                                 bitwidth);
220                 return bitwidth;
221         }
222
223         ret = regmap_fields_write(dmactl->bursten, id, LPAIF_DMACTL_BURSTEN_INCR4);
224         if (ret) {
225                 dev_err(soc_runtime->dev, "error updating bursten field: %d\n", ret);
226                 return ret;
227         }
228
229         ret = regmap_fields_write(dmactl->fifowm, id, LPAIF_DMACTL_FIFOWM_8);
230         if (ret) {
231                 dev_err(soc_runtime->dev, "error updating fifowm field: %d\n", ret);
232                 return ret;
233         }
234
235         switch (dai_id) {
236         case LPASS_DP_RX:
237                 ret = regmap_fields_write(dmactl->burst8, id,
238                                                         LPAIF_DMACTL_BURSTEN_INCR4);
239                 if (ret) {
240                         dev_err(soc_runtime->dev, "error updating burst8en field: %d\n", ret);
241                         return ret;
242                 }
243                 ret = regmap_fields_write(dmactl->burst16, id,
244                                                         LPAIF_DMACTL_BURSTEN_INCR4);
245                 if (ret) {
246                         dev_err(soc_runtime->dev, "error updating burst16en field: %d\n", ret);
247                         return ret;
248                 }
249                 ret = regmap_fields_write(dmactl->dynburst, id,
250                                                         LPAIF_DMACTL_BURSTEN_INCR4);
251                 if (ret) {
252                         dev_err(soc_runtime->dev, "error updating dynbursten field: %d\n", ret);
253                         return ret;
254                 }
255                 break;
256         case MI2S_PRIMARY:
257         case MI2S_SECONDARY:
258         case MI2S_TERTIARY:
259         case MI2S_QUATERNARY:
260         case MI2S_QUINARY:
261                 ret = regmap_fields_write(dmactl->intf, id,
262                                                 LPAIF_DMACTL_AUDINTF(dma_port));
263                 if (ret) {
264                         dev_err(soc_runtime->dev, "error updating audio interface field: %d\n",
265                                         ret);
266                         return ret;
267                 }
268
269                 break;
270         default:
271                 dev_err(soc_runtime->dev, "%s: invalid  interface: %d\n", __func__, dai_id);
272                 break;
273         }
274         switch (bitwidth) {
275         case 16:
276                 switch (channels) {
277                 case 1:
278                 case 2:
279                         regval = LPAIF_DMACTL_WPSCNT_ONE;
280                         break;
281                 case 4:
282                         regval = LPAIF_DMACTL_WPSCNT_TWO;
283                         break;
284                 case 6:
285                         regval = LPAIF_DMACTL_WPSCNT_THREE;
286                         break;
287                 case 8:
288                         regval = LPAIF_DMACTL_WPSCNT_FOUR;
289                         break;
290                 default:
291                         dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n",
292                                 bitwidth, channels);
293                         return -EINVAL;
294                 }
295                 break;
296         case 24:
297         case 32:
298                 switch (channels) {
299                 case 1:
300                         regval = LPAIF_DMACTL_WPSCNT_ONE;
301                         break;
302                 case 2:
303                         regval = (dai_id == LPASS_DP_RX ?
304                         LPAIF_DMACTL_WPSCNT_ONE :
305                         LPAIF_DMACTL_WPSCNT_TWO);
306                         break;
307                 case 4:
308                         regval = (dai_id == LPASS_DP_RX ?
309                         LPAIF_DMACTL_WPSCNT_TWO :
310                         LPAIF_DMACTL_WPSCNT_FOUR);
311                         break;
312                 case 6:
313                         regval = (dai_id == LPASS_DP_RX ?
314                         LPAIF_DMACTL_WPSCNT_THREE :
315                         LPAIF_DMACTL_WPSCNT_SIX);
316                         break;
317                 case 8:
318                         regval = (dai_id == LPASS_DP_RX ?
319                         LPAIF_DMACTL_WPSCNT_FOUR :
320                         LPAIF_DMACTL_WPSCNT_EIGHT);
321                         break;
322                 default:
323                         dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n",
324                                 bitwidth, channels);
325                         return -EINVAL;
326                 }
327                 break;
328         default:
329                 dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n",
330                         bitwidth, channels);
331                 return -EINVAL;
332         }
333
334         ret = regmap_fields_write(dmactl->wpscnt, id, regval);
335         if (ret) {
336                 dev_err(soc_runtime->dev, "error writing to dmactl reg: %d\n",
337                         ret);
338                 return ret;
339         }
340
341         return 0;
342 }
343
344 static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component,
345                                          struct snd_pcm_substream *substream)
346 {
347         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
348         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
349         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
350         struct snd_pcm_runtime *rt = substream->runtime;
351         struct lpass_pcm_data *pcm_data = rt->private_data;
352         struct lpass_variant *v = drvdata->variant;
353         unsigned int reg;
354         int ret;
355         struct regmap *map;
356         unsigned int dai_id = cpu_dai->driver->id;
357
358         if (dai_id == LPASS_DP_RX)
359                 map = drvdata->hdmiif_map;
360         else
361                 map = drvdata->lpaif_map;
362
363         reg = LPAIF_DMACTL_REG(v, pcm_data->dma_ch, substream->stream, dai_id);
364         ret = regmap_write(map, reg, 0);
365         if (ret)
366                 dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
367                         ret);
368
369         return ret;
370 }
371
372 static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
373                                          struct snd_pcm_substream *substream)
374 {
375         struct snd_pcm_runtime *runtime = substream->runtime;
376         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
377         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
378         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
379         struct snd_pcm_runtime *rt = substream->runtime;
380         struct lpass_pcm_data *pcm_data = rt->private_data;
381         struct lpass_variant *v = drvdata->variant;
382         struct lpaif_dmactl *dmactl;
383         struct regmap *map;
384         int ret, id, ch, dir = substream->stream;
385         unsigned int dai_id = cpu_dai->driver->id;
386
387
388         ch = pcm_data->dma_ch;
389         if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
390                 if (dai_id == LPASS_DP_RX) {
391                         dmactl = drvdata->hdmi_rd_dmactl;
392                         map = drvdata->hdmiif_map;
393                 } else {
394                         dmactl = drvdata->rd_dmactl;
395                         map = drvdata->lpaif_map;
396                 }
397
398                 id = pcm_data->dma_ch;
399         } else {
400                 dmactl = drvdata->wr_dmactl;
401                 id = pcm_data->dma_ch - v->wrdma_channel_start;
402                 map = drvdata->lpaif_map;
403         }
404
405         ret = regmap_write(map, LPAIF_DMABASE_REG(v, ch, dir, dai_id),
406                                 runtime->dma_addr);
407         if (ret) {
408                 dev_err(soc_runtime->dev, "error writing to rdmabase reg: %d\n",
409                         ret);
410                 return ret;
411         }
412
413         ret = regmap_write(map, LPAIF_DMABUFF_REG(v, ch, dir, dai_id),
414                         (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);
415         if (ret) {
416                 dev_err(soc_runtime->dev, "error writing to rdmabuff reg: %d\n",
417                         ret);
418                 return ret;
419         }
420
421         ret = regmap_write(map, LPAIF_DMAPER_REG(v, ch, dir, dai_id),
422                         (snd_pcm_lib_period_bytes(substream) >> 2) - 1);
423         if (ret) {
424                 dev_err(soc_runtime->dev, "error writing to rdmaper reg: %d\n",
425                         ret);
426                 return ret;
427         }
428
429         ret = regmap_fields_write(dmactl->enable, id, LPAIF_DMACTL_ENABLE_ON);
430         if (ret) {
431                 dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
432                         ret);
433                 return ret;
434         }
435
436         return 0;
437 }
438
439 static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
440                                          struct snd_pcm_substream *substream,
441                                          int cmd)
442 {
443         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
444         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
445         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
446         struct snd_pcm_runtime *rt = substream->runtime;
447         struct lpass_pcm_data *pcm_data = rt->private_data;
448         struct lpass_variant *v = drvdata->variant;
449         struct lpaif_dmactl *dmactl;
450         struct regmap *map;
451         int ret, ch, id;
452         int dir = substream->stream;
453         unsigned int reg_irqclr = 0, val_irqclr = 0;
454         unsigned int  reg_irqen = 0, val_irqen = 0, val_mask = 0;
455         unsigned int dai_id = cpu_dai->driver->id;
456
457         ch = pcm_data->dma_ch;
458         if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
459                 id = pcm_data->dma_ch;
460                 if (dai_id == LPASS_DP_RX) {
461                         dmactl = drvdata->hdmi_rd_dmactl;
462                         map = drvdata->hdmiif_map;
463                 } else {
464                         dmactl = drvdata->rd_dmactl;
465                         map = drvdata->lpaif_map;
466                 }
467         } else {
468                 dmactl = drvdata->wr_dmactl;
469                 id = pcm_data->dma_ch - v->wrdma_channel_start;
470                 map = drvdata->lpaif_map;
471         }
472
473         switch (cmd) {
474         case SNDRV_PCM_TRIGGER_START:
475         case SNDRV_PCM_TRIGGER_RESUME:
476         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
477                 ret = regmap_fields_write(dmactl->enable, id,
478                                                  LPAIF_DMACTL_ENABLE_ON);
479                 if (ret) {
480                         dev_err(soc_runtime->dev,
481                                 "error writing to rdmactl reg: %d\n", ret);
482                         return ret;
483                 }
484                 switch (dai_id) {
485                 case LPASS_DP_RX:
486                         ret = regmap_fields_write(dmactl->dyncclk, id,
487                                          LPAIF_DMACTL_DYNCLK_ON);
488                         if (ret) {
489                                 dev_err(soc_runtime->dev,
490                                         "error writing to rdmactl reg: %d\n", ret);
491                                 return ret;
492                         }
493                         reg_irqclr = LPASS_HDMITX_APP_IRQCLEAR_REG(v);
494                         val_irqclr = (LPAIF_IRQ_ALL(ch) |
495                                         LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
496                                         LPAIF_IRQ_HDMI_METADONE |
497                                         LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
498
499                         reg_irqen = LPASS_HDMITX_APP_IRQEN_REG(v);
500                         val_mask = (LPAIF_IRQ_ALL(ch) |
501                                         LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
502                                         LPAIF_IRQ_HDMI_METADONE |
503                                         LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
504                         val_irqen = (LPAIF_IRQ_ALL(ch) |
505                                         LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
506                                         LPAIF_IRQ_HDMI_METADONE |
507                                         LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
508                         break;
509                 case MI2S_PRIMARY:
510                 case MI2S_SECONDARY:
511                 case MI2S_TERTIARY:
512                 case MI2S_QUATERNARY:
513                 case MI2S_QUINARY:
514                         reg_irqclr = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
515                         val_irqclr = LPAIF_IRQ_ALL(ch);
516
517
518                         reg_irqen = LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
519                         val_mask = LPAIF_IRQ_ALL(ch);
520                         val_irqen = LPAIF_IRQ_ALL(ch);
521                         break;
522                 default:
523                         dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);
524                         return -EINVAL;
525                 }
526
527                 ret = regmap_update_bits(map, reg_irqclr, val_irqclr, val_irqclr);
528                 if (ret) {
529                         dev_err(soc_runtime->dev, "error writing to irqclear reg: %d\n", ret);
530                         return ret;
531                 }
532                 ret = regmap_update_bits(map, reg_irqen, val_mask, val_irqen);
533                 if (ret) {
534                         dev_err(soc_runtime->dev, "error writing to irqen reg: %d\n", ret);
535                         return ret;
536                 }
537                 break;
538         case SNDRV_PCM_TRIGGER_STOP:
539         case SNDRV_PCM_TRIGGER_SUSPEND:
540         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
541                 ret = regmap_fields_write(dmactl->enable, id,
542                                          LPAIF_DMACTL_ENABLE_OFF);
543                 if (ret) {
544                         dev_err(soc_runtime->dev,
545                                 "error writing to rdmactl reg: %d\n", ret);
546                         return ret;
547                 }
548                 switch (dai_id) {
549                 case LPASS_DP_RX:
550                         ret = regmap_fields_write(dmactl->dyncclk, id,
551                                          LPAIF_DMACTL_DYNCLK_OFF);
552                         if (ret) {
553                                 dev_err(soc_runtime->dev,
554                                         "error writing to rdmactl reg: %d\n", ret);
555                                 return ret;
556                         }
557                         reg_irqen = LPASS_HDMITX_APP_IRQEN_REG(v);
558                         val_mask = (LPAIF_IRQ_ALL(ch) |
559                                         LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
560                                         LPAIF_IRQ_HDMI_METADONE |
561                                         LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
562                         val_irqen = 0;
563                         break;
564                 case MI2S_PRIMARY:
565                 case MI2S_SECONDARY:
566                 case MI2S_TERTIARY:
567                 case MI2S_QUATERNARY:
568                 case MI2S_QUINARY:
569                         reg_irqen = LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
570                         val_mask = LPAIF_IRQ_ALL(ch);
571                         val_irqen = 0;
572                         break;
573                 default:
574                         dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);
575                         return -EINVAL;
576                 }
577
578                 ret = regmap_update_bits(map, reg_irqen, val_mask, val_irqen);
579                 if (ret) {
580                         dev_err(soc_runtime->dev,
581                                 "error writing to irqen reg: %d\n", ret);
582                         return ret;
583                 }
584                 break;
585         }
586
587         return 0;
588 }
589
590 static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
591                 struct snd_soc_component *component,
592                 struct snd_pcm_substream *substream)
593 {
594         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
595         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
596         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
597         struct snd_pcm_runtime *rt = substream->runtime;
598         struct lpass_pcm_data *pcm_data = rt->private_data;
599         struct lpass_variant *v = drvdata->variant;
600         unsigned int base_addr, curr_addr;
601         int ret, ch, dir = substream->stream;
602         struct regmap *map;
603         unsigned int dai_id = cpu_dai->driver->id;
604
605         if (dai_id == LPASS_DP_RX)
606                 map = drvdata->hdmiif_map;
607         else
608                 map = drvdata->lpaif_map;
609
610         ch = pcm_data->dma_ch;
611
612         ret = regmap_read(map,
613                         LPAIF_DMABASE_REG(v, ch, dir, dai_id), &base_addr);
614         if (ret) {
615                 dev_err(soc_runtime->dev,
616                         "error reading from rdmabase reg: %d\n", ret);
617                 return ret;
618         }
619
620         ret = regmap_read(map,
621                         LPAIF_DMACURR_REG(v, ch, dir, dai_id), &curr_addr);
622         if (ret) {
623                 dev_err(soc_runtime->dev,
624                         "error reading from rdmacurr reg: %d\n", ret);
625                 return ret;
626         }
627
628         return bytes_to_frames(substream->runtime, curr_addr - base_addr);
629 }
630
631 static irqreturn_t lpass_dma_interrupt_handler(
632                         struct snd_pcm_substream *substream,
633                         struct lpass_data *drvdata,
634                         int chan, u32 interrupts)
635 {
636         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
637         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
638         struct lpass_variant *v = drvdata->variant;
639         irqreturn_t ret = IRQ_NONE;
640         int rv;
641         unsigned int reg, val, mask;
642         struct regmap *map;
643         unsigned int dai_id = cpu_dai->driver->id;
644
645         mask = LPAIF_IRQ_ALL(chan);
646         switch (dai_id) {
647         case LPASS_DP_RX:
648                 map = drvdata->hdmiif_map;
649                 reg = LPASS_HDMITX_APP_IRQCLEAR_REG(v);
650                 val = (LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(chan) |
651                 LPAIF_IRQ_HDMI_METADONE |
652                 LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(chan));
653         break;
654         case MI2S_PRIMARY:
655         case MI2S_SECONDARY:
656         case MI2S_TERTIARY:
657         case MI2S_QUATERNARY:
658         case MI2S_QUINARY:
659                 map = drvdata->lpaif_map;
660                 reg = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
661                 val = 0;
662         break;
663         default:
664         dev_err(soc_runtime->dev, "%s: invalid  %d interface\n", __func__, dai_id);
665         return -EINVAL;
666         }
667         if (interrupts & LPAIF_IRQ_PER(chan)) {
668                 rv = regmap_update_bits(map, reg, mask, (LPAIF_IRQ_PER(chan) | val));
669                 if (rv) {
670                         dev_err(soc_runtime->dev,
671                                 "error writing to irqclear reg: %d\n", rv);
672                         return IRQ_NONE;
673                 }
674                 snd_pcm_period_elapsed(substream);
675                 ret = IRQ_HANDLED;
676         }
677
678         if (interrupts & LPAIF_IRQ_XRUN(chan)) {
679                 rv = regmap_update_bits(map, reg, mask, (LPAIF_IRQ_XRUN(chan) | val));
680                 if (rv) {
681                         dev_err(soc_runtime->dev,
682                                 "error writing to irqclear reg: %d\n", rv);
683                         return IRQ_NONE;
684                 }
685                 dev_warn(soc_runtime->dev, "xrun warning\n");
686                 snd_pcm_stop_xrun(substream);
687                 ret = IRQ_HANDLED;
688         }
689
690         if (interrupts & LPAIF_IRQ_ERR(chan)) {
691                 rv = regmap_update_bits(map, reg, mask, (LPAIF_IRQ_ERR(chan) | val));
692                 if (rv) {
693                         dev_err(soc_runtime->dev,
694                                 "error writing to irqclear reg: %d\n", rv);
695                         return IRQ_NONE;
696                 }
697                 dev_err(soc_runtime->dev, "bus access error\n");
698                 snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
699                 ret = IRQ_HANDLED;
700         }
701
702         if (interrupts & val) {
703                 rv = regmap_write(map, reg, val);
704                 if (rv) {
705                         dev_err(soc_runtime->dev,
706                         "error writing to irqclear reg: %d\n", rv);
707                         return IRQ_NONE;
708                 }
709                 ret = IRQ_HANDLED;
710         }
711
712         return ret;
713 }
714
715 static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
716 {
717         struct lpass_data *drvdata = data;
718         struct lpass_variant *v = drvdata->variant;
719         unsigned int irqs;
720         int rv, chan;
721
722         rv = regmap_read(drvdata->lpaif_map,
723                         LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
724         if (rv) {
725                 pr_err("error reading from irqstat reg: %d\n", rv);
726                 return IRQ_NONE;
727         }
728
729         /* Handle per channel interrupts */
730         for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++) {
731                 if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan]) {
732                         rv = lpass_dma_interrupt_handler(
733                                                 drvdata->substream[chan],
734                                                 drvdata, chan, irqs);
735                         if (rv != IRQ_HANDLED)
736                                 return rv;
737                 }
738         }
739
740         return IRQ_HANDLED;
741 }
742
743 static irqreturn_t lpass_platform_hdmiif_irq(int irq, void *data)
744 {
745         struct lpass_data *drvdata = data;
746         struct lpass_variant *v = drvdata->variant;
747         unsigned int irqs;
748         int rv, chan;
749
750         rv = regmap_read(drvdata->hdmiif_map,
751                         LPASS_HDMITX_APP_IRQSTAT_REG(v), &irqs);
752         if (rv) {
753                 pr_err("error reading from irqstat reg: %d\n", rv);
754                 return IRQ_NONE;
755         }
756
757         /* Handle per channel interrupts */
758         for (chan = 0; chan < LPASS_MAX_HDMI_DMA_CHANNELS; chan++) {
759                 if (irqs & (LPAIF_IRQ_ALL(chan) | LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(chan) |
760                                 LPAIF_IRQ_HDMI_METADONE |
761                                 LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(chan))
762                         && drvdata->hdmi_substream[chan]) {
763                         rv = lpass_dma_interrupt_handler(
764                                                 drvdata->hdmi_substream[chan],
765                                                 drvdata, chan, irqs);
766                         if (rv != IRQ_HANDLED)
767                                 return rv;
768                 }
769         }
770
771         return IRQ_HANDLED;
772 }
773
774 static int lpass_platform_pcm_new(struct snd_soc_component *component,
775                                   struct snd_soc_pcm_runtime *soc_runtime)
776 {
777         struct snd_pcm *pcm = soc_runtime->pcm;
778         size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
779
780         return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
781                                             component->dev, size);
782 }
783
784 static int lpass_platform_pcmops_suspend(struct snd_soc_component *component)
785 {
786         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
787         struct regmap *map;
788         unsigned int dai_id = component->id;
789
790         if (dai_id == LPASS_DP_RX)
791                 map = drvdata->hdmiif_map;
792         else
793                 map = drvdata->lpaif_map;
794
795         regcache_cache_only(map, true);
796         regcache_mark_dirty(map);
797
798         return 0;
799 }
800
801 static int lpass_platform_pcmops_resume(struct snd_soc_component *component)
802 {
803         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
804         struct regmap *map;
805         unsigned int dai_id = component->id;
806
807         if (dai_id == LPASS_DP_RX)
808                 map = drvdata->hdmiif_map;
809         else
810                 map = drvdata->lpaif_map;
811
812         regcache_cache_only(map, false);
813         return regcache_sync(map);
814 }
815
816
817 static const struct snd_soc_component_driver lpass_component_driver = {
818         .name           = DRV_NAME,
819         .open           = lpass_platform_pcmops_open,
820         .close          = lpass_platform_pcmops_close,
821         .hw_params      = lpass_platform_pcmops_hw_params,
822         .hw_free        = lpass_platform_pcmops_hw_free,
823         .prepare        = lpass_platform_pcmops_prepare,
824         .trigger        = lpass_platform_pcmops_trigger,
825         .pointer        = lpass_platform_pcmops_pointer,
826         .pcm_construct  = lpass_platform_pcm_new,
827         .suspend                = lpass_platform_pcmops_suspend,
828         .resume                 = lpass_platform_pcmops_resume,
829
830 };
831
832 int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
833 {
834         struct lpass_data *drvdata = platform_get_drvdata(pdev);
835         struct lpass_variant *v = drvdata->variant;
836         int ret;
837
838         drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
839         if (drvdata->lpaif_irq < 0)
840                 return -ENODEV;
841
842         /* ensure audio hardware is disabled */
843         ret = regmap_write(drvdata->lpaif_map,
844                         LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
845         if (ret) {
846                 dev_err(&pdev->dev, "error writing to irqen reg: %d\n", ret);
847                 return ret;
848         }
849
850         ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,
851                         lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
852                         "lpass-irq-lpaif", drvdata);
853         if (ret) {
854                 dev_err(&pdev->dev, "irq request failed: %d\n", ret);
855                 return ret;
856         }
857
858         ret = lpass_platform_alloc_dmactl_fields(&pdev->dev,
859                                                  drvdata->lpaif_map);
860         if (ret) {
861                 dev_err(&pdev->dev,
862                         "error initializing dmactl fields: %d\n", ret);
863                 return ret;
864         }
865
866         if (drvdata->hdmi_port_enable) {
867                 drvdata->hdmiif_irq = platform_get_irq_byname(pdev, "lpass-irq-hdmi");
868                 if (drvdata->hdmiif_irq < 0)
869                         return -ENODEV;
870
871                 ret = devm_request_irq(&pdev->dev, drvdata->hdmiif_irq,
872                                 lpass_platform_hdmiif_irq, 0, "lpass-irq-hdmi", drvdata);
873                 if (ret) {
874                         dev_err(&pdev->dev, "irq hdmi request failed: %d\n", ret);
875                         return ret;
876                 }
877                 ret = regmap_write(drvdata->hdmiif_map,
878                                 LPASS_HDMITX_APP_IRQEN_REG(v), 0);
879                 if (ret) {
880                         dev_err(&pdev->dev, "error writing to hdmi irqen reg: %d\n", ret);
881                         return ret;
882                 }
883
884                 ret = lpass_platform_alloc_hdmidmactl_fields(&pdev->dev,
885                                                          drvdata->hdmiif_map);
886                 if (ret) {
887                         dev_err(&pdev->dev,
888                                 "error initializing hdmidmactl fields: %d\n", ret);
889                         return ret;
890                 }
891         }
892         return devm_snd_soc_register_component(&pdev->dev,
893                         &lpass_component_driver, NULL, 0);
894 }
895 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register);
896
897 MODULE_DESCRIPTION("QTi LPASS Platform Driver");
898 MODULE_LICENSE("GPL v2");