pcm.c (8c583f526ee9df5c6693f54ac272b7e103b5f1d2) | pcm.c (ee1e79b72e3cf5eac42ba9de827536f91d4c04e2) |
---|---|
1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 2// 3// This file is provided under a dual BSD/GPLv2 license. When using or 4// redistributing this file, you may do so under either license. 5// 6// Copyright(c) 2018 Intel Corporation. All rights reserved. 7// 8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> 9// 10// PCM Layer, interface between ALSA and IPC. 11// 12 13#include <linux/pm_runtime.h> 14#include <sound/pcm_params.h> 15#include <sound/sof.h> 16#include "sof-priv.h" | 1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 2// 3// This file is provided under a dual BSD/GPLv2 license. When using or 4// redistributing this file, you may do so under either license. 5// 6// Copyright(c) 2018 Intel Corporation. All rights reserved. 7// 8// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> 9// 10// PCM Layer, interface between ALSA and IPC. 11// 12 13#include <linux/pm_runtime.h> 14#include <sound/pcm_params.h> 15#include <sound/sof.h> 16#include "sof-priv.h" |
17#include "sof-audio.h" |
|
17#include "ops.h" 18 | 18#include "ops.h" 19 |
19#define DRV_NAME "sof-audio-component" 20 | |
21/* Create DMA buffer page table for DSP */ 22static int create_page_table(struct snd_soc_component *component, 23 struct snd_pcm_substream *substream, 24 unsigned char *dma_area, size_t size) 25{ 26 struct snd_soc_pcm_runtime *rtd = substream->private_data; | 20/* Create DMA buffer page table for DSP */ 21static int create_page_table(struct snd_soc_component *component, 22 struct snd_pcm_substream *substream, 23 unsigned char *dma_area, size_t size) 24{ 25 struct snd_soc_pcm_runtime *rtd = substream->private_data; |
27 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); | |
28 struct snd_sof_pcm *spcm; 29 struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream); 30 int stream = substream->stream; 31 | 26 struct snd_sof_pcm *spcm; 27 struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream); 28 int stream = substream->stream; 29 |
32 spcm = snd_sof_find_spcm_dai(sdev, rtd); | 30 spcm = snd_sof_find_spcm_dai(component, rtd); |
33 if (!spcm) 34 return -EINVAL; 35 | 31 if (!spcm) 32 return -EINVAL; 33 |
36 return snd_sof_create_page_table(sdev->dev, dmab, | 34 return snd_sof_create_page_table(component->dev, dmab, |
37 spcm->stream[stream].page_table.area, size); 38} 39 40static int sof_pcm_dsp_params(struct snd_sof_pcm *spcm, struct snd_pcm_substream *substream, 41 const struct sof_ipc_pcm_params_reply *reply) 42{ | 35 spcm->stream[stream].page_table.area, size); 36} 37 38static int sof_pcm_dsp_params(struct snd_sof_pcm *spcm, struct snd_pcm_substream *substream, 39 const struct sof_ipc_pcm_params_reply *reply) 40{ |
43 struct snd_sof_dev *sdev = spcm->sdev; | 41 struct snd_soc_component *scomp = spcm->scomp; 42 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 43 |
44 /* validate offset */ 45 int ret = snd_sof_ipc_pcm_params(sdev, substream, reply); 46 47 if (ret < 0) | 44 /* validate offset */ 45 int ret = snd_sof_ipc_pcm_params(sdev, substream, reply); 46 47 if (ret < 0) |
48 dev_err(sdev->dev, "error: got wrong reply for PCM %d\n", | 48 dev_err(scomp->dev, "error: got wrong reply for PCM %d\n", |
49 spcm->pcm.pcm_id); 50 51 return ret; 52} 53 54/* 55 * sof pcm period elapse work 56 */ --- 8 unchanged lines hidden (view full) --- 65 66/* 67 * sof pcm period elapse, this could be called at irq thread context. 68 */ 69void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream) 70{ 71 struct snd_soc_pcm_runtime *rtd = substream->private_data; 72 struct snd_soc_component *component = | 49 spcm->pcm.pcm_id); 50 51 return ret; 52} 53 54/* 55 * sof pcm period elapse work 56 */ --- 8 unchanged lines hidden (view full) --- 65 66/* 67 * sof pcm period elapse, this could be called at irq thread context. 68 */ 69void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream) 70{ 71 struct snd_soc_pcm_runtime *rtd = substream->private_data; 72 struct snd_soc_component *component = |
73 snd_soc_rtdcom_lookup(rtd, DRV_NAME); 74 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); | 73 snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); |
75 struct snd_sof_pcm *spcm; 76 | 74 struct snd_sof_pcm *spcm; 75 |
77 spcm = snd_sof_find_spcm_dai(sdev, rtd); | 76 spcm = snd_sof_find_spcm_dai(component, rtd); |
78 if (!spcm) { | 77 if (!spcm) { |
79 dev_err(sdev->dev, | 78 dev_err(component->dev, |
80 "error: period elapsed for unknown stream!\n"); 81 return; 82 } 83 84 /* 85 * snd_pcm_period_elapsed() can be called in interrupt context 86 * before IRQ_HANDLED is returned. Inside snd_pcm_period_elapsed(), 87 * when the PCM is done draining or xrun happened, a STOP IPC will --- 17 unchanged lines hidden (view full) --- 105 struct sof_ipc_pcm_params pcm; 106 struct sof_ipc_pcm_params_reply ipc_params_reply; 107 int ret; 108 109 /* nothing to do for BE */ 110 if (rtd->dai_link->no_pcm) 111 return 0; 112 | 79 "error: period elapsed for unknown stream!\n"); 80 return; 81 } 82 83 /* 84 * snd_pcm_period_elapsed() can be called in interrupt context 85 * before IRQ_HANDLED is returned. Inside snd_pcm_period_elapsed(), 86 * when the PCM is done draining or xrun happened, a STOP IPC will --- 17 unchanged lines hidden (view full) --- 104 struct sof_ipc_pcm_params pcm; 105 struct sof_ipc_pcm_params_reply ipc_params_reply; 106 int ret; 107 108 /* nothing to do for BE */ 109 if (rtd->dai_link->no_pcm) 110 return 0; 111 |
113 spcm = snd_sof_find_spcm_dai(sdev, rtd); | 112 spcm = snd_sof_find_spcm_dai(component, rtd); |
114 if (!spcm) 115 return -EINVAL; 116 | 113 if (!spcm) 114 return -EINVAL; 115 |
117 dev_dbg(sdev->dev, "pcm: hw params stream %d dir %d\n", | 116 dev_dbg(component->dev, "pcm: hw params stream %d dir %d\n", |
118 spcm->pcm.pcm_id, substream->stream); 119 120 memset(&pcm, 0, sizeof(pcm)); 121 122 /* allocate audio buffer pages */ 123 ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); 124 if (ret < 0) { | 117 spcm->pcm.pcm_id, substream->stream); 118 119 memset(&pcm, 0, sizeof(pcm)); 120 121 /* allocate audio buffer pages */ 122 ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); 123 if (ret < 0) { |
125 dev_err(sdev->dev, "error: could not allocate %d bytes for PCM %d\n", | 124 dev_err(component->dev, "error: could not allocate %d bytes for PCM %d\n", |
126 params_buffer_bytes(params), spcm->pcm.pcm_id); 127 return ret; 128 } 129 if (ret) { 130 /* 131 * ret == 1 means the buffer is changed 132 * create compressed page table for audio firmware 133 * ret == 0 means the buffer is not changed --- 48 unchanged lines hidden (view full) --- 182 } 183 184 /* firmware already configured host stream */ 185 ret = snd_sof_pcm_platform_hw_params(sdev, 186 substream, 187 params, 188 &pcm.params); 189 if (ret < 0) { | 125 params_buffer_bytes(params), spcm->pcm.pcm_id); 126 return ret; 127 } 128 if (ret) { 129 /* 130 * ret == 1 means the buffer is changed 131 * create compressed page table for audio firmware 132 * ret == 0 means the buffer is not changed --- 48 unchanged lines hidden (view full) --- 181 } 182 183 /* firmware already configured host stream */ 184 ret = snd_sof_pcm_platform_hw_params(sdev, 185 substream, 186 params, 187 &pcm.params); 188 if (ret < 0) { |
190 dev_err(sdev->dev, "error: platform hw params failed\n"); | 189 dev_err(component->dev, "error: platform hw params failed\n"); |
191 return ret; 192 } 193 | 190 return ret; 191 } 192 |
194 dev_dbg(sdev->dev, "stream_tag %d", pcm.params.stream_tag); | 193 dev_dbg(component->dev, "stream_tag %d", pcm.params.stream_tag); |
195 196 /* send IPC to the DSP */ 197 ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm), 198 &ipc_params_reply, sizeof(ipc_params_reply)); 199 if (ret < 0) { | 194 195 /* send IPC to the DSP */ 196 ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm), 197 &ipc_params_reply, sizeof(ipc_params_reply)); 198 if (ret < 0) { |
200 dev_err(sdev->dev, "error: hw params ipc failed for stream %d\n", | 199 dev_err(component->dev, "error: hw params ipc failed for stream %d\n", |
201 pcm.params.stream_tag); 202 return ret; 203 } 204 205 ret = sof_pcm_dsp_params(spcm, substream, &ipc_params_reply); 206 if (ret < 0) 207 return ret; 208 --- 33 unchanged lines hidden (view full) --- 242 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); 243 struct snd_sof_pcm *spcm; 244 int ret, err = 0; 245 246 /* nothing to do for BE */ 247 if (rtd->dai_link->no_pcm) 248 return 0; 249 | 200 pcm.params.stream_tag); 201 return ret; 202 } 203 204 ret = sof_pcm_dsp_params(spcm, substream, &ipc_params_reply); 205 if (ret < 0) 206 return ret; 207 --- 33 unchanged lines hidden (view full) --- 241 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); 242 struct snd_sof_pcm *spcm; 243 int ret, err = 0; 244 245 /* nothing to do for BE */ 246 if (rtd->dai_link->no_pcm) 247 return 0; 248 |
250 spcm = snd_sof_find_spcm_dai(sdev, rtd); | 249 spcm = snd_sof_find_spcm_dai(component, rtd); |
251 if (!spcm) 252 return -EINVAL; 253 | 250 if (!spcm) 251 return -EINVAL; 252 |
254 dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id, 255 substream->stream); | 253 dev_dbg(component->dev, "pcm: free stream %d dir %d\n", 254 spcm->pcm.pcm_id, substream->stream); |
256 257 if (spcm->prepared[substream->stream]) { 258 ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); 259 if (ret < 0) 260 err = ret; 261 } 262 263 snd_pcm_lib_free_pages(substream); 264 265 cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work); 266 267 ret = snd_sof_pcm_platform_hw_free(sdev, substream); 268 if (ret < 0) { | 255 256 if (spcm->prepared[substream->stream]) { 257 ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm); 258 if (ret < 0) 259 err = ret; 260 } 261 262 snd_pcm_lib_free_pages(substream); 263 264 cancel_work_sync(&spcm->stream[substream->stream].period_elapsed_work); 265 266 ret = snd_sof_pcm_platform_hw_free(sdev, substream); 267 if (ret < 0) { |
269 dev_err(sdev->dev, "error: platform hw free failed\n"); | 268 dev_err(component->dev, "error: platform hw free failed\n"); |
270 err = ret; 271 } 272 273 return err; 274} 275 276static int sof_pcm_prepare(struct snd_soc_component *component, 277 struct snd_pcm_substream *substream) 278{ 279 struct snd_soc_pcm_runtime *rtd = substream->private_data; | 269 err = ret; 270 } 271 272 return err; 273} 274 275static int sof_pcm_prepare(struct snd_soc_component *component, 276 struct snd_pcm_substream *substream) 277{ 278 struct snd_soc_pcm_runtime *rtd = substream->private_data; |
280 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); | |
281 struct snd_sof_pcm *spcm; 282 int ret; 283 284 /* nothing to do for BE */ 285 if (rtd->dai_link->no_pcm) 286 return 0; 287 | 279 struct snd_sof_pcm *spcm; 280 int ret; 281 282 /* nothing to do for BE */ 283 if (rtd->dai_link->no_pcm) 284 return 0; 285 |
288 spcm = snd_sof_find_spcm_dai(sdev, rtd); | 286 spcm = snd_sof_find_spcm_dai(component, rtd); |
289 if (!spcm) 290 return -EINVAL; 291 292 if (spcm->prepared[substream->stream]) 293 return 0; 294 | 287 if (!spcm) 288 return -EINVAL; 289 290 if (spcm->prepared[substream->stream]) 291 return 0; 292 |
295 dev_dbg(sdev->dev, "pcm: prepare stream %d dir %d\n", spcm->pcm.pcm_id, 296 substream->stream); | 293 dev_dbg(component->dev, "pcm: prepare stream %d dir %d\n", 294 spcm->pcm.pcm_id, substream->stream); |
297 298 /* set hw_params */ 299 ret = sof_pcm_hw_params(component, 300 substream, &spcm->params[substream->stream]); 301 if (ret < 0) { | 295 296 /* set hw_params */ 297 ret = sof_pcm_hw_params(component, 298 substream, &spcm->params[substream->stream]); 299 if (ret < 0) { |
302 dev_err(sdev->dev, "error: set pcm hw_params after resume\n"); | 300 dev_err(component->dev, 301 "error: set pcm hw_params after resume\n"); |
303 return ret; 304 } 305 306 return 0; 307} 308 309/* 310 * FE dai link trigger actions are always executed in non-atomic context because --- 10 unchanged lines hidden (view full) --- 321 bool reset_hw_params = false; 322 bool ipc_first = false; 323 int ret; 324 325 /* nothing to do for BE */ 326 if (rtd->dai_link->no_pcm) 327 return 0; 328 | 302 return ret; 303 } 304 305 return 0; 306} 307 308/* 309 * FE dai link trigger actions are always executed in non-atomic context because --- 10 unchanged lines hidden (view full) --- 320 bool reset_hw_params = false; 321 bool ipc_first = false; 322 int ret; 323 324 /* nothing to do for BE */ 325 if (rtd->dai_link->no_pcm) 326 return 0; 327 |
329 spcm = snd_sof_find_spcm_dai(sdev, rtd); | 328 spcm = snd_sof_find_spcm_dai(component, rtd); |
330 if (!spcm) 331 return -EINVAL; 332 | 329 if (!spcm) 330 return -EINVAL; 331 |
333 dev_dbg(sdev->dev, "pcm: trigger stream %d dir %d cmd %d\n", | 332 dev_dbg(component->dev, "pcm: trigger stream %d dir %d cmd %d\n", |
334 spcm->pcm.pcm_id, substream->stream, cmd); 335 336 stream.hdr.size = sizeof(stream); 337 stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG; 338 stream.comp_id = spcm->stream[substream->stream].comp_id; 339 340 switch (cmd) { 341 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: --- 12 unchanged lines hidden (view full) --- 354 */ 355 spcm->stream[substream->stream].suspend_ignored = false; 356 return 0; 357 } 358 359 /* set up hw_params */ 360 ret = sof_pcm_prepare(component, substream); 361 if (ret < 0) { | 333 spcm->pcm.pcm_id, substream->stream, cmd); 334 335 stream.hdr.size = sizeof(stream); 336 stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG; 337 stream.comp_id = spcm->stream[substream->stream].comp_id; 338 339 switch (cmd) { 340 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: --- 12 unchanged lines hidden (view full) --- 353 */ 354 spcm->stream[substream->stream].suspend_ignored = false; 355 return 0; 356 } 357 358 /* set up hw_params */ 359 ret = sof_pcm_prepare(component, substream); 360 if (ret < 0) { |
362 dev_err(sdev->dev, | 361 dev_err(component->dev, |
363 "error: failed to set up hw_params upon resume\n"); 364 return ret; 365 } 366 367 /* fallthrough */ 368 case SNDRV_PCM_TRIGGER_START: 369 if (spcm->stream[substream->stream].suspend_ignored) { 370 /* --- 20 unchanged lines hidden (view full) --- 391 } 392 /* fallthrough */ 393 case SNDRV_PCM_TRIGGER_STOP: 394 stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP; 395 ipc_first = true; 396 reset_hw_params = true; 397 break; 398 default: | 362 "error: failed to set up hw_params upon resume\n"); 363 return ret; 364 } 365 366 /* fallthrough */ 367 case SNDRV_PCM_TRIGGER_START: 368 if (spcm->stream[substream->stream].suspend_ignored) { 369 /* --- 20 unchanged lines hidden (view full) --- 390 } 391 /* fallthrough */ 392 case SNDRV_PCM_TRIGGER_STOP: 393 stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP; 394 ipc_first = true; 395 reset_hw_params = true; 396 break; 397 default: |
399 dev_err(sdev->dev, "error: unhandled trigger cmd %d\n", cmd); | 398 dev_err(component->dev, "error: unhandled trigger cmd %d\n", 399 cmd); |
400 return -EINVAL; 401 } 402 403 /* 404 * DMA and IPC sequence is different for start and stop. Need to send 405 * STOP IPC before stop DMA 406 */ 407 if (!ipc_first) --- 25 unchanged lines hidden (view full) --- 433 /* nothing to do for BE */ 434 if (rtd->dai_link->no_pcm) 435 return 0; 436 437 /* use dsp ops pointer callback directly if set */ 438 if (sof_ops(sdev)->pcm_pointer) 439 return sof_ops(sdev)->pcm_pointer(sdev, substream); 440 | 400 return -EINVAL; 401 } 402 403 /* 404 * DMA and IPC sequence is different for start and stop. Need to send 405 * STOP IPC before stop DMA 406 */ 407 if (!ipc_first) --- 25 unchanged lines hidden (view full) --- 433 /* nothing to do for BE */ 434 if (rtd->dai_link->no_pcm) 435 return 0; 436 437 /* use dsp ops pointer callback directly if set */ 438 if (sof_ops(sdev)->pcm_pointer) 439 return sof_ops(sdev)->pcm_pointer(sdev, substream); 440 |
441 spcm = snd_sof_find_spcm_dai(sdev, rtd); | 441 spcm = snd_sof_find_spcm_dai(component, rtd); |
442 if (!spcm) 443 return -EINVAL; 444 445 /* read position from DSP */ 446 host = bytes_to_frames(substream->runtime, 447 spcm->stream[substream->stream].posn.host_posn); 448 dai = bytes_to_frames(substream->runtime, 449 spcm->stream[substream->stream].posn.dai_posn); 450 | 442 if (!spcm) 443 return -EINVAL; 444 445 /* read position from DSP */ 446 host = bytes_to_frames(substream->runtime, 447 spcm->stream[substream->stream].posn.host_posn); 448 dai = bytes_to_frames(substream->runtime, 449 spcm->stream[substream->stream].posn.dai_posn); 450 |
451 dev_dbg(sdev->dev, "PCM: stream %d dir %d DMA position %lu DAI position %lu\n", | 451 dev_dbg(component->dev, 452 "PCM: stream %d dir %d DMA position %lu DAI position %lu\n", |
452 spcm->pcm.pcm_id, substream->stream, host, dai); 453 454 return host; 455} 456 457static int sof_pcm_open(struct snd_soc_component *component, 458 struct snd_pcm_substream *substream) 459{ --- 4 unchanged lines hidden (view full) --- 464 struct snd_sof_pcm *spcm; 465 struct snd_soc_tplg_stream_caps *caps; 466 int ret; 467 468 /* nothing to do for BE */ 469 if (rtd->dai_link->no_pcm) 470 return 0; 471 | 453 spcm->pcm.pcm_id, substream->stream, host, dai); 454 455 return host; 456} 457 458static int sof_pcm_open(struct snd_soc_component *component, 459 struct snd_pcm_substream *substream) 460{ --- 4 unchanged lines hidden (view full) --- 465 struct snd_sof_pcm *spcm; 466 struct snd_soc_tplg_stream_caps *caps; 467 int ret; 468 469 /* nothing to do for BE */ 470 if (rtd->dai_link->no_pcm) 471 return 0; 472 |
472 spcm = snd_sof_find_spcm_dai(sdev, rtd); | 473 spcm = snd_sof_find_spcm_dai(component, rtd); |
473 if (!spcm) 474 return -EINVAL; 475 | 474 if (!spcm) 475 return -EINVAL; 476 |
476 dev_dbg(sdev->dev, "pcm: open stream %d dir %d\n", spcm->pcm.pcm_id, 477 substream->stream); | 477 dev_dbg(component->dev, "pcm: open stream %d dir %d\n", 478 spcm->pcm.pcm_id, substream->stream); |
478 479 INIT_WORK(&spcm->stream[substream->stream].period_elapsed_work, 480 sof_pcm_period_elapsed_work); 481 482 caps = &spcm->pcm.caps[substream->stream]; 483 484 /* set any runtime constraints based on topology */ 485 snd_pcm_hw_constraint_step(substream->runtime, 0, --- 13 unchanged lines hidden (view full) --- 499 runtime->hw.periods_max = le32_to_cpu(caps->periods_max); 500 501 /* 502 * caps->buffer_size_min is not used since the 503 * snd_pcm_hardware structure only defines buffer_bytes_max 504 */ 505 runtime->hw.buffer_bytes_max = le32_to_cpu(caps->buffer_size_max); 506 | 479 480 INIT_WORK(&spcm->stream[substream->stream].period_elapsed_work, 481 sof_pcm_period_elapsed_work); 482 483 caps = &spcm->pcm.caps[substream->stream]; 484 485 /* set any runtime constraints based on topology */ 486 snd_pcm_hw_constraint_step(substream->runtime, 0, --- 13 unchanged lines hidden (view full) --- 500 runtime->hw.periods_max = le32_to_cpu(caps->periods_max); 501 502 /* 503 * caps->buffer_size_min is not used since the 504 * snd_pcm_hardware structure only defines buffer_bytes_max 505 */ 506 runtime->hw.buffer_bytes_max = le32_to_cpu(caps->buffer_size_max); 507 |
507 dev_dbg(sdev->dev, "period min %zd max %zd bytes\n", | 508 dev_dbg(component->dev, "period min %zd max %zd bytes\n", |
508 runtime->hw.period_bytes_min, 509 runtime->hw.period_bytes_max); | 509 runtime->hw.period_bytes_min, 510 runtime->hw.period_bytes_max); |
510 dev_dbg(sdev->dev, "period count %d max %d\n", | 511 dev_dbg(component->dev, "period count %d max %d\n", |
511 runtime->hw.periods_min, 512 runtime->hw.periods_max); | 512 runtime->hw.periods_min, 513 runtime->hw.periods_max); |
513 dev_dbg(sdev->dev, "buffer max %zd bytes\n", | 514 dev_dbg(component->dev, "buffer max %zd bytes\n", |
514 runtime->hw.buffer_bytes_max); 515 516 /* set wait time - TODO: come from topology */ 517 substream->wait_time = 500; 518 519 spcm->stream[substream->stream].posn.host_posn = 0; 520 spcm->stream[substream->stream].posn.dai_posn = 0; 521 spcm->stream[substream->stream].substream = substream; 522 spcm->prepared[substream->stream] = false; 523 524 ret = snd_sof_pcm_platform_open(sdev, substream); 525 if (ret < 0) | 515 runtime->hw.buffer_bytes_max); 516 517 /* set wait time - TODO: come from topology */ 518 substream->wait_time = 500; 519 520 spcm->stream[substream->stream].posn.host_posn = 0; 521 spcm->stream[substream->stream].posn.dai_posn = 0; 522 spcm->stream[substream->stream].substream = substream; 523 spcm->prepared[substream->stream] = false; 524 525 ret = snd_sof_pcm_platform_open(sdev, substream); 526 if (ret < 0) |
526 dev_err(sdev->dev, "error: pcm open failed %d\n", ret); | 527 dev_err(component->dev, "error: pcm open failed %d\n", ret); |
527 528 return ret; 529} 530 531static int sof_pcm_close(struct snd_soc_component *component, 532 struct snd_pcm_substream *substream) 533{ 534 struct snd_soc_pcm_runtime *rtd = substream->private_data; 535 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); 536 struct snd_sof_pcm *spcm; 537 int err; 538 539 /* nothing to do for BE */ 540 if (rtd->dai_link->no_pcm) 541 return 0; 542 | 528 529 return ret; 530} 531 532static int sof_pcm_close(struct snd_soc_component *component, 533 struct snd_pcm_substream *substream) 534{ 535 struct snd_soc_pcm_runtime *rtd = substream->private_data; 536 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); 537 struct snd_sof_pcm *spcm; 538 int err; 539 540 /* nothing to do for BE */ 541 if (rtd->dai_link->no_pcm) 542 return 0; 543 |
543 spcm = snd_sof_find_spcm_dai(sdev, rtd); | 544 spcm = snd_sof_find_spcm_dai(component, rtd); |
544 if (!spcm) 545 return -EINVAL; 546 | 545 if (!spcm) 546 return -EINVAL; 547 |
547 dev_dbg(sdev->dev, "pcm: close stream %d dir %d\n", spcm->pcm.pcm_id, 548 substream->stream); | 548 dev_dbg(component->dev, "pcm: close stream %d dir %d\n", 549 spcm->pcm.pcm_id, substream->stream); |
549 550 err = snd_sof_pcm_platform_close(sdev, substream); 551 if (err < 0) { | 550 551 err = snd_sof_pcm_platform_close(sdev, substream); 552 if (err < 0) { |
552 dev_err(sdev->dev, "error: pcm close failed %d\n", | 553 dev_err(component->dev, "error: pcm close failed %d\n", |
553 err); 554 /* 555 * keep going, no point in preventing the close 556 * from happening 557 */ 558 } 559 560 return 0; --- 9 unchanged lines hidden (view full) --- 570{ 571 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); 572 struct snd_sof_pcm *spcm; 573 struct snd_pcm *pcm = rtd->pcm; 574 struct snd_soc_tplg_stream_caps *caps; 575 int stream = SNDRV_PCM_STREAM_PLAYBACK; 576 577 /* find SOF PCM for this RTD */ | 554 err); 555 /* 556 * keep going, no point in preventing the close 557 * from happening 558 */ 559 } 560 561 return 0; --- 9 unchanged lines hidden (view full) --- 571{ 572 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); 573 struct snd_sof_pcm *spcm; 574 struct snd_pcm *pcm = rtd->pcm; 575 struct snd_soc_tplg_stream_caps *caps; 576 int stream = SNDRV_PCM_STREAM_PLAYBACK; 577 578 /* find SOF PCM for this RTD */ |
578 spcm = snd_sof_find_spcm_dai(sdev, rtd); | 579 spcm = snd_sof_find_spcm_dai(component, rtd); |
579 if (!spcm) { | 580 if (!spcm) { |
580 dev_warn(sdev->dev, "warn: can't find PCM with DAI ID %d\n", | 581 dev_warn(component->dev, "warn: can't find PCM with DAI ID %d\n", |
581 rtd->dai_link->id); 582 return 0; 583 } 584 | 582 rtd->dai_link->id); 583 return 0; 584 } 585 |
585 dev_dbg(sdev->dev, "creating new PCM %s\n", spcm->pcm.pcm_name); | 586 dev_dbg(component->dev, "creating new PCM %s\n", spcm->pcm.pcm_name); |
586 587 /* do we need to pre-allocate playback audio buffer pages */ 588 if (!spcm->pcm.playback) 589 goto capture; 590 591 caps = &spcm->pcm.caps[stream]; 592 593 /* pre-allocate playback audio buffer pages */ | 587 588 /* do we need to pre-allocate playback audio buffer pages */ 589 if (!spcm->pcm.playback) 590 goto capture; 591 592 caps = &spcm->pcm.caps[stream]; 593 594 /* pre-allocate playback audio buffer pages */ |
594 dev_dbg(sdev->dev, "spcm: allocate %s playback DMA buffer size 0x%x max 0x%x\n", | 595 dev_dbg(component->dev, 596 "spcm: allocate %s playback DMA buffer size 0x%x max 0x%x\n", |
595 caps->name, caps->buffer_size_min, caps->buffer_size_max); 596 597 snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream, 598 SNDRV_DMA_TYPE_DEV_SG, sdev->dev, 599 le32_to_cpu(caps->buffer_size_min), 600 le32_to_cpu(caps->buffer_size_max)); 601capture: 602 stream = SNDRV_PCM_STREAM_CAPTURE; 603 604 /* do we need to pre-allocate capture audio buffer pages */ 605 if (!spcm->pcm.capture) 606 return 0; 607 608 caps = &spcm->pcm.caps[stream]; 609 610 /* pre-allocate capture audio buffer pages */ | 597 caps->name, caps->buffer_size_min, caps->buffer_size_max); 598 599 snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream, 600 SNDRV_DMA_TYPE_DEV_SG, sdev->dev, 601 le32_to_cpu(caps->buffer_size_min), 602 le32_to_cpu(caps->buffer_size_max)); 603capture: 604 stream = SNDRV_PCM_STREAM_CAPTURE; 605 606 /* do we need to pre-allocate capture audio buffer pages */ 607 if (!spcm->pcm.capture) 608 return 0; 609 610 caps = &spcm->pcm.caps[stream]; 611 612 /* pre-allocate capture audio buffer pages */ |
611 dev_dbg(sdev->dev, "spcm: allocate %s capture DMA buffer size 0x%x max 0x%x\n", | 613 dev_dbg(component->dev, 614 "spcm: allocate %s capture DMA buffer size 0x%x max 0x%x\n", |
612 caps->name, caps->buffer_size_min, caps->buffer_size_max); 613 614 snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream, 615 SNDRV_DMA_TYPE_DEV_SG, sdev->dev, 616 le32_to_cpu(caps->buffer_size_min), 617 le32_to_cpu(caps->buffer_size_max)); 618 619 return 0; --- 4 unchanged lines hidden (view full) --- 624 struct snd_pcm_hw_params *params) 625{ 626 struct snd_interval *rate = hw_param_interval(params, 627 SNDRV_PCM_HW_PARAM_RATE); 628 struct snd_interval *channels = hw_param_interval(params, 629 SNDRV_PCM_HW_PARAM_CHANNELS); 630 struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 631 struct snd_soc_component *component = | 615 caps->name, caps->buffer_size_min, caps->buffer_size_max); 616 617 snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream, 618 SNDRV_DMA_TYPE_DEV_SG, sdev->dev, 619 le32_to_cpu(caps->buffer_size_min), 620 le32_to_cpu(caps->buffer_size_max)); 621 622 return 0; --- 4 unchanged lines hidden (view full) --- 627 struct snd_pcm_hw_params *params) 628{ 629 struct snd_interval *rate = hw_param_interval(params, 630 SNDRV_PCM_HW_PARAM_RATE); 631 struct snd_interval *channels = hw_param_interval(params, 632 SNDRV_PCM_HW_PARAM_CHANNELS); 633 struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 634 struct snd_soc_component *component = |
632 snd_soc_rtdcom_lookup(rtd, DRV_NAME); 633 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); | 635 snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); |
634 struct snd_sof_dai *dai = | 636 struct snd_sof_dai *dai = |
635 snd_sof_find_dai(sdev, (char *)rtd->dai_link->name); | 637 snd_sof_find_dai(component, (char *)rtd->dai_link->name); |
636 637 /* no topology exists for this BE, try a common configuration */ 638 if (!dai) { | 638 639 /* no topology exists for this BE, try a common configuration */ 640 if (!dai) { |
639 dev_warn(sdev->dev, "warning: no topology found for BE DAI %s config\n", | 641 dev_warn(component->dev, 642 "warning: no topology found for BE DAI %s config\n", |
640 rtd->dai_link->name); 641 642 /* set 48k, stereo, 16bits by default */ 643 rate->min = 48000; 644 rate->max = 48000; 645 646 channels->min = 2; 647 channels->max = 2; --- 13 unchanged lines hidden (view full) --- 661 break; 662 case SOF_IPC_FRAME_S24_4LE: 663 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); 664 break; 665 case SOF_IPC_FRAME_S32_LE: 666 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); 667 break; 668 default: | 643 rtd->dai_link->name); 644 645 /* set 48k, stereo, 16bits by default */ 646 rate->min = 48000; 647 rate->max = 48000; 648 649 channels->min = 2; 650 channels->max = 2; --- 13 unchanged lines hidden (view full) --- 664 break; 665 case SOF_IPC_FRAME_S24_4LE: 666 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); 667 break; 668 case SOF_IPC_FRAME_S32_LE: 669 snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); 670 break; 671 default: |
669 dev_err(sdev->dev, "error: No available DAI format!\n"); | 672 dev_err(component->dev, "error: No available DAI format!\n"); |
670 return -EINVAL; 671 } 672 673 /* read rate and channels from topology */ 674 switch (dai->dai_config->type) { 675 case SOF_DAI_INTEL_SSP: 676 rate->min = dai->dai_config->ssp.fsync_rate; 677 rate->max = dai->dai_config->ssp.fsync_rate; 678 channels->min = dai->dai_config->ssp.tdm_slots; 679 channels->max = dai->dai_config->ssp.tdm_slots; 680 | 673 return -EINVAL; 674 } 675 676 /* read rate and channels from topology */ 677 switch (dai->dai_config->type) { 678 case SOF_DAI_INTEL_SSP: 679 rate->min = dai->dai_config->ssp.fsync_rate; 680 rate->max = dai->dai_config->ssp.fsync_rate; 681 channels->min = dai->dai_config->ssp.tdm_slots; 682 channels->max = dai->dai_config->ssp.tdm_slots; 683 |
681 dev_dbg(sdev->dev, | 684 dev_dbg(component->dev, |
682 "rate_min: %d rate_max: %d\n", rate->min, rate->max); | 685 "rate_min: %d rate_max: %d\n", rate->min, rate->max); |
683 dev_dbg(sdev->dev, | 686 dev_dbg(component->dev, |
684 "channels_min: %d channels_max: %d\n", 685 channels->min, channels->max); 686 687 break; 688 case SOF_DAI_INTEL_DMIC: 689 /* DMIC only supports 16 or 32 bit formats */ 690 if (dai->comp_dai.config.frame_fmt == SOF_IPC_FRAME_S24_4LE) { | 687 "channels_min: %d channels_max: %d\n", 688 channels->min, channels->max); 689 690 break; 691 case SOF_DAI_INTEL_DMIC: 692 /* DMIC only supports 16 or 32 bit formats */ 693 if (dai->comp_dai.config.frame_fmt == SOF_IPC_FRAME_S24_4LE) { |
691 dev_err(sdev->dev, | 694 dev_err(component->dev, |
692 "error: invalid fmt %d for DAI type %d\n", 693 dai->comp_dai.config.frame_fmt, 694 dai->dai_config->type); 695 } 696 break; 697 case SOF_DAI_INTEL_HDA: 698 /* do nothing for HDA dai_link */ 699 break; 700 case SOF_DAI_INTEL_ALH: 701 /* do nothing for ALH dai_link */ 702 break; 703 case SOF_DAI_IMX_ESAI: 704 channels->min = dai->dai_config->esai.tdm_slots; 705 channels->max = dai->dai_config->esai.tdm_slots; 706 | 695 "error: invalid fmt %d for DAI type %d\n", 696 dai->comp_dai.config.frame_fmt, 697 dai->dai_config->type); 698 } 699 break; 700 case SOF_DAI_INTEL_HDA: 701 /* do nothing for HDA dai_link */ 702 break; 703 case SOF_DAI_INTEL_ALH: 704 /* do nothing for ALH dai_link */ 705 break; 706 case SOF_DAI_IMX_ESAI: 707 channels->min = dai->dai_config->esai.tdm_slots; 708 channels->max = dai->dai_config->esai.tdm_slots; 709 |
707 dev_dbg(sdev->dev, | 710 dev_dbg(component->dev, |
708 "channels_min: %d channels_max: %d\n", 709 channels->min, channels->max); 710 break; 711 default: | 711 "channels_min: %d channels_max: %d\n", 712 channels->min, channels->max); 713 break; 714 default: |
712 dev_err(sdev->dev, "error: invalid DAI type %d\n", | 715 dev_err(component->dev, "error: invalid DAI type %d\n", |
713 dai->dai_config->type); 714 break; 715 } 716 717 return 0; 718} 719 720static int sof_pcm_probe(struct snd_soc_component *component) --- 8 unchanged lines hidden (view full) --- 729 730 tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, 731 "%s/%s", 732 plat_data->tplg_filename_prefix, 733 plat_data->tplg_filename); 734 if (!tplg_filename) 735 return -ENOMEM; 736 | 716 dai->dai_config->type); 717 break; 718 } 719 720 return 0; 721} 722 723static int sof_pcm_probe(struct snd_soc_component *component) --- 8 unchanged lines hidden (view full) --- 732 733 tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, 734 "%s/%s", 735 plat_data->tplg_filename_prefix, 736 plat_data->tplg_filename); 737 if (!tplg_filename) 738 return -ENOMEM; 739 |
737 ret = snd_sof_load_topology(sdev, tplg_filename); | 740 ret = snd_sof_load_topology(component, tplg_filename); |
738 if (ret < 0) { | 741 if (ret < 0) { |
739 dev_err(sdev->dev, "error: failed to load DSP topology %d\n", | 742 dev_err(component->dev, "error: failed to load DSP topology %d\n", |
740 ret); 741 return ret; 742 } 743 744 return ret; 745} 746 747static void sof_pcm_remove(struct snd_soc_component *component) --- 38 unchanged lines hidden --- | 743 ret); 744 return ret; 745 } 746 747 return ret; 748} 749 750static void sof_pcm_remove(struct snd_soc_component *component) --- 38 unchanged lines hidden --- |