18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Freescale ASRC ALSA SoC Digital Audio Interface (DAI) driver 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright (C) 2014 Freescale Semiconductor, Inc. 68c2ecf20Sopenharmony_ci// 78c2ecf20Sopenharmony_ci// Author: Nicolin Chen <nicoleotsuka@gmail.com> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/clk.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 148c2ecf20Sopenharmony_ci#include <linux/platform_data/dma-imx.h> 158c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 168c2ecf20Sopenharmony_ci#include <sound/dmaengine_pcm.h> 178c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "fsl_asrc.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define IDEAL_RATIO_DECIMAL_DEPTH 26 228c2ecf20Sopenharmony_ci#define DIVIDER_NUM 64 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define pair_err(fmt, ...) \ 258c2ecf20Sopenharmony_ci dev_err(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define pair_dbg(fmt, ...) \ 288c2ecf20Sopenharmony_ci dev_dbg(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* Corresponding to process_option */ 318c2ecf20Sopenharmony_cistatic unsigned int supported_asrc_rate[] = { 328c2ecf20Sopenharmony_ci 5512, 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 338c2ecf20Sopenharmony_ci 64000, 88200, 96000, 128000, 176400, 192000, 348c2ecf20Sopenharmony_ci}; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic struct snd_pcm_hw_constraint_list fsl_asrc_rate_constraints = { 378c2ecf20Sopenharmony_ci .count = ARRAY_SIZE(supported_asrc_rate), 388c2ecf20Sopenharmony_ci .list = supported_asrc_rate, 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* 428c2ecf20Sopenharmony_ci * The following tables map the relationship between asrc_inclk/asrc_outclk in 438c2ecf20Sopenharmony_ci * fsl_asrc.h and the registers of ASRCSR 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_cistatic unsigned char input_clk_map_imx35[ASRC_CLK_MAP_LEN] = { 468c2ecf20Sopenharmony_ci 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 478c2ecf20Sopenharmony_ci 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 488c2ecf20Sopenharmony_ci 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic unsigned char output_clk_map_imx35[ASRC_CLK_MAP_LEN] = { 528c2ecf20Sopenharmony_ci 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 538c2ecf20Sopenharmony_ci 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 548c2ecf20Sopenharmony_ci 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* i.MX53 uses the same map for input and output */ 588c2ecf20Sopenharmony_cistatic unsigned char input_clk_map_imx53[ASRC_CLK_MAP_LEN] = { 598c2ecf20Sopenharmony_ci/* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf */ 608c2ecf20Sopenharmony_ci 0x0, 0x1, 0x2, 0x7, 0x4, 0x5, 0x6, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xf, 0xe, 0xd, 618c2ecf20Sopenharmony_ci 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 628c2ecf20Sopenharmony_ci 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic unsigned char output_clk_map_imx53[ASRC_CLK_MAP_LEN] = { 668c2ecf20Sopenharmony_ci/* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf */ 678c2ecf20Sopenharmony_ci 0x8, 0x9, 0xa, 0x7, 0xc, 0x5, 0x6, 0xb, 0x0, 0x1, 0x2, 0x3, 0x4, 0xf, 0xe, 0xd, 688c2ecf20Sopenharmony_ci 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 698c2ecf20Sopenharmony_ci 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* 738c2ecf20Sopenharmony_ci * i.MX8QM/i.MX8QXP uses the same map for input and output. 748c2ecf20Sopenharmony_ci * clk_map_imx8qm[0] is for i.MX8QM asrc0 758c2ecf20Sopenharmony_ci * clk_map_imx8qm[1] is for i.MX8QM asrc1 768c2ecf20Sopenharmony_ci * clk_map_imx8qxp[0] is for i.MX8QXP asrc0 778c2ecf20Sopenharmony_ci * clk_map_imx8qxp[1] is for i.MX8QXP asrc1 788c2ecf20Sopenharmony_ci */ 798c2ecf20Sopenharmony_cistatic unsigned char clk_map_imx8qm[2][ASRC_CLK_MAP_LEN] = { 808c2ecf20Sopenharmony_ci { 818c2ecf20Sopenharmony_ci 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, 828c2ecf20Sopenharmony_ci 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 838c2ecf20Sopenharmony_ci 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 848c2ecf20Sopenharmony_ci }, 858c2ecf20Sopenharmony_ci { 868c2ecf20Sopenharmony_ci 0xf, 0xf, 0xf, 0xf, 0xf, 0x7, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, 878c2ecf20Sopenharmony_ci 0x0, 0x1, 0x2, 0x3, 0xb, 0xc, 0xf, 0xf, 0xd, 0xe, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 888c2ecf20Sopenharmony_ci 0x4, 0x5, 0x6, 0xf, 0x8, 0x9, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 898c2ecf20Sopenharmony_ci }, 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic unsigned char clk_map_imx8qxp[2][ASRC_CLK_MAP_LEN] = { 938c2ecf20Sopenharmony_ci { 948c2ecf20Sopenharmony_ci 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, 958c2ecf20Sopenharmony_ci 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0xf, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xf, 0xf, 968c2ecf20Sopenharmony_ci 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 978c2ecf20Sopenharmony_ci }, 988c2ecf20Sopenharmony_ci { 998c2ecf20Sopenharmony_ci 0xf, 0xf, 0xf, 0xf, 0xf, 0x7, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, 1008c2ecf20Sopenharmony_ci 0x0, 0x1, 0x2, 0x3, 0x7, 0x8, 0xf, 0xf, 0x9, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 1018c2ecf20Sopenharmony_ci 0xf, 0xf, 0x6, 0xf, 0xf, 0xf, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 1028c2ecf20Sopenharmony_ci }, 1038c2ecf20Sopenharmony_ci}; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/* 1068c2ecf20Sopenharmony_ci * According to RM, the divider range is 1 ~ 8, 1078c2ecf20Sopenharmony_ci * prescaler is power of 2 from 1 ~ 128. 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_cistatic int asrc_clk_divider[DIVIDER_NUM] = { 1108c2ecf20Sopenharmony_ci 1, 2, 4, 8, 16, 32, 64, 128, /* divider = 1 */ 1118c2ecf20Sopenharmony_ci 2, 4, 8, 16, 32, 64, 128, 256, /* divider = 2 */ 1128c2ecf20Sopenharmony_ci 3, 6, 12, 24, 48, 96, 192, 384, /* divider = 3 */ 1138c2ecf20Sopenharmony_ci 4, 8, 16, 32, 64, 128, 256, 512, /* divider = 4 */ 1148c2ecf20Sopenharmony_ci 5, 10, 20, 40, 80, 160, 320, 640, /* divider = 5 */ 1158c2ecf20Sopenharmony_ci 6, 12, 24, 48, 96, 192, 384, 768, /* divider = 6 */ 1168c2ecf20Sopenharmony_ci 7, 14, 28, 56, 112, 224, 448, 896, /* divider = 7 */ 1178c2ecf20Sopenharmony_ci 8, 16, 32, 64, 128, 256, 512, 1024, /* divider = 8 */ 1188c2ecf20Sopenharmony_ci}; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/* 1218c2ecf20Sopenharmony_ci * Check if the divider is available for internal ratio mode 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_cistatic bool fsl_asrc_divider_avail(int clk_rate, int rate, int *div) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci u32 rem, i; 1268c2ecf20Sopenharmony_ci u64 n; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (div) 1298c2ecf20Sopenharmony_ci *div = 0; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (clk_rate == 0 || rate == 0) 1328c2ecf20Sopenharmony_ci return false; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci n = clk_rate; 1358c2ecf20Sopenharmony_ci rem = do_div(n, rate); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci if (div) 1388c2ecf20Sopenharmony_ci *div = n; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (rem != 0) 1418c2ecf20Sopenharmony_ci return false; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci for (i = 0; i < DIVIDER_NUM; i++) { 1448c2ecf20Sopenharmony_ci if (n == asrc_clk_divider[i]) 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (i == DIVIDER_NUM) 1498c2ecf20Sopenharmony_ci return false; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci return true; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci/** 1558c2ecf20Sopenharmony_ci * fsl_asrc_sel_proc - Select the pre-processing and post-processing options 1568c2ecf20Sopenharmony_ci * @inrate: input sample rate 1578c2ecf20Sopenharmony_ci * @outrate: output sample rate 1588c2ecf20Sopenharmony_ci * @pre_proc: return value for pre-processing option 1598c2ecf20Sopenharmony_ci * @post_proc: return value for post-processing option 1608c2ecf20Sopenharmony_ci * 1618c2ecf20Sopenharmony_ci * Make sure to exclude following unsupported cases before 1628c2ecf20Sopenharmony_ci * calling this function: 1638c2ecf20Sopenharmony_ci * 1) inrate > 8.125 * outrate 1648c2ecf20Sopenharmony_ci * 2) inrate > 16.125 * outrate 1658c2ecf20Sopenharmony_ci * 1668c2ecf20Sopenharmony_ci */ 1678c2ecf20Sopenharmony_cistatic void fsl_asrc_sel_proc(int inrate, int outrate, 1688c2ecf20Sopenharmony_ci int *pre_proc, int *post_proc) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci bool post_proc_cond2; 1718c2ecf20Sopenharmony_ci bool post_proc_cond0; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* select pre_proc between [0, 2] */ 1748c2ecf20Sopenharmony_ci if (inrate * 8 > 33 * outrate) 1758c2ecf20Sopenharmony_ci *pre_proc = 2; 1768c2ecf20Sopenharmony_ci else if (inrate * 8 > 15 * outrate) { 1778c2ecf20Sopenharmony_ci if (inrate > 152000) 1788c2ecf20Sopenharmony_ci *pre_proc = 2; 1798c2ecf20Sopenharmony_ci else 1808c2ecf20Sopenharmony_ci *pre_proc = 1; 1818c2ecf20Sopenharmony_ci } else if (inrate < 76000) 1828c2ecf20Sopenharmony_ci *pre_proc = 0; 1838c2ecf20Sopenharmony_ci else if (inrate > 152000) 1848c2ecf20Sopenharmony_ci *pre_proc = 2; 1858c2ecf20Sopenharmony_ci else 1868c2ecf20Sopenharmony_ci *pre_proc = 1; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* Condition for selection of post-processing */ 1898c2ecf20Sopenharmony_ci post_proc_cond2 = (inrate * 15 > outrate * 16 && outrate < 56000) || 1908c2ecf20Sopenharmony_ci (inrate > 56000 && outrate < 56000); 1918c2ecf20Sopenharmony_ci post_proc_cond0 = inrate * 23 < outrate * 8; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (post_proc_cond2) 1948c2ecf20Sopenharmony_ci *post_proc = 2; 1958c2ecf20Sopenharmony_ci else if (post_proc_cond0) 1968c2ecf20Sopenharmony_ci *post_proc = 0; 1978c2ecf20Sopenharmony_ci else 1988c2ecf20Sopenharmony_ci *post_proc = 1; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci/** 2028c2ecf20Sopenharmony_ci * fsl_asrc_request_pair - Request ASRC pair 2038c2ecf20Sopenharmony_ci * @channels: number of channels 2048c2ecf20Sopenharmony_ci * @pair: pointer to pair 2058c2ecf20Sopenharmony_ci * 2068c2ecf20Sopenharmony_ci * It assigns pair by the order of A->C->B because allocation of pair B, 2078c2ecf20Sopenharmony_ci * within range [ANCA, ANCA+ANCB-1], depends on the channels of pair A 2088c2ecf20Sopenharmony_ci * while pair A and pair C are comparatively independent. 2098c2ecf20Sopenharmony_ci */ 2108c2ecf20Sopenharmony_cistatic int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci enum asrc_pair_index index = ASRC_INVALID_PAIR; 2138c2ecf20Sopenharmony_ci struct fsl_asrc *asrc = pair->asrc; 2148c2ecf20Sopenharmony_ci struct device *dev = &asrc->pdev->dev; 2158c2ecf20Sopenharmony_ci unsigned long lock_flags; 2168c2ecf20Sopenharmony_ci int i, ret = 0; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci spin_lock_irqsave(&asrc->lock, lock_flags); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) { 2218c2ecf20Sopenharmony_ci if (asrc->pair[i] != NULL) 2228c2ecf20Sopenharmony_ci continue; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci index = i; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci if (i != ASRC_PAIR_B) 2278c2ecf20Sopenharmony_ci break; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (index == ASRC_INVALID_PAIR) { 2318c2ecf20Sopenharmony_ci dev_err(dev, "all pairs are busy now\n"); 2328c2ecf20Sopenharmony_ci ret = -EBUSY; 2338c2ecf20Sopenharmony_ci } else if (asrc->channel_avail < channels) { 2348c2ecf20Sopenharmony_ci dev_err(dev, "can't afford required channels: %d\n", channels); 2358c2ecf20Sopenharmony_ci ret = -EINVAL; 2368c2ecf20Sopenharmony_ci } else { 2378c2ecf20Sopenharmony_ci asrc->channel_avail -= channels; 2388c2ecf20Sopenharmony_ci asrc->pair[index] = pair; 2398c2ecf20Sopenharmony_ci pair->channels = channels; 2408c2ecf20Sopenharmony_ci pair->index = index; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&asrc->lock, lock_flags); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci return ret; 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci/** 2498c2ecf20Sopenharmony_ci * fsl_asrc_release_pair - Release ASRC pair 2508c2ecf20Sopenharmony_ci * @pair: pair to release 2518c2ecf20Sopenharmony_ci * 2528c2ecf20Sopenharmony_ci * It clears the resource from asrc and releases the occupied channels. 2538c2ecf20Sopenharmony_ci */ 2548c2ecf20Sopenharmony_cistatic void fsl_asrc_release_pair(struct fsl_asrc_pair *pair) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct fsl_asrc *asrc = pair->asrc; 2578c2ecf20Sopenharmony_ci enum asrc_pair_index index = pair->index; 2588c2ecf20Sopenharmony_ci unsigned long lock_flags; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* Make sure the pair is disabled */ 2618c2ecf20Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCTR, 2628c2ecf20Sopenharmony_ci ASRCTR_ASRCEi_MASK(index), 0); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci spin_lock_irqsave(&asrc->lock, lock_flags); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci asrc->channel_avail += pair->channels; 2678c2ecf20Sopenharmony_ci asrc->pair[index] = NULL; 2688c2ecf20Sopenharmony_ci pair->error = 0; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&asrc->lock, lock_flags); 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci/** 2748c2ecf20Sopenharmony_ci * fsl_asrc_set_watermarks- configure input and output thresholds 2758c2ecf20Sopenharmony_ci * @pair: pointer to pair 2768c2ecf20Sopenharmony_ci * @in: input threshold 2778c2ecf20Sopenharmony_ci * @out: output threshold 2788c2ecf20Sopenharmony_ci */ 2798c2ecf20Sopenharmony_cistatic void fsl_asrc_set_watermarks(struct fsl_asrc_pair *pair, u32 in, u32 out) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct fsl_asrc *asrc = pair->asrc; 2828c2ecf20Sopenharmony_ci enum asrc_pair_index index = pair->index; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRMCR(index), 2858c2ecf20Sopenharmony_ci ASRMCRi_EXTTHRSHi_MASK | 2868c2ecf20Sopenharmony_ci ASRMCRi_INFIFO_THRESHOLD_MASK | 2878c2ecf20Sopenharmony_ci ASRMCRi_OUTFIFO_THRESHOLD_MASK, 2888c2ecf20Sopenharmony_ci ASRMCRi_EXTTHRSHi | 2898c2ecf20Sopenharmony_ci ASRMCRi_INFIFO_THRESHOLD(in) | 2908c2ecf20Sopenharmony_ci ASRMCRi_OUTFIFO_THRESHOLD(out)); 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci/** 2948c2ecf20Sopenharmony_ci * fsl_asrc_cal_asrck_divisor - Calculate the total divisor between asrck clock rate and sample rate 2958c2ecf20Sopenharmony_ci * @pair: pointer to pair 2968c2ecf20Sopenharmony_ci * @div: divider 2978c2ecf20Sopenharmony_ci * 2988c2ecf20Sopenharmony_ci * It follows the formula clk_rate = samplerate * (2 ^ prescaler) * divider 2998c2ecf20Sopenharmony_ci */ 3008c2ecf20Sopenharmony_cistatic u32 fsl_asrc_cal_asrck_divisor(struct fsl_asrc_pair *pair, u32 div) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci u32 ps; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* Calculate the divisors: prescaler [2^0, 2^7], divder [1, 8] */ 3058c2ecf20Sopenharmony_ci for (ps = 0; div > 8; ps++) 3068c2ecf20Sopenharmony_ci div >>= 1; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci return ((div - 1) << ASRCDRi_AxCPi_WIDTH) | ps; 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci/** 3128c2ecf20Sopenharmony_ci * fsl_asrc_set_ideal_ratio - Calculate and set the ratio for Ideal Ratio mode only 3138c2ecf20Sopenharmony_ci * @pair: pointer to pair 3148c2ecf20Sopenharmony_ci * @inrate: input rate 3158c2ecf20Sopenharmony_ci * @outrate: output rate 3168c2ecf20Sopenharmony_ci * 3178c2ecf20Sopenharmony_ci * The ratio is a 32-bit fixed point value with 26 fractional bits. 3188c2ecf20Sopenharmony_ci */ 3198c2ecf20Sopenharmony_cistatic int fsl_asrc_set_ideal_ratio(struct fsl_asrc_pair *pair, 3208c2ecf20Sopenharmony_ci int inrate, int outrate) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci struct fsl_asrc *asrc = pair->asrc; 3238c2ecf20Sopenharmony_ci enum asrc_pair_index index = pair->index; 3248c2ecf20Sopenharmony_ci unsigned long ratio; 3258c2ecf20Sopenharmony_ci int i; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (!outrate) { 3288c2ecf20Sopenharmony_ci pair_err("output rate should not be zero\n"); 3298c2ecf20Sopenharmony_ci return -EINVAL; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* Calculate the intergal part of the ratio */ 3338c2ecf20Sopenharmony_ci ratio = (inrate / outrate) << IDEAL_RATIO_DECIMAL_DEPTH; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* ... and then the 26 depth decimal part */ 3368c2ecf20Sopenharmony_ci inrate %= outrate; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci for (i = 1; i <= IDEAL_RATIO_DECIMAL_DEPTH; i++) { 3398c2ecf20Sopenharmony_ci inrate <<= 1; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (inrate < outrate) 3428c2ecf20Sopenharmony_ci continue; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci ratio |= 1 << (IDEAL_RATIO_DECIMAL_DEPTH - i); 3458c2ecf20Sopenharmony_ci inrate -= outrate; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (!inrate) 3488c2ecf20Sopenharmony_ci break; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRIDRL(index), ratio); 3528c2ecf20Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRIDRH(index), ratio >> 24); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci return 0; 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci/** 3588c2ecf20Sopenharmony_ci * fsl_asrc_config_pair - Configure the assigned ASRC pair 3598c2ecf20Sopenharmony_ci * @pair: pointer to pair 3608c2ecf20Sopenharmony_ci * @use_ideal_rate: boolean configuration 3618c2ecf20Sopenharmony_ci * 3628c2ecf20Sopenharmony_ci * It configures those ASRC registers according to a configuration instance 3638c2ecf20Sopenharmony_ci * of struct asrc_config which includes in/output sample rate, width, channel 3648c2ecf20Sopenharmony_ci * and clock settings. 3658c2ecf20Sopenharmony_ci * 3668c2ecf20Sopenharmony_ci * Note: 3678c2ecf20Sopenharmony_ci * The ideal ratio configuration can work with a flexible clock rate setting. 3688c2ecf20Sopenharmony_ci * Using IDEAL_RATIO_RATE gives a faster converting speed but overloads ASRC. 3698c2ecf20Sopenharmony_ci * For a regular audio playback, the clock rate should not be slower than an 3708c2ecf20Sopenharmony_ci * clock rate aligning with the output sample rate; For a use case requiring 3718c2ecf20Sopenharmony_ci * faster conversion, set use_ideal_rate to have the faster speed. 3728c2ecf20Sopenharmony_ci */ 3738c2ecf20Sopenharmony_cistatic int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci struct fsl_asrc_pair_priv *pair_priv = pair->private; 3768c2ecf20Sopenharmony_ci struct asrc_config *config = pair_priv->config; 3778c2ecf20Sopenharmony_ci struct fsl_asrc *asrc = pair->asrc; 3788c2ecf20Sopenharmony_ci struct fsl_asrc_priv *asrc_priv = asrc->private; 3798c2ecf20Sopenharmony_ci enum asrc_pair_index index = pair->index; 3808c2ecf20Sopenharmony_ci enum asrc_word_width input_word_width; 3818c2ecf20Sopenharmony_ci enum asrc_word_width output_word_width; 3828c2ecf20Sopenharmony_ci u32 inrate, outrate, indiv, outdiv; 3838c2ecf20Sopenharmony_ci u32 clk_index[2], div[2]; 3848c2ecf20Sopenharmony_ci u64 clk_rate; 3858c2ecf20Sopenharmony_ci int in, out, channels; 3868c2ecf20Sopenharmony_ci int pre_proc, post_proc; 3878c2ecf20Sopenharmony_ci struct clk *clk; 3888c2ecf20Sopenharmony_ci bool ideal, div_avail; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (!config) { 3918c2ecf20Sopenharmony_ci pair_err("invalid pair config\n"); 3928c2ecf20Sopenharmony_ci return -EINVAL; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci /* Validate channels */ 3968c2ecf20Sopenharmony_ci if (config->channel_num < 1 || config->channel_num > 10) { 3978c2ecf20Sopenharmony_ci pair_err("does not support %d channels\n", config->channel_num); 3988c2ecf20Sopenharmony_ci return -EINVAL; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci switch (snd_pcm_format_width(config->input_format)) { 4028c2ecf20Sopenharmony_ci case 8: 4038c2ecf20Sopenharmony_ci input_word_width = ASRC_WIDTH_8_BIT; 4048c2ecf20Sopenharmony_ci break; 4058c2ecf20Sopenharmony_ci case 16: 4068c2ecf20Sopenharmony_ci input_word_width = ASRC_WIDTH_16_BIT; 4078c2ecf20Sopenharmony_ci break; 4088c2ecf20Sopenharmony_ci case 24: 4098c2ecf20Sopenharmony_ci input_word_width = ASRC_WIDTH_24_BIT; 4108c2ecf20Sopenharmony_ci break; 4118c2ecf20Sopenharmony_ci default: 4128c2ecf20Sopenharmony_ci pair_err("does not support this input format, %d\n", 4138c2ecf20Sopenharmony_ci config->input_format); 4148c2ecf20Sopenharmony_ci return -EINVAL; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci switch (snd_pcm_format_width(config->output_format)) { 4188c2ecf20Sopenharmony_ci case 16: 4198c2ecf20Sopenharmony_ci output_word_width = ASRC_WIDTH_16_BIT; 4208c2ecf20Sopenharmony_ci break; 4218c2ecf20Sopenharmony_ci case 24: 4228c2ecf20Sopenharmony_ci output_word_width = ASRC_WIDTH_24_BIT; 4238c2ecf20Sopenharmony_ci break; 4248c2ecf20Sopenharmony_ci default: 4258c2ecf20Sopenharmony_ci pair_err("does not support this output format, %d\n", 4268c2ecf20Sopenharmony_ci config->output_format); 4278c2ecf20Sopenharmony_ci return -EINVAL; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci inrate = config->input_sample_rate; 4318c2ecf20Sopenharmony_ci outrate = config->output_sample_rate; 4328c2ecf20Sopenharmony_ci ideal = config->inclk == INCLK_NONE; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci /* Validate input and output sample rates */ 4358c2ecf20Sopenharmony_ci for (in = 0; in < ARRAY_SIZE(supported_asrc_rate); in++) 4368c2ecf20Sopenharmony_ci if (inrate == supported_asrc_rate[in]) 4378c2ecf20Sopenharmony_ci break; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci if (in == ARRAY_SIZE(supported_asrc_rate)) { 4408c2ecf20Sopenharmony_ci pair_err("unsupported input sample rate: %dHz\n", inrate); 4418c2ecf20Sopenharmony_ci return -EINVAL; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci for (out = 0; out < ARRAY_SIZE(supported_asrc_rate); out++) 4458c2ecf20Sopenharmony_ci if (outrate == supported_asrc_rate[out]) 4468c2ecf20Sopenharmony_ci break; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if (out == ARRAY_SIZE(supported_asrc_rate)) { 4498c2ecf20Sopenharmony_ci pair_err("unsupported output sample rate: %dHz\n", outrate); 4508c2ecf20Sopenharmony_ci return -EINVAL; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if ((outrate >= 5512 && outrate <= 30000) && 4548c2ecf20Sopenharmony_ci (outrate > 24 * inrate || inrate > 8 * outrate)) { 4558c2ecf20Sopenharmony_ci pair_err("exceed supported ratio range [1/24, 8] for \ 4568c2ecf20Sopenharmony_ci inrate/outrate: %d/%d\n", inrate, outrate); 4578c2ecf20Sopenharmony_ci return -EINVAL; 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci /* Validate input and output clock sources */ 4618c2ecf20Sopenharmony_ci clk_index[IN] = asrc_priv->clk_map[IN][config->inclk]; 4628c2ecf20Sopenharmony_ci clk_index[OUT] = asrc_priv->clk_map[OUT][config->outclk]; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* We only have output clock for ideal ratio mode */ 4658c2ecf20Sopenharmony_ci clk = asrc_priv->asrck_clk[clk_index[ideal ? OUT : IN]]; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci clk_rate = clk_get_rate(clk); 4688c2ecf20Sopenharmony_ci div_avail = fsl_asrc_divider_avail(clk_rate, inrate, &div[IN]); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* 4718c2ecf20Sopenharmony_ci * The divider range is [1, 1024], defined by the hardware. For non- 4728c2ecf20Sopenharmony_ci * ideal ratio configuration, clock rate has to be strictly aligned 4738c2ecf20Sopenharmony_ci * with the sample rate. For ideal ratio configuration, clock rates 4748c2ecf20Sopenharmony_ci * only result in different converting speeds. So remainder does not 4758c2ecf20Sopenharmony_ci * matter, as long as we keep the divider within its valid range. 4768c2ecf20Sopenharmony_ci */ 4778c2ecf20Sopenharmony_ci if (div[IN] == 0 || (!ideal && !div_avail)) { 4788c2ecf20Sopenharmony_ci pair_err("failed to support input sample rate %dHz by asrck_%x\n", 4798c2ecf20Sopenharmony_ci inrate, clk_index[ideal ? OUT : IN]); 4808c2ecf20Sopenharmony_ci return -EINVAL; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci div[IN] = min_t(u32, 1024, div[IN]); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci clk = asrc_priv->asrck_clk[clk_index[OUT]]; 4868c2ecf20Sopenharmony_ci clk_rate = clk_get_rate(clk); 4878c2ecf20Sopenharmony_ci if (ideal && use_ideal_rate) 4888c2ecf20Sopenharmony_ci div_avail = fsl_asrc_divider_avail(clk_rate, IDEAL_RATIO_RATE, &div[OUT]); 4898c2ecf20Sopenharmony_ci else 4908c2ecf20Sopenharmony_ci div_avail = fsl_asrc_divider_avail(clk_rate, outrate, &div[OUT]); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* Output divider has the same limitation as the input one */ 4938c2ecf20Sopenharmony_ci if (div[OUT] == 0 || (!ideal && !div_avail)) { 4948c2ecf20Sopenharmony_ci pair_err("failed to support output sample rate %dHz by asrck_%x\n", 4958c2ecf20Sopenharmony_ci outrate, clk_index[OUT]); 4968c2ecf20Sopenharmony_ci return -EINVAL; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci div[OUT] = min_t(u32, 1024, div[OUT]); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci /* Set the channel number */ 5028c2ecf20Sopenharmony_ci channels = config->channel_num; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (asrc_priv->soc->channel_bits < 4) 5058c2ecf20Sopenharmony_ci channels /= 2; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci /* Update channels for current pair */ 5088c2ecf20Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCNCR, 5098c2ecf20Sopenharmony_ci ASRCNCR_ANCi_MASK(index, asrc_priv->soc->channel_bits), 5108c2ecf20Sopenharmony_ci ASRCNCR_ANCi(index, channels, asrc_priv->soc->channel_bits)); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci /* Default setting: Automatic selection for processing mode */ 5138c2ecf20Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCTR, 5148c2ecf20Sopenharmony_ci ASRCTR_ATSi_MASK(index), ASRCTR_ATS(index)); 5158c2ecf20Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCTR, 5168c2ecf20Sopenharmony_ci ASRCTR_USRi_MASK(index), 0); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci /* Set the input and output clock sources */ 5198c2ecf20Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCSR, 5208c2ecf20Sopenharmony_ci ASRCSR_AICSi_MASK(index) | ASRCSR_AOCSi_MASK(index), 5218c2ecf20Sopenharmony_ci ASRCSR_AICS(index, clk_index[IN]) | 5228c2ecf20Sopenharmony_ci ASRCSR_AOCS(index, clk_index[OUT])); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci /* Calculate the input clock divisors */ 5258c2ecf20Sopenharmony_ci indiv = fsl_asrc_cal_asrck_divisor(pair, div[IN]); 5268c2ecf20Sopenharmony_ci outdiv = fsl_asrc_cal_asrck_divisor(pair, div[OUT]); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci /* Suppose indiv and outdiv includes prescaler, so add its MASK too */ 5298c2ecf20Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCDR(index), 5308c2ecf20Sopenharmony_ci ASRCDRi_AOCPi_MASK(index) | ASRCDRi_AICPi_MASK(index) | 5318c2ecf20Sopenharmony_ci ASRCDRi_AOCDi_MASK(index) | ASRCDRi_AICDi_MASK(index), 5328c2ecf20Sopenharmony_ci ASRCDRi_AOCP(index, outdiv) | ASRCDRi_AICP(index, indiv)); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci /* Implement word_width configurations */ 5358c2ecf20Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRMCR1(index), 5368c2ecf20Sopenharmony_ci ASRMCR1i_OW16_MASK | ASRMCR1i_IWD_MASK, 5378c2ecf20Sopenharmony_ci ASRMCR1i_OW16(output_word_width) | 5388c2ecf20Sopenharmony_ci ASRMCR1i_IWD(input_word_width)); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci /* Enable BUFFER STALL */ 5418c2ecf20Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRMCR(index), 5428c2ecf20Sopenharmony_ci ASRMCRi_BUFSTALLi_MASK, ASRMCRi_BUFSTALLi); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci /* Set default thresholds for input and output FIFO */ 5458c2ecf20Sopenharmony_ci fsl_asrc_set_watermarks(pair, ASRC_INPUTFIFO_THRESHOLD, 5468c2ecf20Sopenharmony_ci ASRC_INPUTFIFO_THRESHOLD); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* Configure the following only for Ideal Ratio mode */ 5498c2ecf20Sopenharmony_ci if (!ideal) 5508c2ecf20Sopenharmony_ci return 0; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci /* Clear ASTSx bit to use Ideal Ratio mode */ 5538c2ecf20Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCTR, 5548c2ecf20Sopenharmony_ci ASRCTR_ATSi_MASK(index), 0); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* Enable Ideal Ratio mode */ 5578c2ecf20Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCTR, 5588c2ecf20Sopenharmony_ci ASRCTR_IDRi_MASK(index) | ASRCTR_USRi_MASK(index), 5598c2ecf20Sopenharmony_ci ASRCTR_IDR(index) | ASRCTR_USR(index)); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci fsl_asrc_sel_proc(inrate, outrate, &pre_proc, &post_proc); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci /* Apply configurations for pre- and post-processing */ 5648c2ecf20Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCFG, 5658c2ecf20Sopenharmony_ci ASRCFG_PREMODi_MASK(index) | ASRCFG_POSTMODi_MASK(index), 5668c2ecf20Sopenharmony_ci ASRCFG_PREMOD(index, pre_proc) | 5678c2ecf20Sopenharmony_ci ASRCFG_POSTMOD(index, post_proc)); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci return fsl_asrc_set_ideal_ratio(pair, inrate, outrate); 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci/** 5738c2ecf20Sopenharmony_ci * fsl_asrc_start_pair - Start the assigned ASRC pair 5748c2ecf20Sopenharmony_ci * @pair: pointer to pair 5758c2ecf20Sopenharmony_ci * 5768c2ecf20Sopenharmony_ci * It enables the assigned pair and makes it stopped at the stall level. 5778c2ecf20Sopenharmony_ci */ 5788c2ecf20Sopenharmony_cistatic void fsl_asrc_start_pair(struct fsl_asrc_pair *pair) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci struct fsl_asrc *asrc = pair->asrc; 5818c2ecf20Sopenharmony_ci enum asrc_pair_index index = pair->index; 5828c2ecf20Sopenharmony_ci int reg, retry = 10, i; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci /* Enable the current pair */ 5858c2ecf20Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCTR, 5868c2ecf20Sopenharmony_ci ASRCTR_ASRCEi_MASK(index), ASRCTR_ASRCE(index)); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci /* Wait for status of initialization */ 5898c2ecf20Sopenharmony_ci do { 5908c2ecf20Sopenharmony_ci udelay(5); 5918c2ecf20Sopenharmony_ci regmap_read(asrc->regmap, REG_ASRCFG, ®); 5928c2ecf20Sopenharmony_ci reg &= ASRCFG_INIRQi_MASK(index); 5938c2ecf20Sopenharmony_ci } while (!reg && --retry); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci /* Make the input fifo to ASRC STALL level */ 5968c2ecf20Sopenharmony_ci regmap_read(asrc->regmap, REG_ASRCNCR, ®); 5978c2ecf20Sopenharmony_ci for (i = 0; i < pair->channels * 4; i++) 5988c2ecf20Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRDI(index), 0); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci /* Enable overload interrupt */ 6018c2ecf20Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRIER, ASRIER_AOLIE); 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci/** 6058c2ecf20Sopenharmony_ci * fsl_asrc_stop_pair - Stop the assigned ASRC pair 6068c2ecf20Sopenharmony_ci * @pair: pointer to pair 6078c2ecf20Sopenharmony_ci */ 6088c2ecf20Sopenharmony_cistatic void fsl_asrc_stop_pair(struct fsl_asrc_pair *pair) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci struct fsl_asrc *asrc = pair->asrc; 6118c2ecf20Sopenharmony_ci enum asrc_pair_index index = pair->index; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci /* Stop the current pair */ 6148c2ecf20Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCTR, 6158c2ecf20Sopenharmony_ci ASRCTR_ASRCEi_MASK(index), 0); 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci/** 6198c2ecf20Sopenharmony_ci * fsl_asrc_get_dma_channel- Get DMA channel according to the pair and direction. 6208c2ecf20Sopenharmony_ci * @pair: pointer to pair 6218c2ecf20Sopenharmony_ci * @dir: DMA direction 6228c2ecf20Sopenharmony_ci */ 6238c2ecf20Sopenharmony_cistatic struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, 6248c2ecf20Sopenharmony_ci bool dir) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci struct fsl_asrc *asrc = pair->asrc; 6278c2ecf20Sopenharmony_ci enum asrc_pair_index index = pair->index; 6288c2ecf20Sopenharmony_ci char name[4]; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci sprintf(name, "%cx%c", dir == IN ? 'r' : 't', index + 'a'); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci return dma_request_slave_channel(&asrc->pdev->dev, name); 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistatic int fsl_asrc_dai_startup(struct snd_pcm_substream *substream, 6368c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); 6398c2ecf20Sopenharmony_ci struct fsl_asrc_priv *asrc_priv = asrc->private; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci /* Odd channel number is not valid for older ASRC (channel_bits==3) */ 6428c2ecf20Sopenharmony_ci if (asrc_priv->soc->channel_bits == 3) 6438c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_step(substream->runtime, 0, 6448c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, 2); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci return snd_pcm_hw_constraint_list(substream->runtime, 0, 6488c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, &fsl_asrc_rate_constraints); 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci/* Select proper clock source for internal ratio mode */ 6528c2ecf20Sopenharmony_cistatic void fsl_asrc_select_clk(struct fsl_asrc_priv *asrc_priv, 6538c2ecf20Sopenharmony_ci struct fsl_asrc_pair *pair, 6548c2ecf20Sopenharmony_ci int in_rate, 6558c2ecf20Sopenharmony_ci int out_rate) 6568c2ecf20Sopenharmony_ci{ 6578c2ecf20Sopenharmony_ci struct fsl_asrc_pair_priv *pair_priv = pair->private; 6588c2ecf20Sopenharmony_ci struct asrc_config *config = pair_priv->config; 6598c2ecf20Sopenharmony_ci int rate[2], select_clk[2]; /* Array size 2 means IN and OUT */ 6608c2ecf20Sopenharmony_ci int clk_rate, clk_index; 6618c2ecf20Sopenharmony_ci int i = 0, j = 0; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci rate[IN] = in_rate; 6648c2ecf20Sopenharmony_ci rate[OUT] = out_rate; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci /* Select proper clock source for internal ratio mode */ 6678c2ecf20Sopenharmony_ci for (j = 0; j < 2; j++) { 6688c2ecf20Sopenharmony_ci for (i = 0; i < ASRC_CLK_MAP_LEN; i++) { 6698c2ecf20Sopenharmony_ci clk_index = asrc_priv->clk_map[j][i]; 6708c2ecf20Sopenharmony_ci clk_rate = clk_get_rate(asrc_priv->asrck_clk[clk_index]); 6718c2ecf20Sopenharmony_ci /* Only match a perfect clock source with no remainder */ 6728c2ecf20Sopenharmony_ci if (fsl_asrc_divider_avail(clk_rate, rate[j], NULL)) 6738c2ecf20Sopenharmony_ci break; 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci select_clk[j] = i; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci /* Switch to ideal ratio mode if there is no proper clock source */ 6808c2ecf20Sopenharmony_ci if (select_clk[IN] == ASRC_CLK_MAP_LEN || select_clk[OUT] == ASRC_CLK_MAP_LEN) { 6818c2ecf20Sopenharmony_ci select_clk[IN] = INCLK_NONE; 6828c2ecf20Sopenharmony_ci select_clk[OUT] = OUTCLK_ASRCK1_CLK; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci config->inclk = select_clk[IN]; 6868c2ecf20Sopenharmony_ci config->outclk = select_clk[OUT]; 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cistatic int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream, 6908c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 6918c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); 6948c2ecf20Sopenharmony_ci struct fsl_asrc_priv *asrc_priv = asrc->private; 6958c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 6968c2ecf20Sopenharmony_ci struct fsl_asrc_pair *pair = runtime->private_data; 6978c2ecf20Sopenharmony_ci struct fsl_asrc_pair_priv *pair_priv = pair->private; 6988c2ecf20Sopenharmony_ci unsigned int channels = params_channels(params); 6998c2ecf20Sopenharmony_ci unsigned int rate = params_rate(params); 7008c2ecf20Sopenharmony_ci struct asrc_config config; 7018c2ecf20Sopenharmony_ci int ret; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci ret = fsl_asrc_request_pair(channels, pair); 7048c2ecf20Sopenharmony_ci if (ret) { 7058c2ecf20Sopenharmony_ci dev_err(dai->dev, "fail to request asrc pair\n"); 7068c2ecf20Sopenharmony_ci return ret; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci pair_priv->config = &config; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci config.pair = pair->index; 7128c2ecf20Sopenharmony_ci config.channel_num = channels; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 7158c2ecf20Sopenharmony_ci config.input_format = params_format(params); 7168c2ecf20Sopenharmony_ci config.output_format = asrc->asrc_format; 7178c2ecf20Sopenharmony_ci config.input_sample_rate = rate; 7188c2ecf20Sopenharmony_ci config.output_sample_rate = asrc->asrc_rate; 7198c2ecf20Sopenharmony_ci } else { 7208c2ecf20Sopenharmony_ci config.input_format = asrc->asrc_format; 7218c2ecf20Sopenharmony_ci config.output_format = params_format(params); 7228c2ecf20Sopenharmony_ci config.input_sample_rate = asrc->asrc_rate; 7238c2ecf20Sopenharmony_ci config.output_sample_rate = rate; 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci fsl_asrc_select_clk(asrc_priv, pair, 7278c2ecf20Sopenharmony_ci config.input_sample_rate, 7288c2ecf20Sopenharmony_ci config.output_sample_rate); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci ret = fsl_asrc_config_pair(pair, false); 7318c2ecf20Sopenharmony_ci if (ret) { 7328c2ecf20Sopenharmony_ci dev_err(dai->dev, "fail to config asrc pair\n"); 7338c2ecf20Sopenharmony_ci return ret; 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci return 0; 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cistatic int fsl_asrc_dai_hw_free(struct snd_pcm_substream *substream, 7408c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 7418c2ecf20Sopenharmony_ci{ 7428c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 7438c2ecf20Sopenharmony_ci struct fsl_asrc_pair *pair = runtime->private_data; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci if (pair) 7468c2ecf20Sopenharmony_ci fsl_asrc_release_pair(pair); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci return 0; 7498c2ecf20Sopenharmony_ci} 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic int fsl_asrc_dai_trigger(struct snd_pcm_substream *substream, int cmd, 7528c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 7538c2ecf20Sopenharmony_ci{ 7548c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 7558c2ecf20Sopenharmony_ci struct fsl_asrc_pair *pair = runtime->private_data; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci switch (cmd) { 7588c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 7598c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 7608c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 7618c2ecf20Sopenharmony_ci fsl_asrc_start_pair(pair); 7628c2ecf20Sopenharmony_ci break; 7638c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 7648c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 7658c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 7668c2ecf20Sopenharmony_ci fsl_asrc_stop_pair(pair); 7678c2ecf20Sopenharmony_ci break; 7688c2ecf20Sopenharmony_ci default: 7698c2ecf20Sopenharmony_ci return -EINVAL; 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci return 0; 7738c2ecf20Sopenharmony_ci} 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops fsl_asrc_dai_ops = { 7768c2ecf20Sopenharmony_ci .startup = fsl_asrc_dai_startup, 7778c2ecf20Sopenharmony_ci .hw_params = fsl_asrc_dai_hw_params, 7788c2ecf20Sopenharmony_ci .hw_free = fsl_asrc_dai_hw_free, 7798c2ecf20Sopenharmony_ci .trigger = fsl_asrc_dai_trigger, 7808c2ecf20Sopenharmony_ci}; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_cistatic int fsl_asrc_dai_probe(struct snd_soc_dai *dai) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci snd_soc_dai_init_dma_data(dai, &asrc->dma_params_tx, 7878c2ecf20Sopenharmony_ci &asrc->dma_params_rx); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci return 0; 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci#define FSL_ASRC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \ 7938c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S16_LE | \ 7948c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_3LE) 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver fsl_asrc_dai = { 7978c2ecf20Sopenharmony_ci .probe = fsl_asrc_dai_probe, 7988c2ecf20Sopenharmony_ci .playback = { 7998c2ecf20Sopenharmony_ci .stream_name = "ASRC-Playback", 8008c2ecf20Sopenharmony_ci .channels_min = 1, 8018c2ecf20Sopenharmony_ci .channels_max = 10, 8028c2ecf20Sopenharmony_ci .rate_min = 5512, 8038c2ecf20Sopenharmony_ci .rate_max = 192000, 8048c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_KNOT, 8058c2ecf20Sopenharmony_ci .formats = FSL_ASRC_FORMATS | 8068c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S8, 8078c2ecf20Sopenharmony_ci }, 8088c2ecf20Sopenharmony_ci .capture = { 8098c2ecf20Sopenharmony_ci .stream_name = "ASRC-Capture", 8108c2ecf20Sopenharmony_ci .channels_min = 1, 8118c2ecf20Sopenharmony_ci .channels_max = 10, 8128c2ecf20Sopenharmony_ci .rate_min = 5512, 8138c2ecf20Sopenharmony_ci .rate_max = 192000, 8148c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_KNOT, 8158c2ecf20Sopenharmony_ci .formats = FSL_ASRC_FORMATS, 8168c2ecf20Sopenharmony_ci }, 8178c2ecf20Sopenharmony_ci .ops = &fsl_asrc_dai_ops, 8188c2ecf20Sopenharmony_ci}; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_cistatic bool fsl_asrc_readable_reg(struct device *dev, unsigned int reg) 8218c2ecf20Sopenharmony_ci{ 8228c2ecf20Sopenharmony_ci switch (reg) { 8238c2ecf20Sopenharmony_ci case REG_ASRCTR: 8248c2ecf20Sopenharmony_ci case REG_ASRIER: 8258c2ecf20Sopenharmony_ci case REG_ASRCNCR: 8268c2ecf20Sopenharmony_ci case REG_ASRCFG: 8278c2ecf20Sopenharmony_ci case REG_ASRCSR: 8288c2ecf20Sopenharmony_ci case REG_ASRCDR1: 8298c2ecf20Sopenharmony_ci case REG_ASRCDR2: 8308c2ecf20Sopenharmony_ci case REG_ASRSTR: 8318c2ecf20Sopenharmony_ci case REG_ASRPM1: 8328c2ecf20Sopenharmony_ci case REG_ASRPM2: 8338c2ecf20Sopenharmony_ci case REG_ASRPM3: 8348c2ecf20Sopenharmony_ci case REG_ASRPM4: 8358c2ecf20Sopenharmony_ci case REG_ASRPM5: 8368c2ecf20Sopenharmony_ci case REG_ASRTFR1: 8378c2ecf20Sopenharmony_ci case REG_ASRCCR: 8388c2ecf20Sopenharmony_ci case REG_ASRDOA: 8398c2ecf20Sopenharmony_ci case REG_ASRDOB: 8408c2ecf20Sopenharmony_ci case REG_ASRDOC: 8418c2ecf20Sopenharmony_ci case REG_ASRIDRHA: 8428c2ecf20Sopenharmony_ci case REG_ASRIDRLA: 8438c2ecf20Sopenharmony_ci case REG_ASRIDRHB: 8448c2ecf20Sopenharmony_ci case REG_ASRIDRLB: 8458c2ecf20Sopenharmony_ci case REG_ASRIDRHC: 8468c2ecf20Sopenharmony_ci case REG_ASRIDRLC: 8478c2ecf20Sopenharmony_ci case REG_ASR76K: 8488c2ecf20Sopenharmony_ci case REG_ASR56K: 8498c2ecf20Sopenharmony_ci case REG_ASRMCRA: 8508c2ecf20Sopenharmony_ci case REG_ASRFSTA: 8518c2ecf20Sopenharmony_ci case REG_ASRMCRB: 8528c2ecf20Sopenharmony_ci case REG_ASRFSTB: 8538c2ecf20Sopenharmony_ci case REG_ASRMCRC: 8548c2ecf20Sopenharmony_ci case REG_ASRFSTC: 8558c2ecf20Sopenharmony_ci case REG_ASRMCR1A: 8568c2ecf20Sopenharmony_ci case REG_ASRMCR1B: 8578c2ecf20Sopenharmony_ci case REG_ASRMCR1C: 8588c2ecf20Sopenharmony_ci return true; 8598c2ecf20Sopenharmony_ci default: 8608c2ecf20Sopenharmony_ci return false; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_cistatic bool fsl_asrc_volatile_reg(struct device *dev, unsigned int reg) 8658c2ecf20Sopenharmony_ci{ 8668c2ecf20Sopenharmony_ci switch (reg) { 8678c2ecf20Sopenharmony_ci case REG_ASRSTR: 8688c2ecf20Sopenharmony_ci case REG_ASRDIA: 8698c2ecf20Sopenharmony_ci case REG_ASRDIB: 8708c2ecf20Sopenharmony_ci case REG_ASRDIC: 8718c2ecf20Sopenharmony_ci case REG_ASRDOA: 8728c2ecf20Sopenharmony_ci case REG_ASRDOB: 8738c2ecf20Sopenharmony_ci case REG_ASRDOC: 8748c2ecf20Sopenharmony_ci case REG_ASRFSTA: 8758c2ecf20Sopenharmony_ci case REG_ASRFSTB: 8768c2ecf20Sopenharmony_ci case REG_ASRFSTC: 8778c2ecf20Sopenharmony_ci case REG_ASRCFG: 8788c2ecf20Sopenharmony_ci return true; 8798c2ecf20Sopenharmony_ci default: 8808c2ecf20Sopenharmony_ci return false; 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci} 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_cistatic bool fsl_asrc_writeable_reg(struct device *dev, unsigned int reg) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci switch (reg) { 8878c2ecf20Sopenharmony_ci case REG_ASRCTR: 8888c2ecf20Sopenharmony_ci case REG_ASRIER: 8898c2ecf20Sopenharmony_ci case REG_ASRCNCR: 8908c2ecf20Sopenharmony_ci case REG_ASRCFG: 8918c2ecf20Sopenharmony_ci case REG_ASRCSR: 8928c2ecf20Sopenharmony_ci case REG_ASRCDR1: 8938c2ecf20Sopenharmony_ci case REG_ASRCDR2: 8948c2ecf20Sopenharmony_ci case REG_ASRSTR: 8958c2ecf20Sopenharmony_ci case REG_ASRPM1: 8968c2ecf20Sopenharmony_ci case REG_ASRPM2: 8978c2ecf20Sopenharmony_ci case REG_ASRPM3: 8988c2ecf20Sopenharmony_ci case REG_ASRPM4: 8998c2ecf20Sopenharmony_ci case REG_ASRPM5: 9008c2ecf20Sopenharmony_ci case REG_ASRTFR1: 9018c2ecf20Sopenharmony_ci case REG_ASRCCR: 9028c2ecf20Sopenharmony_ci case REG_ASRDIA: 9038c2ecf20Sopenharmony_ci case REG_ASRDIB: 9048c2ecf20Sopenharmony_ci case REG_ASRDIC: 9058c2ecf20Sopenharmony_ci case REG_ASRIDRHA: 9068c2ecf20Sopenharmony_ci case REG_ASRIDRLA: 9078c2ecf20Sopenharmony_ci case REG_ASRIDRHB: 9088c2ecf20Sopenharmony_ci case REG_ASRIDRLB: 9098c2ecf20Sopenharmony_ci case REG_ASRIDRHC: 9108c2ecf20Sopenharmony_ci case REG_ASRIDRLC: 9118c2ecf20Sopenharmony_ci case REG_ASR76K: 9128c2ecf20Sopenharmony_ci case REG_ASR56K: 9138c2ecf20Sopenharmony_ci case REG_ASRMCRA: 9148c2ecf20Sopenharmony_ci case REG_ASRMCRB: 9158c2ecf20Sopenharmony_ci case REG_ASRMCRC: 9168c2ecf20Sopenharmony_ci case REG_ASRMCR1A: 9178c2ecf20Sopenharmony_ci case REG_ASRMCR1B: 9188c2ecf20Sopenharmony_ci case REG_ASRMCR1C: 9198c2ecf20Sopenharmony_ci return true; 9208c2ecf20Sopenharmony_ci default: 9218c2ecf20Sopenharmony_ci return false; 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci} 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_cistatic struct reg_default fsl_asrc_reg[] = { 9268c2ecf20Sopenharmony_ci { REG_ASRCTR, 0x0000 }, { REG_ASRIER, 0x0000 }, 9278c2ecf20Sopenharmony_ci { REG_ASRCNCR, 0x0000 }, { REG_ASRCFG, 0x0000 }, 9288c2ecf20Sopenharmony_ci { REG_ASRCSR, 0x0000 }, { REG_ASRCDR1, 0x0000 }, 9298c2ecf20Sopenharmony_ci { REG_ASRCDR2, 0x0000 }, { REG_ASRSTR, 0x0000 }, 9308c2ecf20Sopenharmony_ci { REG_ASRRA, 0x0000 }, { REG_ASRRB, 0x0000 }, 9318c2ecf20Sopenharmony_ci { REG_ASRRC, 0x0000 }, { REG_ASRPM1, 0x0000 }, 9328c2ecf20Sopenharmony_ci { REG_ASRPM2, 0x0000 }, { REG_ASRPM3, 0x0000 }, 9338c2ecf20Sopenharmony_ci { REG_ASRPM4, 0x0000 }, { REG_ASRPM5, 0x0000 }, 9348c2ecf20Sopenharmony_ci { REG_ASRTFR1, 0x0000 }, { REG_ASRCCR, 0x0000 }, 9358c2ecf20Sopenharmony_ci { REG_ASRDIA, 0x0000 }, { REG_ASRDOA, 0x0000 }, 9368c2ecf20Sopenharmony_ci { REG_ASRDIB, 0x0000 }, { REG_ASRDOB, 0x0000 }, 9378c2ecf20Sopenharmony_ci { REG_ASRDIC, 0x0000 }, { REG_ASRDOC, 0x0000 }, 9388c2ecf20Sopenharmony_ci { REG_ASRIDRHA, 0x0000 }, { REG_ASRIDRLA, 0x0000 }, 9398c2ecf20Sopenharmony_ci { REG_ASRIDRHB, 0x0000 }, { REG_ASRIDRLB, 0x0000 }, 9408c2ecf20Sopenharmony_ci { REG_ASRIDRHC, 0x0000 }, { REG_ASRIDRLC, 0x0000 }, 9418c2ecf20Sopenharmony_ci { REG_ASR76K, 0x0A47 }, { REG_ASR56K, 0x0DF3 }, 9428c2ecf20Sopenharmony_ci { REG_ASRMCRA, 0x0000 }, { REG_ASRFSTA, 0x0000 }, 9438c2ecf20Sopenharmony_ci { REG_ASRMCRB, 0x0000 }, { REG_ASRFSTB, 0x0000 }, 9448c2ecf20Sopenharmony_ci { REG_ASRMCRC, 0x0000 }, { REG_ASRFSTC, 0x0000 }, 9458c2ecf20Sopenharmony_ci { REG_ASRMCR1A, 0x0000 }, { REG_ASRMCR1B, 0x0000 }, 9468c2ecf20Sopenharmony_ci { REG_ASRMCR1C, 0x0000 }, 9478c2ecf20Sopenharmony_ci}; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_cistatic const struct regmap_config fsl_asrc_regmap_config = { 9508c2ecf20Sopenharmony_ci .reg_bits = 32, 9518c2ecf20Sopenharmony_ci .reg_stride = 4, 9528c2ecf20Sopenharmony_ci .val_bits = 32, 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci .max_register = REG_ASRMCR1C, 9558c2ecf20Sopenharmony_ci .reg_defaults = fsl_asrc_reg, 9568c2ecf20Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(fsl_asrc_reg), 9578c2ecf20Sopenharmony_ci .readable_reg = fsl_asrc_readable_reg, 9588c2ecf20Sopenharmony_ci .volatile_reg = fsl_asrc_volatile_reg, 9598c2ecf20Sopenharmony_ci .writeable_reg = fsl_asrc_writeable_reg, 9608c2ecf20Sopenharmony_ci .cache_type = REGCACHE_FLAT, 9618c2ecf20Sopenharmony_ci}; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci/** 9648c2ecf20Sopenharmony_ci * fsl_asrc_init - Initialize ASRC registers with a default configuration 9658c2ecf20Sopenharmony_ci * @asrc: ASRC context 9668c2ecf20Sopenharmony_ci */ 9678c2ecf20Sopenharmony_cistatic int fsl_asrc_init(struct fsl_asrc *asrc) 9688c2ecf20Sopenharmony_ci{ 9698c2ecf20Sopenharmony_ci unsigned long ipg_rate; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci /* Halt ASRC internal FP when input FIFO needs data for pair A, B, C */ 9728c2ecf20Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRCTR, ASRCTR_ASRCEN); 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci /* Disable interrupt by default */ 9758c2ecf20Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRIER, 0x0); 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci /* Apply recommended settings for parameters from Reference Manual */ 9788c2ecf20Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRPM1, 0x7fffff); 9798c2ecf20Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRPM2, 0x255555); 9808c2ecf20Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRPM3, 0xff7280); 9818c2ecf20Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRPM4, 0xff7280); 9828c2ecf20Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRPM5, 0xff7280); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci /* Base address for task queue FIFO. Set to 0x7C */ 9858c2ecf20Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRTFR1, 9868c2ecf20Sopenharmony_ci ASRTFR1_TF_BASE_MASK, ASRTFR1_TF_BASE(0xfc)); 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci /* 9898c2ecf20Sopenharmony_ci * Set the period of the 76KHz and 56KHz sampling clocks based on 9908c2ecf20Sopenharmony_ci * the ASRC processing clock. 9918c2ecf20Sopenharmony_ci * On iMX6, ipg_clk = 133MHz, REG_ASR76K = 0x06D6, REG_ASR56K = 0x0947 9928c2ecf20Sopenharmony_ci */ 9938c2ecf20Sopenharmony_ci ipg_rate = clk_get_rate(asrc->ipg_clk); 9948c2ecf20Sopenharmony_ci regmap_write(asrc->regmap, REG_ASR76K, ipg_rate / 76000); 9958c2ecf20Sopenharmony_ci return regmap_write(asrc->regmap, REG_ASR56K, ipg_rate / 56000); 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci/** 9998c2ecf20Sopenharmony_ci * fsl_asrc_isr- Interrupt handler for ASRC 10008c2ecf20Sopenharmony_ci * @irq: irq number 10018c2ecf20Sopenharmony_ci * @dev_id: ASRC context 10028c2ecf20Sopenharmony_ci */ 10038c2ecf20Sopenharmony_cistatic irqreturn_t fsl_asrc_isr(int irq, void *dev_id) 10048c2ecf20Sopenharmony_ci{ 10058c2ecf20Sopenharmony_ci struct fsl_asrc *asrc = (struct fsl_asrc *)dev_id; 10068c2ecf20Sopenharmony_ci struct device *dev = &asrc->pdev->dev; 10078c2ecf20Sopenharmony_ci enum asrc_pair_index index; 10088c2ecf20Sopenharmony_ci u32 status; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci regmap_read(asrc->regmap, REG_ASRSTR, &status); 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci /* Clean overload error */ 10138c2ecf20Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRSTR, ASRSTR_AOLE); 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci /* 10168c2ecf20Sopenharmony_ci * We here use dev_dbg() for all exceptions because ASRC itself does 10178c2ecf20Sopenharmony_ci * not care if FIFO overflowed or underrun while a warning in the 10188c2ecf20Sopenharmony_ci * interrupt would result a ridged conversion. 10198c2ecf20Sopenharmony_ci */ 10208c2ecf20Sopenharmony_ci for (index = ASRC_PAIR_A; index < ASRC_PAIR_MAX_NUM; index++) { 10218c2ecf20Sopenharmony_ci if (!asrc->pair[index]) 10228c2ecf20Sopenharmony_ci continue; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci if (status & ASRSTR_ATQOL) { 10258c2ecf20Sopenharmony_ci asrc->pair[index]->error |= ASRC_TASK_Q_OVERLOAD; 10268c2ecf20Sopenharmony_ci dev_dbg(dev, "ASRC Task Queue FIFO overload\n"); 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci if (status & ASRSTR_AOOL(index)) { 10308c2ecf20Sopenharmony_ci asrc->pair[index]->error |= ASRC_OUTPUT_TASK_OVERLOAD; 10318c2ecf20Sopenharmony_ci pair_dbg("Output Task Overload\n"); 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci if (status & ASRSTR_AIOL(index)) { 10358c2ecf20Sopenharmony_ci asrc->pair[index]->error |= ASRC_INPUT_TASK_OVERLOAD; 10368c2ecf20Sopenharmony_ci pair_dbg("Input Task Overload\n"); 10378c2ecf20Sopenharmony_ci } 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci if (status & ASRSTR_AODO(index)) { 10408c2ecf20Sopenharmony_ci asrc->pair[index]->error |= ASRC_OUTPUT_BUFFER_OVERFLOW; 10418c2ecf20Sopenharmony_ci pair_dbg("Output Data Buffer has overflowed\n"); 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci if (status & ASRSTR_AIDU(index)) { 10458c2ecf20Sopenharmony_ci asrc->pair[index]->error |= ASRC_INPUT_BUFFER_UNDERRUN; 10468c2ecf20Sopenharmony_ci pair_dbg("Input Data Buffer has underflowed\n"); 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci } 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci return IRQ_HANDLED; 10518c2ecf20Sopenharmony_ci} 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_cistatic int fsl_asrc_get_fifo_addr(u8 dir, enum asrc_pair_index index) 10548c2ecf20Sopenharmony_ci{ 10558c2ecf20Sopenharmony_ci return REG_ASRDx(dir, index); 10568c2ecf20Sopenharmony_ci} 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_cistatic int fsl_asrc_probe(struct platform_device *pdev) 10598c2ecf20Sopenharmony_ci{ 10608c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 10618c2ecf20Sopenharmony_ci struct fsl_asrc_priv *asrc_priv; 10628c2ecf20Sopenharmony_ci struct fsl_asrc *asrc; 10638c2ecf20Sopenharmony_ci struct resource *res; 10648c2ecf20Sopenharmony_ci void __iomem *regs; 10658c2ecf20Sopenharmony_ci int irq, ret, i; 10668c2ecf20Sopenharmony_ci u32 map_idx; 10678c2ecf20Sopenharmony_ci char tmp[16]; 10688c2ecf20Sopenharmony_ci u32 width; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci asrc = devm_kzalloc(&pdev->dev, sizeof(*asrc), GFP_KERNEL); 10718c2ecf20Sopenharmony_ci if (!asrc) 10728c2ecf20Sopenharmony_ci return -ENOMEM; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci asrc_priv = devm_kzalloc(&pdev->dev, sizeof(*asrc_priv), GFP_KERNEL); 10758c2ecf20Sopenharmony_ci if (!asrc_priv) 10768c2ecf20Sopenharmony_ci return -ENOMEM; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci asrc->pdev = pdev; 10798c2ecf20Sopenharmony_ci asrc->private = asrc_priv; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci /* Get the addresses and IRQ */ 10828c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 10838c2ecf20Sopenharmony_ci regs = devm_ioremap_resource(&pdev->dev, res); 10848c2ecf20Sopenharmony_ci if (IS_ERR(regs)) 10858c2ecf20Sopenharmony_ci return PTR_ERR(regs); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci asrc->paddr = res->start; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci asrc->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs, 10908c2ecf20Sopenharmony_ci &fsl_asrc_regmap_config); 10918c2ecf20Sopenharmony_ci if (IS_ERR(asrc->regmap)) { 10928c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to init regmap\n"); 10938c2ecf20Sopenharmony_ci return PTR_ERR(asrc->regmap); 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 10978c2ecf20Sopenharmony_ci if (irq < 0) 10988c2ecf20Sopenharmony_ci return irq; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, fsl_asrc_isr, 0, 11018c2ecf20Sopenharmony_ci dev_name(&pdev->dev), asrc); 11028c2ecf20Sopenharmony_ci if (ret) { 11038c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to claim irq %u: %d\n", irq, ret); 11048c2ecf20Sopenharmony_ci return ret; 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci asrc->mem_clk = devm_clk_get(&pdev->dev, "mem"); 11088c2ecf20Sopenharmony_ci if (IS_ERR(asrc->mem_clk)) { 11098c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get mem clock\n"); 11108c2ecf20Sopenharmony_ci return PTR_ERR(asrc->mem_clk); 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci asrc->ipg_clk = devm_clk_get(&pdev->dev, "ipg"); 11148c2ecf20Sopenharmony_ci if (IS_ERR(asrc->ipg_clk)) { 11158c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get ipg clock\n"); 11168c2ecf20Sopenharmony_ci return PTR_ERR(asrc->ipg_clk); 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci asrc->spba_clk = devm_clk_get(&pdev->dev, "spba"); 11208c2ecf20Sopenharmony_ci if (IS_ERR(asrc->spba_clk)) 11218c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "failed to get spba clock\n"); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { 11248c2ecf20Sopenharmony_ci sprintf(tmp, "asrck_%x", i); 11258c2ecf20Sopenharmony_ci asrc_priv->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp); 11268c2ecf20Sopenharmony_ci if (IS_ERR(asrc_priv->asrck_clk[i])) { 11278c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get %s clock\n", tmp); 11288c2ecf20Sopenharmony_ci return PTR_ERR(asrc_priv->asrck_clk[i]); 11298c2ecf20Sopenharmony_ci } 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci asrc_priv->soc = of_device_get_match_data(&pdev->dev); 11338c2ecf20Sopenharmony_ci if (!asrc_priv->soc) { 11348c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get soc data\n"); 11358c2ecf20Sopenharmony_ci return -ENODEV; 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci asrc->use_edma = asrc_priv->soc->use_edma; 11398c2ecf20Sopenharmony_ci asrc->get_dma_channel = fsl_asrc_get_dma_channel; 11408c2ecf20Sopenharmony_ci asrc->request_pair = fsl_asrc_request_pair; 11418c2ecf20Sopenharmony_ci asrc->release_pair = fsl_asrc_release_pair; 11428c2ecf20Sopenharmony_ci asrc->get_fifo_addr = fsl_asrc_get_fifo_addr; 11438c2ecf20Sopenharmony_ci asrc->pair_priv_size = sizeof(struct fsl_asrc_pair_priv); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "fsl,imx35-asrc")) { 11468c2ecf20Sopenharmony_ci asrc_priv->clk_map[IN] = input_clk_map_imx35; 11478c2ecf20Sopenharmony_ci asrc_priv->clk_map[OUT] = output_clk_map_imx35; 11488c2ecf20Sopenharmony_ci } else if (of_device_is_compatible(np, "fsl,imx53-asrc")) { 11498c2ecf20Sopenharmony_ci asrc_priv->clk_map[IN] = input_clk_map_imx53; 11508c2ecf20Sopenharmony_ci asrc_priv->clk_map[OUT] = output_clk_map_imx53; 11518c2ecf20Sopenharmony_ci } else if (of_device_is_compatible(np, "fsl,imx8qm-asrc") || 11528c2ecf20Sopenharmony_ci of_device_is_compatible(np, "fsl,imx8qxp-asrc")) { 11538c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "fsl,asrc-clk-map", &map_idx); 11548c2ecf20Sopenharmony_ci if (ret) { 11558c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get clk map index\n"); 11568c2ecf20Sopenharmony_ci return ret; 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci if (map_idx > 1) { 11608c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "unsupported clk map index\n"); 11618c2ecf20Sopenharmony_ci return -EINVAL; 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "fsl,imx8qm-asrc")) { 11648c2ecf20Sopenharmony_ci asrc_priv->clk_map[IN] = clk_map_imx8qm[map_idx]; 11658c2ecf20Sopenharmony_ci asrc_priv->clk_map[OUT] = clk_map_imx8qm[map_idx]; 11668c2ecf20Sopenharmony_ci } else { 11678c2ecf20Sopenharmony_ci asrc_priv->clk_map[IN] = clk_map_imx8qxp[map_idx]; 11688c2ecf20Sopenharmony_ci asrc_priv->clk_map[OUT] = clk_map_imx8qxp[map_idx]; 11698c2ecf20Sopenharmony_ci } 11708c2ecf20Sopenharmony_ci } 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci ret = fsl_asrc_init(asrc); 11738c2ecf20Sopenharmony_ci if (ret) { 11748c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to init asrc %d\n", ret); 11758c2ecf20Sopenharmony_ci return ret; 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci asrc->channel_avail = 10; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "fsl,asrc-rate", 11818c2ecf20Sopenharmony_ci &asrc->asrc_rate); 11828c2ecf20Sopenharmony_ci if (ret) { 11838c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get output rate\n"); 11848c2ecf20Sopenharmony_ci return ret; 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "fsl,asrc-format", &asrc->asrc_format); 11888c2ecf20Sopenharmony_ci if (ret) { 11898c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "fsl,asrc-width", &width); 11908c2ecf20Sopenharmony_ci if (ret) { 11918c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to decide output format\n"); 11928c2ecf20Sopenharmony_ci return ret; 11938c2ecf20Sopenharmony_ci } 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci switch (width) { 11968c2ecf20Sopenharmony_ci case 16: 11978c2ecf20Sopenharmony_ci asrc->asrc_format = SNDRV_PCM_FORMAT_S16_LE; 11988c2ecf20Sopenharmony_ci break; 11998c2ecf20Sopenharmony_ci case 24: 12008c2ecf20Sopenharmony_ci asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE; 12018c2ecf20Sopenharmony_ci break; 12028c2ecf20Sopenharmony_ci default: 12038c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 12048c2ecf20Sopenharmony_ci "unsupported width, use default S24_LE\n"); 12058c2ecf20Sopenharmony_ci asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE; 12068c2ecf20Sopenharmony_ci break; 12078c2ecf20Sopenharmony_ci } 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci if (!(FSL_ASRC_FORMATS & (1ULL << asrc->asrc_format))) { 12118c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "unsupported width, use default S24_LE\n"); 12128c2ecf20Sopenharmony_ci asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE; 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, asrc); 12168c2ecf20Sopenharmony_ci pm_runtime_enable(&pdev->dev); 12178c2ecf20Sopenharmony_ci spin_lock_init(&asrc->lock); 12188c2ecf20Sopenharmony_ci regcache_cache_only(asrc->regmap, true); 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, &fsl_asrc_component, 12218c2ecf20Sopenharmony_ci &fsl_asrc_dai, 1); 12228c2ecf20Sopenharmony_ci if (ret) { 12238c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to register ASoC DAI\n"); 12248c2ecf20Sopenharmony_ci return ret; 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci return 0; 12288c2ecf20Sopenharmony_ci} 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 12318c2ecf20Sopenharmony_cistatic int fsl_asrc_runtime_resume(struct device *dev) 12328c2ecf20Sopenharmony_ci{ 12338c2ecf20Sopenharmony_ci struct fsl_asrc *asrc = dev_get_drvdata(dev); 12348c2ecf20Sopenharmony_ci struct fsl_asrc_priv *asrc_priv = asrc->private; 12358c2ecf20Sopenharmony_ci int i, ret; 12368c2ecf20Sopenharmony_ci u32 asrctr; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci ret = clk_prepare_enable(asrc->mem_clk); 12398c2ecf20Sopenharmony_ci if (ret) 12408c2ecf20Sopenharmony_ci return ret; 12418c2ecf20Sopenharmony_ci ret = clk_prepare_enable(asrc->ipg_clk); 12428c2ecf20Sopenharmony_ci if (ret) 12438c2ecf20Sopenharmony_ci goto disable_mem_clk; 12448c2ecf20Sopenharmony_ci if (!IS_ERR(asrc->spba_clk)) { 12458c2ecf20Sopenharmony_ci ret = clk_prepare_enable(asrc->spba_clk); 12468c2ecf20Sopenharmony_ci if (ret) 12478c2ecf20Sopenharmony_ci goto disable_ipg_clk; 12488c2ecf20Sopenharmony_ci } 12498c2ecf20Sopenharmony_ci for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { 12508c2ecf20Sopenharmony_ci ret = clk_prepare_enable(asrc_priv->asrck_clk[i]); 12518c2ecf20Sopenharmony_ci if (ret) 12528c2ecf20Sopenharmony_ci goto disable_asrck_clk; 12538c2ecf20Sopenharmony_ci } 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci /* Stop all pairs provisionally */ 12568c2ecf20Sopenharmony_ci regmap_read(asrc->regmap, REG_ASRCTR, &asrctr); 12578c2ecf20Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCTR, 12588c2ecf20Sopenharmony_ci ASRCTR_ASRCEi_ALL_MASK, 0); 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci /* Restore all registers */ 12618c2ecf20Sopenharmony_ci regcache_cache_only(asrc->regmap, false); 12628c2ecf20Sopenharmony_ci regcache_mark_dirty(asrc->regmap); 12638c2ecf20Sopenharmony_ci regcache_sync(asrc->regmap); 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCFG, 12668c2ecf20Sopenharmony_ci ASRCFG_NDPRi_ALL_MASK | ASRCFG_POSTMODi_ALL_MASK | 12678c2ecf20Sopenharmony_ci ASRCFG_PREMODi_ALL_MASK, asrc_priv->regcache_cfg); 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci /* Restart enabled pairs */ 12708c2ecf20Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCTR, 12718c2ecf20Sopenharmony_ci ASRCTR_ASRCEi_ALL_MASK, asrctr); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci return 0; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_cidisable_asrck_clk: 12768c2ecf20Sopenharmony_ci for (i--; i >= 0; i--) 12778c2ecf20Sopenharmony_ci clk_disable_unprepare(asrc_priv->asrck_clk[i]); 12788c2ecf20Sopenharmony_ci if (!IS_ERR(asrc->spba_clk)) 12798c2ecf20Sopenharmony_ci clk_disable_unprepare(asrc->spba_clk); 12808c2ecf20Sopenharmony_cidisable_ipg_clk: 12818c2ecf20Sopenharmony_ci clk_disable_unprepare(asrc->ipg_clk); 12828c2ecf20Sopenharmony_cidisable_mem_clk: 12838c2ecf20Sopenharmony_ci clk_disable_unprepare(asrc->mem_clk); 12848c2ecf20Sopenharmony_ci return ret; 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_cistatic int fsl_asrc_runtime_suspend(struct device *dev) 12888c2ecf20Sopenharmony_ci{ 12898c2ecf20Sopenharmony_ci struct fsl_asrc *asrc = dev_get_drvdata(dev); 12908c2ecf20Sopenharmony_ci struct fsl_asrc_priv *asrc_priv = asrc->private; 12918c2ecf20Sopenharmony_ci int i; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci regmap_read(asrc->regmap, REG_ASRCFG, 12948c2ecf20Sopenharmony_ci &asrc_priv->regcache_cfg); 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci regcache_cache_only(asrc->regmap, true); 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci for (i = 0; i < ASRC_CLK_MAX_NUM; i++) 12998c2ecf20Sopenharmony_ci clk_disable_unprepare(asrc_priv->asrck_clk[i]); 13008c2ecf20Sopenharmony_ci if (!IS_ERR(asrc->spba_clk)) 13018c2ecf20Sopenharmony_ci clk_disable_unprepare(asrc->spba_clk); 13028c2ecf20Sopenharmony_ci clk_disable_unprepare(asrc->ipg_clk); 13038c2ecf20Sopenharmony_ci clk_disable_unprepare(asrc->mem_clk); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci return 0; 13068c2ecf20Sopenharmony_ci} 13078c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_cistatic const struct dev_pm_ops fsl_asrc_pm = { 13108c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL) 13118c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 13128c2ecf20Sopenharmony_ci pm_runtime_force_resume) 13138c2ecf20Sopenharmony_ci}; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_cistatic const struct fsl_asrc_soc_data fsl_asrc_imx35_data = { 13168c2ecf20Sopenharmony_ci .use_edma = false, 13178c2ecf20Sopenharmony_ci .channel_bits = 3, 13188c2ecf20Sopenharmony_ci}; 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_cistatic const struct fsl_asrc_soc_data fsl_asrc_imx53_data = { 13218c2ecf20Sopenharmony_ci .use_edma = false, 13228c2ecf20Sopenharmony_ci .channel_bits = 4, 13238c2ecf20Sopenharmony_ci}; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_cistatic const struct fsl_asrc_soc_data fsl_asrc_imx8qm_data = { 13268c2ecf20Sopenharmony_ci .use_edma = true, 13278c2ecf20Sopenharmony_ci .channel_bits = 4, 13288c2ecf20Sopenharmony_ci}; 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_cistatic const struct fsl_asrc_soc_data fsl_asrc_imx8qxp_data = { 13318c2ecf20Sopenharmony_ci .use_edma = true, 13328c2ecf20Sopenharmony_ci .channel_bits = 4, 13338c2ecf20Sopenharmony_ci}; 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_cistatic const struct of_device_id fsl_asrc_ids[] = { 13368c2ecf20Sopenharmony_ci { .compatible = "fsl,imx35-asrc", .data = &fsl_asrc_imx35_data }, 13378c2ecf20Sopenharmony_ci { .compatible = "fsl,imx53-asrc", .data = &fsl_asrc_imx53_data }, 13388c2ecf20Sopenharmony_ci { .compatible = "fsl,imx8qm-asrc", .data = &fsl_asrc_imx8qm_data }, 13398c2ecf20Sopenharmony_ci { .compatible = "fsl,imx8qxp-asrc", .data = &fsl_asrc_imx8qxp_data }, 13408c2ecf20Sopenharmony_ci {} 13418c2ecf20Sopenharmony_ci}; 13428c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, fsl_asrc_ids); 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_cistatic struct platform_driver fsl_asrc_driver = { 13458c2ecf20Sopenharmony_ci .probe = fsl_asrc_probe, 13468c2ecf20Sopenharmony_ci .driver = { 13478c2ecf20Sopenharmony_ci .name = "fsl-asrc", 13488c2ecf20Sopenharmony_ci .of_match_table = fsl_asrc_ids, 13498c2ecf20Sopenharmony_ci .pm = &fsl_asrc_pm, 13508c2ecf20Sopenharmony_ci }, 13518c2ecf20Sopenharmony_ci}; 13528c2ecf20Sopenharmony_cimodule_platform_driver(fsl_asrc_driver); 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Freescale ASRC ASoC driver"); 13558c2ecf20Sopenharmony_ciMODULE_AUTHOR("Nicolin Chen <nicoleotsuka@gmail.com>"); 13568c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:fsl-asrc"); 13578c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1358