1c72fcc34Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause
2c72fcc34Sopenharmony_ci//
3c72fcc34Sopenharmony_ci// Copyright(c) 2021 Intel Corporation. All rights reserved.
4c72fcc34Sopenharmony_ci//
5c72fcc34Sopenharmony_ci// Author: Jaska Uimonen <jaska.uimonen@linux.intel.com>
6c72fcc34Sopenharmony_ci
7c72fcc34Sopenharmony_ci#include "aconfig.h"
8c72fcc34Sopenharmony_ci#include <stdint.h>
9c72fcc34Sopenharmony_ci#include <errno.h>
10c72fcc34Sopenharmony_ci#include <stdio.h>
11c72fcc34Sopenharmony_ci#include <stdlib.h>
12c72fcc34Sopenharmony_ci#include <string.h>
13c72fcc34Sopenharmony_ci#include <alsa/global.h>
14c72fcc34Sopenharmony_ci#include <alsa/input.h>
15c72fcc34Sopenharmony_ci#include <alsa/output.h>
16c72fcc34Sopenharmony_ci#include <alsa/conf.h>
17c72fcc34Sopenharmony_ci#include <alsa/error.h>
18c72fcc34Sopenharmony_ci#include "dmic-nhlt.h"
19c72fcc34Sopenharmony_ci#include "dmic/dmic-process.h"
20c72fcc34Sopenharmony_ci
21c72fcc34Sopenharmony_cistatic int set_dmic_data(struct intel_nhlt_params *nhlt, snd_config_t *dai_cfg, snd_config_t *top)
22c72fcc34Sopenharmony_ci{
23c72fcc34Sopenharmony_ci	long unmute_ramp_time_ms = 0;
24c72fcc34Sopenharmony_ci	long fifo_word_length = 0;
25c72fcc34Sopenharmony_ci	long driver_version = 0;
26c72fcc34Sopenharmony_ci	long num_pdm_active = 0;
27c72fcc34Sopenharmony_ci	long sample_rate = 0;
28c72fcc34Sopenharmony_ci	long dai_index_t = 0;
29c72fcc34Sopenharmony_ci	long duty_min = 0;
30c72fcc34Sopenharmony_ci	long duty_max = 0;
31c72fcc34Sopenharmony_ci	long clk_min = 0;
32c72fcc34Sopenharmony_ci	long clk_max = 0;
33c72fcc34Sopenharmony_ci	long io_clk = 0;
34c72fcc34Sopenharmony_ci	int ret;
35c72fcc34Sopenharmony_ci
36c72fcc34Sopenharmony_ci	struct dai_values dmic_data[] = {
37c72fcc34Sopenharmony_ci		{ "driver_version", SND_CONFIG_TYPE_INTEGER, NULL, &driver_version, NULL},
38c72fcc34Sopenharmony_ci		{ "io_clk", SND_CONFIG_TYPE_INTEGER, NULL, &io_clk, NULL},
39c72fcc34Sopenharmony_ci		{ "dai_index", SND_CONFIG_TYPE_INTEGER, NULL, &dai_index_t, NULL},
40c72fcc34Sopenharmony_ci		{ "num_pdm_active", SND_CONFIG_TYPE_INTEGER, NULL, &num_pdm_active, NULL},
41c72fcc34Sopenharmony_ci		{ "fifo_word_length", SND_CONFIG_TYPE_INTEGER, NULL, &fifo_word_length, NULL},
42c72fcc34Sopenharmony_ci		{ "clk_min", SND_CONFIG_TYPE_INTEGER, NULL, &clk_min, NULL},
43c72fcc34Sopenharmony_ci		{ "clk_max", SND_CONFIG_TYPE_INTEGER, NULL, &clk_max, NULL},
44c72fcc34Sopenharmony_ci		{ "duty_min", SND_CONFIG_TYPE_INTEGER, NULL, &duty_min, NULL},
45c72fcc34Sopenharmony_ci		{ "duty_max", SND_CONFIG_TYPE_INTEGER, NULL, &duty_max, NULL},
46c72fcc34Sopenharmony_ci		{ "sample_rate", SND_CONFIG_TYPE_INTEGER, NULL, &sample_rate, NULL},
47c72fcc34Sopenharmony_ci		{ "unmute_ramp_time_ms", SND_CONFIG_TYPE_INTEGER, NULL, &unmute_ramp_time_ms, NULL},
48c72fcc34Sopenharmony_ci	};
49c72fcc34Sopenharmony_ci
50c72fcc34Sopenharmony_ci	ret = find_set_values(&dmic_data[0], ARRAY_SIZE(dmic_data), dai_cfg, top, "Class.Dai.DMIC");
51c72fcc34Sopenharmony_ci	if (ret < 0)
52c72fcc34Sopenharmony_ci		return ret;
53c72fcc34Sopenharmony_ci
54c72fcc34Sopenharmony_ci	return dmic_set_params(nhlt, dai_index_t, driver_version, io_clk, num_pdm_active,
55c72fcc34Sopenharmony_ci			       fifo_word_length, clk_min, clk_max, duty_min, duty_max, sample_rate,
56c72fcc34Sopenharmony_ci			       unmute_ramp_time_ms);
57c72fcc34Sopenharmony_ci}
58c72fcc34Sopenharmony_ci
59c72fcc34Sopenharmony_cistatic int set_pdm_data(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
60c72fcc34Sopenharmony_ci{
61c72fcc34Sopenharmony_ci	long mic_a_enable = 0;
62c72fcc34Sopenharmony_ci	long mic_b_enable = 0;
63c72fcc34Sopenharmony_ci	long polarity_a = 0;
64c72fcc34Sopenharmony_ci	long polarity_b = 0;
65c72fcc34Sopenharmony_ci	long clk_edge = 0;
66c72fcc34Sopenharmony_ci	long ctrl_id = 0;
67c72fcc34Sopenharmony_ci	long skew = 0;
68c72fcc34Sopenharmony_ci	int ret;
69c72fcc34Sopenharmony_ci
70c72fcc34Sopenharmony_ci	struct dai_values dmic_pdm_data[] = {
71c72fcc34Sopenharmony_ci		{ "mic_a_enable", SND_CONFIG_TYPE_INTEGER, NULL, &mic_a_enable, NULL},
72c72fcc34Sopenharmony_ci		{ "mic_b_enable", SND_CONFIG_TYPE_INTEGER, NULL, &mic_b_enable, NULL},
73c72fcc34Sopenharmony_ci		{ "polarity_a", SND_CONFIG_TYPE_INTEGER, NULL, &polarity_a, NULL},
74c72fcc34Sopenharmony_ci		{ "polarity_b", SND_CONFIG_TYPE_INTEGER, NULL, &polarity_b, NULL},
75c72fcc34Sopenharmony_ci		{ "clk_edge", SND_CONFIG_TYPE_INTEGER, NULL, &clk_edge, NULL},
76c72fcc34Sopenharmony_ci		{ "ctrl_id", SND_CONFIG_TYPE_INTEGER, NULL, &ctrl_id, NULL},
77c72fcc34Sopenharmony_ci		{ "skew", SND_CONFIG_TYPE_INTEGER, NULL, &skew, NULL},
78c72fcc34Sopenharmony_ci	};
79c72fcc34Sopenharmony_ci
80c72fcc34Sopenharmony_ci	ret = find_set_values(&dmic_pdm_data[0], ARRAY_SIZE(dmic_pdm_data), cfg, top,
81c72fcc34Sopenharmony_ci			      "Class.Base.pdm_config");
82c72fcc34Sopenharmony_ci	if (ret < 0)
83c72fcc34Sopenharmony_ci		return ret;
84c72fcc34Sopenharmony_ci
85c72fcc34Sopenharmony_ci	return dmic_set_pdm_params(nhlt, ctrl_id, mic_a_enable, mic_b_enable, polarity_a,
86c72fcc34Sopenharmony_ci				   polarity_b, clk_edge, skew);
87c72fcc34Sopenharmony_ci}
88c72fcc34Sopenharmony_ci
89c72fcc34Sopenharmony_cistatic int set_mic_data(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
90c72fcc34Sopenharmony_ci{
91c72fcc34Sopenharmony_ci	long sensitivity = 0;
92c72fcc34Sopenharmony_ci	long snr = 0;
93c72fcc34Sopenharmony_ci	int ret;
94c72fcc34Sopenharmony_ci
95c72fcc34Sopenharmony_ci	struct dai_values dmic_mic_data[] = {
96c72fcc34Sopenharmony_ci		{ "snr", SND_CONFIG_TYPE_INTEGER, NULL, &snr, NULL},
97c72fcc34Sopenharmony_ci		{ "sensitivity", SND_CONFIG_TYPE_INTEGER, NULL, &snr, NULL},
98c72fcc34Sopenharmony_ci	};
99c72fcc34Sopenharmony_ci
100c72fcc34Sopenharmony_ci	ret = find_set_values(&dmic_mic_data[0], ARRAY_SIZE(dmic_mic_data), cfg, top,
101c72fcc34Sopenharmony_ci			      "Class.Base.mic_extension");
102c72fcc34Sopenharmony_ci	if (ret < 0)
103c72fcc34Sopenharmony_ci		return ret;
104c72fcc34Sopenharmony_ci
105c72fcc34Sopenharmony_ci	return dmic_set_ext_params(nhlt, snr, sensitivity);
106c72fcc34Sopenharmony_ci}
107c72fcc34Sopenharmony_ci
108c72fcc34Sopenharmony_cistatic int set_vendor_mic_data(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
109c72fcc34Sopenharmony_ci{
110c72fcc34Sopenharmony_ci	long speaker_position_distance = 0;
111c72fcc34Sopenharmony_ci	long horizontal_angle_begin = 0;
112c72fcc34Sopenharmony_ci	long horizontal_angle_end = 0;
113c72fcc34Sopenharmony_ci	long vertical_angle_begin = 0;
114c72fcc34Sopenharmony_ci	long vertical_angle_end = 0;
115c72fcc34Sopenharmony_ci	long frequency_high_band = 0;
116c72fcc34Sopenharmony_ci	long frequency_low_band = 0;
117c72fcc34Sopenharmony_ci	long horizontal_offset = 0;
118c72fcc34Sopenharmony_ci	long vertical_offset = 0;
119c72fcc34Sopenharmony_ci	long direction_angle = 0;
120c72fcc34Sopenharmony_ci	long elevation_angle = 0;
121c72fcc34Sopenharmony_ci	long mic_type = 0;
122c72fcc34Sopenharmony_ci	long location = 0;
123c72fcc34Sopenharmony_ci	long mic_id = 0;
124c72fcc34Sopenharmony_ci	int ret;
125c72fcc34Sopenharmony_ci
126c72fcc34Sopenharmony_ci	struct dai_values dmic_vendor_data[] = {
127c72fcc34Sopenharmony_ci		{ "mic_id", SND_CONFIG_TYPE_INTEGER, NULL, &mic_id, NULL},
128c72fcc34Sopenharmony_ci		{ "mic_type", SND_CONFIG_TYPE_INTEGER, NULL, &mic_type, NULL},
129c72fcc34Sopenharmony_ci		{ "location", SND_CONFIG_TYPE_INTEGER, NULL, &location, NULL},
130c72fcc34Sopenharmony_ci		{ "speaker_position_distance", SND_CONFIG_TYPE_INTEGER, NULL,
131c72fcc34Sopenharmony_ci		  &speaker_position_distance, NULL},
132c72fcc34Sopenharmony_ci		{ "horizontal_offset", SND_CONFIG_TYPE_INTEGER, NULL, &horizontal_offset, NULL},
133c72fcc34Sopenharmony_ci		{ "vertical_offset", SND_CONFIG_TYPE_INTEGER, NULL, &vertical_offset, NULL},
134c72fcc34Sopenharmony_ci		{ "frequency_low_band", SND_CONFIG_TYPE_INTEGER, NULL, &frequency_low_band, NULL},
135c72fcc34Sopenharmony_ci		{ "frequency_high_band", SND_CONFIG_TYPE_INTEGER, NULL, &frequency_high_band, NULL},
136c72fcc34Sopenharmony_ci		{ "direction_angle", SND_CONFIG_TYPE_INTEGER, NULL, &direction_angle, NULL},
137c72fcc34Sopenharmony_ci		{ "elevation_angle", SND_CONFIG_TYPE_INTEGER, NULL, &elevation_angle, NULL},
138c72fcc34Sopenharmony_ci		{ "vertical_angle_begin", SND_CONFIG_TYPE_INTEGER, NULL, &vertical_angle_begin,
139c72fcc34Sopenharmony_ci		  NULL},
140c72fcc34Sopenharmony_ci		{ "vertical_angle_end", SND_CONFIG_TYPE_INTEGER, NULL, &vertical_angle_end, NULL},
141c72fcc34Sopenharmony_ci		{ "horizontal_angle_begin", SND_CONFIG_TYPE_INTEGER, NULL, &horizontal_angle_begin,
142c72fcc34Sopenharmony_ci		  NULL},
143c72fcc34Sopenharmony_ci		{ "horizontal_angle_end", SND_CONFIG_TYPE_INTEGER, NULL, &horizontal_angle_end,
144c72fcc34Sopenharmony_ci		  NULL},
145c72fcc34Sopenharmony_ci	};
146c72fcc34Sopenharmony_ci
147c72fcc34Sopenharmony_ci	ret = find_set_values(&dmic_vendor_data[0], ARRAY_SIZE(dmic_vendor_data), cfg, top,
148c72fcc34Sopenharmony_ci			      "Class.Base.vendor_mic_config");
149c72fcc34Sopenharmony_ci	if (ret < 0)
150c72fcc34Sopenharmony_ci		return ret;
151c72fcc34Sopenharmony_ci
152c72fcc34Sopenharmony_ci	return dmic_set_mic_params(nhlt, mic_id, mic_type, location, speaker_position_distance,
153c72fcc34Sopenharmony_ci				   horizontal_offset, vertical_offset, frequency_low_band,
154c72fcc34Sopenharmony_ci				   frequency_high_band, direction_angle, elevation_angle,
155c72fcc34Sopenharmony_ci				   vertical_angle_begin, vertical_angle_end, horizontal_angle_begin,
156c72fcc34Sopenharmony_ci				   horizontal_angle_end);
157c72fcc34Sopenharmony_ci}
158c72fcc34Sopenharmony_ci
159c72fcc34Sopenharmony_cistatic int set_bytes_data(struct intel_nhlt_params *nhlt ATTRIBUTE_UNUSED, snd_config_t *cfg)
160c72fcc34Sopenharmony_ci{
161c72fcc34Sopenharmony_ci	snd_config_iterator_t i, next;
162c72fcc34Sopenharmony_ci	snd_config_t *n;
163c72fcc34Sopenharmony_ci	const char *bytes;
164c72fcc34Sopenharmony_ci	const char *id;
165c72fcc34Sopenharmony_ci
166c72fcc34Sopenharmony_ci	if (snd_config_get_id(cfg, &id) < 0)
167c72fcc34Sopenharmony_ci		return -EINVAL;
168c72fcc34Sopenharmony_ci
169c72fcc34Sopenharmony_ci	if (strcmp(id, "fir_coeffs"))
170c72fcc34Sopenharmony_ci		return 0;
171c72fcc34Sopenharmony_ci
172c72fcc34Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
173c72fcc34Sopenharmony_ci		n = snd_config_iterator_entry(i);
174c72fcc34Sopenharmony_ci
175c72fcc34Sopenharmony_ci		if (snd_config_get_string(n, &bytes))
176c72fcc34Sopenharmony_ci			return -EINVAL;
177c72fcc34Sopenharmony_ci	}
178c72fcc34Sopenharmony_ci
179c72fcc34Sopenharmony_ci	return 0;
180c72fcc34Sopenharmony_ci}
181c72fcc34Sopenharmony_ci
182c72fcc34Sopenharmony_ci/* init dmic parameters, should be called before parsing dais */
183c72fcc34Sopenharmony_ciint nhlt_dmic_init_params(struct intel_nhlt_params *nhlt)
184c72fcc34Sopenharmony_ci{
185c72fcc34Sopenharmony_ci	return dmic_init_params(nhlt);
186c72fcc34Sopenharmony_ci}
187c72fcc34Sopenharmony_ci
188c72fcc34Sopenharmony_ci/* get dmic endpoint count */
189c72fcc34Sopenharmony_ciint nhlt_dmic_get_ep_count(struct intel_nhlt_params *nhlt)
190c72fcc34Sopenharmony_ci{
191c72fcc34Sopenharmony_ci	return dmic_get_vendor_blob_count(nhlt);
192c72fcc34Sopenharmony_ci}
193c72fcc34Sopenharmony_ci
194c72fcc34Sopenharmony_ciint nhlt_dmic_get_ep(struct intel_nhlt_params *nhlt, struct endpoint_descriptor **eps,
195c72fcc34Sopenharmony_ci		     int index)
196c72fcc34Sopenharmony_ci{
197c72fcc34Sopenharmony_ci	struct endpoint_descriptor ep;
198c72fcc34Sopenharmony_ci	struct mic_array_device_specific_config mic_s_conf;
199c72fcc34Sopenharmony_ci	struct mic_array_device_specific_vendor_config mic_v_conf;
200c72fcc34Sopenharmony_ci	struct mic_snr_sensitivity_extension mic_ext;
201c72fcc34Sopenharmony_ci	struct mic_vendor_config mic_conf;
202c72fcc34Sopenharmony_ci	struct formats_config f_conf;
203c72fcc34Sopenharmony_ci	struct format_config f_conf1;
204c72fcc34Sopenharmony_ci	uint8_t *ep_target;
205c72fcc34Sopenharmony_ci	size_t blob_size;
206c72fcc34Sopenharmony_ci	int ret;
207c72fcc34Sopenharmony_ci	int i;
208c72fcc34Sopenharmony_ci
209c72fcc34Sopenharmony_ci	size_t mic_config_size;
210c72fcc34Sopenharmony_ci	uint32_t sample_rate;
211c72fcc34Sopenharmony_ci	uint16_t channel_count;
212c72fcc34Sopenharmony_ci	uint32_t bits_per_sample;
213c72fcc34Sopenharmony_ci	uint8_t array_type;
214c72fcc34Sopenharmony_ci	uint8_t extension;
215c72fcc34Sopenharmony_ci	uint8_t num_mics;
216c72fcc34Sopenharmony_ci	uint32_t snr;
217c72fcc34Sopenharmony_ci	uint32_t sensitivity;
218c72fcc34Sopenharmony_ci
219c72fcc34Sopenharmony_ci	uint8_t type;
220c72fcc34Sopenharmony_ci	uint8_t panel;
221c72fcc34Sopenharmony_ci	uint32_t speaker_position_distance;
222c72fcc34Sopenharmony_ci	uint32_t horizontal_offset;
223c72fcc34Sopenharmony_ci	uint32_t vertical_offset;
224c72fcc34Sopenharmony_ci	uint8_t frequency_low_band;
225c72fcc34Sopenharmony_ci	uint8_t frequency_high_band;
226c72fcc34Sopenharmony_ci	uint16_t direction_angle;
227c72fcc34Sopenharmony_ci	uint16_t elevation_angle;
228c72fcc34Sopenharmony_ci	uint16_t vertical_angle_begin;
229c72fcc34Sopenharmony_ci	uint16_t vertical_angle_end;
230c72fcc34Sopenharmony_ci	uint16_t horizontal_angle_begin;
231c72fcc34Sopenharmony_ci	uint16_t horizontal_angle_end;
232c72fcc34Sopenharmony_ci
233c72fcc34Sopenharmony_ci	/*
234c72fcc34Sopenharmony_ci	 * nhlt dmic structure:
235c72fcc34Sopenharmony_ci	 *
236c72fcc34Sopenharmony_ci	 * endpoint_descriptor, sizeof(struct endpoint_descriptor)
237c72fcc34Sopenharmony_ci	 *
238c72fcc34Sopenharmony_ci	 * device_specific_config (mic), sizeof(mic_array_device_specific_config)
239c72fcc34Sopenharmony_ci	 * or
240c72fcc34Sopenharmony_ci	 * device_specific_config (mic), sizeof(mic_array_device_specific_vendor_config)
241c72fcc34Sopenharmony_ci	 *
242c72fcc34Sopenharmony_ci	 * formats_config (formats_count), sizeof(struct formats_config)
243c72fcc34Sopenharmony_ci	 * format_config (waveex), sizeof(struct format_config)
244c72fcc34Sopenharmony_ci	 * vendor_blob sizeof(vendor_blob)
245c72fcc34Sopenharmony_ci	 */
246c72fcc34Sopenharmony_ci
247c72fcc34Sopenharmony_ci	/* dmic ep */
248c72fcc34Sopenharmony_ci	ep.link_type = NHLT_LINK_TYPE_PDM;
249c72fcc34Sopenharmony_ci	ep.instance_id = 0;
250c72fcc34Sopenharmony_ci	ep.vendor_id = NHLT_VENDOR_ID_INTEL;
251c72fcc34Sopenharmony_ci	ep.device_id = NHLT_DEVICE_ID_INTEL_PDM_DMIC;
252c72fcc34Sopenharmony_ci	ep.revision_id = 0;
253c72fcc34Sopenharmony_ci	ep.subsystem_id = 0;
254c72fcc34Sopenharmony_ci	ep.device_type = 0;
255c72fcc34Sopenharmony_ci	ep.direction = NHLT_ENDPOINT_DIRECTION_CAPTURE;
256c72fcc34Sopenharmony_ci	ep.virtualbus_id = index;
257c72fcc34Sopenharmony_ci
258c72fcc34Sopenharmony_ci	ret = dmic_get_params(nhlt, index, &sample_rate, &channel_count, &bits_per_sample,
259c72fcc34Sopenharmony_ci			      &array_type, &num_mics, &extension, &snr, &sensitivity);
260c72fcc34Sopenharmony_ci
261c72fcc34Sopenharmony_ci	if (ret) {
262c72fcc34Sopenharmony_ci		fprintf(stderr, "nhlt_dmic_get_ep: dmic_get_params failed\n");
263c72fcc34Sopenharmony_ci		return ret;
264c72fcc34Sopenharmony_ci	}
265c72fcc34Sopenharmony_ci
266c72fcc34Sopenharmony_ci	if (array_type == NHLT_MIC_ARRAY_TYPE_VENDOR_DEFINED) {
267c72fcc34Sopenharmony_ci		mic_v_conf.config.capabilities_size = 4 + num_mics *
268c72fcc34Sopenharmony_ci			sizeof(struct mic_vendor_config);
269c72fcc34Sopenharmony_ci		mic_v_conf.device_config.virtual_slot = 0; /* always 0 for dmic */
270c72fcc34Sopenharmony_ci		mic_v_conf.device_config.config_type = NHLT_DEVICE_CONFIG_TYPE_MICARRAY;
271c72fcc34Sopenharmony_ci		mic_v_conf.number_of_microphones = num_mics;
272c72fcc34Sopenharmony_ci		mic_v_conf.array_type_ex = array_type;
273c72fcc34Sopenharmony_ci		/* precense of extension struct is coded into lower 4 bits of array_type */
274c72fcc34Sopenharmony_ci		if (extension) {
275c72fcc34Sopenharmony_ci			mic_v_conf.array_type_ex = (array_type & ~0x0F) | (0x01 & 0x0F);
276c72fcc34Sopenharmony_ci			mic_v_conf.config.capabilities_size +=
277c72fcc34Sopenharmony_ci				sizeof(struct mic_snr_sensitivity_extension);
278c72fcc34Sopenharmony_ci		}
279c72fcc34Sopenharmony_ci	} else {
280c72fcc34Sopenharmony_ci		mic_s_conf.config.capabilities_size = 3;
281c72fcc34Sopenharmony_ci		mic_s_conf.device_config.virtual_slot = 0; /* always 0 for dmic */
282c72fcc34Sopenharmony_ci		mic_s_conf.device_config.config_type = NHLT_DEVICE_CONFIG_TYPE_MICARRAY;
283c72fcc34Sopenharmony_ci		mic_s_conf.array_type_ex = array_type;
284c72fcc34Sopenharmony_ci		/* presense of extension struct coded into lower 4 bits of array_type */
285c72fcc34Sopenharmony_ci		if (extension) {
286c72fcc34Sopenharmony_ci			mic_s_conf.array_type_ex = (array_type & ~0x0F) | (0x01 & 0x0F);
287c72fcc34Sopenharmony_ci			mic_s_conf.config.capabilities_size +=
288c72fcc34Sopenharmony_ci				sizeof(struct mic_snr_sensitivity_extension);
289c72fcc34Sopenharmony_ci		}
290c72fcc34Sopenharmony_ci	}
291c72fcc34Sopenharmony_ci
292c72fcc34Sopenharmony_ci	/* formats_config */
293c72fcc34Sopenharmony_ci	f_conf.formats_count = 1;
294c72fcc34Sopenharmony_ci
295c72fcc34Sopenharmony_ci	/* fill in wave format extensible types */
296c72fcc34Sopenharmony_ci	f_conf1.format.wFormatTag = 0xFFFE;
297c72fcc34Sopenharmony_ci	f_conf1.format.nSamplesPerSec = sample_rate;
298c72fcc34Sopenharmony_ci	f_conf1.format.nChannels = channel_count;
299c72fcc34Sopenharmony_ci	f_conf1.format.wBitsPerSample = bits_per_sample;
300c72fcc34Sopenharmony_ci	f_conf1.format.nBlockAlign = channel_count * bits_per_sample / 8;
301c72fcc34Sopenharmony_ci	f_conf1.format.nAvgBytesPerSec = f_conf1.format.nSamplesPerSec * f_conf1.format.nBlockAlign;
302c72fcc34Sopenharmony_ci
303c72fcc34Sopenharmony_ci	/* bytes after this value in this struct */
304c72fcc34Sopenharmony_ci	f_conf1.format.cbSize = 22;
305c72fcc34Sopenharmony_ci	/* actual bits in container */
306c72fcc34Sopenharmony_ci	f_conf1.format.wValidBitsPerSample = bits_per_sample;
307c72fcc34Sopenharmony_ci	/* channel map not used at this time */
308c72fcc34Sopenharmony_ci	f_conf1.format.dwChannelMask = 0;
309c72fcc34Sopenharmony_ci	/* WAVE_FORMAT_PCM guid (0x0001) ? */
310c72fcc34Sopenharmony_ci	f_conf1.format.SubFormat[0] = 0;
311c72fcc34Sopenharmony_ci	f_conf1.format.SubFormat[1] = 0;
312c72fcc34Sopenharmony_ci	f_conf1.format.SubFormat[2] = 0;
313c72fcc34Sopenharmony_ci	f_conf1.format.SubFormat[3] = 0;
314c72fcc34Sopenharmony_ci
315c72fcc34Sopenharmony_ci	ret = dmic_get_vendor_blob_size(nhlt, &blob_size);
316c72fcc34Sopenharmony_ci	if (ret) {
317c72fcc34Sopenharmony_ci		fprintf(stderr, "nhlt_dmic_get_ep: dmic_get_vendor_blob_size failed\n");
318c72fcc34Sopenharmony_ci		return ret;
319c72fcc34Sopenharmony_ci	}
320c72fcc34Sopenharmony_ci
321c72fcc34Sopenharmony_ci	f_conf1.vendor_blob.capabilities_size = blob_size;
322c72fcc34Sopenharmony_ci
323c72fcc34Sopenharmony_ci	if (array_type == NHLT_MIC_ARRAY_TYPE_VENDOR_DEFINED)
324c72fcc34Sopenharmony_ci		mic_config_size = sizeof(struct mic_array_device_specific_vendor_config) +
325c72fcc34Sopenharmony_ci			num_mics * sizeof(struct mic_vendor_config);
326c72fcc34Sopenharmony_ci	else
327c72fcc34Sopenharmony_ci		mic_config_size = sizeof(struct mic_array_device_specific_config);
328c72fcc34Sopenharmony_ci
329c72fcc34Sopenharmony_ci	if (extension)
330c72fcc34Sopenharmony_ci		mic_config_size = sizeof(struct mic_snr_sensitivity_extension);
331c72fcc34Sopenharmony_ci
332c72fcc34Sopenharmony_ci	ep.length = sizeof(struct endpoint_descriptor) +
333c72fcc34Sopenharmony_ci		mic_config_size +
334c72fcc34Sopenharmony_ci		sizeof(struct formats_config) +
335c72fcc34Sopenharmony_ci		sizeof(struct format_config) +
336c72fcc34Sopenharmony_ci		blob_size;
337c72fcc34Sopenharmony_ci
338c72fcc34Sopenharmony_ci	/* allocate the final variable length ep struct */
339c72fcc34Sopenharmony_ci	ep_target = calloc(ep.length, sizeof(uint8_t));
340c72fcc34Sopenharmony_ci	if (!ep_target)
341c72fcc34Sopenharmony_ci		return -ENOMEM;
342c72fcc34Sopenharmony_ci
343c72fcc34Sopenharmony_ci	*eps = (struct endpoint_descriptor *)ep_target;
344c72fcc34Sopenharmony_ci
345c72fcc34Sopenharmony_ci	/* copy all parsed sub arrays into the top level array */
346c72fcc34Sopenharmony_ci	memcpy(ep_target, &ep, sizeof(struct endpoint_descriptor));
347c72fcc34Sopenharmony_ci
348c72fcc34Sopenharmony_ci	ep_target += sizeof(struct endpoint_descriptor);
349c72fcc34Sopenharmony_ci
350c72fcc34Sopenharmony_ci	if (array_type == NHLT_MIC_ARRAY_TYPE_VENDOR_DEFINED) {
351c72fcc34Sopenharmony_ci		memcpy(ep_target, &mic_v_conf,
352c72fcc34Sopenharmony_ci		       sizeof(struct mic_array_device_specific_vendor_config));
353c72fcc34Sopenharmony_ci		ep_target += sizeof(struct mic_array_device_specific_vendor_config);
354c72fcc34Sopenharmony_ci		for (i = 0; i < num_mics; i++) {
355c72fcc34Sopenharmony_ci			ret = dmic_get_mic_params(nhlt, i, &type,
356c72fcc34Sopenharmony_ci						  &panel, &speaker_position_distance,
357c72fcc34Sopenharmony_ci						  &horizontal_offset, &vertical_offset,
358c72fcc34Sopenharmony_ci						  &frequency_low_band, &frequency_high_band,
359c72fcc34Sopenharmony_ci						  &direction_angle, &elevation_angle,
360c72fcc34Sopenharmony_ci						  &vertical_angle_begin, &vertical_angle_end,
361c72fcc34Sopenharmony_ci						  &horizontal_angle_begin, &horizontal_angle_end);
362c72fcc34Sopenharmony_ci
363c72fcc34Sopenharmony_ci			if (ret) {
364c72fcc34Sopenharmony_ci				fprintf(stderr, "nhlt_dmic_get_ep: dmic_get_mic_params failed\n");
365c72fcc34Sopenharmony_ci				return ret;
366c72fcc34Sopenharmony_ci			}
367c72fcc34Sopenharmony_ci
368c72fcc34Sopenharmony_ci			mic_conf.type = type;
369c72fcc34Sopenharmony_ci			mic_conf.panel = panel;
370c72fcc34Sopenharmony_ci			mic_conf.speaker_position_distance = speaker_position_distance;
371c72fcc34Sopenharmony_ci			mic_conf.horizontal_offset = horizontal_offset;
372c72fcc34Sopenharmony_ci			mic_conf.vertical_offset = vertical_offset;
373c72fcc34Sopenharmony_ci			mic_conf.frequency_low_band = frequency_low_band;
374c72fcc34Sopenharmony_ci			mic_conf.frequency_high_band = frequency_high_band;
375c72fcc34Sopenharmony_ci			mic_conf.direction_angle = direction_angle;
376c72fcc34Sopenharmony_ci			mic_conf.elevation_angle = elevation_angle;
377c72fcc34Sopenharmony_ci			mic_conf.vertical_angle_begin = vertical_angle_begin;
378c72fcc34Sopenharmony_ci			mic_conf.vertical_angle_end = vertical_angle_end;
379c72fcc34Sopenharmony_ci			mic_conf.horizontal_angle_begin = horizontal_angle_begin;
380c72fcc34Sopenharmony_ci			mic_conf.horizontal_angle_end = horizontal_angle_end;
381c72fcc34Sopenharmony_ci
382c72fcc34Sopenharmony_ci			memcpy(ep_target, &mic_conf, sizeof(struct mic_vendor_config));
383c72fcc34Sopenharmony_ci			ep_target += sizeof(struct mic_vendor_config);
384c72fcc34Sopenharmony_ci		}
385c72fcc34Sopenharmony_ci	} else {
386c72fcc34Sopenharmony_ci		memcpy(ep_target, &mic_s_conf, sizeof(struct mic_array_device_specific_config));
387c72fcc34Sopenharmony_ci		ep_target += sizeof(struct mic_array_device_specific_config);
388c72fcc34Sopenharmony_ci	}
389c72fcc34Sopenharmony_ci
390c72fcc34Sopenharmony_ci	if (extension) {
391c72fcc34Sopenharmony_ci		mic_ext.snr = snr;
392c72fcc34Sopenharmony_ci		mic_ext.sensitivity = sensitivity;
393c72fcc34Sopenharmony_ci		memcpy(ep_target, &mic_ext, sizeof(struct mic_snr_sensitivity_extension));
394c72fcc34Sopenharmony_ci		ep_target += sizeof(struct mic_snr_sensitivity_extension);
395c72fcc34Sopenharmony_ci	}
396c72fcc34Sopenharmony_ci
397c72fcc34Sopenharmony_ci	memcpy(ep_target, &f_conf, sizeof(struct formats_config));
398c72fcc34Sopenharmony_ci	ep_target += sizeof(struct formats_config);
399c72fcc34Sopenharmony_ci
400c72fcc34Sopenharmony_ci	memcpy(ep_target, &f_conf1, sizeof(struct format_config));
401c72fcc34Sopenharmony_ci	ep_target += sizeof(struct format_config);
402c72fcc34Sopenharmony_ci
403c72fcc34Sopenharmony_ci	ret = dmic_get_vendor_blob(nhlt, ep_target);
404c72fcc34Sopenharmony_ci	if (ret) {
405c72fcc34Sopenharmony_ci		fprintf(stderr, "nhlt_dmic_get_ep: dmic_get_vendor_blob failed\n");
406c72fcc34Sopenharmony_ci		return ret;
407c72fcc34Sopenharmony_ci	}
408c72fcc34Sopenharmony_ci
409c72fcc34Sopenharmony_ci	return 0;
410c72fcc34Sopenharmony_ci}
411c72fcc34Sopenharmony_ci
412c72fcc34Sopenharmony_ci/*
413c72fcc34Sopenharmony_ci * Set dmic parameters from topology for dmic coefficient calculation.
414c72fcc34Sopenharmony_ci *
415c72fcc34Sopenharmony_ci * Coefficients are recalculated in case of multiple DAIs in topology and might affect each other.
416c72fcc34Sopenharmony_ci *
417c72fcc34Sopenharmony_ci * You can see an example of topology v2 config of dmic below. In this example the default
418c72fcc34Sopenharmony_ci * object parameters are spelled out for clarity. General parameters like clk_min are parsed with
419c72fcc34Sopenharmony_ci * set_dmic_data and pdm object data with set_pdm_data. Number of pdm's can vary from 1 to 2. Values
420c72fcc34Sopenharmony_ci * are saved into intermediate structs and the vendor specific blob is calculated at the end of
421c72fcc34Sopenharmony_ci * parsing with dmic_calculate.
422c72fcc34Sopenharmony_ci *
423c72fcc34Sopenharmony_ci *	DMIC."0" {
424c72fcc34Sopenharmony_ci *		name NoCodec-6
425c72fcc34Sopenharmony_ci *		id 6
426c72fcc34Sopenharmony_ci *		index 0
427c72fcc34Sopenharmony_ci *		driver_version		1
428c72fcc34Sopenharmony_ci *		io_clk                  38400000
429c72fcc34Sopenharmony_ci *		clk_min			500000
430c72fcc34Sopenharmony_ci *		clk_max			4800000
431c72fcc34Sopenharmony_ci *		duty_min		40
432c72fcc34Sopenharmony_ci *		duty_max		60
433c72fcc34Sopenharmony_ci *		sample_rate		48000
434c72fcc34Sopenharmony_ci *		fifo_word_length	16
435c72fcc34Sopenharmony_ci *		unmute_ramp_time_ms	200
436c72fcc34Sopenharmony_ci *		num_pdm_active          2
437c72fcc34Sopenharmony_ci *
438c72fcc34Sopenharmony_ci *		# PDM controller config
439c72fcc34Sopenharmony_ci *		Object.Base.pdm_config."0" {
440c72fcc34Sopenharmony_ci *			ctrl_id	0
441c72fcc34Sopenharmony_ci *			mic_a_enable	1
442c72fcc34Sopenharmony_ci *			mic_b_enable	1
443c72fcc34Sopenharmony_ci *			polarity_a	0
444c72fcc34Sopenharmony_ci *			polarity_b	0
445c72fcc34Sopenharmony_ci *			clk_edge	0
446c72fcc34Sopenharmony_ci *			skew		0
447c72fcc34Sopenharmony_ci *		}
448c72fcc34Sopenharmony_ci *      }
449c72fcc34Sopenharmony_ci */
450c72fcc34Sopenharmony_ciint nhlt_dmic_set_params(struct intel_nhlt_params *nhlt, snd_config_t *cfg, snd_config_t *top)
451c72fcc34Sopenharmony_ci{
452c72fcc34Sopenharmony_ci	snd_config_t *items;
453c72fcc34Sopenharmony_ci	int ret;
454c72fcc34Sopenharmony_ci	snd_config_iterator_t i, next;
455c72fcc34Sopenharmony_ci	snd_config_t *n;
456c72fcc34Sopenharmony_ci	const char *id;
457c72fcc34Sopenharmony_ci
458c72fcc34Sopenharmony_ci	/* set basic dmic data */
459c72fcc34Sopenharmony_ci	ret = set_dmic_data(nhlt, cfg, top);
460c72fcc34Sopenharmony_ci	if (ret < 0)
461c72fcc34Sopenharmony_ci		return ret;
462c72fcc34Sopenharmony_ci
463c72fcc34Sopenharmony_ci	/* we need to have at least one pdm object */
464c72fcc34Sopenharmony_ci	ret = snd_config_search(cfg, "Object.Base.pdm_config", &items);
465c72fcc34Sopenharmony_ci	if (ret < 0)
466c72fcc34Sopenharmony_ci		return ret;
467c72fcc34Sopenharmony_ci
468c72fcc34Sopenharmony_ci	snd_config_for_each(i, next, items) {
469c72fcc34Sopenharmony_ci		n = snd_config_iterator_entry(i);
470c72fcc34Sopenharmony_ci
471c72fcc34Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
472c72fcc34Sopenharmony_ci			continue;
473c72fcc34Sopenharmony_ci
474c72fcc34Sopenharmony_ci		ret = set_pdm_data(nhlt, n, top);
475c72fcc34Sopenharmony_ci		if (ret < 0)
476c72fcc34Sopenharmony_ci			return ret;
477c72fcc34Sopenharmony_ci	}
478c72fcc34Sopenharmony_ci
479c72fcc34Sopenharmony_ci	/* check for microphone parameter configuration */
480c72fcc34Sopenharmony_ci	ret = snd_config_search(cfg, "Object.Base.mic_extension", &items);
481c72fcc34Sopenharmony_ci	if (!ret) {
482c72fcc34Sopenharmony_ci		snd_config_for_each(i, next, items) {
483c72fcc34Sopenharmony_ci			n = snd_config_iterator_entry(i);
484c72fcc34Sopenharmony_ci
485c72fcc34Sopenharmony_ci			if (snd_config_get_id(n, &id) < 0)
486c72fcc34Sopenharmony_ci				continue;
487c72fcc34Sopenharmony_ci
488c72fcc34Sopenharmony_ci			ret = set_mic_data(nhlt, n, top);
489c72fcc34Sopenharmony_ci			if (ret < 0)
490c72fcc34Sopenharmony_ci				return ret;
491c72fcc34Sopenharmony_ci		}
492c72fcc34Sopenharmony_ci	}
493c72fcc34Sopenharmony_ci
494c72fcc34Sopenharmony_ci	/* check for microphone parameter configuration */
495c72fcc34Sopenharmony_ci	ret = snd_config_search(cfg, "Object.Base.vendor_mic_config", &items);
496c72fcc34Sopenharmony_ci	if (!ret) {
497c72fcc34Sopenharmony_ci		snd_config_for_each(i, next, items) {
498c72fcc34Sopenharmony_ci			n = snd_config_iterator_entry(i);
499c72fcc34Sopenharmony_ci
500c72fcc34Sopenharmony_ci			if (snd_config_get_id(n, &id) < 0)
501c72fcc34Sopenharmony_ci				continue;
502c72fcc34Sopenharmony_ci
503c72fcc34Sopenharmony_ci			set_vendor_mic_data(nhlt, n, top);
504c72fcc34Sopenharmony_ci		}
505c72fcc34Sopenharmony_ci	}
506c72fcc34Sopenharmony_ci
507c72fcc34Sopenharmony_ci	/* check for optional filter coeffs */
508c72fcc34Sopenharmony_ci	ret = snd_config_search(cfg, "Object.Base.data", &items);
509c72fcc34Sopenharmony_ci	if (!ret) {
510c72fcc34Sopenharmony_ci		snd_config_for_each(i, next, items) {
511c72fcc34Sopenharmony_ci			n = snd_config_iterator_entry(i);
512c72fcc34Sopenharmony_ci
513c72fcc34Sopenharmony_ci			if (snd_config_get_id(n, &id) < 0)
514c72fcc34Sopenharmony_ci				continue;
515c72fcc34Sopenharmony_ci
516c72fcc34Sopenharmony_ci			set_bytes_data(nhlt, n);
517c72fcc34Sopenharmony_ci		}
518c72fcc34Sopenharmony_ci	}
519c72fcc34Sopenharmony_ci
520c72fcc34Sopenharmony_ci	ret = dmic_calculate(nhlt);
521c72fcc34Sopenharmony_ci
522c72fcc34Sopenharmony_ci	return ret;
523c72fcc34Sopenharmony_ci}
524