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