174a786cd776e2b7567e584c41d4b5813cd94ac7
[linux-2.6-microblaze.git] / sound / soc / intel / catpt / pcm.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 //
3 // Copyright(c) 2020 Intel Corporation. All rights reserved.
4 //
5 // Author: Cezary Rojewski <cezary.rojewski@intel.com>
6 //
7
8 #include <linux/pm_runtime.h>
9 #include <sound/soc.h>
10 #include <sound/pcm_params.h>
11 #include <uapi/sound/tlv.h>
12 #include "core.h"
13 #include "messages.h"
14
15 struct catpt_stream_template {
16         enum catpt_path_id path_id;
17         enum catpt_stream_type type;
18         u32 persistent_size;
19         u8 num_entries;
20         struct catpt_module_entry entries[];
21 };
22
23 static struct catpt_stream_template system_pb = {
24         .path_id = CATPT_PATH_SSP0_OUT,
25         .type = CATPT_STRM_TYPE_SYSTEM,
26         .num_entries = 1,
27         .entries = {{ CATPT_MODID_PCM_SYSTEM, 0 }},
28 };
29
30 static struct catpt_stream_template system_cp = {
31         .path_id = CATPT_PATH_SSP0_IN,
32         .type = CATPT_STRM_TYPE_CAPTURE,
33         .num_entries = 1,
34         .entries = {{ CATPT_MODID_PCM_CAPTURE, 0 }},
35 };
36
37 static struct catpt_stream_template offload_pb = {
38         .path_id = CATPT_PATH_SSP0_OUT,
39         .type = CATPT_STRM_TYPE_RENDER,
40         .num_entries = 1,
41         .entries = {{ CATPT_MODID_PCM, 0 }},
42 };
43
44 static struct catpt_stream_template loopback_cp = {
45         .path_id = CATPT_PATH_SSP0_OUT,
46         .type = CATPT_STRM_TYPE_LOOPBACK,
47         .num_entries = 1,
48         .entries = {{ CATPT_MODID_PCM_REFERENCE, 0 }},
49 };
50
51 static struct catpt_stream_template bluetooth_pb = {
52         .path_id = CATPT_PATH_SSP1_OUT,
53         .type = CATPT_STRM_TYPE_BLUETOOTH_RENDER,
54         .num_entries = 1,
55         .entries = {{ CATPT_MODID_BLUETOOTH_RENDER, 0 }},
56 };
57
58 static struct catpt_stream_template bluetooth_cp = {
59         .path_id = CATPT_PATH_SSP1_IN,
60         .type = CATPT_STRM_TYPE_BLUETOOTH_CAPTURE,
61         .num_entries = 1,
62         .entries = {{ CATPT_MODID_BLUETOOTH_CAPTURE, 0 }},
63 };
64
65 static struct catpt_stream_template *catpt_topology[] = {
66         [CATPT_STRM_TYPE_RENDER]                = &offload_pb,
67         [CATPT_STRM_TYPE_SYSTEM]                = &system_pb,
68         [CATPT_STRM_TYPE_CAPTURE]               = &system_cp,
69         [CATPT_STRM_TYPE_LOOPBACK]              = &loopback_cp,
70         [CATPT_STRM_TYPE_BLUETOOTH_RENDER]      = &bluetooth_pb,
71         [CATPT_STRM_TYPE_BLUETOOTH_CAPTURE]     = &bluetooth_cp,
72 };
73
74 static struct catpt_stream_template *
75 catpt_get_stream_template(struct snd_pcm_substream *substream)
76 {
77         struct snd_soc_pcm_runtime *rtm = substream->private_data;
78         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtm, 0);
79         enum catpt_stream_type type;
80
81         type = cpu_dai->driver->id;
82
83         /* account for capture in bidirectional dais */
84         switch (type) {
85         case CATPT_STRM_TYPE_SYSTEM:
86                 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
87                         type = CATPT_STRM_TYPE_CAPTURE;
88                 break;
89         case CATPT_STRM_TYPE_BLUETOOTH_RENDER:
90                 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
91                         type = CATPT_STRM_TYPE_BLUETOOTH_CAPTURE;
92                 break;
93         default:
94                 break;
95         };
96
97         return catpt_topology[type];
98 }
99
100 struct catpt_stream_runtime *
101 catpt_stream_find(struct catpt_dev *cdev, u8 stream_hw_id)
102 {
103         struct catpt_stream_runtime *pos, *result = NULL;
104
105         spin_lock(&cdev->list_lock);
106         list_for_each_entry(pos, &cdev->stream_list, node) {
107                 if (pos->info.stream_hw_id == stream_hw_id) {
108                         result = pos;
109                         break;
110                 }
111         }
112
113         spin_unlock(&cdev->list_lock);
114         return result;
115 }
116
117 static u32 catpt_stream_read_position(struct catpt_dev *cdev,
118                                       struct catpt_stream_runtime *stream)
119 {
120         u32 pos;
121
122         memcpy_fromio(&pos, cdev->lpe_ba + stream->info.read_pos_regaddr,
123                       sizeof(pos));
124         return pos;
125 }
126
127 static u32 catpt_stream_volume(struct catpt_dev *cdev,
128                                struct catpt_stream_runtime *stream, u32 channel)
129 {
130         u32 volume, offset;
131
132         if (channel >= CATPT_CHANNELS_MAX)
133                 channel = 0;
134
135         offset = stream->info.volume_regaddr[channel];
136         memcpy_fromio(&volume, cdev->lpe_ba + offset, sizeof(volume));
137         return volume;
138 }
139
140 static u32 catpt_mixer_volume(struct catpt_dev *cdev,
141                               struct catpt_mixer_stream_info *info, u32 channel)
142 {
143         u32 volume, offset;
144
145         if (channel >= CATPT_CHANNELS_MAX)
146                 channel = 0;
147
148         offset = info->volume_regaddr[channel];
149         memcpy_fromio(&volume, cdev->lpe_ba + offset, sizeof(volume));
150         return volume;
151 }
152
153 static void catpt_arrange_page_table(struct snd_pcm_substream *substream,
154                                      struct snd_dma_buffer *pgtbl)
155 {
156         struct snd_pcm_runtime *rtm = substream->runtime;
157         struct snd_dma_buffer *databuf = snd_pcm_get_dma_buf(substream);
158         int i, pages;
159
160         pages = snd_sgbuf_aligned_pages(rtm->dma_bytes);
161
162         for (i = 0; i < pages; i++) {
163                 u32 pfn, offset;
164                 u32 *page_table;
165
166                 pfn = PFN_DOWN(snd_sgbuf_get_addr(databuf, i * PAGE_SIZE));
167                 /* incrementing by 2 on even and 3 on odd */
168                 offset = ((i << 2) + i) >> 1;
169                 page_table = (u32 *)(pgtbl->area + offset);
170
171                 if (i & 1)
172                         *page_table |= (pfn << 4);
173                 else
174                         *page_table |= pfn;
175         }
176 }
177
178 static u32 catpt_get_channel_map(enum catpt_channel_config config)
179 {
180         switch (config) {
181         case CATPT_CHANNEL_CONFIG_MONO:
182                 return GENMASK(31, 4) | CATPT_CHANNEL_CENTER;
183
184         case CATPT_CHANNEL_CONFIG_STEREO:
185                 return GENMASK(31, 8) | CATPT_CHANNEL_LEFT
186                                       | (CATPT_CHANNEL_RIGHT << 4);
187
188         case CATPT_CHANNEL_CONFIG_2_POINT_1:
189                 return GENMASK(31, 12) | CATPT_CHANNEL_LEFT
190                                        | (CATPT_CHANNEL_RIGHT << 4)
191                                        | (CATPT_CHANNEL_LFE << 8);
192
193         case CATPT_CHANNEL_CONFIG_3_POINT_0:
194                 return GENMASK(31, 12) | CATPT_CHANNEL_LEFT
195                                        | (CATPT_CHANNEL_CENTER << 4)
196                                        | (CATPT_CHANNEL_RIGHT << 8);
197
198         case CATPT_CHANNEL_CONFIG_3_POINT_1:
199                 return GENMASK(31, 16) | CATPT_CHANNEL_LEFT
200                                        | (CATPT_CHANNEL_CENTER << 4)
201                                        | (CATPT_CHANNEL_RIGHT << 8)
202                                        | (CATPT_CHANNEL_LFE << 12);
203
204         case CATPT_CHANNEL_CONFIG_QUATRO:
205                 return GENMASK(31, 16) | CATPT_CHANNEL_LEFT
206                                        | (CATPT_CHANNEL_RIGHT << 4)
207                                        | (CATPT_CHANNEL_LEFT_SURROUND << 8)
208                                        | (CATPT_CHANNEL_RIGHT_SURROUND << 12);
209
210         case CATPT_CHANNEL_CONFIG_4_POINT_0:
211                 return GENMASK(31, 16) | CATPT_CHANNEL_LEFT
212                                        | (CATPT_CHANNEL_CENTER << 4)
213                                        | (CATPT_CHANNEL_RIGHT << 8)
214                                        | (CATPT_CHANNEL_CENTER_SURROUND << 12);
215
216         case CATPT_CHANNEL_CONFIG_5_POINT_0:
217                 return GENMASK(31, 20) | CATPT_CHANNEL_LEFT
218                                        | (CATPT_CHANNEL_CENTER << 4)
219                                        | (CATPT_CHANNEL_RIGHT << 8)
220                                        | (CATPT_CHANNEL_LEFT_SURROUND << 12)
221                                        | (CATPT_CHANNEL_RIGHT_SURROUND << 16);
222
223         case CATPT_CHANNEL_CONFIG_5_POINT_1:
224                 return GENMASK(31, 24) | CATPT_CHANNEL_CENTER
225                                        | (CATPT_CHANNEL_LEFT << 4)
226                                        | (CATPT_CHANNEL_RIGHT << 8)
227                                        | (CATPT_CHANNEL_LEFT_SURROUND << 12)
228                                        | (CATPT_CHANNEL_RIGHT_SURROUND << 16)
229                                        | (CATPT_CHANNEL_LFE << 20);
230
231         case CATPT_CHANNEL_CONFIG_DUAL_MONO:
232                 return GENMASK(31, 8) | CATPT_CHANNEL_LEFT
233                                       | (CATPT_CHANNEL_LEFT << 4);
234
235         default:
236                 return U32_MAX;
237         }
238 }
239
240 static enum catpt_channel_config catpt_get_channel_config(u32 num_channels)
241 {
242         switch (num_channels) {
243         case 6:
244                 return CATPT_CHANNEL_CONFIG_5_POINT_1;
245         case 5:
246                 return CATPT_CHANNEL_CONFIG_5_POINT_0;
247         case 4:
248                 return CATPT_CHANNEL_CONFIG_QUATRO;
249         case 3:
250                 return CATPT_CHANNEL_CONFIG_2_POINT_1;
251         case 1:
252                 return CATPT_CHANNEL_CONFIG_MONO;
253         case 2:
254         default:
255                 return CATPT_CHANNEL_CONFIG_STEREO;
256         }
257 }
258
259 static int catpt_dai_startup(struct snd_pcm_substream *substream,
260                              struct snd_soc_dai *dai)
261 {
262         struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
263         struct catpt_stream_template *template;
264         struct catpt_stream_runtime *stream;
265         struct resource *res;
266         int ret;
267
268         template = catpt_get_stream_template(substream);
269
270         stream = kzalloc(sizeof(*stream), GFP_KERNEL);
271         if (!stream)
272                 return -ENOMEM;
273
274         ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, cdev->dev, PAGE_SIZE,
275                                   &stream->pgtbl);
276         if (ret)
277                 goto err_pgtbl;
278
279         res = catpt_request_region(&cdev->dram, template->persistent_size);
280         if (!res) {
281                 ret = -EBUSY;
282                 goto err_request;
283         }
284
285         catpt_dsp_update_srampge(cdev, &cdev->dram, cdev->spec->dram_mask);
286
287         stream->template = template;
288         stream->persistent = res;
289         stream->substream = substream;
290         INIT_LIST_HEAD(&stream->node);
291         snd_soc_dai_set_dma_data(dai, substream, stream);
292
293         spin_lock(&cdev->list_lock);
294         list_add_tail(&stream->node, &cdev->stream_list);
295         spin_unlock(&cdev->list_lock);
296
297         return 0;
298
299 err_request:
300         snd_dma_free_pages(&stream->pgtbl);
301 err_pgtbl:
302         kfree(stream);
303         return ret;
304 }
305
306 static void catpt_dai_shutdown(struct snd_pcm_substream *substream,
307                                struct snd_soc_dai *dai)
308 {
309         struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
310         struct catpt_stream_runtime *stream;
311
312         stream = snd_soc_dai_get_dma_data(dai, substream);
313
314         spin_lock(&cdev->list_lock);
315         list_del(&stream->node);
316         spin_unlock(&cdev->list_lock);
317
318         release_resource(stream->persistent);
319         kfree(stream->persistent);
320         catpt_dsp_update_srampge(cdev, &cdev->dram, cdev->spec->dram_mask);
321
322         snd_dma_free_pages(&stream->pgtbl);
323         kfree(stream);
324         snd_soc_dai_set_dma_data(dai, substream, NULL);
325 }
326
327 static int catpt_dai_hw_params(struct snd_pcm_substream *substream,
328                                struct snd_pcm_hw_params *params,
329                                struct snd_soc_dai *dai)
330 {
331         struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
332         struct catpt_stream_runtime *stream;
333         struct catpt_audio_format afmt;
334         struct catpt_ring_info rinfo;
335         struct snd_pcm_runtime *rtm = substream->runtime;
336         struct snd_dma_buffer *dmab;
337         int ret;
338
339         stream = snd_soc_dai_get_dma_data(dai, substream);
340         if (stream->allocated)
341                 return 0;
342
343         memset(&afmt, 0, sizeof(afmt));
344         afmt.sample_rate = params_rate(params);
345         afmt.bit_depth = params_physical_width(params);
346         afmt.valid_bit_depth = params_width(params);
347         afmt.num_channels = params_channels(params);
348         afmt.channel_config = catpt_get_channel_config(afmt.num_channels);
349         afmt.channel_map = catpt_get_channel_map(afmt.channel_config);
350         afmt.interleaving = CATPT_INTERLEAVING_PER_CHANNEL;
351
352         dmab = snd_pcm_get_dma_buf(substream);
353         catpt_arrange_page_table(substream, &stream->pgtbl);
354
355         memset(&rinfo, 0, sizeof(rinfo));
356         rinfo.page_table_addr = stream->pgtbl.addr;
357         rinfo.num_pages = DIV_ROUND_UP(rtm->dma_bytes, PAGE_SIZE);
358         rinfo.size = rtm->dma_bytes;
359         rinfo.offset = 0;
360         rinfo.ring_first_page_pfn = PFN_DOWN(snd_sgbuf_get_addr(dmab, 0));
361
362         ret = catpt_ipc_alloc_stream(cdev, stream->template->path_id,
363                                      stream->template->type,
364                                      &afmt, &rinfo,
365                                      stream->template->num_entries,
366                                      stream->template->entries,
367                                      stream->persistent,
368                                      cdev->scratch,
369                                      &stream->info);
370         if (ret)
371                 return CATPT_IPC_ERROR(ret);
372
373         stream->allocated = true;
374         return 0;
375 }
376
377 static int catpt_dai_hw_free(struct snd_pcm_substream *substream,
378                              struct snd_soc_dai *dai)
379 {
380         struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
381         struct catpt_stream_runtime *stream;
382
383         stream = snd_soc_dai_get_dma_data(dai, substream);
384         if (!stream->allocated)
385                 return 0;
386
387         catpt_ipc_reset_stream(cdev, stream->info.stream_hw_id);
388         catpt_ipc_free_stream(cdev, stream->info.stream_hw_id);
389
390         stream->allocated = false;
391         return 0;
392 }
393
394 static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol);
395
396 static int catpt_dai_apply_usettings(struct snd_soc_dai *dai,
397                                      struct catpt_stream_runtime *stream)
398 {
399         struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
400         struct snd_soc_component *component = dai->component;
401         struct snd_kcontrol *pos, *kctl = NULL;
402         const char *name;
403         int ret;
404         u32 id = stream->info.stream_hw_id;
405
406         /* only selected streams have individual controls */
407         switch (id) {
408         case CATPT_PIN_ID_OFFLOAD1:
409                 name = "Media0 Playback Volume";
410                 break;
411         case CATPT_PIN_ID_OFFLOAD2:
412                 name = "Media1 Playback Volume";
413                 break;
414         case CATPT_PIN_ID_CAPTURE1:
415                 name = "Mic Capture Volume";
416                 break;
417         case CATPT_PIN_ID_REFERENCE:
418                 name = "Loopback Mute";
419                 break;
420         default:
421                 return 0;
422         };
423
424         list_for_each_entry(pos, &component->card->snd_card->controls, list) {
425                 if (pos->private_data == component &&
426                     !strncmp(name, pos->id.name, sizeof(pos->id.name))) {
427                         kctl = pos;
428                         break;
429                 }
430         }
431         if (!kctl)
432                 return -ENOENT;
433
434         if (stream->template->type != CATPT_STRM_TYPE_LOOPBACK)
435                 return catpt_set_dspvol(cdev, id, (long *)kctl->private_value);
436         ret = catpt_ipc_mute_loopback(cdev, id, *(bool *)kctl->private_value);
437         if (ret)
438                 return CATPT_IPC_ERROR(ret);
439         return 0;
440 }
441
442 static int catpt_dai_prepare(struct snd_pcm_substream *substream,
443                              struct snd_soc_dai *dai)
444 {
445         struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
446         struct catpt_stream_runtime *stream;
447         int ret;
448
449         stream = snd_soc_dai_get_dma_data(dai, substream);
450         if (stream->prepared)
451                 return 0;
452
453         ret = catpt_ipc_reset_stream(cdev, stream->info.stream_hw_id);
454         if (ret)
455                 return CATPT_IPC_ERROR(ret);
456
457         ret = catpt_ipc_pause_stream(cdev, stream->info.stream_hw_id);
458         if (ret)
459                 return CATPT_IPC_ERROR(ret);
460
461         ret = catpt_dsp_update_lpclock(cdev);
462         if (ret)
463                 return ret;
464
465         ret = catpt_dai_apply_usettings(dai, stream);
466         if (ret)
467                 return ret;
468
469         stream->prepared = true;
470         return 0;
471 }
472
473 static int catpt_dai_trigger(struct snd_pcm_substream *substream, int cmd,
474                              struct snd_soc_dai *dai)
475 {
476         struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
477         struct catpt_stream_runtime *stream;
478         struct snd_pcm_runtime *runtime = substream->runtime;
479         snd_pcm_uframes_t pos;
480         int ret;
481
482         stream = snd_soc_dai_get_dma_data(dai, substream);
483
484         switch (cmd) {
485         case SNDRV_PCM_TRIGGER_START:
486                 /* only offload is set_write_pos driven */
487                 if (stream->template->type != CATPT_STRM_TYPE_RENDER)
488                         goto resume_stream;
489
490                 pos = frames_to_bytes(runtime, runtime->start_threshold);
491                 /*
492                  * Dsp operates on buffer halves, thus max 2x set_write_pos
493                  * (entire buffer filled) prior to stream start.
494                  */
495                 ret = catpt_ipc_set_write_pos(cdev, stream->info.stream_hw_id,
496                                               pos, false, false);
497                 if (ret)
498                         return CATPT_IPC_ERROR(ret);
499                 fallthrough;
500         case SNDRV_PCM_TRIGGER_RESUME:
501         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
502         resume_stream:
503                 ret = catpt_ipc_resume_stream(cdev, stream->info.stream_hw_id);
504                 if (ret)
505                         return CATPT_IPC_ERROR(ret);
506                 break;
507
508         case SNDRV_PCM_TRIGGER_STOP:
509                 stream->prepared = false;
510                 catpt_dsp_update_lpclock(cdev);
511                 fallthrough;
512         case SNDRV_PCM_TRIGGER_SUSPEND:
513         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
514                 ret = catpt_ipc_pause_stream(cdev, stream->info.stream_hw_id);
515                 if (ret)
516                         return CATPT_IPC_ERROR(ret);
517                 break;
518
519         default:
520                 break;
521         }
522
523         return 0;
524 }
525
526 void catpt_stream_update_position(struct catpt_dev *cdev,
527                                   struct catpt_stream_runtime *stream,
528                                   struct catpt_notify_position *pos)
529 {
530         struct snd_pcm_substream *substream = stream->substream;
531         struct snd_pcm_runtime *r = substream->runtime;
532         snd_pcm_uframes_t dsppos, newpos;
533         int ret;
534
535         dsppos = bytes_to_frames(r, pos->stream_position);
536
537         if (!stream->prepared)
538                 goto exit;
539         /* only offload is set_write_pos driven */
540         if (stream->template->type != CATPT_STRM_TYPE_RENDER)
541                 goto exit;
542
543         if (dsppos >= r->buffer_size / 2)
544                 newpos = r->buffer_size / 2;
545         else
546                 newpos = 0;
547         /*
548          * Dsp operates on buffer halves, thus on every notify position
549          * (buffer half consumed) update wp to allow stream progression.
550          */
551         ret = catpt_ipc_set_write_pos(cdev, stream->info.stream_hw_id,
552                                       frames_to_bytes(r, newpos),
553                                       false, false);
554         if (ret) {
555                 dev_err(cdev->dev, "update position for stream %d failed: %d\n",
556                         stream->info.stream_hw_id, ret);
557                 return;
558         }
559 exit:
560         snd_pcm_period_elapsed(substream);
561 }
562
563 /* 200 ms for 2 32-bit channels at 48kHz (native format) */
564 #define CATPT_BUFFER_MAX_SIZE   76800
565 #define CATPT_PCM_PERIODS_MAX   4
566 #define CATPT_PCM_PERIODS_MIN   2
567
568 static const struct snd_pcm_hardware catpt_pcm_hardware = {
569         .info                   = SNDRV_PCM_INFO_MMAP |
570                                   SNDRV_PCM_INFO_MMAP_VALID |
571                                   SNDRV_PCM_INFO_INTERLEAVED |
572                                   SNDRV_PCM_INFO_PAUSE |
573                                   SNDRV_PCM_INFO_RESUME |
574                                   SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
575         .formats                = SNDRV_PCM_FMTBIT_S16_LE |
576                                   SNDRV_PCM_FMTBIT_S24_LE |
577                                   SNDRV_PCM_FMTBIT_S32_LE,
578         .period_bytes_min       = PAGE_SIZE,
579         .period_bytes_max       = CATPT_BUFFER_MAX_SIZE / CATPT_PCM_PERIODS_MIN,
580         .periods_min            = CATPT_PCM_PERIODS_MIN,
581         .periods_max            = CATPT_PCM_PERIODS_MAX,
582         .buffer_bytes_max       = CATPT_BUFFER_MAX_SIZE,
583 };
584
585 static int catpt_component_pcm_construct(struct snd_soc_component *component,
586                                          struct snd_soc_pcm_runtime *rtm)
587 {
588         struct catpt_dev *cdev = dev_get_drvdata(component->dev);
589
590         snd_pcm_set_managed_buffer_all(rtm->pcm, SNDRV_DMA_TYPE_DEV_SG,
591                                        cdev->dev,
592                                        catpt_pcm_hardware.buffer_bytes_max,
593                                        catpt_pcm_hardware.buffer_bytes_max);
594
595         return 0;
596 }
597
598 static int catpt_component_open(struct snd_soc_component *component,
599                                 struct snd_pcm_substream *substream)
600 {
601         struct snd_soc_pcm_runtime *rtm = substream->private_data;
602
603         if (rtm->dai_link->no_pcm)
604                 return 0;
605         snd_soc_set_runtime_hwparams(substream, &catpt_pcm_hardware);
606         return 0;
607 }
608
609 static snd_pcm_uframes_t
610 catpt_component_pointer(struct snd_soc_component *component,
611                         struct snd_pcm_substream *substream)
612 {
613         struct catpt_dev *cdev = dev_get_drvdata(component->dev);
614         struct catpt_stream_runtime *stream;
615         struct snd_soc_pcm_runtime *rtm = substream->private_data;
616         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtm, 0);
617         u32 pos;
618
619         if (rtm->dai_link->no_pcm)
620                 return 0;
621
622         stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
623         pos = catpt_stream_read_position(cdev, stream);
624
625         return bytes_to_frames(substream->runtime, pos);
626 }
627
628 static const struct snd_soc_dai_ops catpt_fe_dai_ops = {
629         .startup = catpt_dai_startup,
630         .shutdown = catpt_dai_shutdown,
631         .hw_params = catpt_dai_hw_params,
632         .hw_free = catpt_dai_hw_free,
633         .prepare = catpt_dai_prepare,
634         .trigger = catpt_dai_trigger,
635 };
636
637 static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm,
638                              struct snd_soc_dai *dai)
639 {
640         struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtm, 0);
641         struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
642         struct catpt_ssp_device_format devfmt;
643         int ret;
644
645         devfmt.iface = dai->driver->id;
646         devfmt.channels = codec_dai->driver->capture.channels_max;
647
648         switch (devfmt.iface) {
649         case CATPT_SSP_IFACE_0:
650                 devfmt.mclk = CATPT_MCLK_FREQ_24_MHZ;
651
652                 switch (devfmt.channels) {
653                 case 4:
654                         devfmt.mode = CATPT_SSP_MODE_TDM_PROVIDER;
655                         devfmt.clock_divider = 4;
656                         break;
657                 case 2:
658                 default:
659                         devfmt.mode = CATPT_SSP_MODE_I2S_PROVIDER;
660                         devfmt.clock_divider = 9;
661                         break;
662                 }
663                 break;
664
665         case CATPT_SSP_IFACE_1:
666                 devfmt.mclk = CATPT_MCLK_OFF;
667                 devfmt.mode = CATPT_SSP_MODE_I2S_CONSUMER;
668                 devfmt.clock_divider = 0;
669                 break;
670         }
671
672         ret = catpt_ipc_set_device_format(cdev, &devfmt);
673         if (ret)
674                 return CATPT_IPC_ERROR(ret);
675
676         /* store device format set for given SSP */
677         memcpy(&cdev->devfmt[devfmt.iface], &devfmt, sizeof(devfmt));
678         return 0;
679 }
680
681 static struct snd_soc_dai_driver dai_drivers[] = {
682 /* FE DAIs */
683 {
684         .name  = "System Pin",
685         .id = CATPT_STRM_TYPE_SYSTEM,
686         .ops = &catpt_fe_dai_ops,
687         .playback = {
688                 .stream_name = "System Playback",
689                 .channels_min = 2,
690                 .channels_max = 2,
691                 .rates = SNDRV_PCM_RATE_48000,
692                 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
693         },
694         .capture = {
695                 .stream_name = "Analog Capture",
696                 .channels_min = 2,
697                 .channels_max = 4,
698                 .rates = SNDRV_PCM_RATE_48000,
699                 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
700         },
701 },
702 {
703         .name  = "Offload0 Pin",
704         .id = CATPT_STRM_TYPE_RENDER,
705         .ops = &catpt_fe_dai_ops,
706         .playback = {
707                 .stream_name = "Offload0 Playback",
708                 .channels_min = 2,
709                 .channels_max = 2,
710                 .rates = SNDRV_PCM_RATE_8000_192000,
711                 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
712         },
713 },
714 {
715         .name  = "Offload1 Pin",
716         .id = CATPT_STRM_TYPE_RENDER,
717         .ops = &catpt_fe_dai_ops,
718         .playback = {
719                 .stream_name = "Offload1 Playback",
720                 .channels_min = 2,
721                 .channels_max = 2,
722                 .rates = SNDRV_PCM_RATE_8000_192000,
723                 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
724         },
725 },
726 {
727         .name  = "Loopback Pin",
728         .id = CATPT_STRM_TYPE_LOOPBACK,
729         .ops = &catpt_fe_dai_ops,
730         .capture = {
731                 .stream_name = "Loopback Capture",
732                 .channels_min = 2,
733                 .channels_max = 2,
734                 .rates = SNDRV_PCM_RATE_48000,
735                 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
736         },
737 },
738 {
739         .name  = "Bluetooth Pin",
740         .id = CATPT_STRM_TYPE_BLUETOOTH_RENDER,
741         .ops = &catpt_fe_dai_ops,
742         .playback = {
743                 .stream_name = "Bluetooth Playback",
744                 .channels_min = 1,
745                 .channels_max = 1,
746                 .rates = SNDRV_PCM_RATE_8000,
747                 .formats = SNDRV_PCM_FMTBIT_S16_LE,
748         },
749         .capture = {
750                 .stream_name = "Bluetooth Capture",
751                 .channels_min = 1,
752                 .channels_max = 1,
753                 .rates = SNDRV_PCM_RATE_8000,
754                 .formats = SNDRV_PCM_FMTBIT_S16_LE,
755         },
756 },
757 /* BE DAIs */
758 {
759         .name = "ssp0-port",
760         .id = CATPT_SSP_IFACE_0,
761         .pcm_new = catpt_dai_pcm_new,
762         .playback = {
763                 .channels_min = 1,
764                 .channels_max = 8,
765         },
766         .capture = {
767                 .channels_min = 1,
768                 .channels_max = 8,
769         },
770 },
771 {
772         .name = "ssp1-port",
773         .id = CATPT_SSP_IFACE_1,
774         .pcm_new = catpt_dai_pcm_new,
775         .playback = {
776                 .channels_min = 1,
777                 .channels_max = 8,
778         },
779         .capture = {
780                 .channels_min = 1,
781                 .channels_max = 8,
782         },
783 },
784 };
785
786 #define DSP_VOLUME_MAX          S32_MAX /* 0db */
787 #define DSP_VOLUME_STEP_MAX     30
788
789 static u32 ctlvol_to_dspvol(u32 value)
790 {
791         if (value > DSP_VOLUME_STEP_MAX)
792                 value = 0;
793         return DSP_VOLUME_MAX >> (DSP_VOLUME_STEP_MAX - value);
794 }
795
796 static u32 dspvol_to_ctlvol(u32 volume)
797 {
798         if (volume > DSP_VOLUME_MAX)
799                 return DSP_VOLUME_STEP_MAX;
800         return volume ? __fls(volume) : 0;
801 }
802
803 static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol)
804 {
805         u32 dspvol;
806         int ret, i;
807
808         for (i = 1; i < CATPT_CHANNELS_MAX; i++)
809                 if (ctlvol[i] != ctlvol[0])
810                         break;
811
812         if (i == CATPT_CHANNELS_MAX) {
813                 dspvol = ctlvol_to_dspvol(ctlvol[0]);
814
815                 ret = catpt_ipc_set_volume(cdev, stream_id,
816                                            CATPT_ALL_CHANNELS_MASK, dspvol,
817                                            0, CATPT_AUDIO_CURVE_NONE);
818         } else {
819                 for (i = 0; i < CATPT_CHANNELS_MAX; i++) {
820                         dspvol = ctlvol_to_dspvol(ctlvol[i]);
821
822                         ret = catpt_ipc_set_volume(cdev, stream_id,
823                                                    i, dspvol,
824                                                    0, CATPT_AUDIO_CURVE_NONE);
825                         if (ret)
826                                 break;
827                 }
828         }
829
830         if (ret)
831                 return CATPT_IPC_ERROR(ret);
832         return 0;
833 }
834
835 static int catpt_volume_info(struct snd_kcontrol *kcontrol,
836                              struct snd_ctl_elem_info *uinfo)
837 {
838         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
839         uinfo->count = CATPT_CHANNELS_MAX;
840         uinfo->value.integer.min = 0;
841         uinfo->value.integer.max = DSP_VOLUME_STEP_MAX;
842         return 0;
843 }
844
845 static int catpt_mixer_volume_get(struct snd_kcontrol *kcontrol,
846                                   struct snd_ctl_elem_value *ucontrol)
847 {
848         struct snd_soc_component *component =
849                 snd_soc_kcontrol_component(kcontrol);
850         struct catpt_dev *cdev = dev_get_drvdata(component->dev);
851         u32 dspvol;
852         int i;
853
854         pm_runtime_get_sync(cdev->dev);
855
856         for (i = 0; i < CATPT_CHANNELS_MAX; i++) {
857                 dspvol = catpt_mixer_volume(cdev, &cdev->mixer, i);
858                 ucontrol->value.integer.value[i] = dspvol_to_ctlvol(dspvol);
859         }
860
861         pm_runtime_mark_last_busy(cdev->dev);
862         pm_runtime_put_autosuspend(cdev->dev);
863
864         return 0;
865 }
866
867 static int catpt_mixer_volume_put(struct snd_kcontrol *kcontrol,
868                                   struct snd_ctl_elem_value *ucontrol)
869 {
870         struct snd_soc_component *component =
871                 snd_soc_kcontrol_component(kcontrol);
872         struct catpt_dev *cdev = dev_get_drvdata(component->dev);
873         int ret;
874
875         pm_runtime_get_sync(cdev->dev);
876
877         ret = catpt_set_dspvol(cdev, cdev->mixer.mixer_hw_id,
878                                ucontrol->value.integer.value);
879
880         pm_runtime_mark_last_busy(cdev->dev);
881         pm_runtime_put_autosuspend(cdev->dev);
882
883         return ret;
884 }
885
886 static int catpt_stream_volume_get(struct snd_kcontrol *kcontrol,
887                                    struct snd_ctl_elem_value *ucontrol,
888                                    enum catpt_pin_id pin_id)
889 {
890         struct snd_soc_component *component =
891                 snd_soc_kcontrol_component(kcontrol);
892         struct catpt_dev *cdev = dev_get_drvdata(component->dev);
893         struct catpt_stream_runtime *stream;
894         long *ctlvol = (long *)kcontrol->private_value;
895         u32 dspvol;
896         int i;
897
898         stream = catpt_stream_find(cdev, pin_id);
899         if (!stream) {
900                 for (i = 0; i < CATPT_CHANNELS_MAX; i++)
901                         ucontrol->value.integer.value[i] = ctlvol[i];
902                 return 0;
903         }
904
905         pm_runtime_get_sync(cdev->dev);
906
907         for (i = 0; i < CATPT_CHANNELS_MAX; i++) {
908                 dspvol = catpt_stream_volume(cdev, stream, i);
909                 ucontrol->value.integer.value[i] = dspvol_to_ctlvol(dspvol);
910         }
911
912         pm_runtime_mark_last_busy(cdev->dev);
913         pm_runtime_put_autosuspend(cdev->dev);
914
915         return 0;
916 }
917
918 static int catpt_stream_volume_put(struct snd_kcontrol *kcontrol,
919                                    struct snd_ctl_elem_value *ucontrol,
920                                    enum catpt_pin_id pin_id)
921 {
922         struct snd_soc_component *component =
923                 snd_soc_kcontrol_component(kcontrol);
924         struct catpt_dev *cdev = dev_get_drvdata(component->dev);
925         struct catpt_stream_runtime *stream;
926         long *ctlvol = (long *)kcontrol->private_value;
927         int ret, i;
928
929         stream = catpt_stream_find(cdev, pin_id);
930         if (!stream) {
931                 for (i = 0; i < CATPT_CHANNELS_MAX; i++)
932                         ctlvol[i] = ucontrol->value.integer.value[i];
933                 return 0;
934         }
935
936         pm_runtime_get_sync(cdev->dev);
937
938         ret = catpt_set_dspvol(cdev, stream->info.stream_hw_id,
939                                ucontrol->value.integer.value);
940
941         pm_runtime_mark_last_busy(cdev->dev);
942         pm_runtime_put_autosuspend(cdev->dev);
943
944         if (ret)
945                 return ret;
946
947         for (i = 0; i < CATPT_CHANNELS_MAX; i++)
948                 ctlvol[i] = ucontrol->value.integer.value[i];
949         return 0;
950 }
951
952 static int catpt_offload1_volume_get(struct snd_kcontrol *kctl,
953                                      struct snd_ctl_elem_value *uctl)
954 {
955         return catpt_stream_volume_get(kctl, uctl, CATPT_PIN_ID_OFFLOAD1);
956 }
957
958 static int catpt_offload1_volume_put(struct snd_kcontrol *kctl,
959                                      struct snd_ctl_elem_value *uctl)
960 {
961         return catpt_stream_volume_put(kctl, uctl, CATPT_PIN_ID_OFFLOAD1);
962 }
963
964 static int catpt_offload2_volume_get(struct snd_kcontrol *kctl,
965                                      struct snd_ctl_elem_value *uctl)
966 {
967         return catpt_stream_volume_get(kctl, uctl, CATPT_PIN_ID_OFFLOAD2);
968 }
969
970 static int catpt_offload2_volume_put(struct snd_kcontrol *kctl,
971                                      struct snd_ctl_elem_value *uctl)
972 {
973         return catpt_stream_volume_put(kctl, uctl, CATPT_PIN_ID_OFFLOAD2);
974 }
975
976 static int catpt_capture_volume_get(struct snd_kcontrol *kctl,
977                                     struct snd_ctl_elem_value *uctl)
978 {
979         return catpt_stream_volume_get(kctl, uctl, CATPT_PIN_ID_CAPTURE1);
980 }
981
982 static int catpt_capture_volume_put(struct snd_kcontrol *kctl,
983                                     struct snd_ctl_elem_value *uctl)
984 {
985         return catpt_stream_volume_put(kctl, uctl, CATPT_PIN_ID_CAPTURE1);
986 }
987
988 static int catpt_loopback_switch_get(struct snd_kcontrol *kcontrol,
989                                      struct snd_ctl_elem_value *ucontrol)
990 {
991         ucontrol->value.integer.value[0] = *(bool *)kcontrol->private_value;
992         return 0;
993 }
994
995 static int catpt_loopback_switch_put(struct snd_kcontrol *kcontrol,
996                                      struct snd_ctl_elem_value *ucontrol)
997 {
998         struct snd_soc_component *component =
999                 snd_soc_kcontrol_component(kcontrol);
1000         struct catpt_dev *cdev = dev_get_drvdata(component->dev);
1001         struct catpt_stream_runtime *stream;
1002         bool mute;
1003         int ret;
1004
1005         mute = (bool)ucontrol->value.integer.value[0];
1006         stream = catpt_stream_find(cdev, CATPT_PIN_ID_REFERENCE);
1007         if (!stream) {
1008                 *(bool *)kcontrol->private_value = mute;
1009                 return 0;
1010         }
1011
1012         pm_runtime_get_sync(cdev->dev);
1013
1014         ret = catpt_ipc_mute_loopback(cdev, stream->info.stream_hw_id, mute);
1015
1016         pm_runtime_mark_last_busy(cdev->dev);
1017         pm_runtime_put_autosuspend(cdev->dev);
1018
1019         if (ret)
1020                 return CATPT_IPC_ERROR(ret);
1021
1022         *(bool *)kcontrol->private_value = mute;
1023         return 0;
1024 }
1025
1026 static int catpt_waves_switch_get(struct snd_kcontrol *kcontrol,
1027                                   struct snd_ctl_elem_value *ucontrol)
1028 {
1029         return 0;
1030 }
1031
1032 static int catpt_waves_switch_put(struct snd_kcontrol *kcontrol,
1033                                   struct snd_ctl_elem_value *ucontrol)
1034 {
1035         return 0;
1036 }
1037
1038 static int catpt_waves_param_get(struct snd_kcontrol *kcontrol,
1039                                  unsigned int __user *bytes,
1040                                  unsigned int size)
1041 {
1042         return 0;
1043 }
1044
1045 static int catpt_waves_param_put(struct snd_kcontrol *kcontrol,
1046                                  const unsigned int __user *bytes,
1047                                  unsigned int size)
1048 {
1049         return 0;
1050 }
1051
1052 static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(catpt_volume_tlv, -9000, 300, 1);
1053
1054 #define CATPT_VOLUME_CTL(kname, sname) \
1055 {       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1056         .name = (kname), \
1057         .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
1058                   SNDRV_CTL_ELEM_ACCESS_READWRITE, \
1059         .info = catpt_volume_info, \
1060         .get = catpt_##sname##_volume_get, \
1061         .put = catpt_##sname##_volume_put, \
1062         .tlv.p = catpt_volume_tlv, \
1063         .private_value = (unsigned long) \
1064                 &(long[CATPT_CHANNELS_MAX]) {0} }
1065
1066 static const struct snd_kcontrol_new component_kcontrols[] = {
1067 /* Master volume (mixer stream) */
1068 CATPT_VOLUME_CTL("Master Playback Volume", mixer),
1069 /* Individual volume controls for offload and capture */
1070 CATPT_VOLUME_CTL("Media0 Playback Volume", offload1),
1071 CATPT_VOLUME_CTL("Media1 Playback Volume", offload2),
1072 CATPT_VOLUME_CTL("Mic Capture Volume", capture),
1073 SOC_SINGLE_BOOL_EXT("Loopback Mute", (unsigned long)&(bool[1]) {0},
1074                     catpt_loopback_switch_get, catpt_loopback_switch_put),
1075 /* Enable or disable WAVES module */
1076 SOC_SINGLE_BOOL_EXT("Waves Switch", 0,
1077                     catpt_waves_switch_get, catpt_waves_switch_put),
1078 /* WAVES module parameter control */
1079 SND_SOC_BYTES_TLV("Waves Set Param", 128,
1080                   catpt_waves_param_get, catpt_waves_param_put),
1081 };
1082
1083 static const struct snd_soc_dapm_widget component_widgets[] = {
1084         SND_SOC_DAPM_AIF_IN("SSP0 CODEC IN", NULL, 0, SND_SOC_NOPM, 0, 0),
1085         SND_SOC_DAPM_AIF_OUT("SSP0 CODEC OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
1086         SND_SOC_DAPM_AIF_IN("SSP1 BT IN", NULL, 0, SND_SOC_NOPM, 0, 0),
1087         SND_SOC_DAPM_AIF_OUT("SSP1 BT OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
1088
1089         SND_SOC_DAPM_MIXER("Playback VMixer", SND_SOC_NOPM, 0, 0, NULL, 0),
1090 };
1091
1092 static const struct snd_soc_dapm_route component_routes[] = {
1093         {"Playback VMixer", NULL, "System Playback"},
1094         {"Playback VMixer", NULL, "Offload0 Playback"},
1095         {"Playback VMixer", NULL, "Offload1 Playback"},
1096
1097         {"SSP0 CODEC OUT", NULL, "Playback VMixer"},
1098
1099         {"Analog Capture", NULL, "SSP0 CODEC IN"},
1100         {"Loopback Capture", NULL, "SSP0 CODEC IN"},
1101
1102         {"SSP1 BT OUT", NULL, "Bluetooth Playback"},
1103         {"Bluetooth Capture", NULL, "SSP1 BT IN"},
1104 };
1105
1106 static const struct snd_soc_component_driver catpt_comp_driver = {
1107         .name = "catpt-platform",
1108
1109         .pcm_construct = catpt_component_pcm_construct,
1110         .open = catpt_component_open,
1111         .pointer = catpt_component_pointer,
1112
1113         .controls = component_kcontrols,
1114         .num_controls = ARRAY_SIZE(component_kcontrols),
1115         .dapm_widgets = component_widgets,
1116         .num_dapm_widgets = ARRAY_SIZE(component_widgets),
1117         .dapm_routes = component_routes,
1118         .num_dapm_routes = ARRAY_SIZE(component_routes),
1119 };
1120
1121 int catpt_arm_stream_templates(struct catpt_dev *cdev)
1122 {
1123         struct resource *res;
1124         u32 scratch_size = 0;
1125         int i, j;
1126
1127         for (i = 0; i < ARRAY_SIZE(catpt_topology); i++) {
1128                 struct catpt_stream_template *template;
1129                 struct catpt_module_entry *entry;
1130                 struct catpt_module_type *type;
1131
1132                 template = catpt_topology[i];
1133                 template->persistent_size = 0;
1134
1135                 for (j = 0; j < template->num_entries; j++) {
1136                         entry = &template->entries[j];
1137                         type = &cdev->modules[entry->module_id];
1138
1139                         if (!type->loaded)
1140                                 return -ENOENT;
1141
1142                         entry->entry_point = type->entry_point;
1143                         template->persistent_size += type->persistent_size;
1144                         if (type->scratch_size > scratch_size)
1145                                 scratch_size = type->scratch_size;
1146                 }
1147         }
1148
1149         if (scratch_size) {
1150                 /* allocate single scratch area for all modules */
1151                 res = catpt_request_region(&cdev->dram, scratch_size);
1152                 if (!res)
1153                         return -EBUSY;
1154                 cdev->scratch = res;
1155         }
1156
1157         return 0;
1158 }
1159
1160 int catpt_register_plat_component(struct catpt_dev *cdev)
1161 {
1162         struct snd_soc_component *component;
1163         int ret;
1164
1165         component = devm_kzalloc(cdev->dev, sizeof(*component), GFP_KERNEL);
1166         if (!component)
1167                 return -ENOMEM;
1168
1169         ret = snd_soc_component_initialize(component, &catpt_comp_driver,
1170                                            cdev->dev);
1171         if (ret)
1172                 return ret;
1173
1174         component->name = catpt_comp_driver.name;
1175         return snd_soc_add_component(component, dai_drivers,
1176                                      ARRAY_SIZE(dai_drivers));
1177 }