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