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 22 static inline struct hdac_ext_stream * 23 hda_compr_get_stream(struct snd_compr_stream *cstream) 24 { 25 return cstream->runtime->private_data; 26 } 27 28 static int hda_probes_compr_startup(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 48 static int hda_probes_compr_shutdown(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 69 static 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 103 static 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 113 static 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 */ 129 static const struct sof_probes_host_ops hda_probes_ops = { 130 .startup = hda_probes_compr_startup, 131 .shutdown = hda_probes_compr_shutdown, 132 .set_params = hda_probes_compr_set_params, 133 .trigger = hda_probes_compr_trigger, 134 .pointer = hda_probes_compr_pointer, 135 }; 136 137 int 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 143 void hda_probes_unregister(struct snd_sof_dev *sdev) 144 { 145 sof_client_dev_unregister(sdev, "hda-probes", 0); 146 } 147 148 MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT); 149