Merge branch 'work.namei' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[linux-2.6-microblaze.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         snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
160
161         return 0;
162 }
163
164 static int lpass_platform_pcmops_close(struct snd_soc_component *component,
165                                        struct snd_pcm_substream *substream)
166 {
167         struct snd_pcm_runtime *runtime = substream->runtime;
168         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
169         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
170         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
171         struct lpass_variant *v = drvdata->variant;
172         struct lpass_pcm_data *data;
173         unsigned int dai_id = cpu_dai->driver->id;
174
175         data = runtime->private_data;
176         if (dai_id == LPASS_DP_RX)
177                 drvdata->hdmi_substream[data->dma_ch] = NULL;
178         else
179                 drvdata->substream[data->dma_ch] = NULL;
180         if (v->free_dma_channel)
181                 v->free_dma_channel(drvdata, data->dma_ch, dai_id);
182
183         kfree(data);
184         return 0;
185 }
186
187 static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
188                                            struct snd_pcm_substream *substream,
189                                            struct snd_pcm_hw_params *params)
190 {
191         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
192         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
193         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
194         struct snd_pcm_runtime *rt = substream->runtime;
195         struct lpass_pcm_data *pcm_data = rt->private_data;
196         struct lpass_variant *v = drvdata->variant;
197         snd_pcm_format_t format = params_format(params);
198         unsigned int channels = params_channels(params);
199         unsigned int regval;
200         struct lpaif_dmactl *dmactl;
201         int id, dir = substream->stream;
202         int bitwidth;
203         int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start;
204         unsigned int dai_id = cpu_dai->driver->id;
205
206         if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
207                 id = pcm_data->dma_ch;
208                 if (dai_id == LPASS_DP_RX)
209                         dmactl = drvdata->hdmi_rd_dmactl;
210                 else
211                         dmactl = drvdata->rd_dmactl;
212
213         } else {
214                 dmactl = drvdata->wr_dmactl;
215                 id = pcm_data->dma_ch - v->wrdma_channel_start;
216         }
217
218         bitwidth = snd_pcm_format_width(format);
219         if (bitwidth < 0) {
220                 dev_err(soc_runtime->dev, "invalid bit width given: %d\n",
221                                 bitwidth);
222                 return bitwidth;
223         }
224
225         ret = regmap_fields_write(dmactl->bursten, id, LPAIF_DMACTL_BURSTEN_INCR4);
226         if (ret) {
227                 dev_err(soc_runtime->dev, "error updating bursten field: %d\n", ret);
228                 return ret;
229         }
230
231         ret = regmap_fields_write(dmactl->fifowm, id, LPAIF_DMACTL_FIFOWM_8);
232         if (ret) {
233                 dev_err(soc_runtime->dev, "error updating fifowm field: %d\n", ret);
234                 return ret;
235         }
236
237         switch (dai_id) {
238         case LPASS_DP_RX:
239                 ret = regmap_fields_write(dmactl->burst8, id,
240                                                         LPAIF_DMACTL_BURSTEN_INCR4);
241                 if (ret) {
242                         dev_err(soc_runtime->dev, "error updating burst8en field: %d\n", ret);
243                         return ret;
244                 }
245                 ret = regmap_fields_write(dmactl->burst16, id,
246                                                         LPAIF_DMACTL_BURSTEN_INCR4);
247                 if (ret) {
248                         dev_err(soc_runtime->dev, "error updating burst16en field: %d\n", ret);
249                         return ret;
250                 }
251                 ret = regmap_fields_write(dmactl->dynburst, id,
252                                                         LPAIF_DMACTL_BURSTEN_INCR4);
253                 if (ret) {
254                         dev_err(soc_runtime->dev, "error updating dynbursten field: %d\n", ret);
255                         return ret;
256                 }
257                 break;
258         case MI2S_PRIMARY:
259         case MI2S_SECONDARY:
260         case MI2S_TERTIARY:
261         case MI2S_QUATERNARY:
262         case MI2S_QUINARY:
263                 ret = regmap_fields_write(dmactl->intf, id,
264                                                 LPAIF_DMACTL_AUDINTF(dma_port));
265                 if (ret) {
266                         dev_err(soc_runtime->dev, "error updating audio interface field: %d\n",
267                                         ret);
268                         return ret;
269                 }
270
271                 break;
272         default:
273                 dev_err(soc_runtime->dev, "%s: invalid  interface: %d\n", __func__, dai_id);
274                 break;
275         }
276         switch (bitwidth) {
277         case 16:
278                 switch (channels) {
279                 case 1:
280                 case 2:
281                         regval = LPAIF_DMACTL_WPSCNT_ONE;
282                         break;
283                 case 4:
284                         regval = LPAIF_DMACTL_WPSCNT_TWO;
285                         break;
286                 case 6:
287                         regval = LPAIF_DMACTL_WPSCNT_THREE;
288                         break;
289                 case 8:
290                         regval = LPAIF_DMACTL_WPSCNT_FOUR;
291                         break;
292                 default:
293                         dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n",
294                                 bitwidth, channels);
295                         return -EINVAL;
296                 }
297                 break;
298         case 24:
299         case 32:
300                 switch (channels) {
301                 case 1:
302                         regval = LPAIF_DMACTL_WPSCNT_ONE;
303                         break;
304                 case 2:
305                         regval = (dai_id == LPASS_DP_RX ?
306                         LPAIF_DMACTL_WPSCNT_ONE :
307                         LPAIF_DMACTL_WPSCNT_TWO);
308                         break;
309                 case 4:
310                         regval = (dai_id == LPASS_DP_RX ?
311                         LPAIF_DMACTL_WPSCNT_TWO :
312                         LPAIF_DMACTL_WPSCNT_FOUR);
313                         break;
314                 case 6:
315                         regval = (dai_id == LPASS_DP_RX ?
316                         LPAIF_DMACTL_WPSCNT_THREE :
317                         LPAIF_DMACTL_WPSCNT_SIX);
318                         break;
319                 case 8:
320                         regval = (dai_id == LPASS_DP_RX ?
321                         LPAIF_DMACTL_WPSCNT_FOUR :
322                         LPAIF_DMACTL_WPSCNT_EIGHT);
323                         break;
324                 default:
325                         dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n",
326                                 bitwidth, channels);
327                         return -EINVAL;
328                 }
329                 break;
330         default:
331                 dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n",
332                         bitwidth, channels);
333                 return -EINVAL;
334         }
335
336         ret = regmap_fields_write(dmactl->wpscnt, id, regval);
337         if (ret) {
338                 dev_err(soc_runtime->dev, "error writing to dmactl reg: %d\n",
339                         ret);
340                 return ret;
341         }
342
343         return 0;
344 }
345
346 static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component,
347                                          struct snd_pcm_substream *substream)
348 {
349         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
350         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
351         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
352         struct snd_pcm_runtime *rt = substream->runtime;
353         struct lpass_pcm_data *pcm_data = rt->private_data;
354         struct lpass_variant *v = drvdata->variant;
355         unsigned int reg;
356         int ret;
357         struct regmap *map;
358         unsigned int dai_id = cpu_dai->driver->id;
359
360         if (dai_id == LPASS_DP_RX)
361                 map = drvdata->hdmiif_map;
362         else
363                 map = drvdata->lpaif_map;
364
365         reg = LPAIF_DMACTL_REG(v, pcm_data->dma_ch, substream->stream, dai_id);
366         ret = regmap_write(map, reg, 0);
367         if (ret)
368                 dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
369                         ret);
370
371         return ret;
372 }
373
374 static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
375                                          struct snd_pcm_substream *substream)
376 {
377         struct snd_pcm_runtime *runtime = substream->runtime;
378         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
379         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
380         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
381         struct snd_pcm_runtime *rt = substream->runtime;
382         struct lpass_pcm_data *pcm_data = rt->private_data;
383         struct lpass_variant *v = drvdata->variant;
384         struct lpaif_dmactl *dmactl;
385         struct regmap *map;
386         int ret, id, ch, dir = substream->stream;
387         unsigned int dai_id = cpu_dai->driver->id;
388
389
390         ch = pcm_data->dma_ch;
391         if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
392                 if (dai_id == LPASS_DP_RX) {
393                         dmactl = drvdata->hdmi_rd_dmactl;
394                         map = drvdata->hdmiif_map;
395                 } else {
396                         dmactl = drvdata->rd_dmactl;
397                         map = drvdata->lpaif_map;
398                 }
399
400                 id = pcm_data->dma_ch;
401         } else {
402                 dmactl = drvdata->wr_dmactl;
403                 id = pcm_data->dma_ch - v->wrdma_channel_start;
404                 map = drvdata->lpaif_map;
405         }
406
407         ret = regmap_write(map, LPAIF_DMABASE_REG(v, ch, dir, dai_id),
408                                 runtime->dma_addr);
409         if (ret) {
410                 dev_err(soc_runtime->dev, "error writing to rdmabase reg: %d\n",
411                         ret);
412                 return ret;
413         }
414
415         ret = regmap_write(map, LPAIF_DMABUFF_REG(v, ch, dir, dai_id),
416                         (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);
417         if (ret) {
418                 dev_err(soc_runtime->dev, "error writing to rdmabuff reg: %d\n",
419                         ret);
420                 return ret;
421         }
422
423         ret = regmap_write(map, LPAIF_DMAPER_REG(v, ch, dir, dai_id),
424                         (snd_pcm_lib_period_bytes(substream) >> 2) - 1);
425         if (ret) {
426                 dev_err(soc_runtime->dev, "error writing to rdmaper reg: %d\n",
427                         ret);
428                 return ret;
429         }
430
431         ret = regmap_fields_write(dmactl->enable, id, LPAIF_DMACTL_ENABLE_ON);
432         if (ret) {
433                 dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
434                         ret);
435                 return ret;
436         }
437
438         return 0;
439 }
440
441 static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
442                                          struct snd_pcm_substream *substream,
443                                          int cmd)
444 {
445         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
446         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
447         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
448         struct snd_pcm_runtime *rt = substream->runtime;
449         struct lpass_pcm_data *pcm_data = rt->private_data;
450         struct lpass_variant *v = drvdata->variant;
451         struct lpaif_dmactl *dmactl;
452         struct regmap *map;
453         int ret, ch, id;
454         int dir = substream->stream;
455         unsigned int reg_irqclr = 0, val_irqclr = 0;
456         unsigned int  reg_irqen = 0, val_irqen = 0, val_mask = 0;
457         unsigned int dai_id = cpu_dai->driver->id;
458
459         ch = pcm_data->dma_ch;
460         if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
461                 id = pcm_data->dma_ch;
462                 if (dai_id == LPASS_DP_RX) {
463                         dmactl = drvdata->hdmi_rd_dmactl;
464                         map = drvdata->hdmiif_map;
465                 } else {
466                         dmactl = drvdata->rd_dmactl;
467                         map = drvdata->lpaif_map;
468                 }
469         } else {
470                 dmactl = drvdata->wr_dmactl;
471                 id = pcm_data->dma_ch - v->wrdma_channel_start;
472                 map = drvdata->lpaif_map;
473         }
474
475         switch (cmd) {
476         case SNDRV_PCM_TRIGGER_START:
477         case SNDRV_PCM_TRIGGER_RESUME:
478         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
479                 ret = regmap_fields_write(dmactl->enable, id,
480                                                  LPAIF_DMACTL_ENABLE_ON);
481                 if (ret) {
482                         dev_err(soc_runtime->dev,
483                                 "error writing to rdmactl reg: %d\n", ret);
484                         return ret;
485                 }
486                 switch (dai_id) {
487                 case LPASS_DP_RX:
488                         ret = regmap_fields_write(dmactl->dyncclk, id,
489                                          LPAIF_DMACTL_DYNCLK_ON);
490                         if (ret) {
491                                 dev_err(soc_runtime->dev,
492                                         "error writing to rdmactl reg: %d\n", ret);
493                                 return ret;
494                         }
495                         reg_irqclr = LPASS_HDMITX_APP_IRQCLEAR_REG(v);
496                         val_irqclr = (LPAIF_IRQ_ALL(ch) |
497                                         LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
498                                         LPAIF_IRQ_HDMI_METADONE |
499                                         LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
500
501                         reg_irqen = LPASS_HDMITX_APP_IRQEN_REG(v);
502                         val_mask = (LPAIF_IRQ_ALL(ch) |
503                                         LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
504                                         LPAIF_IRQ_HDMI_METADONE |
505                                         LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
506                         val_irqen = (LPAIF_IRQ_ALL(ch) |
507                                         LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
508                                         LPAIF_IRQ_HDMI_METADONE |
509                                         LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
510                         break;
511                 case MI2S_PRIMARY:
512                 case MI2S_SECONDARY:
513                 case MI2S_TERTIARY:
514                 case MI2S_QUATERNARY:
515                 case MI2S_QUINARY:
516                         reg_irqclr = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
517                         val_irqclr = LPAIF_IRQ_ALL(ch);
518
519
520                         reg_irqen = LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
521                         val_mask = LPAIF_IRQ_ALL(ch);
522                         val_irqen = LPAIF_IRQ_ALL(ch);
523                         break;
524                 default:
525                         dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);
526                         return -EINVAL;
527                 }
528
529                 ret = regmap_update_bits(map, reg_irqclr, val_irqclr, val_irqclr);
530                 if (ret) {
531                         dev_err(soc_runtime->dev, "error writing to irqclear reg: %d\n", ret);
532                         return ret;
533                 }
534                 ret = regmap_update_bits(map, reg_irqen, val_mask, val_irqen);
535                 if (ret) {
536                         dev_err(soc_runtime->dev, "error writing to irqen reg: %d\n", ret);
537                         return ret;
538                 }
539                 break;
540         case SNDRV_PCM_TRIGGER_STOP:
541         case SNDRV_PCM_TRIGGER_SUSPEND:
542         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
543                 ret = regmap_fields_write(dmactl->enable, id,
544                                          LPAIF_DMACTL_ENABLE_OFF);
545                 if (ret) {
546                         dev_err(soc_runtime->dev,
547                                 "error writing to rdmactl reg: %d\n", ret);
548                         return ret;
549                 }
550                 switch (dai_id) {
551                 case LPASS_DP_RX:
552                         ret = regmap_fields_write(dmactl->dyncclk, id,
553                                          LPAIF_DMACTL_DYNCLK_OFF);
554                         if (ret) {
555                                 dev_err(soc_runtime->dev,
556                                         "error writing to rdmactl reg: %d\n", ret);
557                                 return ret;
558                         }
559                         reg_irqen = LPASS_HDMITX_APP_IRQEN_REG(v);
560                         val_mask = (LPAIF_IRQ_ALL(ch) |
561                                         LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
562                                         LPAIF_IRQ_HDMI_METADONE |
563                                         LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
564                         val_irqen = 0;
565                         break;
566                 case MI2S_PRIMARY:
567                 case MI2S_SECONDARY:
568                 case MI2S_TERTIARY:
569                 case MI2S_QUATERNARY:
570                 case MI2S_QUINARY:
571                         reg_irqen = LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
572                         val_mask = LPAIF_IRQ_ALL(ch);
573                         val_irqen = 0;
574                         break;
575                 default:
576                         dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);
577                         return -EINVAL;
578                 }
579
580                 ret = regmap_update_bits(map, reg_irqen, val_mask, val_irqen);
581                 if (ret) {
582                         dev_err(soc_runtime->dev,
583                                 "error writing to irqen reg: %d\n", ret);
584                         return ret;
585                 }
586                 break;
587         }
588
589         return 0;
590 }
591
592 static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
593                 struct snd_soc_component *component,
594                 struct snd_pcm_substream *substream)
595 {
596         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
597         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
598         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
599         struct snd_pcm_runtime *rt = substream->runtime;
600         struct lpass_pcm_data *pcm_data = rt->private_data;
601         struct lpass_variant *v = drvdata->variant;
602         unsigned int base_addr, curr_addr;
603         int ret, ch, dir = substream->stream;
604         struct regmap *map;
605         unsigned int dai_id = cpu_dai->driver->id;
606
607         if (dai_id == LPASS_DP_RX)
608                 map = drvdata->hdmiif_map;
609         else
610                 map = drvdata->lpaif_map;
611
612         ch = pcm_data->dma_ch;
613
614         ret = regmap_read(map,
615                         LPAIF_DMABASE_REG(v, ch, dir, dai_id), &base_addr);
616         if (ret) {
617                 dev_err(soc_runtime->dev,
618                         "error reading from rdmabase reg: %d\n", ret);
619                 return ret;
620         }
621
622         ret = regmap_read(map,
623                         LPAIF_DMACURR_REG(v, ch, dir, dai_id), &curr_addr);
624         if (ret) {
625                 dev_err(soc_runtime->dev,
626                         "error reading from rdmacurr reg: %d\n", ret);
627                 return ret;
628         }
629
630         return bytes_to_frames(substream->runtime, curr_addr - base_addr);
631 }
632
633 static int lpass_platform_pcmops_mmap(struct snd_soc_component *component,
634                                       struct snd_pcm_substream *substream,
635                                       struct vm_area_struct *vma)
636 {
637         struct snd_pcm_runtime *runtime = substream->runtime;
638
639         return dma_mmap_coherent(component->dev, vma, runtime->dma_area,
640                                  runtime->dma_addr, runtime->dma_bytes);
641 }
642
643 static irqreturn_t lpass_dma_interrupt_handler(
644                         struct snd_pcm_substream *substream,
645                         struct lpass_data *drvdata,
646                         int chan, u32 interrupts)
647 {
648         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
649         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
650         struct lpass_variant *v = drvdata->variant;
651         irqreturn_t ret = IRQ_NONE;
652         int rv;
653         unsigned int reg, val, mask;
654         struct regmap *map;
655         unsigned int dai_id = cpu_dai->driver->id;
656
657         mask = LPAIF_IRQ_ALL(chan);
658         switch (dai_id) {
659         case LPASS_DP_RX:
660                 map = drvdata->hdmiif_map;
661                 reg = LPASS_HDMITX_APP_IRQCLEAR_REG(v);
662                 val = (LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(chan) |
663                 LPAIF_IRQ_HDMI_METADONE |
664                 LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(chan));
665         break;
666         case MI2S_PRIMARY:
667         case MI2S_SECONDARY:
668         case MI2S_TERTIARY:
669         case MI2S_QUATERNARY:
670         case MI2S_QUINARY:
671                 map = drvdata->lpaif_map;
672                 reg = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
673                 val = 0;
674         break;
675         default:
676         dev_err(soc_runtime->dev, "%s: invalid  %d interface\n", __func__, dai_id);
677         return -EINVAL;
678         }
679         if (interrupts & LPAIF_IRQ_PER(chan)) {
680                 rv = regmap_update_bits(map, reg, mask, (LPAIF_IRQ_PER(chan) | val));
681                 if (rv) {
682                         dev_err(soc_runtime->dev,
683                                 "error writing to irqclear reg: %d\n", rv);
684                         return IRQ_NONE;
685                 }
686                 snd_pcm_period_elapsed(substream);
687                 ret = IRQ_HANDLED;
688         }
689
690         if (interrupts & LPAIF_IRQ_XRUN(chan)) {
691                 rv = regmap_update_bits(map, reg, mask, (LPAIF_IRQ_XRUN(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_warn(soc_runtime->dev, "xrun warning\n");
698                 snd_pcm_stop_xrun(substream);
699                 ret = IRQ_HANDLED;
700         }
701
702         if (interrupts & LPAIF_IRQ_ERR(chan)) {
703                 rv = regmap_update_bits(map, reg, mask, (LPAIF_IRQ_ERR(chan) | 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                 dev_err(soc_runtime->dev, "bus access error\n");
710                 snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
711                 ret = IRQ_HANDLED;
712         }
713
714         if (interrupts & val) {
715                 rv = regmap_write(map, reg, val);
716                 if (rv) {
717                         dev_err(soc_runtime->dev,
718                         "error writing to irqclear reg: %d\n", rv);
719                         return IRQ_NONE;
720                 }
721                 ret = IRQ_HANDLED;
722         }
723
724         return ret;
725 }
726
727 static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
728 {
729         struct lpass_data *drvdata = data;
730         struct lpass_variant *v = drvdata->variant;
731         unsigned int irqs;
732         int rv, chan;
733
734         rv = regmap_read(drvdata->lpaif_map,
735                         LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
736         if (rv) {
737                 pr_err("error reading from irqstat reg: %d\n", rv);
738                 return IRQ_NONE;
739         }
740
741         /* Handle per channel interrupts */
742         for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++) {
743                 if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan]) {
744                         rv = lpass_dma_interrupt_handler(
745                                                 drvdata->substream[chan],
746                                                 drvdata, chan, irqs);
747                         if (rv != IRQ_HANDLED)
748                                 return rv;
749                 }
750         }
751
752         return IRQ_HANDLED;
753 }
754
755 static irqreturn_t lpass_platform_hdmiif_irq(int irq, void *data)
756 {
757         struct lpass_data *drvdata = data;
758         struct lpass_variant *v = drvdata->variant;
759         unsigned int irqs;
760         int rv, chan;
761
762         rv = regmap_read(drvdata->hdmiif_map,
763                         LPASS_HDMITX_APP_IRQSTAT_REG(v), &irqs);
764         if (rv) {
765                 pr_err("error reading from irqstat reg: %d\n", rv);
766                 return IRQ_NONE;
767         }
768
769         /* Handle per channel interrupts */
770         for (chan = 0; chan < LPASS_MAX_HDMI_DMA_CHANNELS; chan++) {
771                 if (irqs & (LPAIF_IRQ_ALL(chan) | LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(chan) |
772                                 LPAIF_IRQ_HDMI_METADONE |
773                                 LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(chan))
774                         && drvdata->hdmi_substream[chan]) {
775                         rv = lpass_dma_interrupt_handler(
776                                                 drvdata->hdmi_substream[chan],
777                                                 drvdata, chan, irqs);
778                         if (rv != IRQ_HANDLED)
779                                 return rv;
780                 }
781         }
782
783         return IRQ_HANDLED;
784 }
785
786 static int lpass_platform_pcm_new(struct snd_soc_component *component,
787                                   struct snd_soc_pcm_runtime *soc_runtime)
788 {
789         struct snd_pcm *pcm = soc_runtime->pcm;
790         struct snd_pcm_substream *psubstream, *csubstream;
791         int ret;
792         size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
793
794         psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
795         if (psubstream) {
796                 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
797                                         component->dev,
798                                         size, &psubstream->dma_buffer);
799                 if (ret) {
800                         dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
801                         return ret;
802                 }
803         }
804
805         csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
806         if (csubstream) {
807                 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
808                                         component->dev,
809                                         size, &csubstream->dma_buffer);
810                 if (ret) {
811                         dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
812                         if (psubstream)
813                                 snd_dma_free_pages(&psubstream->dma_buffer);
814                         return ret;
815                 }
816
817         }
818
819         return 0;
820 }
821
822 static void lpass_platform_pcm_free(struct snd_soc_component *component,
823                                     struct snd_pcm *pcm)
824 {
825         struct snd_pcm_substream *substream;
826         int i;
827
828         for_each_pcm_streams(i) {
829                 substream = pcm->streams[i].substream;
830                 if (substream) {
831                         snd_dma_free_pages(&substream->dma_buffer);
832                         substream->dma_buffer.area = NULL;
833                         substream->dma_buffer.addr = 0;
834                 }
835         }
836 }
837
838 static int lpass_platform_pcmops_suspend(struct snd_soc_component *component)
839 {
840         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
841         struct regmap *map;
842         unsigned int dai_id = component->id;
843
844         if (dai_id == LPASS_DP_RX)
845                 map = drvdata->hdmiif_map;
846         else
847                 map = drvdata->lpaif_map;
848
849         regcache_cache_only(map, true);
850         regcache_mark_dirty(map);
851
852         return 0;
853 }
854
855 static int lpass_platform_pcmops_resume(struct snd_soc_component *component)
856 {
857         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
858         struct regmap *map;
859         unsigned int dai_id = component->id;
860
861         if (dai_id == LPASS_DP_RX)
862                 map = drvdata->hdmiif_map;
863         else
864                 map = drvdata->lpaif_map;
865
866         regcache_cache_only(map, false);
867         return regcache_sync(map);
868 }
869
870
871 static const struct snd_soc_component_driver lpass_component_driver = {
872         .name           = DRV_NAME,
873         .open           = lpass_platform_pcmops_open,
874         .close          = lpass_platform_pcmops_close,
875         .hw_params      = lpass_platform_pcmops_hw_params,
876         .hw_free        = lpass_platform_pcmops_hw_free,
877         .prepare        = lpass_platform_pcmops_prepare,
878         .trigger        = lpass_platform_pcmops_trigger,
879         .pointer        = lpass_platform_pcmops_pointer,
880         .mmap           = lpass_platform_pcmops_mmap,
881         .pcm_construct  = lpass_platform_pcm_new,
882         .pcm_destruct   = lpass_platform_pcm_free,
883         .suspend                = lpass_platform_pcmops_suspend,
884         .resume                 = lpass_platform_pcmops_resume,
885
886 };
887
888 int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
889 {
890         struct lpass_data *drvdata = platform_get_drvdata(pdev);
891         struct lpass_variant *v = drvdata->variant;
892         int ret;
893
894         drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
895         if (drvdata->lpaif_irq < 0)
896                 return -ENODEV;
897
898         /* ensure audio hardware is disabled */
899         ret = regmap_write(drvdata->lpaif_map,
900                         LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
901         if (ret) {
902                 dev_err(&pdev->dev, "error writing to irqen reg: %d\n", ret);
903                 return ret;
904         }
905
906         ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,
907                         lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
908                         "lpass-irq-lpaif", drvdata);
909         if (ret) {
910                 dev_err(&pdev->dev, "irq request failed: %d\n", ret);
911                 return ret;
912         }
913
914         ret = lpass_platform_alloc_dmactl_fields(&pdev->dev,
915                                                  drvdata->lpaif_map);
916         if (ret) {
917                 dev_err(&pdev->dev,
918                         "error initializing dmactl fields: %d\n", ret);
919                 return ret;
920         }
921
922         if (drvdata->hdmi_port_enable) {
923                 drvdata->hdmiif_irq = platform_get_irq_byname(pdev, "lpass-irq-hdmi");
924                 if (drvdata->hdmiif_irq < 0)
925                         return -ENODEV;
926
927                 ret = devm_request_irq(&pdev->dev, drvdata->hdmiif_irq,
928                                 lpass_platform_hdmiif_irq, 0, "lpass-irq-hdmi", drvdata);
929                 if (ret) {
930                         dev_err(&pdev->dev, "irq hdmi request failed: %d\n", ret);
931                         return ret;
932                 }
933                 ret = regmap_write(drvdata->hdmiif_map,
934                                 LPASS_HDMITX_APP_IRQEN_REG(v), 0);
935                 if (ret) {
936                         dev_err(&pdev->dev, "error writing to hdmi irqen reg: %d\n", ret);
937                         return ret;
938                 }
939
940                 ret = lpass_platform_alloc_hdmidmactl_fields(&pdev->dev,
941                                                          drvdata->hdmiif_map);
942                 if (ret) {
943                         dev_err(&pdev->dev,
944                                 "error initializing hdmidmactl fields: %d\n", ret);
945                         return ret;
946                 }
947         }
948         return devm_snd_soc_register_component(&pdev->dev,
949                         &lpass_component_driver, NULL, 0);
950 }
951 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register);
952
953 MODULE_DESCRIPTION("QTi LPASS Platform Driver");
954 MODULE_LICENSE("GPL v2");