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
lpass_platform_alloc_dmactl_fields(struct device * dev,struct regmap * map)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
lpass_platform_alloc_hdmidmactl_fields(struct device * dev,struct regmap * map)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
lpass_platform_pcmops_open(struct snd_soc_component * component,struct snd_pcm_substream * substream)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
lpass_platform_pcmops_close(struct snd_soc_component * component,struct snd_pcm_substream * substream)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
lpass_platform_pcmops_hw_params(struct snd_soc_component * component,struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)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
lpass_platform_pcmops_hw_free(struct snd_soc_component * component,struct snd_pcm_substream * substream)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
lpass_platform_pcmops_prepare(struct snd_soc_component * component,struct snd_pcm_substream * substream)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
lpass_platform_pcmops_trigger(struct snd_soc_component * component,struct snd_pcm_substream * substream,int cmd)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_write(map, reg_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
lpass_platform_pcmops_pointer(struct snd_soc_component * component,struct snd_pcm_substream * substream)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
lpass_platform_pcmops_mmap(struct snd_soc_component * component,struct snd_pcm_substream * substream,struct vm_area_struct * vma)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
lpass_dma_interrupt_handler(struct snd_pcm_substream * substream,struct lpass_data * drvdata,int chan,u32 interrupts)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 = 0, val = 0;
654 struct regmap *map;
655 unsigned int dai_id = cpu_dai->driver->id;
656
657 switch (dai_id) {
658 case LPASS_DP_RX:
659 map = drvdata->hdmiif_map;
660 reg = LPASS_HDMITX_APP_IRQCLEAR_REG(v);
661 val = (LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(chan) |
662 LPAIF_IRQ_HDMI_METADONE |
663 LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(chan));
664 break;
665 case MI2S_PRIMARY:
666 case MI2S_SECONDARY:
667 case MI2S_TERTIARY:
668 case MI2S_QUATERNARY:
669 case MI2S_QUINARY:
670 map = drvdata->lpaif_map;
671 reg = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
672 val = 0;
673 break;
674 default:
675 dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);
676 return -EINVAL;
677 }
678 if (interrupts & LPAIF_IRQ_PER(chan)) {
679
680 rv = regmap_write(map, reg, 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_write(map, reg, 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_write(map, reg, 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
lpass_platform_lpaif_irq(int irq,void * data)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
lpass_platform_hdmiif_irq(int irq,void * data)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
lpass_platform_pcm_new(struct snd_soc_component * component,struct snd_soc_pcm_runtime * soc_runtime)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 = -EINVAL;
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
lpass_platform_pcm_free(struct snd_soc_component * component,struct snd_pcm * pcm)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 const struct snd_soc_component_driver lpass_component_driver = {
839 .name = DRV_NAME,
840 .open = lpass_platform_pcmops_open,
841 .close = lpass_platform_pcmops_close,
842 .hw_params = lpass_platform_pcmops_hw_params,
843 .hw_free = lpass_platform_pcmops_hw_free,
844 .prepare = lpass_platform_pcmops_prepare,
845 .trigger = lpass_platform_pcmops_trigger,
846 .pointer = lpass_platform_pcmops_pointer,
847 .mmap = lpass_platform_pcmops_mmap,
848 .pcm_construct = lpass_platform_pcm_new,
849 .pcm_destruct = lpass_platform_pcm_free,
850
851 };
852
asoc_qcom_lpass_platform_register(struct platform_device * pdev)853 int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
854 {
855 struct lpass_data *drvdata = platform_get_drvdata(pdev);
856 struct lpass_variant *v = drvdata->variant;
857 int ret;
858
859 drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
860 if (drvdata->lpaif_irq < 0)
861 return -ENODEV;
862
863 /* ensure audio hardware is disabled */
864 ret = regmap_write(drvdata->lpaif_map,
865 LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
866 if (ret) {
867 dev_err(&pdev->dev, "error writing to irqen reg: %d\n", ret);
868 return ret;
869 }
870
871 ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,
872 lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
873 "lpass-irq-lpaif", drvdata);
874 if (ret) {
875 dev_err(&pdev->dev, "irq request failed: %d\n", ret);
876 return ret;
877 }
878
879 ret = lpass_platform_alloc_dmactl_fields(&pdev->dev,
880 drvdata->lpaif_map);
881 if (ret) {
882 dev_err(&pdev->dev,
883 "error initializing dmactl fields: %d\n", ret);
884 return ret;
885 }
886
887 if (drvdata->hdmi_port_enable) {
888 drvdata->hdmiif_irq = platform_get_irq_byname(pdev, "lpass-irq-hdmi");
889 if (drvdata->hdmiif_irq < 0)
890 return -ENODEV;
891
892 ret = devm_request_irq(&pdev->dev, drvdata->hdmiif_irq,
893 lpass_platform_hdmiif_irq, 0, "lpass-irq-hdmi", drvdata);
894 if (ret) {
895 dev_err(&pdev->dev, "irq hdmi request failed: %d\n", ret);
896 return ret;
897 }
898 ret = regmap_write(drvdata->hdmiif_map,
899 LPASS_HDMITX_APP_IRQEN_REG(v), 0);
900 if (ret) {
901 dev_err(&pdev->dev, "error writing to hdmi irqen reg: %d\n", ret);
902 return ret;
903 }
904
905 ret = lpass_platform_alloc_hdmidmactl_fields(&pdev->dev,
906 drvdata->hdmiif_map);
907 if (ret) {
908 dev_err(&pdev->dev,
909 "error initializing hdmidmactl fields: %d\n", ret);
910 return ret;
911 }
912 }
913 return devm_snd_soc_register_component(&pdev->dev,
914 &lpass_component_driver, NULL, 0);
915 }
916 EXPORT_SYMBOL_GPL(asoc_qcom_lpass_platform_register);
917
918 MODULE_DESCRIPTION("QTi LPASS Platform Driver");
919 MODULE_LICENSE("GPL v2");
920