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