xref: /kernel/linux/linux-6.6/sound/soc/intel/catpt/pcm.c (revision 62306a36)
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
15struct 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
23static 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
30static 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
37static 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
44static 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
51static 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
58static 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
65static 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
74static struct catpt_stream_template *
75catpt_get_stream_template(struct snd_pcm_substream *substream)
76{
77	struct snd_soc_pcm_runtime *rtm = asoc_substream_to_rtd(substream);
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
100struct catpt_stream_runtime *
101catpt_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
117static 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
127static 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
140static 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
153static 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
178static 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
240static 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
259static int catpt_dai_startup(struct snd_pcm_substream *substream,
260			     struct snd_soc_dai *dai)
261{
262	struct catpt_stream_template *template;
263	struct catpt_stream_runtime *stream;
264	struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
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
299err_request:
300	snd_dma_free_pages(&stream->pgtbl);
301err_pgtbl:
302	kfree(stream);
303	return ret;
304}
305
306static void catpt_dai_shutdown(struct snd_pcm_substream *substream,
307			       struct snd_soc_dai *dai)
308{
309	struct catpt_stream_runtime *stream;
310	struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
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
327static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol);
328
329static int catpt_dai_apply_usettings(struct snd_soc_dai *dai,
330				     struct catpt_stream_runtime *stream)
331{
332	struct snd_soc_component *component = dai->component;
333	struct snd_kcontrol *pos;
334	struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
335	const char *name;
336	int ret;
337	u32 id = stream->info.stream_hw_id;
338
339	/* only selected streams have individual controls */
340	switch (id) {
341	case CATPT_PIN_ID_OFFLOAD1:
342		name = "Media0 Playback Volume";
343		break;
344	case CATPT_PIN_ID_OFFLOAD2:
345		name = "Media1 Playback Volume";
346		break;
347	case CATPT_PIN_ID_CAPTURE1:
348		name = "Mic Capture Volume";
349		break;
350	case CATPT_PIN_ID_REFERENCE:
351		name = "Loopback Mute";
352		break;
353	default:
354		return 0;
355	}
356
357	list_for_each_entry(pos, &component->card->snd_card->controls, list) {
358		if (pos->private_data == component &&
359		    !strncmp(name, pos->id.name, sizeof(pos->id.name)))
360			break;
361	}
362	if (list_entry_is_head(pos, &component->card->snd_card->controls, list))
363		return -ENOENT;
364
365	if (stream->template->type != CATPT_STRM_TYPE_LOOPBACK)
366		return catpt_set_dspvol(cdev, id, (long *)pos->private_value);
367	ret = catpt_ipc_mute_loopback(cdev, id, *(bool *)pos->private_value);
368	if (ret)
369		return CATPT_IPC_ERROR(ret);
370	return 0;
371}
372
373static int catpt_dai_hw_params(struct snd_pcm_substream *substream,
374			       struct snd_pcm_hw_params *params,
375			       struct snd_soc_dai *dai)
376{
377	struct snd_pcm_runtime *rtm = substream->runtime;
378	struct snd_dma_buffer *dmab;
379	struct catpt_stream_runtime *stream;
380	struct catpt_audio_format afmt;
381	struct catpt_ring_info rinfo;
382	struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
383	int ret;
384
385	stream = snd_soc_dai_get_dma_data(dai, substream);
386	if (stream->allocated)
387		return 0;
388
389	memset(&afmt, 0, sizeof(afmt));
390	afmt.sample_rate = params_rate(params);
391	afmt.bit_depth = params_physical_width(params);
392	afmt.valid_bit_depth = params_width(params);
393	afmt.num_channels = params_channels(params);
394	afmt.channel_config = catpt_get_channel_config(afmt.num_channels);
395	afmt.channel_map = catpt_get_channel_map(afmt.channel_config);
396	afmt.interleaving = CATPT_INTERLEAVING_PER_CHANNEL;
397
398	dmab = snd_pcm_get_dma_buf(substream);
399	catpt_arrange_page_table(substream, &stream->pgtbl);
400
401	memset(&rinfo, 0, sizeof(rinfo));
402	rinfo.page_table_addr = stream->pgtbl.addr;
403	rinfo.num_pages = DIV_ROUND_UP(rtm->dma_bytes, PAGE_SIZE);
404	rinfo.size = rtm->dma_bytes;
405	rinfo.offset = 0;
406	rinfo.ring_first_page_pfn = PFN_DOWN(snd_sgbuf_get_addr(dmab, 0));
407
408	ret = catpt_ipc_alloc_stream(cdev, stream->template->path_id,
409				     stream->template->type,
410				     &afmt, &rinfo,
411				     stream->template->num_entries,
412				     stream->template->entries,
413				     stream->persistent,
414				     cdev->scratch,
415				     &stream->info);
416	if (ret)
417		return CATPT_IPC_ERROR(ret);
418
419	ret = catpt_dai_apply_usettings(dai, stream);
420	if (ret)
421		return ret;
422
423	stream->allocated = true;
424	return 0;
425}
426
427static int catpt_dai_hw_free(struct snd_pcm_substream *substream,
428			     struct snd_soc_dai *dai)
429{
430	struct catpt_stream_runtime *stream;
431	struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
432
433	stream = snd_soc_dai_get_dma_data(dai, substream);
434	if (!stream->allocated)
435		return 0;
436
437	catpt_ipc_reset_stream(cdev, stream->info.stream_hw_id);
438	catpt_ipc_free_stream(cdev, stream->info.stream_hw_id);
439
440	stream->allocated = false;
441	return 0;
442}
443
444static int catpt_dai_prepare(struct snd_pcm_substream *substream,
445			     struct snd_soc_dai *dai)
446{
447	struct catpt_stream_runtime *stream;
448	struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
449	int ret;
450
451	stream = snd_soc_dai_get_dma_data(dai, substream);
452	if (stream->prepared)
453		return 0;
454
455	ret = catpt_ipc_reset_stream(cdev, stream->info.stream_hw_id);
456	if (ret)
457		return CATPT_IPC_ERROR(ret);
458
459	ret = catpt_ipc_pause_stream(cdev, stream->info.stream_hw_id);
460	if (ret)
461		return CATPT_IPC_ERROR(ret);
462
463	stream->prepared = true;
464	return 0;
465}
466
467static int catpt_dai_trigger(struct snd_pcm_substream *substream, int cmd,
468			     struct snd_soc_dai *dai)
469{
470	struct snd_pcm_runtime *runtime = substream->runtime;
471	struct catpt_stream_runtime *stream;
472	struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
473	snd_pcm_uframes_t pos;
474	int ret;
475
476	stream = snd_soc_dai_get_dma_data(dai, substream);
477
478	switch (cmd) {
479	case SNDRV_PCM_TRIGGER_START:
480		/* only offload is set_write_pos driven */
481		if (stream->template->type != CATPT_STRM_TYPE_RENDER)
482			goto resume_stream;
483
484		pos = frames_to_bytes(runtime, runtime->start_threshold);
485		/*
486		 * Dsp operates on buffer halves, thus max 2x set_write_pos
487		 * (entire buffer filled) prior to stream start.
488		 */
489		ret = catpt_ipc_set_write_pos(cdev, stream->info.stream_hw_id,
490					      pos, false, false);
491		if (ret)
492			return CATPT_IPC_ERROR(ret);
493		fallthrough;
494	case SNDRV_PCM_TRIGGER_RESUME:
495	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
496	resume_stream:
497		catpt_dsp_update_lpclock(cdev);
498		ret = catpt_ipc_resume_stream(cdev, stream->info.stream_hw_id);
499		if (ret)
500			return CATPT_IPC_ERROR(ret);
501		break;
502
503	case SNDRV_PCM_TRIGGER_STOP:
504		stream->prepared = false;
505		fallthrough;
506	case SNDRV_PCM_TRIGGER_SUSPEND:
507	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
508		ret = catpt_ipc_pause_stream(cdev, stream->info.stream_hw_id);
509		catpt_dsp_update_lpclock(cdev);
510		if (ret)
511			return CATPT_IPC_ERROR(ret);
512		break;
513
514	default:
515		break;
516	}
517
518	return 0;
519}
520
521void catpt_stream_update_position(struct catpt_dev *cdev,
522				  struct catpt_stream_runtime *stream,
523				  struct catpt_notify_position *pos)
524{
525	struct snd_pcm_substream *substream = stream->substream;
526	struct snd_pcm_runtime *r = substream->runtime;
527	snd_pcm_uframes_t dsppos, newpos;
528	int ret;
529
530	dsppos = bytes_to_frames(r, pos->stream_position);
531
532	if (!stream->prepared)
533		goto exit;
534	/* only offload is set_write_pos driven */
535	if (stream->template->type != CATPT_STRM_TYPE_RENDER)
536		goto exit;
537
538	if (dsppos >= r->buffer_size / 2)
539		newpos = r->buffer_size / 2;
540	else
541		newpos = 0;
542	/*
543	 * Dsp operates on buffer halves, thus on every notify position
544	 * (buffer half consumed) update wp to allow stream progression.
545	 */
546	ret = catpt_ipc_set_write_pos(cdev, stream->info.stream_hw_id,
547				      frames_to_bytes(r, newpos),
548				      false, false);
549	if (ret) {
550		dev_err(cdev->dev, "update position for stream %d failed: %d\n",
551			stream->info.stream_hw_id, ret);
552		return;
553	}
554exit:
555	snd_pcm_period_elapsed(substream);
556}
557
558/* 200 ms for 2 32-bit channels at 48kHz (native format) */
559#define CATPT_BUFFER_MAX_SIZE	76800
560#define CATPT_PCM_PERIODS_MAX	4
561#define CATPT_PCM_PERIODS_MIN	2
562
563static const struct snd_pcm_hardware catpt_pcm_hardware = {
564	.info			= SNDRV_PCM_INFO_MMAP |
565				  SNDRV_PCM_INFO_MMAP_VALID |
566				  SNDRV_PCM_INFO_INTERLEAVED |
567				  SNDRV_PCM_INFO_PAUSE |
568				  SNDRV_PCM_INFO_RESUME |
569				  SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
570	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
571				  SNDRV_PCM_FMTBIT_S24_LE |
572				  SNDRV_PCM_FMTBIT_S32_LE,
573	.period_bytes_min	= PAGE_SIZE,
574	.period_bytes_max	= CATPT_BUFFER_MAX_SIZE / CATPT_PCM_PERIODS_MIN,
575	.periods_min		= CATPT_PCM_PERIODS_MIN,
576	.periods_max		= CATPT_PCM_PERIODS_MAX,
577	.buffer_bytes_max	= CATPT_BUFFER_MAX_SIZE,
578};
579
580static int catpt_component_pcm_construct(struct snd_soc_component *component,
581					 struct snd_soc_pcm_runtime *rtm)
582{
583	struct catpt_dev *cdev = dev_get_drvdata(component->dev);
584
585	snd_pcm_set_managed_buffer_all(rtm->pcm, SNDRV_DMA_TYPE_DEV_SG,
586				       cdev->dev,
587				       catpt_pcm_hardware.buffer_bytes_max,
588				       catpt_pcm_hardware.buffer_bytes_max);
589
590	return 0;
591}
592
593static int catpt_component_open(struct snd_soc_component *component,
594				struct snd_pcm_substream *substream)
595{
596	struct snd_soc_pcm_runtime *rtm = asoc_substream_to_rtd(substream);
597
598	if (!rtm->dai_link->no_pcm)
599		snd_soc_set_runtime_hwparams(substream, &catpt_pcm_hardware);
600	return 0;
601}
602
603static snd_pcm_uframes_t
604catpt_component_pointer(struct snd_soc_component *component,
605			struct snd_pcm_substream *substream)
606{
607	struct snd_soc_pcm_runtime *rtm = asoc_substream_to_rtd(substream);
608	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtm, 0);
609	struct catpt_stream_runtime *stream;
610	struct catpt_dev *cdev = dev_get_drvdata(component->dev);
611	u32 pos;
612
613	if (rtm->dai_link->no_pcm)
614		return 0;
615
616	stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
617	pos = catpt_stream_read_position(cdev, stream);
618
619	return bytes_to_frames(substream->runtime, pos);
620}
621
622static const struct snd_soc_dai_ops catpt_fe_dai_ops = {
623	.startup = catpt_dai_startup,
624	.shutdown = catpt_dai_shutdown,
625	.hw_params = catpt_dai_hw_params,
626	.hw_free = catpt_dai_hw_free,
627	.prepare = catpt_dai_prepare,
628	.trigger = catpt_dai_trigger,
629};
630
631static int catpt_dai_pcm_new(struct snd_soc_pcm_runtime *rtm,
632			     struct snd_soc_dai *dai)
633{
634	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtm, 0);
635	struct catpt_ssp_device_format devfmt;
636	struct catpt_dev *cdev = dev_get_drvdata(dai->dev);
637	int ret;
638
639	devfmt.iface = dai->driver->id;
640	devfmt.channels = codec_dai->driver->capture.channels_max;
641
642	switch (devfmt.iface) {
643	case CATPT_SSP_IFACE_0:
644		devfmt.mclk = CATPT_MCLK_FREQ_24_MHZ;
645
646		switch (devfmt.channels) {
647		case 4:
648			devfmt.mode = CATPT_SSP_MODE_TDM_PROVIDER;
649			devfmt.clock_divider = 4;
650			break;
651		case 2:
652		default:
653			devfmt.mode = CATPT_SSP_MODE_I2S_PROVIDER;
654			devfmt.clock_divider = 9;
655			break;
656		}
657		break;
658
659	case CATPT_SSP_IFACE_1:
660		devfmt.mclk = CATPT_MCLK_OFF;
661		devfmt.mode = CATPT_SSP_MODE_I2S_CONSUMER;
662		devfmt.clock_divider = 0;
663		break;
664	}
665
666	/* see if this is a new configuration */
667	if (!memcmp(&cdev->devfmt[devfmt.iface], &devfmt, sizeof(devfmt)))
668		return 0;
669
670	ret = pm_runtime_resume_and_get(cdev->dev);
671	if (ret < 0 && ret != -EACCES)
672		return ret;
673
674	ret = catpt_ipc_set_device_format(cdev, &devfmt);
675
676	pm_runtime_mark_last_busy(cdev->dev);
677	pm_runtime_put_autosuspend(cdev->dev);
678
679	if (ret)
680		return CATPT_IPC_ERROR(ret);
681
682	/* store device format set for given SSP */
683	memcpy(&cdev->devfmt[devfmt.iface], &devfmt, sizeof(devfmt));
684	return 0;
685}
686
687static const struct snd_soc_dai_ops catpt_dai_ops = {
688	.pcm_new = catpt_dai_pcm_new,
689};
690
691static struct snd_soc_dai_driver dai_drivers[] = {
692/* FE DAIs */
693{
694	.name  = "System Pin",
695	.id = CATPT_STRM_TYPE_SYSTEM,
696	.ops = &catpt_fe_dai_ops,
697	.playback = {
698		.stream_name = "System Playback",
699		.channels_min = 2,
700		.channels_max = 2,
701		.rates = SNDRV_PCM_RATE_48000,
702		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
703	},
704	.capture = {
705		.stream_name = "Analog Capture",
706		.channels_min = 2,
707		.channels_max = 4,
708		.rates = SNDRV_PCM_RATE_48000,
709		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
710	},
711},
712{
713	.name  = "Offload0 Pin",
714	.id = CATPT_STRM_TYPE_RENDER,
715	.ops = &catpt_fe_dai_ops,
716	.playback = {
717		.stream_name = "Offload0 Playback",
718		.channels_min = 2,
719		.channels_max = 2,
720		.rates = SNDRV_PCM_RATE_8000_192000,
721		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
722	},
723},
724{
725	.name  = "Offload1 Pin",
726	.id = CATPT_STRM_TYPE_RENDER,
727	.ops = &catpt_fe_dai_ops,
728	.playback = {
729		.stream_name = "Offload1 Playback",
730		.channels_min = 2,
731		.channels_max = 2,
732		.rates = SNDRV_PCM_RATE_8000_192000,
733		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
734	},
735},
736{
737	.name  = "Loopback Pin",
738	.id = CATPT_STRM_TYPE_LOOPBACK,
739	.ops = &catpt_fe_dai_ops,
740	.capture = {
741		.stream_name = "Loopback Capture",
742		.channels_min = 2,
743		.channels_max = 2,
744		.rates = SNDRV_PCM_RATE_48000,
745		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
746	},
747},
748{
749	.name  = "Bluetooth Pin",
750	.id = CATPT_STRM_TYPE_BLUETOOTH_RENDER,
751	.ops = &catpt_fe_dai_ops,
752	.playback = {
753		.stream_name = "Bluetooth Playback",
754		.channels_min = 1,
755		.channels_max = 1,
756		.rates = SNDRV_PCM_RATE_8000,
757		.formats = SNDRV_PCM_FMTBIT_S16_LE,
758	},
759	.capture = {
760		.stream_name = "Bluetooth Capture",
761		.channels_min = 1,
762		.channels_max = 1,
763		.rates = SNDRV_PCM_RATE_8000,
764		.formats = SNDRV_PCM_FMTBIT_S16_LE,
765	},
766},
767/* BE DAIs */
768{
769	.name = "ssp0-port",
770	.id = CATPT_SSP_IFACE_0,
771	.playback = {
772		.channels_min = 1,
773		.channels_max = 8,
774	},
775	.capture = {
776		.channels_min = 1,
777		.channels_max = 8,
778	},
779	.ops = &catpt_dai_ops,
780},
781{
782	.name = "ssp1-port",
783	.id = CATPT_SSP_IFACE_1,
784	.playback = {
785		.channels_min = 1,
786		.channels_max = 8,
787	},
788	.capture = {
789		.channels_min = 1,
790		.channels_max = 8,
791	},
792	.ops = &catpt_dai_ops,
793},
794};
795
796#define DSP_VOLUME_MAX		S32_MAX /* 0db */
797#define DSP_VOLUME_STEP_MAX	30
798
799static u32 ctlvol_to_dspvol(u32 value)
800{
801	if (value > DSP_VOLUME_STEP_MAX)
802		value = 0;
803	return DSP_VOLUME_MAX >> (DSP_VOLUME_STEP_MAX - value);
804}
805
806static u32 dspvol_to_ctlvol(u32 volume)
807{
808	if (volume > DSP_VOLUME_MAX)
809		return DSP_VOLUME_STEP_MAX;
810	return volume ? __fls(volume) : 0;
811}
812
813static int catpt_set_dspvol(struct catpt_dev *cdev, u8 stream_id, long *ctlvol)
814{
815	u32 dspvol;
816	int ret, i;
817
818	for (i = 1; i < CATPT_CHANNELS_MAX; i++)
819		if (ctlvol[i] != ctlvol[0])
820			break;
821
822	if (i == CATPT_CHANNELS_MAX) {
823		dspvol = ctlvol_to_dspvol(ctlvol[0]);
824
825		ret = catpt_ipc_set_volume(cdev, stream_id,
826					   CATPT_ALL_CHANNELS_MASK, dspvol,
827					   0, CATPT_AUDIO_CURVE_NONE);
828	} else {
829		for (i = 0; i < CATPT_CHANNELS_MAX; i++) {
830			dspvol = ctlvol_to_dspvol(ctlvol[i]);
831
832			ret = catpt_ipc_set_volume(cdev, stream_id,
833						   i, dspvol,
834						   0, CATPT_AUDIO_CURVE_NONE);
835			if (ret)
836				break;
837		}
838	}
839
840	if (ret)
841		return CATPT_IPC_ERROR(ret);
842	return 0;
843}
844
845static int catpt_volume_info(struct snd_kcontrol *kcontrol,
846			     struct snd_ctl_elem_info *uinfo)
847{
848	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
849	uinfo->count = CATPT_CHANNELS_MAX;
850	uinfo->value.integer.min = 0;
851	uinfo->value.integer.max = DSP_VOLUME_STEP_MAX;
852	return 0;
853}
854
855static int catpt_mixer_volume_get(struct snd_kcontrol *kcontrol,
856				  struct snd_ctl_elem_value *ucontrol)
857{
858	struct snd_soc_component *component =
859		snd_soc_kcontrol_component(kcontrol);
860	struct catpt_dev *cdev = dev_get_drvdata(component->dev);
861	u32 dspvol;
862	int ret;
863	int i;
864
865	ret = pm_runtime_resume_and_get(cdev->dev);
866	if (ret < 0 && ret != -EACCES)
867		return ret;
868
869	for (i = 0; i < CATPT_CHANNELS_MAX; i++) {
870		dspvol = catpt_mixer_volume(cdev, &cdev->mixer, i);
871		ucontrol->value.integer.value[i] = dspvol_to_ctlvol(dspvol);
872	}
873
874	pm_runtime_mark_last_busy(cdev->dev);
875	pm_runtime_put_autosuspend(cdev->dev);
876
877	return 0;
878}
879
880static int catpt_mixer_volume_put(struct snd_kcontrol *kcontrol,
881				  struct snd_ctl_elem_value *ucontrol)
882{
883	struct snd_soc_component *component =
884		snd_soc_kcontrol_component(kcontrol);
885	struct catpt_dev *cdev = dev_get_drvdata(component->dev);
886	int ret;
887
888	ret = pm_runtime_resume_and_get(cdev->dev);
889	if (ret < 0 && ret != -EACCES)
890		return ret;
891
892	ret = catpt_set_dspvol(cdev, cdev->mixer.mixer_hw_id,
893			       ucontrol->value.integer.value);
894
895	pm_runtime_mark_last_busy(cdev->dev);
896	pm_runtime_put_autosuspend(cdev->dev);
897
898	return ret;
899}
900
901static int catpt_stream_volume_get(struct snd_kcontrol *kcontrol,
902				   struct snd_ctl_elem_value *ucontrol,
903				   enum catpt_pin_id pin_id)
904{
905	struct snd_soc_component *component =
906		snd_soc_kcontrol_component(kcontrol);
907	struct catpt_stream_runtime *stream;
908	struct catpt_dev *cdev = dev_get_drvdata(component->dev);
909	long *ctlvol = (long *)kcontrol->private_value;
910	u32 dspvol;
911	int ret;
912	int i;
913
914	stream = catpt_stream_find(cdev, pin_id);
915	if (!stream) {
916		for (i = 0; i < CATPT_CHANNELS_MAX; i++)
917			ucontrol->value.integer.value[i] = ctlvol[i];
918		return 0;
919	}
920
921	ret = pm_runtime_resume_and_get(cdev->dev);
922	if (ret < 0 && ret != -EACCES)
923		return ret;
924
925	for (i = 0; i < CATPT_CHANNELS_MAX; i++) {
926		dspvol = catpt_stream_volume(cdev, stream, i);
927		ucontrol->value.integer.value[i] = dspvol_to_ctlvol(dspvol);
928	}
929
930	pm_runtime_mark_last_busy(cdev->dev);
931	pm_runtime_put_autosuspend(cdev->dev);
932
933	return 0;
934}
935
936static int catpt_stream_volume_put(struct snd_kcontrol *kcontrol,
937				   struct snd_ctl_elem_value *ucontrol,
938				   enum catpt_pin_id pin_id)
939{
940	struct snd_soc_component *component =
941		snd_soc_kcontrol_component(kcontrol);
942	struct catpt_stream_runtime *stream;
943	struct catpt_dev *cdev = dev_get_drvdata(component->dev);
944	long *ctlvol = (long *)kcontrol->private_value;
945	int ret, i;
946
947	stream = catpt_stream_find(cdev, pin_id);
948	if (!stream) {
949		for (i = 0; i < CATPT_CHANNELS_MAX; i++)
950			ctlvol[i] = ucontrol->value.integer.value[i];
951		return 0;
952	}
953
954	ret = pm_runtime_resume_and_get(cdev->dev);
955	if (ret < 0 && ret != -EACCES)
956		return ret;
957
958	ret = catpt_set_dspvol(cdev, stream->info.stream_hw_id,
959			       ucontrol->value.integer.value);
960
961	pm_runtime_mark_last_busy(cdev->dev);
962	pm_runtime_put_autosuspend(cdev->dev);
963
964	if (ret)
965		return ret;
966
967	for (i = 0; i < CATPT_CHANNELS_MAX; i++)
968		ctlvol[i] = ucontrol->value.integer.value[i];
969	return 0;
970}
971
972static int catpt_offload1_volume_get(struct snd_kcontrol *kctl,
973				     struct snd_ctl_elem_value *uctl)
974{
975	return catpt_stream_volume_get(kctl, uctl, CATPT_PIN_ID_OFFLOAD1);
976}
977
978static int catpt_offload1_volume_put(struct snd_kcontrol *kctl,
979				     struct snd_ctl_elem_value *uctl)
980{
981	return catpt_stream_volume_put(kctl, uctl, CATPT_PIN_ID_OFFLOAD1);
982}
983
984static int catpt_offload2_volume_get(struct snd_kcontrol *kctl,
985				     struct snd_ctl_elem_value *uctl)
986{
987	return catpt_stream_volume_get(kctl, uctl, CATPT_PIN_ID_OFFLOAD2);
988}
989
990static int catpt_offload2_volume_put(struct snd_kcontrol *kctl,
991				     struct snd_ctl_elem_value *uctl)
992{
993	return catpt_stream_volume_put(kctl, uctl, CATPT_PIN_ID_OFFLOAD2);
994}
995
996static int catpt_capture_volume_get(struct snd_kcontrol *kctl,
997				    struct snd_ctl_elem_value *uctl)
998{
999	return catpt_stream_volume_get(kctl, uctl, CATPT_PIN_ID_CAPTURE1);
1000}
1001
1002static int catpt_capture_volume_put(struct snd_kcontrol *kctl,
1003				    struct snd_ctl_elem_value *uctl)
1004{
1005	return catpt_stream_volume_put(kctl, uctl, CATPT_PIN_ID_CAPTURE1);
1006}
1007
1008static int catpt_loopback_switch_get(struct snd_kcontrol *kcontrol,
1009				     struct snd_ctl_elem_value *ucontrol)
1010{
1011	ucontrol->value.integer.value[0] = *(bool *)kcontrol->private_value;
1012	return 0;
1013}
1014
1015static int catpt_loopback_switch_put(struct snd_kcontrol *kcontrol,
1016				     struct snd_ctl_elem_value *ucontrol)
1017{
1018	struct snd_soc_component *component =
1019		snd_soc_kcontrol_component(kcontrol);
1020	struct catpt_stream_runtime *stream;
1021	struct catpt_dev *cdev = dev_get_drvdata(component->dev);
1022	bool mute;
1023	int ret;
1024
1025	mute = (bool)ucontrol->value.integer.value[0];
1026	stream = catpt_stream_find(cdev, CATPT_PIN_ID_REFERENCE);
1027	if (!stream) {
1028		*(bool *)kcontrol->private_value = mute;
1029		return 0;
1030	}
1031
1032	ret = pm_runtime_resume_and_get(cdev->dev);
1033	if (ret < 0 && ret != -EACCES)
1034		return ret;
1035
1036	ret = catpt_ipc_mute_loopback(cdev, stream->info.stream_hw_id, mute);
1037
1038	pm_runtime_mark_last_busy(cdev->dev);
1039	pm_runtime_put_autosuspend(cdev->dev);
1040
1041	if (ret)
1042		return CATPT_IPC_ERROR(ret);
1043
1044	*(bool *)kcontrol->private_value = mute;
1045	return 0;
1046}
1047
1048static int catpt_waves_switch_get(struct snd_kcontrol *kcontrol,
1049				  struct snd_ctl_elem_value *ucontrol)
1050{
1051	return 0;
1052}
1053
1054static int catpt_waves_switch_put(struct snd_kcontrol *kcontrol,
1055				  struct snd_ctl_elem_value *ucontrol)
1056{
1057	return 0;
1058}
1059
1060static int catpt_waves_param_get(struct snd_kcontrol *kcontrol,
1061				 unsigned int __user *bytes,
1062				 unsigned int size)
1063{
1064	return 0;
1065}
1066
1067static int catpt_waves_param_put(struct snd_kcontrol *kcontrol,
1068				 const unsigned int __user *bytes,
1069				 unsigned int size)
1070{
1071	return 0;
1072}
1073
1074static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(catpt_volume_tlv, -9000, 300, 1);
1075
1076#define CATPT_VOLUME_CTL(kname, sname) \
1077{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1078	.name = (kname), \
1079	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
1080		  SNDRV_CTL_ELEM_ACCESS_READWRITE, \
1081	.info = catpt_volume_info, \
1082	.get = catpt_##sname##_volume_get, \
1083	.put = catpt_##sname##_volume_put, \
1084	.tlv.p = catpt_volume_tlv, \
1085	.private_value = (unsigned long) \
1086		&(long[CATPT_CHANNELS_MAX]) {0} }
1087
1088static const struct snd_kcontrol_new component_kcontrols[] = {
1089/* Master volume (mixer stream) */
1090CATPT_VOLUME_CTL("Master Playback Volume", mixer),
1091/* Individual volume controls for offload and capture */
1092CATPT_VOLUME_CTL("Media0 Playback Volume", offload1),
1093CATPT_VOLUME_CTL("Media1 Playback Volume", offload2),
1094CATPT_VOLUME_CTL("Mic Capture Volume", capture),
1095SOC_SINGLE_BOOL_EXT("Loopback Mute", (unsigned long)&(bool[1]) {0},
1096		    catpt_loopback_switch_get, catpt_loopback_switch_put),
1097/* Enable or disable WAVES module */
1098SOC_SINGLE_BOOL_EXT("Waves Switch", 0,
1099		    catpt_waves_switch_get, catpt_waves_switch_put),
1100/* WAVES module parameter control */
1101SND_SOC_BYTES_TLV("Waves Set Param", 128,
1102		  catpt_waves_param_get, catpt_waves_param_put),
1103};
1104
1105static const struct snd_soc_dapm_widget component_widgets[] = {
1106	SND_SOC_DAPM_AIF_IN("SSP0 CODEC IN", NULL, 0, SND_SOC_NOPM, 0, 0),
1107	SND_SOC_DAPM_AIF_OUT("SSP0 CODEC OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
1108	SND_SOC_DAPM_AIF_IN("SSP1 BT IN", NULL, 0, SND_SOC_NOPM, 0, 0),
1109	SND_SOC_DAPM_AIF_OUT("SSP1 BT OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
1110
1111	SND_SOC_DAPM_MIXER("Playback VMixer", SND_SOC_NOPM, 0, 0, NULL, 0),
1112};
1113
1114static const struct snd_soc_dapm_route component_routes[] = {
1115	{"Playback VMixer", NULL, "System Playback"},
1116	{"Playback VMixer", NULL, "Offload0 Playback"},
1117	{"Playback VMixer", NULL, "Offload1 Playback"},
1118
1119	{"SSP0 CODEC OUT", NULL, "Playback VMixer"},
1120
1121	{"Analog Capture", NULL, "SSP0 CODEC IN"},
1122	{"Loopback Capture", NULL, "SSP0 CODEC IN"},
1123
1124	{"SSP1 BT OUT", NULL, "Bluetooth Playback"},
1125	{"Bluetooth Capture", NULL, "SSP1 BT IN"},
1126};
1127
1128static const struct snd_soc_component_driver catpt_comp_driver = {
1129	.name = "catpt-platform",
1130
1131	.pcm_construct = catpt_component_pcm_construct,
1132	.open = catpt_component_open,
1133	.pointer = catpt_component_pointer,
1134
1135	.controls = component_kcontrols,
1136	.num_controls = ARRAY_SIZE(component_kcontrols),
1137	.dapm_widgets = component_widgets,
1138	.num_dapm_widgets = ARRAY_SIZE(component_widgets),
1139	.dapm_routes = component_routes,
1140	.num_dapm_routes = ARRAY_SIZE(component_routes),
1141};
1142
1143int catpt_arm_stream_templates(struct catpt_dev *cdev)
1144{
1145	struct resource *res;
1146	u32 scratch_size = 0;
1147	int i, j;
1148
1149	for (i = 0; i < ARRAY_SIZE(catpt_topology); i++) {
1150		struct catpt_stream_template *template;
1151		struct catpt_module_entry *entry;
1152		struct catpt_module_type *type;
1153
1154		template = catpt_topology[i];
1155		template->persistent_size = 0;
1156
1157		for (j = 0; j < template->num_entries; j++) {
1158			entry = &template->entries[j];
1159			type = &cdev->modules[entry->module_id];
1160
1161			if (!type->loaded)
1162				return -ENOENT;
1163
1164			entry->entry_point = type->entry_point;
1165			template->persistent_size += type->persistent_size;
1166			if (type->scratch_size > scratch_size)
1167				scratch_size = type->scratch_size;
1168		}
1169	}
1170
1171	if (scratch_size) {
1172		/* allocate single scratch area for all modules */
1173		res = catpt_request_region(&cdev->dram, scratch_size);
1174		if (!res)
1175			return -EBUSY;
1176		cdev->scratch = res;
1177	}
1178
1179	return 0;
1180}
1181
1182int catpt_register_plat_component(struct catpt_dev *cdev)
1183{
1184	struct snd_soc_component *component;
1185	int ret;
1186
1187	component = devm_kzalloc(cdev->dev, sizeof(*component), GFP_KERNEL);
1188	if (!component)
1189		return -ENOMEM;
1190
1191	ret = snd_soc_component_initialize(component, &catpt_comp_driver,
1192					   cdev->dev);
1193	if (ret)
1194		return ret;
1195
1196	component->name = catpt_comp_driver.name;
1197	return snd_soc_add_component(component, dai_drivers,
1198				     ARRAY_SIZE(dai_drivers));
1199}
1200