18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * fireworks_command.c - a part of driver for Fireworks based devices 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2013-2014 Takashi Sakamoto 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "./fireworks.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* 118c2ecf20Sopenharmony_ci * This driver uses transaction version 1 or later to use extended hardware 128c2ecf20Sopenharmony_ci * information. Then too old devices are not available. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Each commands are not required to have continuous sequence numbers. This 158c2ecf20Sopenharmony_ci * number is just used to match command and response. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * This module support a part of commands. Please see FFADO if you want to see 188c2ecf20Sopenharmony_ci * whole commands. But there are some commands which FFADO don't implement. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Fireworks also supports AV/C general commands and AV/C Stream Format 218c2ecf20Sopenharmony_ci * Information commands. But this module don't use them. 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define KERNEL_SEQNUM_MIN (SND_EFW_TRANSACTION_USER_SEQNUM_MAX + 2) 258c2ecf20Sopenharmony_ci#define KERNEL_SEQNUM_MAX ((u32)~0) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* for clock source and sampling rate */ 288c2ecf20Sopenharmony_cistruct efc_clock { 298c2ecf20Sopenharmony_ci u32 source; 308c2ecf20Sopenharmony_ci u32 sampling_rate; 318c2ecf20Sopenharmony_ci u32 index; 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* command categories */ 358c2ecf20Sopenharmony_cienum efc_category { 368c2ecf20Sopenharmony_ci EFC_CAT_HWINFO = 0, 378c2ecf20Sopenharmony_ci EFC_CAT_TRANSPORT = 2, 388c2ecf20Sopenharmony_ci EFC_CAT_HWCTL = 3, 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* hardware info category commands */ 428c2ecf20Sopenharmony_cienum efc_cmd_hwinfo { 438c2ecf20Sopenharmony_ci EFC_CMD_HWINFO_GET_CAPS = 0, 448c2ecf20Sopenharmony_ci EFC_CMD_HWINFO_GET_POLLED = 1, 458c2ecf20Sopenharmony_ci EFC_CMD_HWINFO_SET_RESP_ADDR = 2 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cienum efc_cmd_transport { 498c2ecf20Sopenharmony_ci EFC_CMD_TRANSPORT_SET_TX_MODE = 0 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* hardware control category commands */ 538c2ecf20Sopenharmony_cienum efc_cmd_hwctl { 548c2ecf20Sopenharmony_ci EFC_CMD_HWCTL_SET_CLOCK = 0, 558c2ecf20Sopenharmony_ci EFC_CMD_HWCTL_GET_CLOCK = 1, 568c2ecf20Sopenharmony_ci EFC_CMD_HWCTL_IDENTIFY = 5 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* return values in response */ 608c2ecf20Sopenharmony_cienum efr_status { 618c2ecf20Sopenharmony_ci EFR_STATUS_OK = 0, 628c2ecf20Sopenharmony_ci EFR_STATUS_BAD = 1, 638c2ecf20Sopenharmony_ci EFR_STATUS_BAD_COMMAND = 2, 648c2ecf20Sopenharmony_ci EFR_STATUS_COMM_ERR = 3, 658c2ecf20Sopenharmony_ci EFR_STATUS_BAD_QUAD_COUNT = 4, 668c2ecf20Sopenharmony_ci EFR_STATUS_UNSUPPORTED = 5, 678c2ecf20Sopenharmony_ci EFR_STATUS_1394_TIMEOUT = 6, 688c2ecf20Sopenharmony_ci EFR_STATUS_DSP_TIMEOUT = 7, 698c2ecf20Sopenharmony_ci EFR_STATUS_BAD_RATE = 8, 708c2ecf20Sopenharmony_ci EFR_STATUS_BAD_CLOCK = 9, 718c2ecf20Sopenharmony_ci EFR_STATUS_BAD_CHANNEL = 10, 728c2ecf20Sopenharmony_ci EFR_STATUS_BAD_PAN = 11, 738c2ecf20Sopenharmony_ci EFR_STATUS_FLASH_BUSY = 12, 748c2ecf20Sopenharmony_ci EFR_STATUS_BAD_MIRROR = 13, 758c2ecf20Sopenharmony_ci EFR_STATUS_BAD_LED = 14, 768c2ecf20Sopenharmony_ci EFR_STATUS_BAD_PARAMETER = 15, 778c2ecf20Sopenharmony_ci EFR_STATUS_INCOMPLETE = 0x80000000 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic const char *const efr_status_names[] = { 818c2ecf20Sopenharmony_ci [EFR_STATUS_OK] = "OK", 828c2ecf20Sopenharmony_ci [EFR_STATUS_BAD] = "bad", 838c2ecf20Sopenharmony_ci [EFR_STATUS_BAD_COMMAND] = "bad command", 848c2ecf20Sopenharmony_ci [EFR_STATUS_COMM_ERR] = "comm err", 858c2ecf20Sopenharmony_ci [EFR_STATUS_BAD_QUAD_COUNT] = "bad quad count", 868c2ecf20Sopenharmony_ci [EFR_STATUS_UNSUPPORTED] = "unsupported", 878c2ecf20Sopenharmony_ci [EFR_STATUS_1394_TIMEOUT] = "1394 timeout", 888c2ecf20Sopenharmony_ci [EFR_STATUS_DSP_TIMEOUT] = "DSP timeout", 898c2ecf20Sopenharmony_ci [EFR_STATUS_BAD_RATE] = "bad rate", 908c2ecf20Sopenharmony_ci [EFR_STATUS_BAD_CLOCK] = "bad clock", 918c2ecf20Sopenharmony_ci [EFR_STATUS_BAD_CHANNEL] = "bad channel", 928c2ecf20Sopenharmony_ci [EFR_STATUS_BAD_PAN] = "bad pan", 938c2ecf20Sopenharmony_ci [EFR_STATUS_FLASH_BUSY] = "flash busy", 948c2ecf20Sopenharmony_ci [EFR_STATUS_BAD_MIRROR] = "bad mirror", 958c2ecf20Sopenharmony_ci [EFR_STATUS_BAD_LED] = "bad LED", 968c2ecf20Sopenharmony_ci [EFR_STATUS_BAD_PARAMETER] = "bad parameter", 978c2ecf20Sopenharmony_ci [EFR_STATUS_BAD_PARAMETER + 1] = "incomplete" 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic int 1018c2ecf20Sopenharmony_ciefw_transaction(struct snd_efw *efw, unsigned int category, 1028c2ecf20Sopenharmony_ci unsigned int command, 1038c2ecf20Sopenharmony_ci const __be32 *params, unsigned int param_bytes, 1048c2ecf20Sopenharmony_ci const __be32 *resp, unsigned int resp_bytes) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct snd_efw_transaction *header; 1078c2ecf20Sopenharmony_ci __be32 *buf; 1088c2ecf20Sopenharmony_ci u32 seqnum; 1098c2ecf20Sopenharmony_ci unsigned int buf_bytes, cmd_bytes; 1108c2ecf20Sopenharmony_ci int err; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* calculate buffer size*/ 1138c2ecf20Sopenharmony_ci buf_bytes = sizeof(struct snd_efw_transaction) + 1148c2ecf20Sopenharmony_ci max(param_bytes, resp_bytes); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci /* keep buffer */ 1178c2ecf20Sopenharmony_ci buf = kzalloc(buf_bytes, GFP_KERNEL); 1188c2ecf20Sopenharmony_ci if (buf == NULL) 1198c2ecf20Sopenharmony_ci return -ENOMEM; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* to keep consistency of sequence number */ 1228c2ecf20Sopenharmony_ci spin_lock(&efw->lock); 1238c2ecf20Sopenharmony_ci if ((efw->seqnum < KERNEL_SEQNUM_MIN) || 1248c2ecf20Sopenharmony_ci (efw->seqnum >= KERNEL_SEQNUM_MAX - 2)) 1258c2ecf20Sopenharmony_ci efw->seqnum = KERNEL_SEQNUM_MIN; 1268c2ecf20Sopenharmony_ci else 1278c2ecf20Sopenharmony_ci efw->seqnum += 2; 1288c2ecf20Sopenharmony_ci seqnum = efw->seqnum; 1298c2ecf20Sopenharmony_ci spin_unlock(&efw->lock); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* fill transaction header fields */ 1328c2ecf20Sopenharmony_ci cmd_bytes = sizeof(struct snd_efw_transaction) + param_bytes; 1338c2ecf20Sopenharmony_ci header = (struct snd_efw_transaction *)buf; 1348c2ecf20Sopenharmony_ci header->length = cpu_to_be32(cmd_bytes / sizeof(__be32)); 1358c2ecf20Sopenharmony_ci header->version = cpu_to_be32(1); 1368c2ecf20Sopenharmony_ci header->seqnum = cpu_to_be32(seqnum); 1378c2ecf20Sopenharmony_ci header->category = cpu_to_be32(category); 1388c2ecf20Sopenharmony_ci header->command = cpu_to_be32(command); 1398c2ecf20Sopenharmony_ci header->status = 0; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* fill transaction command parameters */ 1428c2ecf20Sopenharmony_ci memcpy(header->params, params, param_bytes); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci err = snd_efw_transaction_run(efw->unit, buf, cmd_bytes, 1458c2ecf20Sopenharmony_ci buf, buf_bytes); 1468c2ecf20Sopenharmony_ci if (err < 0) 1478c2ecf20Sopenharmony_ci goto end; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* check transaction header fields */ 1508c2ecf20Sopenharmony_ci if ((be32_to_cpu(header->version) < 1) || 1518c2ecf20Sopenharmony_ci (be32_to_cpu(header->category) != category) || 1528c2ecf20Sopenharmony_ci (be32_to_cpu(header->command) != command) || 1538c2ecf20Sopenharmony_ci (be32_to_cpu(header->status) != EFR_STATUS_OK)) { 1548c2ecf20Sopenharmony_ci dev_err(&efw->unit->device, "EFW command failed [%u/%u]: %s\n", 1558c2ecf20Sopenharmony_ci be32_to_cpu(header->category), 1568c2ecf20Sopenharmony_ci be32_to_cpu(header->command), 1578c2ecf20Sopenharmony_ci efr_status_names[be32_to_cpu(header->status)]); 1588c2ecf20Sopenharmony_ci err = -EIO; 1598c2ecf20Sopenharmony_ci goto end; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (resp == NULL) 1638c2ecf20Sopenharmony_ci goto end; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* fill transaction response parameters */ 1668c2ecf20Sopenharmony_ci memset((void *)resp, 0, resp_bytes); 1678c2ecf20Sopenharmony_ci resp_bytes = min_t(unsigned int, resp_bytes, 1688c2ecf20Sopenharmony_ci be32_to_cpu(header->length) * sizeof(__be32) - 1698c2ecf20Sopenharmony_ci sizeof(struct snd_efw_transaction)); 1708c2ecf20Sopenharmony_ci memcpy((void *)resp, &buf[6], resp_bytes); 1718c2ecf20Sopenharmony_ciend: 1728c2ecf20Sopenharmony_ci kfree(buf); 1738c2ecf20Sopenharmony_ci return err; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci/* 1778c2ecf20Sopenharmony_ci * The address in host system for transaction response is changable when the 1788c2ecf20Sopenharmony_ci * device supports. struct hwinfo.flags includes its flag. The default is 1798c2ecf20Sopenharmony_ci * MEMORY_SPACE_EFW_RESPONSE. 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_ciint snd_efw_command_set_resp_addr(struct snd_efw *efw, 1828c2ecf20Sopenharmony_ci u16 addr_high, u32 addr_low) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci __be32 addr[2]; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci addr[0] = cpu_to_be32(addr_high); 1878c2ecf20Sopenharmony_ci addr[1] = cpu_to_be32(addr_low); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (!efw->resp_addr_changable) 1908c2ecf20Sopenharmony_ci return -ENOSYS; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return efw_transaction(efw, EFC_CAT_HWCTL, 1938c2ecf20Sopenharmony_ci EFC_CMD_HWINFO_SET_RESP_ADDR, 1948c2ecf20Sopenharmony_ci addr, sizeof(addr), NULL, 0); 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci/* 1988c2ecf20Sopenharmony_ci * This is for timestamp processing. In Windows mode, all 32bit fields of second 1998c2ecf20Sopenharmony_ci * CIP header in AMDTP transmit packet is used for 'presentation timestamp'. In 2008c2ecf20Sopenharmony_ci * 'no data' packet the value of this field is 0x90ffffff. 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_ciint snd_efw_command_set_tx_mode(struct snd_efw *efw, 2038c2ecf20Sopenharmony_ci enum snd_efw_transport_mode mode) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci __be32 param = cpu_to_be32(mode); 2068c2ecf20Sopenharmony_ci return efw_transaction(efw, EFC_CAT_TRANSPORT, 2078c2ecf20Sopenharmony_ci EFC_CMD_TRANSPORT_SET_TX_MODE, 2088c2ecf20Sopenharmony_ci ¶m, sizeof(param), NULL, 0); 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ciint snd_efw_command_get_hwinfo(struct snd_efw *efw, 2128c2ecf20Sopenharmony_ci struct snd_efw_hwinfo *hwinfo) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci int err; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci err = efw_transaction(efw, EFC_CAT_HWINFO, 2178c2ecf20Sopenharmony_ci EFC_CMD_HWINFO_GET_CAPS, 2188c2ecf20Sopenharmony_ci NULL, 0, (__be32 *)hwinfo, sizeof(*hwinfo)); 2198c2ecf20Sopenharmony_ci if (err < 0) 2208c2ecf20Sopenharmony_ci goto end; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->flags); 2238c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->guid_hi); 2248c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->guid_lo); 2258c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->type); 2268c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->version); 2278c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->supported_clocks); 2288c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->amdtp_rx_pcm_channels); 2298c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->amdtp_tx_pcm_channels); 2308c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->phys_out); 2318c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->phys_in); 2328c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->phys_out_grp_count); 2338c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->phys_in_grp_count); 2348c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->midi_out_ports); 2358c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->midi_in_ports); 2368c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->max_sample_rate); 2378c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->min_sample_rate); 2388c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->dsp_version); 2398c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->arm_version); 2408c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->mixer_playback_channels); 2418c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->mixer_capture_channels); 2428c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->fpga_version); 2438c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->amdtp_rx_pcm_channels_2x); 2448c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->amdtp_tx_pcm_channels_2x); 2458c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->amdtp_rx_pcm_channels_4x); 2468c2ecf20Sopenharmony_ci be32_to_cpus(&hwinfo->amdtp_tx_pcm_channels_4x); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* ensure terminated */ 2498c2ecf20Sopenharmony_ci hwinfo->vendor_name[HWINFO_NAME_SIZE_BYTES - 1] = '\0'; 2508c2ecf20Sopenharmony_ci hwinfo->model_name[HWINFO_NAME_SIZE_BYTES - 1] = '\0'; 2518c2ecf20Sopenharmony_ciend: 2528c2ecf20Sopenharmony_ci return err; 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ciint snd_efw_command_get_phys_meters(struct snd_efw *efw, 2568c2ecf20Sopenharmony_ci struct snd_efw_phys_meters *meters, 2578c2ecf20Sopenharmony_ci unsigned int len) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci u32 *buf = (u32 *)meters; 2608c2ecf20Sopenharmony_ci unsigned int i; 2618c2ecf20Sopenharmony_ci int err; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci err = efw_transaction(efw, EFC_CAT_HWINFO, 2648c2ecf20Sopenharmony_ci EFC_CMD_HWINFO_GET_POLLED, 2658c2ecf20Sopenharmony_ci NULL, 0, (__be32 *)meters, len); 2668c2ecf20Sopenharmony_ci if (err >= 0) 2678c2ecf20Sopenharmony_ci for (i = 0; i < len / sizeof(u32); i++) 2688c2ecf20Sopenharmony_ci be32_to_cpus(&buf[i]); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci return err; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic int 2748c2ecf20Sopenharmony_cicommand_get_clock(struct snd_efw *efw, struct efc_clock *clock) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci int err; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci err = efw_transaction(efw, EFC_CAT_HWCTL, 2798c2ecf20Sopenharmony_ci EFC_CMD_HWCTL_GET_CLOCK, 2808c2ecf20Sopenharmony_ci NULL, 0, 2818c2ecf20Sopenharmony_ci (__be32 *)clock, sizeof(struct efc_clock)); 2828c2ecf20Sopenharmony_ci if (err >= 0) { 2838c2ecf20Sopenharmony_ci be32_to_cpus(&clock->source); 2848c2ecf20Sopenharmony_ci be32_to_cpus(&clock->sampling_rate); 2858c2ecf20Sopenharmony_ci be32_to_cpus(&clock->index); 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci return err; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci/* give UINT_MAX if set nothing */ 2928c2ecf20Sopenharmony_cistatic int 2938c2ecf20Sopenharmony_cicommand_set_clock(struct snd_efw *efw, 2948c2ecf20Sopenharmony_ci unsigned int source, unsigned int rate) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct efc_clock clock = {0}; 2978c2ecf20Sopenharmony_ci int err; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* check arguments */ 3008c2ecf20Sopenharmony_ci if ((source == UINT_MAX) && (rate == UINT_MAX)) { 3018c2ecf20Sopenharmony_ci err = -EINVAL; 3028c2ecf20Sopenharmony_ci goto end; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* get current status */ 3068c2ecf20Sopenharmony_ci err = command_get_clock(efw, &clock); 3078c2ecf20Sopenharmony_ci if (err < 0) 3088c2ecf20Sopenharmony_ci goto end; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* no need */ 3118c2ecf20Sopenharmony_ci if ((clock.source == source) && (clock.sampling_rate == rate)) 3128c2ecf20Sopenharmony_ci goto end; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci /* set params */ 3158c2ecf20Sopenharmony_ci if ((source != UINT_MAX) && (clock.source != source)) 3168c2ecf20Sopenharmony_ci clock.source = source; 3178c2ecf20Sopenharmony_ci if ((rate != UINT_MAX) && (clock.sampling_rate != rate)) 3188c2ecf20Sopenharmony_ci clock.sampling_rate = rate; 3198c2ecf20Sopenharmony_ci clock.index = 0; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci cpu_to_be32s(&clock.source); 3228c2ecf20Sopenharmony_ci cpu_to_be32s(&clock.sampling_rate); 3238c2ecf20Sopenharmony_ci cpu_to_be32s(&clock.index); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci err = efw_transaction(efw, EFC_CAT_HWCTL, 3268c2ecf20Sopenharmony_ci EFC_CMD_HWCTL_SET_CLOCK, 3278c2ecf20Sopenharmony_ci (__be32 *)&clock, sizeof(struct efc_clock), 3288c2ecf20Sopenharmony_ci NULL, 0); 3298c2ecf20Sopenharmony_ci if (err < 0) 3308c2ecf20Sopenharmony_ci goto end; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* 3338c2ecf20Sopenharmony_ci * With firmware version 5.8, just after changing clock state, these 3348c2ecf20Sopenharmony_ci * parameters are not immediately retrieved by get command. In my 3358c2ecf20Sopenharmony_ci * trial, there needs to be 100msec to get changed parameters. 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_ci msleep(150); 3388c2ecf20Sopenharmony_ciend: 3398c2ecf20Sopenharmony_ci return err; 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ciint snd_efw_command_get_clock_source(struct snd_efw *efw, 3438c2ecf20Sopenharmony_ci enum snd_efw_clock_source *source) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci int err; 3468c2ecf20Sopenharmony_ci struct efc_clock clock = {0}; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci err = command_get_clock(efw, &clock); 3498c2ecf20Sopenharmony_ci if (err >= 0) 3508c2ecf20Sopenharmony_ci *source = clock.source; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci return err; 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ciint snd_efw_command_get_sampling_rate(struct snd_efw *efw, unsigned int *rate) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci int err; 3588c2ecf20Sopenharmony_ci struct efc_clock clock = {0}; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci err = command_get_clock(efw, &clock); 3618c2ecf20Sopenharmony_ci if (err >= 0) 3628c2ecf20Sopenharmony_ci *rate = clock.sampling_rate; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci return err; 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ciint snd_efw_command_set_sampling_rate(struct snd_efw *efw, unsigned int rate) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci return command_set_clock(efw, UINT_MAX, rate); 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 372