blob: 9d5f64a583a388bd501973c32ae3d5d086d6acc6 [file] [log] [blame]
Mark Browna4b12992014-03-12 23:04:35 +00001/*
2 * Intel SST Haswell/Broadwell PCM Support
3 *
4 * Copyright (C) 2013, Intel Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/module.h>
18#include <linux/dma-mapping.h>
19#include <linux/slab.h>
20#include <linux/module.h>
21#include <linux/delay.h>
22#include <asm/page.h>
23#include <asm/pgtable.h>
24#include <sound/core.h>
25#include <sound/pcm.h>
26#include <sound/pcm_params.h>
27#include <sound/dmaengine_pcm.h>
28#include <sound/soc.h>
29#include <sound/tlv.h>
30#include <sound/compress_driver.h>
31
32#include "sst-haswell-ipc.h"
33#include "sst-dsp-priv.h"
34#include "sst-dsp.h"
35
36#define HSW_PCM_COUNT 6
37#define HSW_VOLUME_MAX 0x7FFFFFFF /* 0dB */
38
39/* simple volume table */
40static const u32 volume_map[] = {
41 HSW_VOLUME_MAX >> 30,
42 HSW_VOLUME_MAX >> 29,
43 HSW_VOLUME_MAX >> 28,
44 HSW_VOLUME_MAX >> 27,
45 HSW_VOLUME_MAX >> 26,
46 HSW_VOLUME_MAX >> 25,
47 HSW_VOLUME_MAX >> 24,
48 HSW_VOLUME_MAX >> 23,
49 HSW_VOLUME_MAX >> 22,
50 HSW_VOLUME_MAX >> 21,
51 HSW_VOLUME_MAX >> 20,
52 HSW_VOLUME_MAX >> 19,
53 HSW_VOLUME_MAX >> 18,
54 HSW_VOLUME_MAX >> 17,
55 HSW_VOLUME_MAX >> 16,
56 HSW_VOLUME_MAX >> 15,
57 HSW_VOLUME_MAX >> 14,
58 HSW_VOLUME_MAX >> 13,
59 HSW_VOLUME_MAX >> 12,
60 HSW_VOLUME_MAX >> 11,
61 HSW_VOLUME_MAX >> 10,
62 HSW_VOLUME_MAX >> 9,
63 HSW_VOLUME_MAX >> 8,
64 HSW_VOLUME_MAX >> 7,
65 HSW_VOLUME_MAX >> 6,
66 HSW_VOLUME_MAX >> 5,
67 HSW_VOLUME_MAX >> 4,
68 HSW_VOLUME_MAX >> 3,
69 HSW_VOLUME_MAX >> 2,
70 HSW_VOLUME_MAX >> 1,
71 HSW_VOLUME_MAX >> 0,
72};
73
74#define HSW_PCM_PERIODS_MAX 64
75#define HSW_PCM_PERIODS_MIN 2
76
77static const struct snd_pcm_hardware hsw_pcm_hardware = {
78 .info = SNDRV_PCM_INFO_MMAP |
79 SNDRV_PCM_INFO_MMAP_VALID |
80 SNDRV_PCM_INFO_INTERLEAVED |
81 SNDRV_PCM_INFO_PAUSE |
82 SNDRV_PCM_INFO_RESUME |
83 SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
84 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE |
85 SNDRV_PCM_FMTBIT_S32_LE,
86 .period_bytes_min = PAGE_SIZE,
87 .period_bytes_max = (HSW_PCM_PERIODS_MAX / HSW_PCM_PERIODS_MIN) * PAGE_SIZE,
88 .periods_min = HSW_PCM_PERIODS_MIN,
89 .periods_max = HSW_PCM_PERIODS_MAX,
90 .buffer_bytes_max = HSW_PCM_PERIODS_MAX * PAGE_SIZE,
91};
92
93/* private data for each PCM DSP stream */
94struct hsw_pcm_data {
95 int dai_id;
96 struct sst_hsw_stream *stream;
97 u32 volume[2];
98 struct snd_pcm_substream *substream;
99 struct snd_compr_stream *cstream;
100 unsigned int wpos;
101 struct mutex mutex;
Liam Girdwood916152c2014-05-02 16:56:32 +0100102 bool allocated;
Mark Browna4b12992014-03-12 23:04:35 +0000103};
104
105/* private data for the driver */
106struct hsw_priv_data {
107 /* runtime DSP */
108 struct sst_hsw *hsw;
109
110 /* page tables */
Liam Girdwood0b708c82014-05-02 16:56:30 +0100111 struct snd_dma_buffer dmab[HSW_PCM_COUNT][2];
Mark Browna4b12992014-03-12 23:04:35 +0000112
113 /* DAI data */
114 struct hsw_pcm_data pcm[HSW_PCM_COUNT];
115};
116
Liam Girdwood916152c2014-05-02 16:56:32 +0100117static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data);
118
Mark Browna4b12992014-03-12 23:04:35 +0000119static inline u32 hsw_mixer_to_ipc(unsigned int value)
120{
121 if (value >= ARRAY_SIZE(volume_map))
122 return volume_map[0];
123 else
124 return volume_map[value];
125}
126
127static inline unsigned int hsw_ipc_to_mixer(u32 value)
128{
129 int i;
130
131 for (i = 0; i < ARRAY_SIZE(volume_map); i++) {
132 if (volume_map[i] >= value)
133 return i;
134 }
135
136 return i - 1;
137}
138
139static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
140 struct snd_ctl_elem_value *ucontrol)
141{
142 struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
143 struct soc_mixer_control *mc =
144 (struct soc_mixer_control *)kcontrol->private_value;
145 struct hsw_priv_data *pdata =
146 snd_soc_platform_get_drvdata(platform);
147 struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
148 struct sst_hsw *hsw = pdata->hsw;
149 u32 volume;
150
151 mutex_lock(&pcm_data->mutex);
152
153 if (!pcm_data->stream) {
154 pcm_data->volume[0] =
155 hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
156 pcm_data->volume[1] =
157 hsw_mixer_to_ipc(ucontrol->value.integer.value[1]);
158 mutex_unlock(&pcm_data->mutex);
159 return 0;
160 }
161
162 if (ucontrol->value.integer.value[0] ==
163 ucontrol->value.integer.value[1]) {
164 volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
165 sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 2, volume);
166 } else {
167 volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
168 sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 0, volume);
169 volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[1]);
170 sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 1, volume);
171 }
172
173 mutex_unlock(&pcm_data->mutex);
174 return 0;
175}
176
177static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
178 struct snd_ctl_elem_value *ucontrol)
179{
180 struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
181 struct soc_mixer_control *mc =
182 (struct soc_mixer_control *)kcontrol->private_value;
183 struct hsw_priv_data *pdata =
184 snd_soc_platform_get_drvdata(platform);
185 struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
186 struct sst_hsw *hsw = pdata->hsw;
187 u32 volume;
188
189 mutex_lock(&pcm_data->mutex);
190
191 if (!pcm_data->stream) {
192 ucontrol->value.integer.value[0] =
193 hsw_ipc_to_mixer(pcm_data->volume[0]);
194 ucontrol->value.integer.value[1] =
195 hsw_ipc_to_mixer(pcm_data->volume[1]);
196 mutex_unlock(&pcm_data->mutex);
197 return 0;
198 }
199
200 sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 0, &volume);
201 ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume);
202 sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 1, &volume);
203 ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume);
204 mutex_unlock(&pcm_data->mutex);
205
206 return 0;
207}
208
209static int hsw_volume_put(struct snd_kcontrol *kcontrol,
210 struct snd_ctl_elem_value *ucontrol)
211{
212 struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
213 struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
214 struct sst_hsw *hsw = pdata->hsw;
215 u32 volume;
216
217 if (ucontrol->value.integer.value[0] ==
218 ucontrol->value.integer.value[1]) {
219
220 volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
221 sst_hsw_mixer_set_volume(hsw, 0, 2, volume);
222
223 } else {
224 volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
225 sst_hsw_mixer_set_volume(hsw, 0, 0, volume);
226
227 volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[1]);
228 sst_hsw_mixer_set_volume(hsw, 0, 1, volume);
229 }
230
231 return 0;
232}
233
234static int hsw_volume_get(struct snd_kcontrol *kcontrol,
235 struct snd_ctl_elem_value *ucontrol)
236{
237 struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol);
238 struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
239 struct sst_hsw *hsw = pdata->hsw;
240 unsigned int volume = 0;
241
242 sst_hsw_mixer_get_volume(hsw, 0, 0, &volume);
243 ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume);
244
245 sst_hsw_mixer_get_volume(hsw, 0, 1, &volume);
246 ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume);
247
248 return 0;
249}
250
251/* TLV used by both global and stream volumes */
252static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1);
253
254/* System Pin has no volume control */
255static const struct snd_kcontrol_new hsw_volume_controls[] = {
256 /* Global DSP volume */
257 SOC_DOUBLE_EXT_TLV("Master Playback Volume", 0, 0, 8,
258 ARRAY_SIZE(volume_map) -1, 0,
259 hsw_volume_get, hsw_volume_put, hsw_vol_tlv),
260 /* Offload 0 volume */
261 SOC_DOUBLE_EXT_TLV("Media0 Playback Volume", 1, 0, 8,
262 ARRAY_SIZE(volume_map), 0,
263 hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
264 /* Offload 1 volume */
265 SOC_DOUBLE_EXT_TLV("Media1 Playback Volume", 2, 0, 8,
266 ARRAY_SIZE(volume_map), 0,
267 hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
268 /* Loopback volume */
269 SOC_DOUBLE_EXT_TLV("Loopback Capture Volume", 3, 0, 8,
270 ARRAY_SIZE(volume_map), 0,
271 hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
272 /* Mic Capture volume */
273 SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8,
274 ARRAY_SIZE(volume_map), 0,
275 hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
276};
277
278/* Create DMA buffer page table for DSP */
Liam Girdwood0b708c82014-05-02 16:56:30 +0100279static int create_adsp_page_table(struct snd_pcm_substream *substream,
280 struct hsw_priv_data *pdata, struct snd_soc_pcm_runtime *rtd,
281 unsigned char *dma_area, size_t size, int pcm)
Mark Browna4b12992014-03-12 23:04:35 +0000282{
Liam Girdwood0b708c82014-05-02 16:56:30 +0100283 struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream);
284 int i, pages, stream = substream->stream;
Mark Browna4b12992014-03-12 23:04:35 +0000285
Liam Girdwood0b708c82014-05-02 16:56:30 +0100286 pages = snd_sgbuf_aligned_pages(size);
Mark Browna4b12992014-03-12 23:04:35 +0000287
288 dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n",
289 dma_area, size, pages);
290
291 for (i = 0; i < pages; i++) {
292 u32 idx = (((i << 2) + i)) >> 1;
Liam Girdwood0b708c82014-05-02 16:56:30 +0100293 u32 pfn = snd_sgbuf_get_addr(dmab, i * PAGE_SIZE) >> PAGE_SHIFT;
Mark Browna4b12992014-03-12 23:04:35 +0000294 u32 *pg_table;
295
296 dev_dbg(rtd->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn);
297
Liam Girdwood0b708c82014-05-02 16:56:30 +0100298 pg_table = (u32 *)(pdata->dmab[pcm][stream].area + idx);
Mark Browna4b12992014-03-12 23:04:35 +0000299
300 if (i & 1)
301 *pg_table |= (pfn << 4);
302 else
303 *pg_table |= pfn;
304 }
305
306 return 0;
307}
308
309/* this may get called several times by oss emulation */
310static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
311 struct snd_pcm_hw_params *params)
312{
313 struct snd_soc_pcm_runtime *rtd = substream->private_data;
314 struct snd_pcm_runtime *runtime = substream->runtime;
315 struct hsw_priv_data *pdata =
316 snd_soc_platform_get_drvdata(rtd->platform);
317 struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
318 struct sst_hsw *hsw = pdata->hsw;
319 struct sst_module *module_data;
320 struct sst_dsp *dsp;
Liam Girdwood0b708c82014-05-02 16:56:30 +0100321 struct snd_dma_buffer *dmab;
Mark Browna4b12992014-03-12 23:04:35 +0000322 enum sst_hsw_stream_type stream_type;
323 enum sst_hsw_stream_path_id path_id;
324 u32 rate, bits, map, pages, module_id;
325 u8 channels;
326 int ret;
327
Liam Girdwood916152c2014-05-02 16:56:32 +0100328 /* check if we are being called a subsequent time */
329 if (pcm_data->allocated) {
330 ret = sst_hsw_stream_reset(hsw, pcm_data->stream);
331 if (ret < 0)
332 dev_dbg(rtd->dev, "error: reset stream failed %d\n",
333 ret);
334
335 ret = sst_hsw_stream_free(hsw, pcm_data->stream);
336 if (ret < 0) {
337 dev_dbg(rtd->dev, "error: free stream failed %d\n",
338 ret);
339 return ret;
340 }
341 pcm_data->allocated = false;
342
343 pcm_data->stream = sst_hsw_stream_new(hsw, rtd->cpu_dai->id,
344 hsw_notify_pointer, pcm_data);
345 if (pcm_data->stream == NULL) {
346 dev_err(rtd->dev, "error: failed to create stream\n");
347 return -EINVAL;
348 }
349 }
350
Mark Browna4b12992014-03-12 23:04:35 +0000351 /* stream direction */
352 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
353 path_id = SST_HSW_STREAM_PATH_SSP0_OUT;
354 else
355 path_id = SST_HSW_STREAM_PATH_SSP0_IN;
356
357 /* DSP stream type depends on DAI ID */
358 switch (rtd->cpu_dai->id) {
359 case 0:
360 stream_type = SST_HSW_STREAM_TYPE_SYSTEM;
361 module_id = SST_HSW_MODULE_PCM_SYSTEM;
362 break;
363 case 1:
364 case 2:
365 stream_type = SST_HSW_STREAM_TYPE_RENDER;
366 module_id = SST_HSW_MODULE_PCM;
367 break;
368 case 3:
369 /* path ID needs to be OUT for loopback */
370 stream_type = SST_HSW_STREAM_TYPE_LOOPBACK;
371 path_id = SST_HSW_STREAM_PATH_SSP0_OUT;
372 module_id = SST_HSW_MODULE_PCM_REFERENCE;
373 break;
374 case 4:
375 stream_type = SST_HSW_STREAM_TYPE_CAPTURE;
376 module_id = SST_HSW_MODULE_PCM_CAPTURE;
377 break;
378 default:
379 dev_err(rtd->dev, "error: invalid DAI ID %d\n",
380 rtd->cpu_dai->id);
381 return -EINVAL;
382 };
383
384 ret = sst_hsw_stream_format(hsw, pcm_data->stream,
385 path_id, stream_type, SST_HSW_STREAM_FORMAT_PCM_FORMAT);
386 if (ret < 0) {
387 dev_err(rtd->dev, "error: failed to set format %d\n", ret);
388 return ret;
389 }
390
391 rate = params_rate(params);
392 ret = sst_hsw_stream_set_rate(hsw, pcm_data->stream, rate);
393 if (ret < 0) {
394 dev_err(rtd->dev, "error: could not set rate %d\n", rate);
395 return ret;
396 }
397
398 switch (params_format(params)) {
399 case SNDRV_PCM_FORMAT_S16_LE:
400 bits = SST_HSW_DEPTH_16BIT;
401 sst_hsw_stream_set_valid(hsw, pcm_data->stream, 16);
402 break;
403 case SNDRV_PCM_FORMAT_S24_LE:
404 bits = SST_HSW_DEPTH_24BIT;
405 sst_hsw_stream_set_valid(hsw, pcm_data->stream, 32);
406 break;
407 default:
408 dev_err(rtd->dev, "error: invalid format %d\n",
409 params_format(params));
410 return -EINVAL;
411 }
412
413 ret = sst_hsw_stream_set_bits(hsw, pcm_data->stream, bits);
414 if (ret < 0) {
415 dev_err(rtd->dev, "error: could not set bits %d\n", bits);
416 return ret;
417 }
418
419 /* we only support stereo atm */
420 channels = params_channels(params);
421 if (channels != 2) {
422 dev_err(rtd->dev, "error: invalid channels %d\n", channels);
423 return -EINVAL;
424 }
425
426 map = create_channel_map(SST_HSW_CHANNEL_CONFIG_STEREO);
427 sst_hsw_stream_set_map_config(hsw, pcm_data->stream,
428 map, SST_HSW_CHANNEL_CONFIG_STEREO);
429
430 ret = sst_hsw_stream_set_channels(hsw, pcm_data->stream, channels);
431 if (ret < 0) {
432 dev_err(rtd->dev, "error: could not set channels %d\n",
433 channels);
434 return ret;
435 }
436
437 ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
438 if (ret < 0) {
439 dev_err(rtd->dev, "error: could not allocate %d bytes for PCM %d\n",
440 params_buffer_bytes(params), ret);
441 return ret;
442 }
443
Liam Girdwood0b708c82014-05-02 16:56:30 +0100444 dmab = snd_pcm_get_dma_buf(substream);
445
446 ret = create_adsp_page_table(substream, pdata, rtd, runtime->dma_area,
447 runtime->dma_bytes, rtd->cpu_dai->id);
Mark Browna4b12992014-03-12 23:04:35 +0000448 if (ret < 0)
449 return ret;
450
451 sst_hsw_stream_set_style(hsw, pcm_data->stream,
452 SST_HSW_INTERLEAVING_PER_CHANNEL);
453
454 if (runtime->dma_bytes % PAGE_SIZE)
455 pages = (runtime->dma_bytes / PAGE_SIZE) + 1;
456 else
457 pages = runtime->dma_bytes / PAGE_SIZE;
458
459 ret = sst_hsw_stream_buffer(hsw, pcm_data->stream,
Liam Girdwood0b708c82014-05-02 16:56:30 +0100460 pdata->dmab[rtd->cpu_dai->id][substream->stream].addr,
Mark Browna4b12992014-03-12 23:04:35 +0000461 pages, runtime->dma_bytes, 0,
Liam Girdwood0b708c82014-05-02 16:56:30 +0100462 snd_sgbuf_get_addr(dmab, 0) >> PAGE_SHIFT);
Mark Browna4b12992014-03-12 23:04:35 +0000463 if (ret < 0) {
464 dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret);
465 return ret;
466 }
467
468 dsp = sst_hsw_get_dsp(hsw);
469
470 module_data = sst_module_get_from_id(dsp, module_id);
471 if (module_data == NULL) {
472 dev_err(rtd->dev, "error: failed to get module config\n");
473 return -EINVAL;
474 }
475
476 /* we use hardcoded memory offsets atm, will be updated for new FW */
477 if (stream_type == SST_HSW_STREAM_TYPE_CAPTURE) {
478 sst_hsw_stream_set_module_info(hsw, pcm_data->stream,
479 SST_HSW_MODULE_PCM_CAPTURE, module_data->entry);
480 sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream,
481 0x449400, 0x4000);
482 sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream,
483 0x400000, 0);
484 } else { /* stream_type == SST_HSW_STREAM_TYPE_SYSTEM */
485 sst_hsw_stream_set_module_info(hsw, pcm_data->stream,
486 SST_HSW_MODULE_PCM_SYSTEM, module_data->entry);
487
488 sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream,
489 module_data->offset, module_data->size);
490 sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream,
491 0x44d400, 0x3800);
492
493 sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream,
494 module_data->offset, module_data->size);
495 sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream,
496 0x400000, 0);
497 }
498
499 ret = sst_hsw_stream_commit(hsw, pcm_data->stream);
500 if (ret < 0) {
501 dev_err(rtd->dev, "error: failed to commit stream %d\n", ret);
502 return ret;
503 }
Liam Girdwood916152c2014-05-02 16:56:32 +0100504 pcm_data->allocated = true;
Mark Browna4b12992014-03-12 23:04:35 +0000505
506 ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1);
507 if (ret < 0)
508 dev_err(rtd->dev, "error: failed to pause %d\n", ret);
509
510 return 0;
511}
512
513static int hsw_pcm_hw_free(struct snd_pcm_substream *substream)
514{
515 snd_pcm_lib_free_pages(substream);
516 return 0;
517}
518
519static int hsw_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
520{
521 struct snd_soc_pcm_runtime *rtd = substream->private_data;
522 struct hsw_priv_data *pdata =
523 snd_soc_platform_get_drvdata(rtd->platform);
524 struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
525 struct sst_hsw *hsw = pdata->hsw;
526
527 switch (cmd) {
528 case SNDRV_PCM_TRIGGER_START:
529 case SNDRV_PCM_TRIGGER_RESUME:
530 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
531 sst_hsw_stream_resume(hsw, pcm_data->stream, 0);
532 break;
533 case SNDRV_PCM_TRIGGER_STOP:
534 case SNDRV_PCM_TRIGGER_SUSPEND:
535 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
536 sst_hsw_stream_pause(hsw, pcm_data->stream, 0);
537 break;
538 default:
539 break;
540 }
541
542 return 0;
543}
544
545static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data)
546{
547 struct hsw_pcm_data *pcm_data = data;
548 struct snd_pcm_substream *substream = pcm_data->substream;
549 struct snd_pcm_runtime *runtime = substream->runtime;
550 struct snd_soc_pcm_runtime *rtd = substream->private_data;
551 u32 pos;
552
553 pos = frames_to_bytes(runtime,
554 (runtime->control->appl_ptr % runtime->buffer_size));
555
556 dev_dbg(rtd->dev, "PCM: App pointer %d bytes\n", pos);
557
558 /* let alsa know we have play a period */
559 snd_pcm_period_elapsed(substream);
560 return pos;
561}
562
563static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream)
564{
565 struct snd_soc_pcm_runtime *rtd = substream->private_data;
566 struct snd_pcm_runtime *runtime = substream->runtime;
567 struct hsw_priv_data *pdata =
568 snd_soc_platform_get_drvdata(rtd->platform);
569 struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
570 struct sst_hsw *hsw = pdata->hsw;
571 snd_pcm_uframes_t offset;
Liam Girdwood51b4e242014-05-02 16:56:33 +0100572 uint64_t ppos;
573 u32 position = sst_hsw_get_dsp_position(hsw, pcm_data->stream);
Mark Browna4b12992014-03-12 23:04:35 +0000574
Liam Girdwood51b4e242014-05-02 16:56:33 +0100575 offset = bytes_to_frames(runtime, position);
576 ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream);
Mark Browna4b12992014-03-12 23:04:35 +0000577
Liam Girdwood51b4e242014-05-02 16:56:33 +0100578 dev_dbg(rtd->dev, "PCM: DMA pointer %du bytes, pos %llu\n",
579 position, ppos);
Mark Browna4b12992014-03-12 23:04:35 +0000580 return offset;
581}
582
583static int hsw_pcm_open(struct snd_pcm_substream *substream)
584{
585 struct snd_soc_pcm_runtime *rtd = substream->private_data;
586 struct hsw_priv_data *pdata =
587 snd_soc_platform_get_drvdata(rtd->platform);
588 struct hsw_pcm_data *pcm_data;
589 struct sst_hsw *hsw = pdata->hsw;
590
591 pcm_data = &pdata->pcm[rtd->cpu_dai->id];
592
593 mutex_lock(&pcm_data->mutex);
594
595 snd_soc_pcm_set_drvdata(rtd, pcm_data);
596 pcm_data->substream = substream;
597
598 snd_soc_set_runtime_hwparams(substream, &hsw_pcm_hardware);
599
600 pcm_data->stream = sst_hsw_stream_new(hsw, rtd->cpu_dai->id,
601 hsw_notify_pointer, pcm_data);
602 if (pcm_data->stream == NULL) {
603 dev_err(rtd->dev, "error: failed to create stream\n");
604 mutex_unlock(&pcm_data->mutex);
605 return -EINVAL;
606 }
607
608 /* Set previous saved volume */
609 sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0,
610 0, pcm_data->volume[0]);
611 sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0,
612 1, pcm_data->volume[1]);
613
614 mutex_unlock(&pcm_data->mutex);
615 return 0;
616}
617
618static int hsw_pcm_close(struct snd_pcm_substream *substream)
619{
620 struct snd_soc_pcm_runtime *rtd = substream->private_data;
621 struct hsw_priv_data *pdata =
622 snd_soc_platform_get_drvdata(rtd->platform);
623 struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
624 struct sst_hsw *hsw = pdata->hsw;
625 int ret;
626
627 mutex_lock(&pcm_data->mutex);
628 ret = sst_hsw_stream_reset(hsw, pcm_data->stream);
629 if (ret < 0) {
630 dev_dbg(rtd->dev, "error: reset stream failed %d\n", ret);
631 goto out;
632 }
633
634 ret = sst_hsw_stream_free(hsw, pcm_data->stream);
635 if (ret < 0) {
636 dev_dbg(rtd->dev, "error: free stream failed %d\n", ret);
637 goto out;
638 }
Liam Girdwood916152c2014-05-02 16:56:32 +0100639 pcm_data->allocated = 0;
Mark Browna4b12992014-03-12 23:04:35 +0000640 pcm_data->stream = NULL;
641
642out:
643 mutex_unlock(&pcm_data->mutex);
644 return ret;
645}
646
647static struct snd_pcm_ops hsw_pcm_ops = {
648 .open = hsw_pcm_open,
649 .close = hsw_pcm_close,
650 .ioctl = snd_pcm_lib_ioctl,
651 .hw_params = hsw_pcm_hw_params,
652 .hw_free = hsw_pcm_hw_free,
653 .trigger = hsw_pcm_trigger,
654 .pointer = hsw_pcm_pointer,
Liam Girdwood0b708c82014-05-02 16:56:30 +0100655 .page = snd_pcm_sgbuf_ops_page,
Mark Browna4b12992014-03-12 23:04:35 +0000656};
657
658static void hsw_pcm_free(struct snd_pcm *pcm)
659{
660 snd_pcm_lib_preallocate_free_for_all(pcm);
661}
662
663static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
664{
665 struct snd_pcm *pcm = rtd->pcm;
Liam Girdwood10df3502014-05-02 16:56:31 +0100666 struct snd_soc_platform *platform = rtd->platform;
667 struct sst_pdata *pdata = dev_get_platdata(platform->dev);
668 struct device *dev = pdata->dma_dev;
Mark Browna4b12992014-03-12 23:04:35 +0000669 int ret = 0;
670
Mark Browna4b12992014-03-12 23:04:35 +0000671 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream ||
672 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
673 ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
Liam Girdwood0b708c82014-05-02 16:56:30 +0100674 SNDRV_DMA_TYPE_DEV_SG,
Liam Girdwood10df3502014-05-02 16:56:31 +0100675 dev,
Mark Browna4b12992014-03-12 23:04:35 +0000676 hsw_pcm_hardware.buffer_bytes_max,
677 hsw_pcm_hardware.buffer_bytes_max);
678 if (ret) {
679 dev_err(rtd->dev, "dma buffer allocation failed %d\n",
680 ret);
681 return ret;
682 }
683 }
684
685 return ret;
686}
687
688#define HSW_FORMATS \
689 (SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE |\
690 SNDRV_PCM_FMTBIT_S32_LE)
691
692static struct snd_soc_dai_driver hsw_dais[] = {
693 {
694 .name = "System Pin",
695 .playback = {
696 .stream_name = "System Playback",
697 .channels_min = 2,
698 .channels_max = 2,
699 .rates = SNDRV_PCM_RATE_48000,
700 .formats = SNDRV_PCM_FMTBIT_S16_LE,
701 },
702 },
703 {
704 /* PCM */
705 .name = "Offload0 Pin",
706 .playback = {
707 .stream_name = "Offload0 Playback",
708 .channels_min = 2,
709 .channels_max = 2,
710 .rates = SNDRV_PCM_RATE_8000_192000,
711 .formats = HSW_FORMATS,
712 },
713 },
714 {
715 /* PCM */
716 .name = "Offload1 Pin",
717 .playback = {
718 .stream_name = "Offload1 Playback",
719 .channels_min = 2,
720 .channels_max = 2,
721 .rates = SNDRV_PCM_RATE_8000_192000,
722 .formats = HSW_FORMATS,
723 },
724 },
725 {
726 .name = "Loopback Pin",
727 .capture = {
728 .stream_name = "Loopback Capture",
729 .channels_min = 2,
730 .channels_max = 2,
731 .rates = SNDRV_PCM_RATE_8000_192000,
732 .formats = HSW_FORMATS,
733 },
734 },
735 {
736 .name = "Capture Pin",
737 .capture = {
738 .stream_name = "Analog Capture",
739 .channels_min = 2,
740 .channels_max = 2,
741 .rates = SNDRV_PCM_RATE_8000_192000,
742 .formats = HSW_FORMATS,
743 },
744 },
745};
746
747static const struct snd_soc_dapm_widget widgets[] = {
748
749 /* Backend DAIs */
750 SND_SOC_DAPM_AIF_IN("SSP0 CODEC IN", NULL, 0, SND_SOC_NOPM, 0, 0),
751 SND_SOC_DAPM_AIF_OUT("SSP0 CODEC OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
752 SND_SOC_DAPM_AIF_IN("SSP1 BT IN", NULL, 0, SND_SOC_NOPM, 0, 0),
753 SND_SOC_DAPM_AIF_OUT("SSP1 BT OUT", NULL, 0, SND_SOC_NOPM, 0, 0),
754
755 /* Global Playback Mixer */
756 SND_SOC_DAPM_MIXER("Playback VMixer", SND_SOC_NOPM, 0, 0, NULL, 0),
757};
758
759static const struct snd_soc_dapm_route graph[] = {
760
761 /* Playback Mixer */
762 {"Playback VMixer", NULL, "System Playback"},
763 {"Playback VMixer", NULL, "Offload0 Playback"},
764 {"Playback VMixer", NULL, "Offload1 Playback"},
765
766 {"SSP0 CODEC OUT", NULL, "Playback VMixer"},
767
768 {"Analog Capture", NULL, "SSP0 CODEC IN"},
769};
770
771static int hsw_pcm_probe(struct snd_soc_platform *platform)
772{
773 struct sst_pdata *pdata = dev_get_platdata(platform->dev);
774 struct hsw_priv_data *priv_data;
Liam Girdwoode9024f0b2014-05-05 13:20:23 +0100775 struct device *dma_dev;
Liam Girdwood0b708c82014-05-02 16:56:30 +0100776 int i, ret = 0;
Mark Browna4b12992014-03-12 23:04:35 +0000777
778 if (!pdata)
779 return -ENODEV;
780
Liam Girdwoode9024f0b2014-05-05 13:20:23 +0100781 dma_dev = pdata->dma_dev;
782
Mark Browna4b12992014-03-12 23:04:35 +0000783 priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL);
784 priv_data->hsw = pdata->dsp;
785 snd_soc_platform_set_drvdata(platform, priv_data);
786
787 /* allocate DSP buffer page tables */
788 for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
789
790 mutex_init(&priv_data->pcm[i].mutex);
791
792 /* playback */
793 if (hsw_dais[i].playback.channels_min) {
Liam Girdwood0b708c82014-05-02 16:56:30 +0100794 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev,
795 PAGE_SIZE, &priv_data->dmab[i][0]);
796 if (ret < 0)
Mark Browna4b12992014-03-12 23:04:35 +0000797 goto err;
798 }
799
800 /* capture */
801 if (hsw_dais[i].capture.channels_min) {
Liam Girdwood0b708c82014-05-02 16:56:30 +0100802 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev,
803 PAGE_SIZE, &priv_data->dmab[i][1]);
804 if (ret < 0)
Mark Browna4b12992014-03-12 23:04:35 +0000805 goto err;
806 }
807 }
808
809 return 0;
810
811err:
812 for (;i >= 0; i--) {
813 if (hsw_dais[i].playback.channels_min)
Liam Girdwood0b708c82014-05-02 16:56:30 +0100814 snd_dma_free_pages(&priv_data->dmab[i][0]);
Mark Browna4b12992014-03-12 23:04:35 +0000815 if (hsw_dais[i].capture.channels_min)
Liam Girdwood0b708c82014-05-02 16:56:30 +0100816 snd_dma_free_pages(&priv_data->dmab[i][1]);
Mark Browna4b12992014-03-12 23:04:35 +0000817 }
Liam Girdwood0b708c82014-05-02 16:56:30 +0100818 return ret;
Mark Browna4b12992014-03-12 23:04:35 +0000819}
820
821static int hsw_pcm_remove(struct snd_soc_platform *platform)
822{
823 struct hsw_priv_data *priv_data =
824 snd_soc_platform_get_drvdata(platform);
825 int i;
826
827 for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
828 if (hsw_dais[i].playback.channels_min)
Liam Girdwood0b708c82014-05-02 16:56:30 +0100829 snd_dma_free_pages(&priv_data->dmab[i][0]);
Mark Browna4b12992014-03-12 23:04:35 +0000830 if (hsw_dais[i].capture.channels_min)
Liam Girdwood0b708c82014-05-02 16:56:30 +0100831 snd_dma_free_pages(&priv_data->dmab[i][1]);
Mark Browna4b12992014-03-12 23:04:35 +0000832 }
833
834 return 0;
835}
836
837static struct snd_soc_platform_driver hsw_soc_platform = {
838 .probe = hsw_pcm_probe,
839 .remove = hsw_pcm_remove,
840 .ops = &hsw_pcm_ops,
841 .pcm_new = hsw_pcm_new,
842 .pcm_free = hsw_pcm_free,
843 .controls = hsw_volume_controls,
844 .num_controls = ARRAY_SIZE(hsw_volume_controls),
845 .dapm_widgets = widgets,
846 .num_dapm_widgets = ARRAY_SIZE(widgets),
847 .dapm_routes = graph,
848 .num_dapm_routes = ARRAY_SIZE(graph),
849};
850
851static const struct snd_soc_component_driver hsw_dai_component = {
852 .name = "haswell-dai",
853};
854
855static int hsw_pcm_dev_probe(struct platform_device *pdev)
856{
857 struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
858 int ret;
859
860 ret = sst_hsw_dsp_init(&pdev->dev, sst_pdata);
861 if (ret < 0)
862 return -ENODEV;
863
864 ret = snd_soc_register_platform(&pdev->dev, &hsw_soc_platform);
865 if (ret < 0)
866 goto err_plat;
867
868 ret = snd_soc_register_component(&pdev->dev, &hsw_dai_component,
869 hsw_dais, ARRAY_SIZE(hsw_dais));
870 if (ret < 0)
871 goto err_comp;
872
873 return 0;
874
875err_comp:
876 snd_soc_unregister_platform(&pdev->dev);
877err_plat:
878 sst_hsw_dsp_free(&pdev->dev, sst_pdata);
879 return 0;
880}
881
882static int hsw_pcm_dev_remove(struct platform_device *pdev)
883{
884 struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev);
885
886 snd_soc_unregister_platform(&pdev->dev);
887 snd_soc_unregister_component(&pdev->dev);
888 sst_hsw_dsp_free(&pdev->dev, sst_pdata);
889
890 return 0;
891}
892
893static struct platform_driver hsw_pcm_driver = {
894 .driver = {
895 .name = "haswell-pcm-audio",
896 .owner = THIS_MODULE,
897 },
898
899 .probe = hsw_pcm_dev_probe,
900 .remove = hsw_pcm_dev_remove,
901};
902module_platform_driver(hsw_pcm_driver);
903
904MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");
905MODULE_DESCRIPTION("Haswell/Lynxpoint + Broadwell/Wildcatpoint PCM");
906MODULE_LICENSE("GPL v2");
907MODULE_ALIAS("platform:haswell-pcm-audio");