hda-probes.c (4430B)
1// SPDX-License-Identifier: (GPL-2.0-only 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) 2019-2021 Intel Corporation. All rights reserved. 7// 8// Author: Cezary Rojewski <cezary.rojewski@intel.com> 9// Converted to SOF client: 10// Ranjani Sridharan <ranjani.sridharan@linux.intel.com> 11// Peter Ujfalusi <peter.ujfalusi@linux.intel.com> 12// 13 14#include <linux/module.h> 15#include <sound/hdaudio_ext.h> 16#include <sound/soc.h> 17#include "../sof-priv.h" 18#include "../sof-client-probes.h" 19#include "../sof-client.h" 20#include "hda.h" 21 22static inline struct hdac_ext_stream * 23hda_compr_get_stream(struct snd_compr_stream *cstream) 24{ 25 return cstream->runtime->private_data; 26} 27 28static int hda_probes_compr_assign(struct sof_client_dev *cdev, 29 struct snd_compr_stream *cstream, 30 struct snd_soc_dai *dai, u32 *stream_id) 31{ 32 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 33 struct hdac_ext_stream *hext_stream; 34 35 hext_stream = hda_dsp_stream_get(sdev, cstream->direction, 0); 36 if (!hext_stream) 37 return -EBUSY; 38 39 hdac_stream(hext_stream)->curr_pos = 0; 40 hdac_stream(hext_stream)->cstream = cstream; 41 cstream->runtime->private_data = hext_stream; 42 43 *stream_id = hdac_stream(hext_stream)->stream_tag; 44 45 return 0; 46} 47 48static int hda_probes_compr_free(struct sof_client_dev *cdev, 49 struct snd_compr_stream *cstream, 50 struct snd_soc_dai *dai) 51{ 52 struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream); 53 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 54 int ret; 55 56 ret = hda_dsp_stream_put(sdev, cstream->direction, 57 hdac_stream(hext_stream)->stream_tag); 58 if (ret < 0) { 59 dev_dbg(sdev->dev, "stream put failed: %d\n", ret); 60 return ret; 61 } 62 63 hdac_stream(hext_stream)->cstream = NULL; 64 cstream->runtime->private_data = NULL; 65 66 return 0; 67} 68 69static int hda_probes_compr_set_params(struct sof_client_dev *cdev, 70 struct snd_compr_stream *cstream, 71 struct snd_compr_params *params, 72 struct snd_soc_dai *dai) 73{ 74 struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream); 75 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 76 struct hdac_stream *hstream = hdac_stream(hext_stream); 77 struct snd_dma_buffer *dmab; 78 u32 bits, rate; 79 int bps, ret; 80 81 dmab = cstream->runtime->dma_buffer_p; 82 /* compr params do not store bit depth, default to S32_LE */ 83 bps = snd_pcm_format_physical_width(SNDRV_PCM_FORMAT_S32_LE); 84 if (bps < 0) 85 return bps; 86 bits = hda_dsp_get_bits(sdev, bps); 87 rate = hda_dsp_get_mult_div(sdev, params->codec.sample_rate); 88 89 hstream->format_val = rate | bits | (params->codec.ch_out - 1); 90 hstream->bufsize = cstream->runtime->buffer_size; 91 hstream->period_bytes = cstream->runtime->fragment_size; 92 hstream->no_period_wakeup = 0; 93 94 ret = hda_dsp_stream_hw_params(sdev, hext_stream, dmab, NULL); 95 if (ret < 0) { 96 dev_err(sdev->dev, "error: hdac prepare failed: %d\n", ret); 97 return ret; 98 } 99 100 return 0; 101} 102 103static int hda_probes_compr_trigger(struct sof_client_dev *cdev, 104 struct snd_compr_stream *cstream, 105 int cmd, struct snd_soc_dai *dai) 106{ 107 struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream); 108 struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev); 109 110 return hda_dsp_stream_trigger(sdev, hext_stream, cmd); 111} 112 113static int hda_probes_compr_pointer(struct sof_client_dev *cdev, 114 struct snd_compr_stream *cstream, 115 struct snd_compr_tstamp *tstamp, 116 struct snd_soc_dai *dai) 117{ 118 struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream); 119 struct snd_soc_pcm_stream *pstream; 120 121 pstream = &dai->driver->capture; 122 tstamp->copied_total = hdac_stream(hext_stream)->curr_pos; 123 tstamp->sampling_rate = snd_pcm_rate_bit_to_rate(pstream->rates); 124 125 return 0; 126} 127 128/* SOF client implementation */ 129static const struct sof_probes_host_ops hda_probes_ops = { 130 .assign = hda_probes_compr_assign, 131 .free = hda_probes_compr_free, 132 .set_params = hda_probes_compr_set_params, 133 .trigger = hda_probes_compr_trigger, 134 .pointer = hda_probes_compr_pointer, 135}; 136 137int hda_probes_register(struct snd_sof_dev *sdev) 138{ 139 return sof_client_dev_register(sdev, "hda-probes", 0, &hda_probes_ops, 140 sizeof(hda_probes_ops)); 141} 142 143void hda_probes_unregister(struct snd_sof_dev *sdev) 144{ 145 sof_client_dev_unregister(sdev, "hda-probes", 0); 146} 147 148MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT);