ASoC: qcom: use asoc_substream_to_rtd()
[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      (16 * 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_pcmops_open(struct snd_soc_component *component,
54                                       struct snd_pcm_substream *substream)
55 {
56         struct snd_pcm_runtime *runtime = substream->runtime;
57         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
58         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
59         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
60         struct lpass_variant *v = drvdata->variant;
61         int ret, dma_ch, dir = substream->stream;
62         struct lpass_pcm_data *data;
63
64         data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);
65         if (!data)
66                 return -ENOMEM;
67
68         data->i2s_port = cpu_dai->driver->id;
69         runtime->private_data = data;
70
71         if (v->alloc_dma_channel)
72                 dma_ch = v->alloc_dma_channel(drvdata, dir);
73         else
74                 dma_ch = 0;
75
76         if (dma_ch < 0)
77                 return dma_ch;
78
79         drvdata->substream[dma_ch] = substream;
80
81         ret = regmap_write(drvdata->lpaif_map,
82                         LPAIF_DMACTL_REG(v, dma_ch, dir), 0);
83         if (ret) {
84                 dev_err(soc_runtime->dev,
85                         "error writing to rdmactl reg: %d\n", ret);
86                 return ret;
87         }
88
89         data->dma_ch = dma_ch;
90
91         snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
92
93         runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
94
95         ret = snd_pcm_hw_constraint_integer(runtime,
96                         SNDRV_PCM_HW_PARAM_PERIODS);
97         if (ret < 0) {
98                 dev_err(soc_runtime->dev, "setting constraints failed: %d\n",
99                         ret);
100                 return -EINVAL;
101         }
102
103         snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
104
105         return 0;
106 }
107
108 static int lpass_platform_pcmops_close(struct snd_soc_component *component,
109                                        struct snd_pcm_substream *substream)
110 {
111         struct snd_pcm_runtime *runtime = substream->runtime;
112         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
113         struct lpass_variant *v = drvdata->variant;
114         struct lpass_pcm_data *data;
115
116         data = runtime->private_data;
117         drvdata->substream[data->dma_ch] = NULL;
118         if (v->free_dma_channel)
119                 v->free_dma_channel(drvdata, data->dma_ch);
120
121         return 0;
122 }
123
124 static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
125                                            struct snd_pcm_substream *substream,
126                                            struct snd_pcm_hw_params *params)
127 {
128         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
129         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
130         struct snd_pcm_runtime *rt = substream->runtime;
131         struct lpass_pcm_data *pcm_data = rt->private_data;
132         struct lpass_variant *v = drvdata->variant;
133         snd_pcm_format_t format = params_format(params);
134         unsigned int channels = params_channels(params);
135         unsigned int regval;
136         int ch, dir = substream->stream;
137         int bitwidth;
138         int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start;
139
140         ch = pcm_data->dma_ch;
141
142         bitwidth = snd_pcm_format_width(format);
143         if (bitwidth < 0) {
144                 dev_err(soc_runtime->dev, "invalid bit width given: %d\n",
145                                 bitwidth);
146                 return bitwidth;
147         }
148
149         regval = LPAIF_DMACTL_BURSTEN_INCR4 |
150                         LPAIF_DMACTL_AUDINTF(dma_port) |
151                         LPAIF_DMACTL_FIFOWM_8;
152
153         switch (bitwidth) {
154         case 16:
155                 switch (channels) {
156                 case 1:
157                 case 2:
158                         regval |= LPAIF_DMACTL_WPSCNT_ONE;
159                         break;
160                 case 4:
161                         regval |= LPAIF_DMACTL_WPSCNT_TWO;
162                         break;
163                 case 6:
164                         regval |= LPAIF_DMACTL_WPSCNT_THREE;
165                         break;
166                 case 8:
167                         regval |= LPAIF_DMACTL_WPSCNT_FOUR;
168                         break;
169                 default:
170                         dev_err(soc_runtime->dev,
171                                 "invalid PCM config given: bw=%d, ch=%u\n",
172                                 bitwidth, channels);
173                         return -EINVAL;
174                 }
175                 break;
176         case 24:
177         case 32:
178                 switch (channels) {
179                 case 1:
180                         regval |= LPAIF_DMACTL_WPSCNT_ONE;
181                         break;
182                 case 2:
183                         regval |= LPAIF_DMACTL_WPSCNT_TWO;
184                         break;
185                 case 4:
186                         regval |= LPAIF_DMACTL_WPSCNT_FOUR;
187                         break;
188                 case 6:
189                         regval |= LPAIF_DMACTL_WPSCNT_SIX;
190                         break;
191                 case 8:
192                         regval |= LPAIF_DMACTL_WPSCNT_EIGHT;
193                         break;
194                 default:
195                         dev_err(soc_runtime->dev,
196                                 "invalid PCM config given: bw=%d, ch=%u\n",
197                                 bitwidth, channels);
198                         return -EINVAL;
199                 }
200                 break;
201         default:
202                 dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n",
203                         bitwidth, channels);
204                 return -EINVAL;
205         }
206
207         ret = regmap_write(drvdata->lpaif_map,
208                         LPAIF_DMACTL_REG(v, ch, dir), regval);
209         if (ret) {
210                 dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
211                         ret);
212                 return ret;
213         }
214
215         return 0;
216 }
217
218 static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component,
219                                          struct snd_pcm_substream *substream)
220 {
221         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
222         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
223         struct snd_pcm_runtime *rt = substream->runtime;
224         struct lpass_pcm_data *pcm_data = rt->private_data;
225         struct lpass_variant *v = drvdata->variant;
226         unsigned int reg;
227         int ret;
228
229         reg = LPAIF_DMACTL_REG(v, pcm_data->dma_ch, substream->stream);
230         ret = regmap_write(drvdata->lpaif_map, reg, 0);
231         if (ret)
232                 dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
233                         ret);
234
235         return ret;
236 }
237
238 static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
239                                          struct snd_pcm_substream *substream)
240 {
241         struct snd_pcm_runtime *runtime = substream->runtime;
242         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
243         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
244         struct snd_pcm_runtime *rt = substream->runtime;
245         struct lpass_pcm_data *pcm_data = rt->private_data;
246         struct lpass_variant *v = drvdata->variant;
247         int ret, ch, dir = substream->stream;
248
249         ch = pcm_data->dma_ch;
250
251         ret = regmap_write(drvdata->lpaif_map,
252                         LPAIF_DMABASE_REG(v, ch, dir),
253                         runtime->dma_addr);
254         if (ret) {
255                 dev_err(soc_runtime->dev, "error writing to rdmabase reg: %d\n",
256                         ret);
257                 return ret;
258         }
259
260         ret = regmap_write(drvdata->lpaif_map,
261                         LPAIF_DMABUFF_REG(v, ch, dir),
262                         (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);
263         if (ret) {
264                 dev_err(soc_runtime->dev, "error writing to rdmabuff reg: %d\n",
265                         ret);
266                 return ret;
267         }
268
269         ret = regmap_write(drvdata->lpaif_map,
270                         LPAIF_DMAPER_REG(v, ch, dir),
271                         (snd_pcm_lib_period_bytes(substream) >> 2) - 1);
272         if (ret) {
273                 dev_err(soc_runtime->dev, "error writing to rdmaper reg: %d\n",
274                         ret);
275                 return ret;
276         }
277
278         ret = regmap_update_bits(drvdata->lpaif_map,
279                         LPAIF_DMACTL_REG(v, ch, dir),
280                         LPAIF_DMACTL_ENABLE_MASK, LPAIF_DMACTL_ENABLE_ON);
281         if (ret) {
282                 dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
283                         ret);
284                 return ret;
285         }
286
287         return 0;
288 }
289
290 static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
291                                          struct snd_pcm_substream *substream,
292                                          int cmd)
293 {
294         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
295         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
296         struct snd_pcm_runtime *rt = substream->runtime;
297         struct lpass_pcm_data *pcm_data = rt->private_data;
298         struct lpass_variant *v = drvdata->variant;
299         int ret, ch, dir = substream->stream;
300
301         ch = pcm_data->dma_ch;
302
303         switch (cmd) {
304         case SNDRV_PCM_TRIGGER_START:
305         case SNDRV_PCM_TRIGGER_RESUME:
306         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
307                 /* clear status before enabling interrupts */
308                 ret = regmap_write(drvdata->lpaif_map,
309                                 LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
310                                 LPAIF_IRQ_ALL(ch));
311                 if (ret) {
312                         dev_err(soc_runtime->dev,
313                                 "error writing to irqclear reg: %d\n", ret);
314                         return ret;
315                 }
316
317                 ret = regmap_update_bits(drvdata->lpaif_map,
318                                 LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
319                                 LPAIF_IRQ_ALL(ch),
320                                 LPAIF_IRQ_ALL(ch));
321                 if (ret) {
322                         dev_err(soc_runtime->dev,
323                                 "error writing to irqen reg: %d\n", ret);
324                         return ret;
325                 }
326
327                 ret = regmap_update_bits(drvdata->lpaif_map,
328                                 LPAIF_DMACTL_REG(v, ch, dir),
329                                 LPAIF_DMACTL_ENABLE_MASK,
330                                 LPAIF_DMACTL_ENABLE_ON);
331                 if (ret) {
332                         dev_err(soc_runtime->dev,
333                                 "error writing to rdmactl reg: %d\n", ret);
334                         return ret;
335                 }
336                 break;
337         case SNDRV_PCM_TRIGGER_STOP:
338         case SNDRV_PCM_TRIGGER_SUSPEND:
339         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
340                 ret = regmap_update_bits(drvdata->lpaif_map,
341                                 LPAIF_DMACTL_REG(v, ch, dir),
342                                 LPAIF_DMACTL_ENABLE_MASK,
343                                 LPAIF_DMACTL_ENABLE_OFF);
344                 if (ret) {
345                         dev_err(soc_runtime->dev,
346                                 "error writing to rdmactl reg: %d\n", ret);
347                         return ret;
348                 }
349
350                 ret = regmap_update_bits(drvdata->lpaif_map,
351                                 LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
352                                 LPAIF_IRQ_ALL(ch), 0);
353                 if (ret) {
354                         dev_err(soc_runtime->dev,
355                                 "error writing to irqen reg: %d\n", ret);
356                         return ret;
357                 }
358                 break;
359         }
360
361         return 0;
362 }
363
364 static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
365                 struct snd_soc_component *component,
366                 struct snd_pcm_substream *substream)
367 {
368         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
369         struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
370         struct snd_pcm_runtime *rt = substream->runtime;
371         struct lpass_pcm_data *pcm_data = rt->private_data;
372         struct lpass_variant *v = drvdata->variant;
373         unsigned int base_addr, curr_addr;
374         int ret, ch, dir = substream->stream;
375
376         ch = pcm_data->dma_ch;
377
378         ret = regmap_read(drvdata->lpaif_map,
379                         LPAIF_DMABASE_REG(v, ch, dir), &base_addr);
380         if (ret) {
381                 dev_err(soc_runtime->dev,
382                         "error reading from rdmabase reg: %d\n", ret);
383                 return ret;
384         }
385
386         ret = regmap_read(drvdata->lpaif_map,
387                         LPAIF_DMACURR_REG(v, ch, dir), &curr_addr);
388         if (ret) {
389                 dev_err(soc_runtime->dev,
390                         "error reading from rdmacurr reg: %d\n", ret);
391                 return ret;
392         }
393
394         return bytes_to_frames(substream->runtime, curr_addr - base_addr);
395 }
396
397 static int lpass_platform_pcmops_mmap(struct snd_soc_component *component,
398                                       struct snd_pcm_substream *substream,
399                                       struct vm_area_struct *vma)
400 {
401         struct snd_pcm_runtime *runtime = substream->runtime;
402
403         return dma_mmap_coherent(substream->pcm->card->dev, vma,
404                         runtime->dma_area, runtime->dma_addr,
405                         runtime->dma_bytes);
406 }
407
408 static irqreturn_t lpass_dma_interrupt_handler(
409                         struct snd_pcm_substream *substream,
410                         struct lpass_data *drvdata,
411                         int chan, u32 interrupts)
412 {
413         struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
414         struct lpass_variant *v = drvdata->variant;
415         irqreturn_t ret = IRQ_NONE;
416         int rv;
417
418         if (interrupts & LPAIF_IRQ_PER(chan)) {
419                 rv = regmap_write(drvdata->lpaif_map,
420                                 LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
421                                 LPAIF_IRQ_PER(chan));
422                 if (rv) {
423                         dev_err(soc_runtime->dev,
424                                 "error writing to irqclear reg: %d\n", rv);
425                         return IRQ_NONE;
426                 }
427                 snd_pcm_period_elapsed(substream);
428                 ret = IRQ_HANDLED;
429         }
430
431         if (interrupts & LPAIF_IRQ_XRUN(chan)) {
432                 rv = regmap_write(drvdata->lpaif_map,
433                                 LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
434                                 LPAIF_IRQ_XRUN(chan));
435                 if (rv) {
436                         dev_err(soc_runtime->dev,
437                                 "error writing to irqclear reg: %d\n", rv);
438                         return IRQ_NONE;
439                 }
440                 dev_warn(soc_runtime->dev, "xrun warning\n");
441                 snd_pcm_stop_xrun(substream);
442                 ret = IRQ_HANDLED;
443         }
444
445         if (interrupts & LPAIF_IRQ_ERR(chan)) {
446                 rv = regmap_write(drvdata->lpaif_map,
447                                 LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
448                                 LPAIF_IRQ_ERR(chan));
449                 if (rv) {
450                         dev_err(soc_runtime->dev,
451                                 "error writing to irqclear reg: %d\n", rv);
452                         return IRQ_NONE;
453                 }
454                 dev_err(soc_runtime->dev, "bus access error\n");
455                 snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
456                 ret = IRQ_HANDLED;
457         }
458
459         return ret;
460 }
461
462 static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
463 {
464         struct lpass_data *drvdata = data;
465         struct lpass_variant *v = drvdata->variant;
466         unsigned int irqs;
467         int rv, chan;
468
469         rv = regmap_read(drvdata->lpaif_map,
470                         LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
471         if (rv) {
472                 pr_err("error reading from irqstat reg: %d\n", rv);
473                 return IRQ_NONE;
474         }
475
476         /* Handle per channel interrupts */
477         for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++) {
478                 if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan]) {
479                         rv = lpass_dma_interrupt_handler(
480                                                 drvdata->substream[chan],
481                                                 drvdata, chan, irqs);
482                         if (rv != IRQ_HANDLED)
483                                 return rv;
484                 }
485         }
486
487         return IRQ_HANDLED;
488 }
489
490 static int lpass_platform_pcm_new(struct snd_soc_component *component,
491                                   struct snd_soc_pcm_runtime *soc_runtime)
492 {
493         struct snd_pcm *pcm = soc_runtime->pcm;
494         struct snd_pcm_substream *psubstream, *csubstream;
495         int ret = -EINVAL;
496         size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
497
498         psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
499         if (psubstream) {
500                 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
501                                         component->dev,
502                                         size, &psubstream->dma_buffer);
503                 if (ret) {
504                         dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
505                         return ret;
506                 }
507         }
508
509         csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
510         if (csubstream) {
511                 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
512                                         component->dev,
513                                         size, &csubstream->dma_buffer);
514                 if (ret) {
515                         dev_err(soc_runtime->dev, "Cannot allocate buffer(s)\n");
516                         if (psubstream)
517                                 snd_dma_free_pages(&psubstream->dma_buffer);
518                         return ret;
519                 }
520
521         }
522
523         return 0;
524 }
525
526 static void lpass_platform_pcm_free(struct snd_soc_component *component,
527                                     struct snd_pcm *pcm)
528 {
529         struct snd_pcm_substream *substream;
530         int i;
531
532         for_each_pcm_streams(i) {
533                 substream = pcm->streams[i].substream;
534                 if (substream) {
535                         snd_dma_free_pages(&substream->dma_buffer);
536                         substream->dma_buffer.area = NULL;
537                         substream->dma_buffer.addr = 0;
538                 }
539         }
540 }
541
542 static const struct snd_soc_component_driver lpass_component_driver = {
543         .name           = DRV_NAME,
544         .open           = lpass_platform_pcmops_open,
545         .close          = lpass_platform_pcmops_close,
546         .hw_params      = lpass_platform_pcmops_hw_params,
547         .hw_free        = lpass_platform_pcmops_hw_free,
548         .prepare        = lpass_platform_pcmops_prepare,
549         .trigger        = lpass_platform_pcmops_trigger,
550         .pointer        = lpass_platform_pcmops_pointer,
551         .mmap           = lpass_platform_pcmops_mmap,
552         .pcm_construct  = lpass_platform_pcm_new,
553         .pcm_destruct   = lpass_platform_pcm_free,
554
555 };
556
557 int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
558 {
559         struct lpass_data *drvdata = platform_get_drvdata(pdev);
560         struct lpass_variant *v = drvdata->variant;
561         int ret;
562
563         drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
564         if (drvdata->lpaif_irq < 0)
565                 return -ENODEV;
566
567         /* ensure audio hardware is disabled */
568         ret = regmap_write(drvdata->lpaif_map,
569                         LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
570         if (ret) {
571                 dev_err(&pdev->dev, "error writing to irqen reg: %d\n", ret);
572                 return ret;
573         }
574
575         ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,
576                         lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
577                         "lpass-irq-lpaif", drvdata);
578         if (ret) {
579                 dev_err(&pdev->dev, "irq request failed: %d\n", ret);
580                 return ret;
581         }
582
583
584         return devm_snd_soc_register_component(&pdev->dev,
585                         &lpass_component_driver, NULL, 0);
586 }
587 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register);
588
589 MODULE_DESCRIPTION("QTi LPASS Platform Driver");
590 MODULE_LICENSE("GPL v2");