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