12ba28053SFabio Estevam // SPDX-License-Identifier: GPL-2.0 22ba28053SFabio Estevam // 32ba28053SFabio Estevam // Freescale ASRC ALSA SoC Digital Audio Interface (DAI) driver 42ba28053SFabio Estevam // 52ba28053SFabio Estevam // Copyright (C) 2014 Freescale Semiconductor, Inc. 62ba28053SFabio Estevam // 72ba28053SFabio Estevam // Author: Nicolin Chen <nicoleotsuka@gmail.com> 83117bb31SNicolin Chen 93117bb31SNicolin Chen #include <linux/clk.h> 103117bb31SNicolin Chen #include <linux/delay.h> 113117bb31SNicolin Chen #include <linux/dma-mapping.h> 123117bb31SNicolin Chen #include <linux/module.h> 133117bb31SNicolin Chen #include <linux/of_platform.h> 143117bb31SNicolin Chen #include <linux/platform_data/dma-imx.h> 153117bb31SNicolin Chen #include <linux/pm_runtime.h> 163117bb31SNicolin Chen #include <sound/dmaengine_pcm.h> 173117bb31SNicolin Chen #include <sound/pcm_params.h> 183117bb31SNicolin Chen 193117bb31SNicolin Chen #include "fsl_asrc.h" 203117bb31SNicolin Chen 213117bb31SNicolin Chen #define IDEAL_RATIO_DECIMAL_DEPTH 26 223117bb31SNicolin Chen 233117bb31SNicolin Chen #define pair_err(fmt, ...) \ 24*7470704dSShengjiu Wang dev_err(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) 253117bb31SNicolin Chen 263117bb31SNicolin Chen #define pair_dbg(fmt, ...) \ 27*7470704dSShengjiu Wang dev_dbg(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) 283117bb31SNicolin Chen 293117bb31SNicolin Chen /* Corresponding to process_option */ 30d281bf5dSS.j. Wang static unsigned int supported_asrc_rate[] = { 31d281bf5dSS.j. Wang 5512, 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 32d281bf5dSS.j. Wang 64000, 88200, 96000, 128000, 176400, 192000, 333117bb31SNicolin Chen }; 343117bb31SNicolin Chen 35d281bf5dSS.j. Wang static struct snd_pcm_hw_constraint_list fsl_asrc_rate_constraints = { 36d281bf5dSS.j. Wang .count = ARRAY_SIZE(supported_asrc_rate), 37d281bf5dSS.j. Wang .list = supported_asrc_rate, 383117bb31SNicolin Chen }; 393117bb31SNicolin Chen 403117bb31SNicolin Chen /** 413117bb31SNicolin Chen * The following tables map the relationship between asrc_inclk/asrc_outclk in 423117bb31SNicolin Chen * fsl_asrc.h and the registers of ASRCSR 433117bb31SNicolin Chen */ 44c05f10f2SShengjiu Wang static unsigned char input_clk_map_imx35[ASRC_CLK_MAP_LEN] = { 453117bb31SNicolin Chen 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 46c05f10f2SShengjiu Wang 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 47c05f10f2SShengjiu Wang 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 483117bb31SNicolin Chen }; 493117bb31SNicolin Chen 50c05f10f2SShengjiu Wang static unsigned char output_clk_map_imx35[ASRC_CLK_MAP_LEN] = { 513117bb31SNicolin Chen 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 52c05f10f2SShengjiu Wang 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 53c05f10f2SShengjiu Wang 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 543117bb31SNicolin Chen }; 553117bb31SNicolin Chen 563117bb31SNicolin Chen /* i.MX53 uses the same map for input and output */ 57c05f10f2SShengjiu Wang static unsigned char input_clk_map_imx53[ASRC_CLK_MAP_LEN] = { 583117bb31SNicolin Chen /* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf */ 593117bb31SNicolin Chen 0x0, 0x1, 0x2, 0x7, 0x4, 0x5, 0x6, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xf, 0xe, 0xd, 60c05f10f2SShengjiu Wang 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 61c05f10f2SShengjiu Wang 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 623117bb31SNicolin Chen }; 633117bb31SNicolin Chen 64c05f10f2SShengjiu Wang static unsigned char output_clk_map_imx53[ASRC_CLK_MAP_LEN] = { 653117bb31SNicolin Chen /* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf */ 663117bb31SNicolin Chen 0x8, 0x9, 0xa, 0x7, 0xc, 0x5, 0x6, 0xb, 0x0, 0x1, 0x2, 0x3, 0x4, 0xf, 0xe, 0xd, 67c05f10f2SShengjiu Wang 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 68c05f10f2SShengjiu Wang 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 693117bb31SNicolin Chen }; 703117bb31SNicolin Chen 71c05f10f2SShengjiu Wang /** 72c05f10f2SShengjiu Wang * i.MX8QM/i.MX8QXP uses the same map for input and output. 73c05f10f2SShengjiu Wang * clk_map_imx8qm[0] is for i.MX8QM asrc0 74c05f10f2SShengjiu Wang * clk_map_imx8qm[1] is for i.MX8QM asrc1 75c05f10f2SShengjiu Wang * clk_map_imx8qxp[0] is for i.MX8QXP asrc0 76c05f10f2SShengjiu Wang * clk_map_imx8qxp[1] is for i.MX8QXP asrc1 77c05f10f2SShengjiu Wang */ 78c05f10f2SShengjiu Wang static unsigned char clk_map_imx8qm[2][ASRC_CLK_MAP_LEN] = { 79c05f10f2SShengjiu Wang { 80c05f10f2SShengjiu Wang 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, 81c05f10f2SShengjiu Wang 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 82c05f10f2SShengjiu Wang 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 83c05f10f2SShengjiu Wang }, 84c05f10f2SShengjiu Wang { 85c05f10f2SShengjiu Wang 0xf, 0xf, 0xf, 0xf, 0xf, 0x7, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, 86c05f10f2SShengjiu Wang 0x0, 0x1, 0x2, 0x3, 0xb, 0xc, 0xf, 0xf, 0xd, 0xe, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 87c05f10f2SShengjiu Wang 0x4, 0x5, 0x6, 0xf, 0x8, 0x9, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 88c05f10f2SShengjiu Wang }, 89c05f10f2SShengjiu Wang }; 90c05f10f2SShengjiu Wang 91c05f10f2SShengjiu Wang static unsigned char clk_map_imx8qxp[2][ASRC_CLK_MAP_LEN] = { 92c05f10f2SShengjiu Wang { 93c05f10f2SShengjiu Wang 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, 94c05f10f2SShengjiu Wang 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0xf, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xf, 0xf, 95c05f10f2SShengjiu Wang 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 96c05f10f2SShengjiu Wang }, 97c05f10f2SShengjiu Wang { 98c05f10f2SShengjiu Wang 0xf, 0xf, 0xf, 0xf, 0xf, 0x7, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, 99c05f10f2SShengjiu Wang 0x0, 0x1, 0x2, 0x3, 0x7, 0x8, 0xf, 0xf, 0x9, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 100c05f10f2SShengjiu Wang 0xf, 0xf, 0x6, 0xf, 0xf, 0xf, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 101c05f10f2SShengjiu Wang }, 102c05f10f2SShengjiu Wang }; 1033117bb31SNicolin Chen 1043117bb31SNicolin Chen /** 1054aecaa0aSS.j. Wang * Select the pre-processing and post-processing options 1064aecaa0aSS.j. Wang * Make sure to exclude following unsupported cases before 1074aecaa0aSS.j. Wang * calling this function: 1084aecaa0aSS.j. Wang * 1) inrate > 8.125 * outrate 1094aecaa0aSS.j. Wang * 2) inrate > 16.125 * outrate 1104aecaa0aSS.j. Wang * 1114aecaa0aSS.j. Wang * inrate: input sample rate 1124aecaa0aSS.j. Wang * outrate: output sample rate 1134aecaa0aSS.j. Wang * pre_proc: return value for pre-processing option 1144aecaa0aSS.j. Wang * post_proc: return value for post-processing option 1154aecaa0aSS.j. Wang */ 1164aecaa0aSS.j. Wang static void fsl_asrc_sel_proc(int inrate, int outrate, 1174aecaa0aSS.j. Wang int *pre_proc, int *post_proc) 1184aecaa0aSS.j. Wang { 1194aecaa0aSS.j. Wang bool post_proc_cond2; 1204aecaa0aSS.j. Wang bool post_proc_cond0; 1214aecaa0aSS.j. Wang 1224aecaa0aSS.j. Wang /* select pre_proc between [0, 2] */ 1234aecaa0aSS.j. Wang if (inrate * 8 > 33 * outrate) 1244aecaa0aSS.j. Wang *pre_proc = 2; 1254aecaa0aSS.j. Wang else if (inrate * 8 > 15 * outrate) { 1264aecaa0aSS.j. Wang if (inrate > 152000) 1274aecaa0aSS.j. Wang *pre_proc = 2; 1284aecaa0aSS.j. Wang else 1294aecaa0aSS.j. Wang *pre_proc = 1; 1304aecaa0aSS.j. Wang } else if (inrate < 76000) 1314aecaa0aSS.j. Wang *pre_proc = 0; 1324aecaa0aSS.j. Wang else if (inrate > 152000) 1334aecaa0aSS.j. Wang *pre_proc = 2; 1344aecaa0aSS.j. Wang else 1354aecaa0aSS.j. Wang *pre_proc = 1; 1364aecaa0aSS.j. Wang 1374aecaa0aSS.j. Wang /* Condition for selection of post-processing */ 1384aecaa0aSS.j. Wang post_proc_cond2 = (inrate * 15 > outrate * 16 && outrate < 56000) || 1394aecaa0aSS.j. Wang (inrate > 56000 && outrate < 56000); 1404aecaa0aSS.j. Wang post_proc_cond0 = inrate * 23 < outrate * 8; 1414aecaa0aSS.j. Wang 1424aecaa0aSS.j. Wang if (post_proc_cond2) 1434aecaa0aSS.j. Wang *post_proc = 2; 1444aecaa0aSS.j. Wang else if (post_proc_cond0) 1454aecaa0aSS.j. Wang *post_proc = 0; 1464aecaa0aSS.j. Wang else 1474aecaa0aSS.j. Wang *post_proc = 1; 1484aecaa0aSS.j. Wang } 1494aecaa0aSS.j. Wang 1504aecaa0aSS.j. Wang /** 1513117bb31SNicolin Chen * Request ASRC pair 1523117bb31SNicolin Chen * 1533117bb31SNicolin Chen * It assigns pair by the order of A->C->B because allocation of pair B, 1543117bb31SNicolin Chen * within range [ANCA, ANCA+ANCB-1], depends on the channels of pair A 1553117bb31SNicolin Chen * while pair A and pair C are comparatively independent. 1563117bb31SNicolin Chen */ 157703df441SShengjiu Wang int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair) 1583117bb31SNicolin Chen { 1593117bb31SNicolin Chen enum asrc_pair_index index = ASRC_INVALID_PAIR; 160*7470704dSShengjiu Wang struct fsl_asrc *asrc = pair->asrc; 161*7470704dSShengjiu Wang struct device *dev = &asrc->pdev->dev; 1623117bb31SNicolin Chen unsigned long lock_flags; 1633117bb31SNicolin Chen int i, ret = 0; 1643117bb31SNicolin Chen 165*7470704dSShengjiu Wang spin_lock_irqsave(&asrc->lock, lock_flags); 1663117bb31SNicolin Chen 1673117bb31SNicolin Chen for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) { 168*7470704dSShengjiu Wang if (asrc->pair[i] != NULL) 1693117bb31SNicolin Chen continue; 1703117bb31SNicolin Chen 1713117bb31SNicolin Chen index = i; 1723117bb31SNicolin Chen 1733117bb31SNicolin Chen if (i != ASRC_PAIR_B) 1743117bb31SNicolin Chen break; 1753117bb31SNicolin Chen } 1763117bb31SNicolin Chen 1773117bb31SNicolin Chen if (index == ASRC_INVALID_PAIR) { 1783117bb31SNicolin Chen dev_err(dev, "all pairs are busy now\n"); 1793117bb31SNicolin Chen ret = -EBUSY; 180*7470704dSShengjiu Wang } else if (asrc->channel_avail < channels) { 1813117bb31SNicolin Chen dev_err(dev, "can't afford required channels: %d\n", channels); 1823117bb31SNicolin Chen ret = -EINVAL; 1833117bb31SNicolin Chen } else { 184*7470704dSShengjiu Wang asrc->channel_avail -= channels; 185*7470704dSShengjiu Wang asrc->pair[index] = pair; 1863117bb31SNicolin Chen pair->channels = channels; 1873117bb31SNicolin Chen pair->index = index; 1883117bb31SNicolin Chen } 1893117bb31SNicolin Chen 190*7470704dSShengjiu Wang spin_unlock_irqrestore(&asrc->lock, lock_flags); 1913117bb31SNicolin Chen 1923117bb31SNicolin Chen return ret; 1933117bb31SNicolin Chen } 1943117bb31SNicolin Chen 1953117bb31SNicolin Chen /** 1963117bb31SNicolin Chen * Release ASRC pair 1973117bb31SNicolin Chen * 198*7470704dSShengjiu Wang * It clears the resource from asrc and releases the occupied channels. 1993117bb31SNicolin Chen */ 200703df441SShengjiu Wang void fsl_asrc_release_pair(struct fsl_asrc_pair *pair) 2013117bb31SNicolin Chen { 202*7470704dSShengjiu Wang struct fsl_asrc *asrc = pair->asrc; 2033117bb31SNicolin Chen enum asrc_pair_index index = pair->index; 2043117bb31SNicolin Chen unsigned long lock_flags; 2053117bb31SNicolin Chen 2063117bb31SNicolin Chen /* Make sure the pair is disabled */ 207*7470704dSShengjiu Wang regmap_update_bits(asrc->regmap, REG_ASRCTR, 2083117bb31SNicolin Chen ASRCTR_ASRCEi_MASK(index), 0); 2093117bb31SNicolin Chen 210*7470704dSShengjiu Wang spin_lock_irqsave(&asrc->lock, lock_flags); 2113117bb31SNicolin Chen 212*7470704dSShengjiu Wang asrc->channel_avail += pair->channels; 213*7470704dSShengjiu Wang asrc->pair[index] = NULL; 2143117bb31SNicolin Chen pair->error = 0; 2153117bb31SNicolin Chen 216*7470704dSShengjiu Wang spin_unlock_irqrestore(&asrc->lock, lock_flags); 2173117bb31SNicolin Chen } 2183117bb31SNicolin Chen 2193117bb31SNicolin Chen /** 2203117bb31SNicolin Chen * Configure input and output thresholds 2213117bb31SNicolin Chen */ 2223117bb31SNicolin Chen static void fsl_asrc_set_watermarks(struct fsl_asrc_pair *pair, u32 in, u32 out) 2233117bb31SNicolin Chen { 224*7470704dSShengjiu Wang struct fsl_asrc *asrc = pair->asrc; 2253117bb31SNicolin Chen enum asrc_pair_index index = pair->index; 2263117bb31SNicolin Chen 227*7470704dSShengjiu Wang regmap_update_bits(asrc->regmap, REG_ASRMCR(index), 2283117bb31SNicolin Chen ASRMCRi_EXTTHRSHi_MASK | 2293117bb31SNicolin Chen ASRMCRi_INFIFO_THRESHOLD_MASK | 2303117bb31SNicolin Chen ASRMCRi_OUTFIFO_THRESHOLD_MASK, 2313117bb31SNicolin Chen ASRMCRi_EXTTHRSHi | 2323117bb31SNicolin Chen ASRMCRi_INFIFO_THRESHOLD(in) | 2333117bb31SNicolin Chen ASRMCRi_OUTFIFO_THRESHOLD(out)); 2343117bb31SNicolin Chen } 2353117bb31SNicolin Chen 2363117bb31SNicolin Chen /** 2373117bb31SNicolin Chen * Calculate the total divisor between asrck clock rate and sample rate 2383117bb31SNicolin Chen * 2393117bb31SNicolin Chen * It follows the formula clk_rate = samplerate * (2 ^ prescaler) * divider 2403117bb31SNicolin Chen */ 2413117bb31SNicolin Chen static u32 fsl_asrc_cal_asrck_divisor(struct fsl_asrc_pair *pair, u32 div) 2423117bb31SNicolin Chen { 2433117bb31SNicolin Chen u32 ps; 2443117bb31SNicolin Chen 2453117bb31SNicolin Chen /* Calculate the divisors: prescaler [2^0, 2^7], divder [1, 8] */ 2463117bb31SNicolin Chen for (ps = 0; div > 8; ps++) 2473117bb31SNicolin Chen div >>= 1; 2483117bb31SNicolin Chen 2493117bb31SNicolin Chen return ((div - 1) << ASRCDRi_AxCPi_WIDTH) | ps; 2503117bb31SNicolin Chen } 2513117bb31SNicolin Chen 2523117bb31SNicolin Chen /** 2533117bb31SNicolin Chen * Calculate and set the ratio for Ideal Ratio mode only 2543117bb31SNicolin Chen * 2553117bb31SNicolin Chen * The ratio is a 32-bit fixed point value with 26 fractional bits. 2563117bb31SNicolin Chen */ 2573117bb31SNicolin Chen static int fsl_asrc_set_ideal_ratio(struct fsl_asrc_pair *pair, 2583117bb31SNicolin Chen int inrate, int outrate) 2593117bb31SNicolin Chen { 260*7470704dSShengjiu Wang struct fsl_asrc *asrc = pair->asrc; 2613117bb31SNicolin Chen enum asrc_pair_index index = pair->index; 2623117bb31SNicolin Chen unsigned long ratio; 2633117bb31SNicolin Chen int i; 2643117bb31SNicolin Chen 2653117bb31SNicolin Chen if (!outrate) { 2663117bb31SNicolin Chen pair_err("output rate should not be zero\n"); 2673117bb31SNicolin Chen return -EINVAL; 2683117bb31SNicolin Chen } 2693117bb31SNicolin Chen 2703117bb31SNicolin Chen /* Calculate the intergal part of the ratio */ 2713117bb31SNicolin Chen ratio = (inrate / outrate) << IDEAL_RATIO_DECIMAL_DEPTH; 2723117bb31SNicolin Chen 2733117bb31SNicolin Chen /* ... and then the 26 depth decimal part */ 2743117bb31SNicolin Chen inrate %= outrate; 2753117bb31SNicolin Chen 2763117bb31SNicolin Chen for (i = 1; i <= IDEAL_RATIO_DECIMAL_DEPTH; i++) { 2773117bb31SNicolin Chen inrate <<= 1; 2783117bb31SNicolin Chen 2793117bb31SNicolin Chen if (inrate < outrate) 2803117bb31SNicolin Chen continue; 2813117bb31SNicolin Chen 2823117bb31SNicolin Chen ratio |= 1 << (IDEAL_RATIO_DECIMAL_DEPTH - i); 2833117bb31SNicolin Chen inrate -= outrate; 2843117bb31SNicolin Chen 2853117bb31SNicolin Chen if (!inrate) 2863117bb31SNicolin Chen break; 2873117bb31SNicolin Chen } 2883117bb31SNicolin Chen 289*7470704dSShengjiu Wang regmap_write(asrc->regmap, REG_ASRIDRL(index), ratio); 290*7470704dSShengjiu Wang regmap_write(asrc->regmap, REG_ASRIDRH(index), ratio >> 24); 2913117bb31SNicolin Chen 2923117bb31SNicolin Chen return 0; 2933117bb31SNicolin Chen } 2943117bb31SNicolin Chen 2953117bb31SNicolin Chen /** 2963117bb31SNicolin Chen * Configure the assigned ASRC pair 2973117bb31SNicolin Chen * 2983117bb31SNicolin Chen * It configures those ASRC registers according to a configuration instance 2993117bb31SNicolin Chen * of struct asrc_config which includes in/output sample rate, width, channel 3003117bb31SNicolin Chen * and clock settings. 301b39eb1e2SShengjiu Wang * 302b39eb1e2SShengjiu Wang * Note: 303b39eb1e2SShengjiu Wang * The ideal ratio configuration can work with a flexible clock rate setting. 304b39eb1e2SShengjiu Wang * Using IDEAL_RATIO_RATE gives a faster converting speed but overloads ASRC. 305b39eb1e2SShengjiu Wang * For a regular audio playback, the clock rate should not be slower than an 306b39eb1e2SShengjiu Wang * clock rate aligning with the output sample rate; For a use case requiring 307b39eb1e2SShengjiu Wang * faster conversion, set use_ideal_rate to have the faster speed. 3083117bb31SNicolin Chen */ 309b39eb1e2SShengjiu Wang static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate) 3103117bb31SNicolin Chen { 3113117bb31SNicolin Chen struct asrc_config *config = pair->config; 312*7470704dSShengjiu Wang struct fsl_asrc *asrc = pair->asrc; 3133117bb31SNicolin Chen enum asrc_pair_index index = pair->index; 3144bf62571SShengjiu Wang enum asrc_word_width input_word_width; 3154bf62571SShengjiu Wang enum asrc_word_width output_word_width; 3164e13eb72SNicolin Chen u32 inrate, outrate, indiv, outdiv; 317b39eb1e2SShengjiu Wang u32 clk_index[2], div[2], rem[2]; 318b39eb1e2SShengjiu Wang u64 clk_rate; 3193117bb31SNicolin Chen int in, out, channels; 3204aecaa0aSS.j. Wang int pre_proc, post_proc; 3213117bb31SNicolin Chen struct clk *clk; 3224e13eb72SNicolin Chen bool ideal; 3233117bb31SNicolin Chen 3243117bb31SNicolin Chen if (!config) { 3253117bb31SNicolin Chen pair_err("invalid pair config\n"); 3263117bb31SNicolin Chen return -EINVAL; 3273117bb31SNicolin Chen } 3283117bb31SNicolin Chen 3293117bb31SNicolin Chen /* Validate channels */ 3303117bb31SNicolin Chen if (config->channel_num < 1 || config->channel_num > 10) { 3313117bb31SNicolin Chen pair_err("does not support %d channels\n", config->channel_num); 3323117bb31SNicolin Chen return -EINVAL; 3333117bb31SNicolin Chen } 3343117bb31SNicolin Chen 3354bf62571SShengjiu Wang switch (snd_pcm_format_width(config->input_format)) { 3364bf62571SShengjiu Wang case 8: 3374bf62571SShengjiu Wang input_word_width = ASRC_WIDTH_8_BIT; 3384bf62571SShengjiu Wang break; 3394bf62571SShengjiu Wang case 16: 3404bf62571SShengjiu Wang input_word_width = ASRC_WIDTH_16_BIT; 3414bf62571SShengjiu Wang break; 3424bf62571SShengjiu Wang case 24: 3434bf62571SShengjiu Wang input_word_width = ASRC_WIDTH_24_BIT; 3444bf62571SShengjiu Wang break; 3454bf62571SShengjiu Wang default: 3464bf62571SShengjiu Wang pair_err("does not support this input format, %d\n", 3474bf62571SShengjiu Wang config->input_format); 3484bf62571SShengjiu Wang return -EINVAL; 3494bf62571SShengjiu Wang } 3504bf62571SShengjiu Wang 3514bf62571SShengjiu Wang switch (snd_pcm_format_width(config->output_format)) { 3524bf62571SShengjiu Wang case 16: 3534bf62571SShengjiu Wang output_word_width = ASRC_WIDTH_16_BIT; 3544bf62571SShengjiu Wang break; 3554bf62571SShengjiu Wang case 24: 3564bf62571SShengjiu Wang output_word_width = ASRC_WIDTH_24_BIT; 3574bf62571SShengjiu Wang break; 3584bf62571SShengjiu Wang default: 3594bf62571SShengjiu Wang pair_err("does not support this output format, %d\n", 3604bf62571SShengjiu Wang config->output_format); 3613117bb31SNicolin Chen return -EINVAL; 3623117bb31SNicolin Chen } 3633117bb31SNicolin Chen 3644e13eb72SNicolin Chen inrate = config->input_sample_rate; 3654e13eb72SNicolin Chen outrate = config->output_sample_rate; 3664e13eb72SNicolin Chen ideal = config->inclk == INCLK_NONE; 3674e13eb72SNicolin Chen 3683117bb31SNicolin Chen /* Validate input and output sample rates */ 369d281bf5dSS.j. Wang for (in = 0; in < ARRAY_SIZE(supported_asrc_rate); in++) 370d281bf5dSS.j. Wang if (inrate == supported_asrc_rate[in]) 3713117bb31SNicolin Chen break; 3723117bb31SNicolin Chen 373d281bf5dSS.j. Wang if (in == ARRAY_SIZE(supported_asrc_rate)) { 3743117bb31SNicolin Chen pair_err("unsupported input sample rate: %dHz\n", inrate); 3753117bb31SNicolin Chen return -EINVAL; 3763117bb31SNicolin Chen } 3773117bb31SNicolin Chen 3783117bb31SNicolin Chen for (out = 0; out < ARRAY_SIZE(supported_asrc_rate); out++) 3793117bb31SNicolin Chen if (outrate == supported_asrc_rate[out]) 3803117bb31SNicolin Chen break; 3813117bb31SNicolin Chen 3823117bb31SNicolin Chen if (out == ARRAY_SIZE(supported_asrc_rate)) { 3833117bb31SNicolin Chen pair_err("unsupported output sample rate: %dHz\n", outrate); 3843117bb31SNicolin Chen return -EINVAL; 3853117bb31SNicolin Chen } 3863117bb31SNicolin Chen 387d281bf5dSS.j. Wang if ((outrate >= 5512 && outrate <= 30000) && 388b06c58c2SS.j. Wang (outrate > 24 * inrate || inrate > 8 * outrate)) { 389fff6e03cSZidan Wang pair_err("exceed supported ratio range [1/24, 8] for \ 390fff6e03cSZidan Wang inrate/outrate: %d/%d\n", inrate, outrate); 391fff6e03cSZidan Wang return -EINVAL; 392fff6e03cSZidan Wang } 393fff6e03cSZidan Wang 3943117bb31SNicolin Chen /* Validate input and output clock sources */ 395*7470704dSShengjiu Wang clk_index[IN] = asrc->clk_map[IN][config->inclk]; 396*7470704dSShengjiu Wang clk_index[OUT] = asrc->clk_map[OUT][config->outclk]; 3973117bb31SNicolin Chen 3983117bb31SNicolin Chen /* We only have output clock for ideal ratio mode */ 399*7470704dSShengjiu Wang clk = asrc->asrck_clk[clk_index[ideal ? OUT : IN]]; 4003117bb31SNicolin Chen 401b39eb1e2SShengjiu Wang clk_rate = clk_get_rate(clk); 402b39eb1e2SShengjiu Wang rem[IN] = do_div(clk_rate, inrate); 403b39eb1e2SShengjiu Wang div[IN] = (u32)clk_rate; 404b39eb1e2SShengjiu Wang 405b39eb1e2SShengjiu Wang /* 406b39eb1e2SShengjiu Wang * The divider range is [1, 1024], defined by the hardware. For non- 407b39eb1e2SShengjiu Wang * ideal ratio configuration, clock rate has to be strictly aligned 408b39eb1e2SShengjiu Wang * with the sample rate. For ideal ratio configuration, clock rates 409b39eb1e2SShengjiu Wang * only result in different converting speeds. So remainder does not 410b39eb1e2SShengjiu Wang * matter, as long as we keep the divider within its valid range. 411b39eb1e2SShengjiu Wang */ 412b39eb1e2SShengjiu Wang if (div[IN] == 0 || (!ideal && (div[IN] > 1024 || rem[IN] != 0))) { 4133117bb31SNicolin Chen pair_err("failed to support input sample rate %dHz by asrck_%x\n", 4143117bb31SNicolin Chen inrate, clk_index[ideal ? OUT : IN]); 4153117bb31SNicolin Chen return -EINVAL; 4163117bb31SNicolin Chen } 4173117bb31SNicolin Chen 418b39eb1e2SShengjiu Wang div[IN] = min_t(u32, 1024, div[IN]); 419b39eb1e2SShengjiu Wang 420*7470704dSShengjiu Wang clk = asrc->asrck_clk[clk_index[OUT]]; 421b39eb1e2SShengjiu Wang clk_rate = clk_get_rate(clk); 422b39eb1e2SShengjiu Wang if (ideal && use_ideal_rate) 423b39eb1e2SShengjiu Wang rem[OUT] = do_div(clk_rate, IDEAL_RATIO_RATE); 4243117bb31SNicolin Chen else 425b39eb1e2SShengjiu Wang rem[OUT] = do_div(clk_rate, outrate); 426b39eb1e2SShengjiu Wang div[OUT] = clk_rate; 4273117bb31SNicolin Chen 428b39eb1e2SShengjiu Wang /* Output divider has the same limitation as the input one */ 429b39eb1e2SShengjiu Wang if (div[OUT] == 0 || (!ideal && (div[OUT] > 1024 || rem[OUT] != 0))) { 4303117bb31SNicolin Chen pair_err("failed to support output sample rate %dHz by asrck_%x\n", 4313117bb31SNicolin Chen outrate, clk_index[OUT]); 4323117bb31SNicolin Chen return -EINVAL; 4333117bb31SNicolin Chen } 4343117bb31SNicolin Chen 435b39eb1e2SShengjiu Wang div[OUT] = min_t(u32, 1024, div[OUT]); 436b39eb1e2SShengjiu Wang 4373117bb31SNicolin Chen /* Set the channel number */ 4383117bb31SNicolin Chen channels = config->channel_num; 4393117bb31SNicolin Chen 440*7470704dSShengjiu Wang if (asrc->soc->channel_bits < 4) 4413117bb31SNicolin Chen channels /= 2; 4423117bb31SNicolin Chen 4433117bb31SNicolin Chen /* Update channels for current pair */ 444*7470704dSShengjiu Wang regmap_update_bits(asrc->regmap, REG_ASRCNCR, 445*7470704dSShengjiu Wang ASRCNCR_ANCi_MASK(index, asrc->soc->channel_bits), 446*7470704dSShengjiu Wang ASRCNCR_ANCi(index, channels, asrc->soc->channel_bits)); 4473117bb31SNicolin Chen 4483117bb31SNicolin Chen /* Default setting: Automatic selection for processing mode */ 449*7470704dSShengjiu Wang regmap_update_bits(asrc->regmap, REG_ASRCTR, 4503117bb31SNicolin Chen ASRCTR_ATSi_MASK(index), ASRCTR_ATS(index)); 451*7470704dSShengjiu Wang regmap_update_bits(asrc->regmap, REG_ASRCTR, 4523117bb31SNicolin Chen ASRCTR_USRi_MASK(index), 0); 4533117bb31SNicolin Chen 4543117bb31SNicolin Chen /* Set the input and output clock sources */ 455*7470704dSShengjiu Wang regmap_update_bits(asrc->regmap, REG_ASRCSR, 4563117bb31SNicolin Chen ASRCSR_AICSi_MASK(index) | ASRCSR_AOCSi_MASK(index), 4573117bb31SNicolin Chen ASRCSR_AICS(index, clk_index[IN]) | 4583117bb31SNicolin Chen ASRCSR_AOCS(index, clk_index[OUT])); 4593117bb31SNicolin Chen 4603117bb31SNicolin Chen /* Calculate the input clock divisors */ 4613117bb31SNicolin Chen indiv = fsl_asrc_cal_asrck_divisor(pair, div[IN]); 4623117bb31SNicolin Chen outdiv = fsl_asrc_cal_asrck_divisor(pair, div[OUT]); 4633117bb31SNicolin Chen 4643117bb31SNicolin Chen /* Suppose indiv and outdiv includes prescaler, so add its MASK too */ 465*7470704dSShengjiu Wang regmap_update_bits(asrc->regmap, REG_ASRCDR(index), 4663117bb31SNicolin Chen ASRCDRi_AOCPi_MASK(index) | ASRCDRi_AICPi_MASK(index) | 4673117bb31SNicolin Chen ASRCDRi_AOCDi_MASK(index) | ASRCDRi_AICDi_MASK(index), 4683117bb31SNicolin Chen ASRCDRi_AOCP(index, outdiv) | ASRCDRi_AICP(index, indiv)); 4693117bb31SNicolin Chen 4703117bb31SNicolin Chen /* Implement word_width configurations */ 471*7470704dSShengjiu Wang regmap_update_bits(asrc->regmap, REG_ASRMCR1(index), 4723117bb31SNicolin Chen ASRMCR1i_OW16_MASK | ASRMCR1i_IWD_MASK, 4734bf62571SShengjiu Wang ASRMCR1i_OW16(output_word_width) | 4744bf62571SShengjiu Wang ASRMCR1i_IWD(input_word_width)); 4753117bb31SNicolin Chen 4763117bb31SNicolin Chen /* Enable BUFFER STALL */ 477*7470704dSShengjiu Wang regmap_update_bits(asrc->regmap, REG_ASRMCR(index), 4783117bb31SNicolin Chen ASRMCRi_BUFSTALLi_MASK, ASRMCRi_BUFSTALLi); 4793117bb31SNicolin Chen 4803117bb31SNicolin Chen /* Set default thresholds for input and output FIFO */ 4813117bb31SNicolin Chen fsl_asrc_set_watermarks(pair, ASRC_INPUTFIFO_THRESHOLD, 4823117bb31SNicolin Chen ASRC_INPUTFIFO_THRESHOLD); 4833117bb31SNicolin Chen 4844091fb95SMasahiro Yamada /* Configure the following only for Ideal Ratio mode */ 4853117bb31SNicolin Chen if (!ideal) 4863117bb31SNicolin Chen return 0; 4873117bb31SNicolin Chen 4883117bb31SNicolin Chen /* Clear ASTSx bit to use Ideal Ratio mode */ 489*7470704dSShengjiu Wang regmap_update_bits(asrc->regmap, REG_ASRCTR, 4903117bb31SNicolin Chen ASRCTR_ATSi_MASK(index), 0); 4913117bb31SNicolin Chen 4923117bb31SNicolin Chen /* Enable Ideal Ratio mode */ 493*7470704dSShengjiu Wang regmap_update_bits(asrc->regmap, REG_ASRCTR, 4943117bb31SNicolin Chen ASRCTR_IDRi_MASK(index) | ASRCTR_USRi_MASK(index), 4953117bb31SNicolin Chen ASRCTR_IDR(index) | ASRCTR_USR(index)); 4963117bb31SNicolin Chen 4974aecaa0aSS.j. Wang fsl_asrc_sel_proc(inrate, outrate, &pre_proc, &post_proc); 4984aecaa0aSS.j. Wang 4993117bb31SNicolin Chen /* Apply configurations for pre- and post-processing */ 500*7470704dSShengjiu Wang regmap_update_bits(asrc->regmap, REG_ASRCFG, 5013117bb31SNicolin Chen ASRCFG_PREMODi_MASK(index) | ASRCFG_POSTMODi_MASK(index), 5024aecaa0aSS.j. Wang ASRCFG_PREMOD(index, pre_proc) | 5034aecaa0aSS.j. Wang ASRCFG_POSTMOD(index, post_proc)); 5043117bb31SNicolin Chen 5053117bb31SNicolin Chen return fsl_asrc_set_ideal_ratio(pair, inrate, outrate); 5063117bb31SNicolin Chen } 5073117bb31SNicolin Chen 5083117bb31SNicolin Chen /** 5093117bb31SNicolin Chen * Start the assigned ASRC pair 5103117bb31SNicolin Chen * 5113117bb31SNicolin Chen * It enables the assigned pair and makes it stopped at the stall level. 5123117bb31SNicolin Chen */ 5133117bb31SNicolin Chen static void fsl_asrc_start_pair(struct fsl_asrc_pair *pair) 5143117bb31SNicolin Chen { 515*7470704dSShengjiu Wang struct fsl_asrc *asrc = pair->asrc; 5163117bb31SNicolin Chen enum asrc_pair_index index = pair->index; 5173117bb31SNicolin Chen int reg, retry = 10, i; 5183117bb31SNicolin Chen 5193117bb31SNicolin Chen /* Enable the current pair */ 520*7470704dSShengjiu Wang regmap_update_bits(asrc->regmap, REG_ASRCTR, 5213117bb31SNicolin Chen ASRCTR_ASRCEi_MASK(index), ASRCTR_ASRCE(index)); 5223117bb31SNicolin Chen 5233117bb31SNicolin Chen /* Wait for status of initialization */ 5243117bb31SNicolin Chen do { 5253117bb31SNicolin Chen udelay(5); 526*7470704dSShengjiu Wang regmap_read(asrc->regmap, REG_ASRCFG, ®); 5273117bb31SNicolin Chen reg &= ASRCFG_INIRQi_MASK(index); 5283117bb31SNicolin Chen } while (!reg && --retry); 5293117bb31SNicolin Chen 5303117bb31SNicolin Chen /* Make the input fifo to ASRC STALL level */ 531*7470704dSShengjiu Wang regmap_read(asrc->regmap, REG_ASRCNCR, ®); 5323117bb31SNicolin Chen for (i = 0; i < pair->channels * 4; i++) 533*7470704dSShengjiu Wang regmap_write(asrc->regmap, REG_ASRDI(index), 0); 5343117bb31SNicolin Chen 5353117bb31SNicolin Chen /* Enable overload interrupt */ 536*7470704dSShengjiu Wang regmap_write(asrc->regmap, REG_ASRIER, ASRIER_AOLIE); 5373117bb31SNicolin Chen } 5383117bb31SNicolin Chen 5393117bb31SNicolin Chen /** 5403117bb31SNicolin Chen * Stop the assigned ASRC pair 5413117bb31SNicolin Chen */ 5423117bb31SNicolin Chen static void fsl_asrc_stop_pair(struct fsl_asrc_pair *pair) 5433117bb31SNicolin Chen { 544*7470704dSShengjiu Wang struct fsl_asrc *asrc = pair->asrc; 5453117bb31SNicolin Chen enum asrc_pair_index index = pair->index; 5463117bb31SNicolin Chen 5473117bb31SNicolin Chen /* Stop the current pair */ 548*7470704dSShengjiu Wang regmap_update_bits(asrc->regmap, REG_ASRCTR, 5493117bb31SNicolin Chen ASRCTR_ASRCEi_MASK(index), 0); 5503117bb31SNicolin Chen } 5513117bb31SNicolin Chen 5523117bb31SNicolin Chen /** 5533117bb31SNicolin Chen * Get DMA channel according to the pair and direction. 5543117bb31SNicolin Chen */ 5553117bb31SNicolin Chen struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, bool dir) 5563117bb31SNicolin Chen { 557*7470704dSShengjiu Wang struct fsl_asrc *asrc = pair->asrc; 5583117bb31SNicolin Chen enum asrc_pair_index index = pair->index; 5593117bb31SNicolin Chen char name[4]; 5603117bb31SNicolin Chen 5613117bb31SNicolin Chen sprintf(name, "%cx%c", dir == IN ? 'r' : 't', index + 'a'); 5623117bb31SNicolin Chen 563*7470704dSShengjiu Wang return dma_request_slave_channel(&asrc->pdev->dev, name); 5643117bb31SNicolin Chen } 5653117bb31SNicolin Chen EXPORT_SYMBOL_GPL(fsl_asrc_get_dma_channel); 5663117bb31SNicolin Chen 56753f67a78SS.j. Wang static int fsl_asrc_dai_startup(struct snd_pcm_substream *substream, 56853f67a78SS.j. Wang struct snd_soc_dai *dai) 56953f67a78SS.j. Wang { 570*7470704dSShengjiu Wang struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); 57153f67a78SS.j. Wang 57253f67a78SS.j. Wang /* Odd channel number is not valid for older ASRC (channel_bits==3) */ 573*7470704dSShengjiu Wang if (asrc->soc->channel_bits == 3) 57453f67a78SS.j. Wang snd_pcm_hw_constraint_step(substream->runtime, 0, 57553f67a78SS.j. Wang SNDRV_PCM_HW_PARAM_CHANNELS, 2); 57653f67a78SS.j. Wang 577d281bf5dSS.j. Wang 578d281bf5dSS.j. Wang return snd_pcm_hw_constraint_list(substream->runtime, 0, 579d281bf5dSS.j. Wang SNDRV_PCM_HW_PARAM_RATE, &fsl_asrc_rate_constraints); 58053f67a78SS.j. Wang } 58153f67a78SS.j. Wang 5823117bb31SNicolin Chen static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream, 5833117bb31SNicolin Chen struct snd_pcm_hw_params *params, 5843117bb31SNicolin Chen struct snd_soc_dai *dai) 5853117bb31SNicolin Chen { 586*7470704dSShengjiu Wang struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); 5873117bb31SNicolin Chen struct snd_pcm_runtime *runtime = substream->runtime; 5883117bb31SNicolin Chen struct fsl_asrc_pair *pair = runtime->private_data; 5893117bb31SNicolin Chen unsigned int channels = params_channels(params); 5903117bb31SNicolin Chen unsigned int rate = params_rate(params); 5913117bb31SNicolin Chen struct asrc_config config; 5924bf62571SShengjiu Wang snd_pcm_format_t format; 5934bf62571SShengjiu Wang int ret; 5943117bb31SNicolin Chen 5953117bb31SNicolin Chen ret = fsl_asrc_request_pair(channels, pair); 5963117bb31SNicolin Chen if (ret) { 5973117bb31SNicolin Chen dev_err(dai->dev, "fail to request asrc pair\n"); 5983117bb31SNicolin Chen return ret; 5993117bb31SNicolin Chen } 6003117bb31SNicolin Chen 6013117bb31SNicolin Chen pair->config = &config; 6023117bb31SNicolin Chen 603*7470704dSShengjiu Wang if (asrc->asrc_width == 16) 6044bf62571SShengjiu Wang format = SNDRV_PCM_FORMAT_S16_LE; 6053117bb31SNicolin Chen else 6064bf62571SShengjiu Wang format = SNDRV_PCM_FORMAT_S24_LE; 6073117bb31SNicolin Chen 6083117bb31SNicolin Chen config.pair = pair->index; 6093117bb31SNicolin Chen config.channel_num = channels; 6103117bb31SNicolin Chen config.inclk = INCLK_NONE; 6113117bb31SNicolin Chen config.outclk = OUTCLK_ASRCK1_CLK; 6123117bb31SNicolin Chen 6133117bb31SNicolin Chen if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 6144bf62571SShengjiu Wang config.input_format = params_format(params); 6154bf62571SShengjiu Wang config.output_format = format; 6163117bb31SNicolin Chen config.input_sample_rate = rate; 617*7470704dSShengjiu Wang config.output_sample_rate = asrc->asrc_rate; 6183117bb31SNicolin Chen } else { 6194bf62571SShengjiu Wang config.input_format = format; 6204bf62571SShengjiu Wang config.output_format = params_format(params); 621*7470704dSShengjiu Wang config.input_sample_rate = asrc->asrc_rate; 6223117bb31SNicolin Chen config.output_sample_rate = rate; 6233117bb31SNicolin Chen } 6243117bb31SNicolin Chen 625b39eb1e2SShengjiu Wang ret = fsl_asrc_config_pair(pair, false); 6263117bb31SNicolin Chen if (ret) { 6273117bb31SNicolin Chen dev_err(dai->dev, "fail to config asrc pair\n"); 6283117bb31SNicolin Chen return ret; 6293117bb31SNicolin Chen } 6303117bb31SNicolin Chen 6313117bb31SNicolin Chen return 0; 6323117bb31SNicolin Chen } 6333117bb31SNicolin Chen 6343117bb31SNicolin Chen static int fsl_asrc_dai_hw_free(struct snd_pcm_substream *substream, 6353117bb31SNicolin Chen struct snd_soc_dai *dai) 6363117bb31SNicolin Chen { 6373117bb31SNicolin Chen struct snd_pcm_runtime *runtime = substream->runtime; 6383117bb31SNicolin Chen struct fsl_asrc_pair *pair = runtime->private_data; 6393117bb31SNicolin Chen 6403117bb31SNicolin Chen if (pair) 6413117bb31SNicolin Chen fsl_asrc_release_pair(pair); 6423117bb31SNicolin Chen 6433117bb31SNicolin Chen return 0; 6443117bb31SNicolin Chen } 6453117bb31SNicolin Chen 6463117bb31SNicolin Chen static int fsl_asrc_dai_trigger(struct snd_pcm_substream *substream, int cmd, 6473117bb31SNicolin Chen struct snd_soc_dai *dai) 6483117bb31SNicolin Chen { 6493117bb31SNicolin Chen struct snd_pcm_runtime *runtime = substream->runtime; 6503117bb31SNicolin Chen struct fsl_asrc_pair *pair = runtime->private_data; 6513117bb31SNicolin Chen 6523117bb31SNicolin Chen switch (cmd) { 6533117bb31SNicolin Chen case SNDRV_PCM_TRIGGER_START: 6543117bb31SNicolin Chen case SNDRV_PCM_TRIGGER_RESUME: 6553117bb31SNicolin Chen case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 6563117bb31SNicolin Chen fsl_asrc_start_pair(pair); 6573117bb31SNicolin Chen break; 6583117bb31SNicolin Chen case SNDRV_PCM_TRIGGER_STOP: 6593117bb31SNicolin Chen case SNDRV_PCM_TRIGGER_SUSPEND: 6603117bb31SNicolin Chen case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 6613117bb31SNicolin Chen fsl_asrc_stop_pair(pair); 6623117bb31SNicolin Chen break; 6633117bb31SNicolin Chen default: 6643117bb31SNicolin Chen return -EINVAL; 6653117bb31SNicolin Chen } 6663117bb31SNicolin Chen 6673117bb31SNicolin Chen return 0; 6683117bb31SNicolin Chen } 6693117bb31SNicolin Chen 67029a22ebfSGustavo A. R. Silva static const struct snd_soc_dai_ops fsl_asrc_dai_ops = { 67153f67a78SS.j. Wang .startup = fsl_asrc_dai_startup, 6723117bb31SNicolin Chen .hw_params = fsl_asrc_dai_hw_params, 6733117bb31SNicolin Chen .hw_free = fsl_asrc_dai_hw_free, 6743117bb31SNicolin Chen .trigger = fsl_asrc_dai_trigger, 6753117bb31SNicolin Chen }; 6763117bb31SNicolin Chen 6773117bb31SNicolin Chen static int fsl_asrc_dai_probe(struct snd_soc_dai *dai) 6783117bb31SNicolin Chen { 679*7470704dSShengjiu Wang struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); 6803117bb31SNicolin Chen 681*7470704dSShengjiu Wang snd_soc_dai_init_dma_data(dai, &asrc->dma_params_tx, 682*7470704dSShengjiu Wang &asrc->dma_params_rx); 6833117bb31SNicolin Chen 6843117bb31SNicolin Chen return 0; 6853117bb31SNicolin Chen } 6863117bb31SNicolin Chen 6873117bb31SNicolin Chen #define FSL_ASRC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \ 6883117bb31SNicolin Chen SNDRV_PCM_FMTBIT_S16_LE | \ 689109539c9SShengjiu Wang SNDRV_PCM_FMTBIT_S24_3LE) 6903117bb31SNicolin Chen 6913117bb31SNicolin Chen static struct snd_soc_dai_driver fsl_asrc_dai = { 6923117bb31SNicolin Chen .probe = fsl_asrc_dai_probe, 6933117bb31SNicolin Chen .playback = { 6943117bb31SNicolin Chen .stream_name = "ASRC-Playback", 6953117bb31SNicolin Chen .channels_min = 1, 6963117bb31SNicolin Chen .channels_max = 10, 697d281bf5dSS.j. Wang .rate_min = 5512, 698d281bf5dSS.j. Wang .rate_max = 192000, 699d281bf5dSS.j. Wang .rates = SNDRV_PCM_RATE_KNOT, 700109539c9SShengjiu Wang .formats = FSL_ASRC_FORMATS | 701109539c9SShengjiu Wang SNDRV_PCM_FMTBIT_S8, 7023117bb31SNicolin Chen }, 7033117bb31SNicolin Chen .capture = { 7043117bb31SNicolin Chen .stream_name = "ASRC-Capture", 7053117bb31SNicolin Chen .channels_min = 1, 7063117bb31SNicolin Chen .channels_max = 10, 707d281bf5dSS.j. Wang .rate_min = 5512, 708d281bf5dSS.j. Wang .rate_max = 192000, 709d281bf5dSS.j. Wang .rates = SNDRV_PCM_RATE_KNOT, 7103117bb31SNicolin Chen .formats = FSL_ASRC_FORMATS, 7113117bb31SNicolin Chen }, 7123117bb31SNicolin Chen .ops = &fsl_asrc_dai_ops, 7133117bb31SNicolin Chen }; 7143117bb31SNicolin Chen 7153117bb31SNicolin Chen static bool fsl_asrc_readable_reg(struct device *dev, unsigned int reg) 7163117bb31SNicolin Chen { 7173117bb31SNicolin Chen switch (reg) { 7183117bb31SNicolin Chen case REG_ASRCTR: 7193117bb31SNicolin Chen case REG_ASRIER: 7203117bb31SNicolin Chen case REG_ASRCNCR: 7213117bb31SNicolin Chen case REG_ASRCFG: 7223117bb31SNicolin Chen case REG_ASRCSR: 7233117bb31SNicolin Chen case REG_ASRCDR1: 7243117bb31SNicolin Chen case REG_ASRCDR2: 7253117bb31SNicolin Chen case REG_ASRSTR: 7263117bb31SNicolin Chen case REG_ASRPM1: 7273117bb31SNicolin Chen case REG_ASRPM2: 7283117bb31SNicolin Chen case REG_ASRPM3: 7293117bb31SNicolin Chen case REG_ASRPM4: 7303117bb31SNicolin Chen case REG_ASRPM5: 7313117bb31SNicolin Chen case REG_ASRTFR1: 7323117bb31SNicolin Chen case REG_ASRCCR: 7333117bb31SNicolin Chen case REG_ASRDOA: 7343117bb31SNicolin Chen case REG_ASRDOB: 7353117bb31SNicolin Chen case REG_ASRDOC: 7363117bb31SNicolin Chen case REG_ASRIDRHA: 7373117bb31SNicolin Chen case REG_ASRIDRLA: 7383117bb31SNicolin Chen case REG_ASRIDRHB: 7393117bb31SNicolin Chen case REG_ASRIDRLB: 7403117bb31SNicolin Chen case REG_ASRIDRHC: 7413117bb31SNicolin Chen case REG_ASRIDRLC: 7423117bb31SNicolin Chen case REG_ASR76K: 7433117bb31SNicolin Chen case REG_ASR56K: 7443117bb31SNicolin Chen case REG_ASRMCRA: 7453117bb31SNicolin Chen case REG_ASRFSTA: 7463117bb31SNicolin Chen case REG_ASRMCRB: 7473117bb31SNicolin Chen case REG_ASRFSTB: 7483117bb31SNicolin Chen case REG_ASRMCRC: 7493117bb31SNicolin Chen case REG_ASRFSTC: 7503117bb31SNicolin Chen case REG_ASRMCR1A: 7513117bb31SNicolin Chen case REG_ASRMCR1B: 7523117bb31SNicolin Chen case REG_ASRMCR1C: 7533117bb31SNicolin Chen return true; 7543117bb31SNicolin Chen default: 7553117bb31SNicolin Chen return false; 7563117bb31SNicolin Chen } 7573117bb31SNicolin Chen } 7583117bb31SNicolin Chen 7593117bb31SNicolin Chen static bool fsl_asrc_volatile_reg(struct device *dev, unsigned int reg) 7603117bb31SNicolin Chen { 7613117bb31SNicolin Chen switch (reg) { 7623117bb31SNicolin Chen case REG_ASRSTR: 7633117bb31SNicolin Chen case REG_ASRDIA: 7643117bb31SNicolin Chen case REG_ASRDIB: 7653117bb31SNicolin Chen case REG_ASRDIC: 7663117bb31SNicolin Chen case REG_ASRDOA: 7673117bb31SNicolin Chen case REG_ASRDOB: 7683117bb31SNicolin Chen case REG_ASRDOC: 7693117bb31SNicolin Chen case REG_ASRFSTA: 7703117bb31SNicolin Chen case REG_ASRFSTB: 7713117bb31SNicolin Chen case REG_ASRFSTC: 7723117bb31SNicolin Chen case REG_ASRCFG: 7733117bb31SNicolin Chen return true; 7743117bb31SNicolin Chen default: 7753117bb31SNicolin Chen return false; 7763117bb31SNicolin Chen } 7773117bb31SNicolin Chen } 7783117bb31SNicolin Chen 7793117bb31SNicolin Chen static bool fsl_asrc_writeable_reg(struct device *dev, unsigned int reg) 7803117bb31SNicolin Chen { 7813117bb31SNicolin Chen switch (reg) { 7823117bb31SNicolin Chen case REG_ASRCTR: 7833117bb31SNicolin Chen case REG_ASRIER: 7843117bb31SNicolin Chen case REG_ASRCNCR: 7853117bb31SNicolin Chen case REG_ASRCFG: 7863117bb31SNicolin Chen case REG_ASRCSR: 7873117bb31SNicolin Chen case REG_ASRCDR1: 7883117bb31SNicolin Chen case REG_ASRCDR2: 7893117bb31SNicolin Chen case REG_ASRSTR: 7903117bb31SNicolin Chen case REG_ASRPM1: 7913117bb31SNicolin Chen case REG_ASRPM2: 7923117bb31SNicolin Chen case REG_ASRPM3: 7933117bb31SNicolin Chen case REG_ASRPM4: 7943117bb31SNicolin Chen case REG_ASRPM5: 7953117bb31SNicolin Chen case REG_ASRTFR1: 7963117bb31SNicolin Chen case REG_ASRCCR: 7973117bb31SNicolin Chen case REG_ASRDIA: 7983117bb31SNicolin Chen case REG_ASRDIB: 7993117bb31SNicolin Chen case REG_ASRDIC: 8003117bb31SNicolin Chen case REG_ASRIDRHA: 8013117bb31SNicolin Chen case REG_ASRIDRLA: 8023117bb31SNicolin Chen case REG_ASRIDRHB: 8033117bb31SNicolin Chen case REG_ASRIDRLB: 8043117bb31SNicolin Chen case REG_ASRIDRHC: 8053117bb31SNicolin Chen case REG_ASRIDRLC: 8063117bb31SNicolin Chen case REG_ASR76K: 8073117bb31SNicolin Chen case REG_ASR56K: 8083117bb31SNicolin Chen case REG_ASRMCRA: 8093117bb31SNicolin Chen case REG_ASRMCRB: 8103117bb31SNicolin Chen case REG_ASRMCRC: 8113117bb31SNicolin Chen case REG_ASRMCR1A: 8123117bb31SNicolin Chen case REG_ASRMCR1B: 8133117bb31SNicolin Chen case REG_ASRMCR1C: 8143117bb31SNicolin Chen return true; 8153117bb31SNicolin Chen default: 8163117bb31SNicolin Chen return false; 8173117bb31SNicolin Chen } 8183117bb31SNicolin Chen } 8193117bb31SNicolin Chen 82086a570c5SNicolin Chen static struct reg_default fsl_asrc_reg[] = { 82186a570c5SNicolin Chen { REG_ASRCTR, 0x0000 }, { REG_ASRIER, 0x0000 }, 82286a570c5SNicolin Chen { REG_ASRCNCR, 0x0000 }, { REG_ASRCFG, 0x0000 }, 82386a570c5SNicolin Chen { REG_ASRCSR, 0x0000 }, { REG_ASRCDR1, 0x0000 }, 82486a570c5SNicolin Chen { REG_ASRCDR2, 0x0000 }, { REG_ASRSTR, 0x0000 }, 82586a570c5SNicolin Chen { REG_ASRRA, 0x0000 }, { REG_ASRRB, 0x0000 }, 82686a570c5SNicolin Chen { REG_ASRRC, 0x0000 }, { REG_ASRPM1, 0x0000 }, 82786a570c5SNicolin Chen { REG_ASRPM2, 0x0000 }, { REG_ASRPM3, 0x0000 }, 82886a570c5SNicolin Chen { REG_ASRPM4, 0x0000 }, { REG_ASRPM5, 0x0000 }, 82986a570c5SNicolin Chen { REG_ASRTFR1, 0x0000 }, { REG_ASRCCR, 0x0000 }, 83086a570c5SNicolin Chen { REG_ASRDIA, 0x0000 }, { REG_ASRDOA, 0x0000 }, 83186a570c5SNicolin Chen { REG_ASRDIB, 0x0000 }, { REG_ASRDOB, 0x0000 }, 83286a570c5SNicolin Chen { REG_ASRDIC, 0x0000 }, { REG_ASRDOC, 0x0000 }, 83386a570c5SNicolin Chen { REG_ASRIDRHA, 0x0000 }, { REG_ASRIDRLA, 0x0000 }, 83486a570c5SNicolin Chen { REG_ASRIDRHB, 0x0000 }, { REG_ASRIDRLB, 0x0000 }, 83586a570c5SNicolin Chen { REG_ASRIDRHC, 0x0000 }, { REG_ASRIDRLC, 0x0000 }, 83686a570c5SNicolin Chen { REG_ASR76K, 0x0A47 }, { REG_ASR56K, 0x0DF3 }, 83786a570c5SNicolin Chen { REG_ASRMCRA, 0x0000 }, { REG_ASRFSTA, 0x0000 }, 83886a570c5SNicolin Chen { REG_ASRMCRB, 0x0000 }, { REG_ASRFSTB, 0x0000 }, 83986a570c5SNicolin Chen { REG_ASRMCRC, 0x0000 }, { REG_ASRFSTC, 0x0000 }, 84086a570c5SNicolin Chen { REG_ASRMCR1A, 0x0000 }, { REG_ASRMCR1B, 0x0000 }, 84186a570c5SNicolin Chen { REG_ASRMCR1C, 0x0000 }, 84286a570c5SNicolin Chen }; 84386a570c5SNicolin Chen 844bf16d883SXiubo Li static const struct regmap_config fsl_asrc_regmap_config = { 8453117bb31SNicolin Chen .reg_bits = 32, 8463117bb31SNicolin Chen .reg_stride = 4, 8473117bb31SNicolin Chen .val_bits = 32, 8483117bb31SNicolin Chen 8493117bb31SNicolin Chen .max_register = REG_ASRMCR1C, 85086a570c5SNicolin Chen .reg_defaults = fsl_asrc_reg, 85186a570c5SNicolin Chen .num_reg_defaults = ARRAY_SIZE(fsl_asrc_reg), 8523117bb31SNicolin Chen .readable_reg = fsl_asrc_readable_reg, 8533117bb31SNicolin Chen .volatile_reg = fsl_asrc_volatile_reg, 8543117bb31SNicolin Chen .writeable_reg = fsl_asrc_writeable_reg, 855b4138868SMarek Vasut .cache_type = REGCACHE_FLAT, 8563117bb31SNicolin Chen }; 8573117bb31SNicolin Chen 8583117bb31SNicolin Chen /** 8593117bb31SNicolin Chen * Initialize ASRC registers with a default configurations 8603117bb31SNicolin Chen */ 861*7470704dSShengjiu Wang static int fsl_asrc_init(struct fsl_asrc *asrc) 8623117bb31SNicolin Chen { 8633117bb31SNicolin Chen /* Halt ASRC internal FP when input FIFO needs data for pair A, B, C */ 864*7470704dSShengjiu Wang regmap_write(asrc->regmap, REG_ASRCTR, ASRCTR_ASRCEN); 8653117bb31SNicolin Chen 8663117bb31SNicolin Chen /* Disable interrupt by default */ 867*7470704dSShengjiu Wang regmap_write(asrc->regmap, REG_ASRIER, 0x0); 8683117bb31SNicolin Chen 8693117bb31SNicolin Chen /* Apply recommended settings for parameters from Reference Manual */ 870*7470704dSShengjiu Wang regmap_write(asrc->regmap, REG_ASRPM1, 0x7fffff); 871*7470704dSShengjiu Wang regmap_write(asrc->regmap, REG_ASRPM2, 0x255555); 872*7470704dSShengjiu Wang regmap_write(asrc->regmap, REG_ASRPM3, 0xff7280); 873*7470704dSShengjiu Wang regmap_write(asrc->regmap, REG_ASRPM4, 0xff7280); 874*7470704dSShengjiu Wang regmap_write(asrc->regmap, REG_ASRPM5, 0xff7280); 8753117bb31SNicolin Chen 8763117bb31SNicolin Chen /* Base address for task queue FIFO. Set to 0x7C */ 877*7470704dSShengjiu Wang regmap_update_bits(asrc->regmap, REG_ASRTFR1, 8783117bb31SNicolin Chen ASRTFR1_TF_BASE_MASK, ASRTFR1_TF_BASE(0xfc)); 8793117bb31SNicolin Chen 8803117bb31SNicolin Chen /* Set the processing clock for 76KHz to 133M */ 881*7470704dSShengjiu Wang regmap_write(asrc->regmap, REG_ASR76K, 0x06D6); 8823117bb31SNicolin Chen 8833117bb31SNicolin Chen /* Set the processing clock for 56KHz to 133M */ 884*7470704dSShengjiu Wang return regmap_write(asrc->regmap, REG_ASR56K, 0x0947); 8853117bb31SNicolin Chen } 8863117bb31SNicolin Chen 8873117bb31SNicolin Chen /** 8883117bb31SNicolin Chen * Interrupt handler for ASRC 8893117bb31SNicolin Chen */ 8903117bb31SNicolin Chen static irqreturn_t fsl_asrc_isr(int irq, void *dev_id) 8913117bb31SNicolin Chen { 892*7470704dSShengjiu Wang struct fsl_asrc *asrc = (struct fsl_asrc *)dev_id; 893*7470704dSShengjiu Wang struct device *dev = &asrc->pdev->dev; 8943117bb31SNicolin Chen enum asrc_pair_index index; 8953117bb31SNicolin Chen u32 status; 8963117bb31SNicolin Chen 897*7470704dSShengjiu Wang regmap_read(asrc->regmap, REG_ASRSTR, &status); 8983117bb31SNicolin Chen 8993117bb31SNicolin Chen /* Clean overload error */ 900*7470704dSShengjiu Wang regmap_write(asrc->regmap, REG_ASRSTR, ASRSTR_AOLE); 9013117bb31SNicolin Chen 9023117bb31SNicolin Chen /* 9033117bb31SNicolin Chen * We here use dev_dbg() for all exceptions because ASRC itself does 9043117bb31SNicolin Chen * not care if FIFO overflowed or underrun while a warning in the 9053117bb31SNicolin Chen * interrupt would result a ridged conversion. 9063117bb31SNicolin Chen */ 9073117bb31SNicolin Chen for (index = ASRC_PAIR_A; index < ASRC_PAIR_MAX_NUM; index++) { 908*7470704dSShengjiu Wang if (!asrc->pair[index]) 9093117bb31SNicolin Chen continue; 9103117bb31SNicolin Chen 9113117bb31SNicolin Chen if (status & ASRSTR_ATQOL) { 912*7470704dSShengjiu Wang asrc->pair[index]->error |= ASRC_TASK_Q_OVERLOAD; 9133117bb31SNicolin Chen dev_dbg(dev, "ASRC Task Queue FIFO overload\n"); 9143117bb31SNicolin Chen } 9153117bb31SNicolin Chen 9163117bb31SNicolin Chen if (status & ASRSTR_AOOL(index)) { 917*7470704dSShengjiu Wang asrc->pair[index]->error |= ASRC_OUTPUT_TASK_OVERLOAD; 9183117bb31SNicolin Chen pair_dbg("Output Task Overload\n"); 9193117bb31SNicolin Chen } 9203117bb31SNicolin Chen 9213117bb31SNicolin Chen if (status & ASRSTR_AIOL(index)) { 922*7470704dSShengjiu Wang asrc->pair[index]->error |= ASRC_INPUT_TASK_OVERLOAD; 9233117bb31SNicolin Chen pair_dbg("Input Task Overload\n"); 9243117bb31SNicolin Chen } 9253117bb31SNicolin Chen 9263117bb31SNicolin Chen if (status & ASRSTR_AODO(index)) { 927*7470704dSShengjiu Wang asrc->pair[index]->error |= ASRC_OUTPUT_BUFFER_OVERFLOW; 9283117bb31SNicolin Chen pair_dbg("Output Data Buffer has overflowed\n"); 9293117bb31SNicolin Chen } 9303117bb31SNicolin Chen 9313117bb31SNicolin Chen if (status & ASRSTR_AIDU(index)) { 932*7470704dSShengjiu Wang asrc->pair[index]->error |= ASRC_INPUT_BUFFER_UNDERRUN; 9333117bb31SNicolin Chen pair_dbg("Input Data Buffer has underflowed\n"); 9343117bb31SNicolin Chen } 9353117bb31SNicolin Chen } 9363117bb31SNicolin Chen 9373117bb31SNicolin Chen return IRQ_HANDLED; 9383117bb31SNicolin Chen } 9393117bb31SNicolin Chen 9403117bb31SNicolin Chen static int fsl_asrc_probe(struct platform_device *pdev) 9413117bb31SNicolin Chen { 9423117bb31SNicolin Chen struct device_node *np = pdev->dev.of_node; 943*7470704dSShengjiu Wang struct fsl_asrc *asrc; 9443117bb31SNicolin Chen struct resource *res; 9453117bb31SNicolin Chen void __iomem *regs; 9463117bb31SNicolin Chen int irq, ret, i; 947c05f10f2SShengjiu Wang u32 map_idx; 9483117bb31SNicolin Chen char tmp[16]; 9493117bb31SNicolin Chen 950*7470704dSShengjiu Wang asrc = devm_kzalloc(&pdev->dev, sizeof(*asrc), GFP_KERNEL); 951*7470704dSShengjiu Wang if (!asrc) 9523117bb31SNicolin Chen return -ENOMEM; 9533117bb31SNicolin Chen 954*7470704dSShengjiu Wang asrc->pdev = pdev; 9553117bb31SNicolin Chen 9563117bb31SNicolin Chen /* Get the addresses and IRQ */ 9573117bb31SNicolin Chen res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 9583117bb31SNicolin Chen regs = devm_ioremap_resource(&pdev->dev, res); 9593117bb31SNicolin Chen if (IS_ERR(regs)) 9603117bb31SNicolin Chen return PTR_ERR(regs); 9613117bb31SNicolin Chen 962*7470704dSShengjiu Wang asrc->paddr = res->start; 9633117bb31SNicolin Chen 964*7470704dSShengjiu Wang asrc->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs, 9653117bb31SNicolin Chen &fsl_asrc_regmap_config); 966*7470704dSShengjiu Wang if (IS_ERR(asrc->regmap)) { 9673117bb31SNicolin Chen dev_err(&pdev->dev, "failed to init regmap\n"); 968*7470704dSShengjiu Wang return PTR_ERR(asrc->regmap); 9693117bb31SNicolin Chen } 9703117bb31SNicolin Chen 9713117bb31SNicolin Chen irq = platform_get_irq(pdev, 0); 972cf9441adSStephen Boyd if (irq < 0) 9733117bb31SNicolin Chen return irq; 9743117bb31SNicolin Chen 9753117bb31SNicolin Chen ret = devm_request_irq(&pdev->dev, irq, fsl_asrc_isr, 0, 976*7470704dSShengjiu Wang dev_name(&pdev->dev), asrc); 9773117bb31SNicolin Chen if (ret) { 9783117bb31SNicolin Chen dev_err(&pdev->dev, "failed to claim irq %u: %d\n", irq, ret); 9793117bb31SNicolin Chen return ret; 9803117bb31SNicolin Chen } 9813117bb31SNicolin Chen 982*7470704dSShengjiu Wang asrc->mem_clk = devm_clk_get(&pdev->dev, "mem"); 983*7470704dSShengjiu Wang if (IS_ERR(asrc->mem_clk)) { 9843117bb31SNicolin Chen dev_err(&pdev->dev, "failed to get mem clock\n"); 985*7470704dSShengjiu Wang return PTR_ERR(asrc->mem_clk); 9863117bb31SNicolin Chen } 9873117bb31SNicolin Chen 988*7470704dSShengjiu Wang asrc->ipg_clk = devm_clk_get(&pdev->dev, "ipg"); 989*7470704dSShengjiu Wang if (IS_ERR(asrc->ipg_clk)) { 9903117bb31SNicolin Chen dev_err(&pdev->dev, "failed to get ipg clock\n"); 991*7470704dSShengjiu Wang return PTR_ERR(asrc->ipg_clk); 9923117bb31SNicolin Chen } 9933117bb31SNicolin Chen 994*7470704dSShengjiu Wang asrc->spba_clk = devm_clk_get(&pdev->dev, "spba"); 995*7470704dSShengjiu Wang if (IS_ERR(asrc->spba_clk)) 99613b8a97aSShengjiu Wang dev_warn(&pdev->dev, "failed to get spba clock\n"); 99713b8a97aSShengjiu Wang 9983117bb31SNicolin Chen for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { 9993117bb31SNicolin Chen sprintf(tmp, "asrck_%x", i); 1000*7470704dSShengjiu Wang asrc->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp); 1001*7470704dSShengjiu Wang if (IS_ERR(asrc->asrck_clk[i])) { 10023117bb31SNicolin Chen dev_err(&pdev->dev, "failed to get %s clock\n", tmp); 1003*7470704dSShengjiu Wang return PTR_ERR(asrc->asrck_clk[i]); 10043117bb31SNicolin Chen } 10053117bb31SNicolin Chen } 10063117bb31SNicolin Chen 1007*7470704dSShengjiu Wang asrc->soc = of_device_get_match_data(&pdev->dev); 1008*7470704dSShengjiu Wang if (!asrc->soc) { 1009c05f10f2SShengjiu Wang dev_err(&pdev->dev, "failed to get soc data\n"); 1010c05f10f2SShengjiu Wang return -ENODEV; 1011c05f10f2SShengjiu Wang } 1012c05f10f2SShengjiu Wang 1013f3d8ac8cSFabio Estevam if (of_device_is_compatible(np, "fsl,imx35-asrc")) { 1014*7470704dSShengjiu Wang asrc->clk_map[IN] = input_clk_map_imx35; 1015*7470704dSShengjiu Wang asrc->clk_map[OUT] = output_clk_map_imx35; 1016c05f10f2SShengjiu Wang } else if (of_device_is_compatible(np, "fsl,imx53-asrc")) { 1017*7470704dSShengjiu Wang asrc->clk_map[IN] = input_clk_map_imx53; 1018*7470704dSShengjiu Wang asrc->clk_map[OUT] = output_clk_map_imx53; 1019c05f10f2SShengjiu Wang } else if (of_device_is_compatible(np, "fsl,imx8qm-asrc") || 1020c05f10f2SShengjiu Wang of_device_is_compatible(np, "fsl,imx8qxp-asrc")) { 1021c05f10f2SShengjiu Wang ret = of_property_read_u32(np, "fsl,asrc-clk-map", &map_idx); 1022c05f10f2SShengjiu Wang if (ret) { 1023c05f10f2SShengjiu Wang dev_err(&pdev->dev, "failed to get clk map index\n"); 1024c05f10f2SShengjiu Wang return ret; 1025c05f10f2SShengjiu Wang } 1026c05f10f2SShengjiu Wang 1027c05f10f2SShengjiu Wang if (map_idx > 1) { 1028c05f10f2SShengjiu Wang dev_err(&pdev->dev, "unsupported clk map index\n"); 1029c05f10f2SShengjiu Wang return -EINVAL; 1030c05f10f2SShengjiu Wang } 1031c05f10f2SShengjiu Wang if (of_device_is_compatible(np, "fsl,imx8qm-asrc")) { 1032*7470704dSShengjiu Wang asrc->clk_map[IN] = clk_map_imx8qm[map_idx]; 1033*7470704dSShengjiu Wang asrc->clk_map[OUT] = clk_map_imx8qm[map_idx]; 10343117bb31SNicolin Chen } else { 1035*7470704dSShengjiu Wang asrc->clk_map[IN] = clk_map_imx8qxp[map_idx]; 1036*7470704dSShengjiu Wang asrc->clk_map[OUT] = clk_map_imx8qxp[map_idx]; 1037c05f10f2SShengjiu Wang } 10383117bb31SNicolin Chen } 10393117bb31SNicolin Chen 1040*7470704dSShengjiu Wang ret = fsl_asrc_init(asrc); 10413117bb31SNicolin Chen if (ret) { 10423117bb31SNicolin Chen dev_err(&pdev->dev, "failed to init asrc %d\n", ret); 1043c0296950SFabio Estevam return ret; 10443117bb31SNicolin Chen } 10453117bb31SNicolin Chen 1046*7470704dSShengjiu Wang asrc->channel_avail = 10; 10473117bb31SNicolin Chen 10483117bb31SNicolin Chen ret = of_property_read_u32(np, "fsl,asrc-rate", 1049*7470704dSShengjiu Wang &asrc->asrc_rate); 10503117bb31SNicolin Chen if (ret) { 10513117bb31SNicolin Chen dev_err(&pdev->dev, "failed to get output rate\n"); 1052c0296950SFabio Estevam return ret; 10533117bb31SNicolin Chen } 10543117bb31SNicolin Chen 10553117bb31SNicolin Chen ret = of_property_read_u32(np, "fsl,asrc-width", 1056*7470704dSShengjiu Wang &asrc->asrc_width); 10573117bb31SNicolin Chen if (ret) { 10583117bb31SNicolin Chen dev_err(&pdev->dev, "failed to get output width\n"); 1059c0296950SFabio Estevam return ret; 10603117bb31SNicolin Chen } 10613117bb31SNicolin Chen 1062*7470704dSShengjiu Wang if (asrc->asrc_width != 16 && asrc->asrc_width != 24) { 10633117bb31SNicolin Chen dev_warn(&pdev->dev, "unsupported width, switching to 24bit\n"); 1064*7470704dSShengjiu Wang asrc->asrc_width = 24; 10653117bb31SNicolin Chen } 10663117bb31SNicolin Chen 1067*7470704dSShengjiu Wang platform_set_drvdata(pdev, asrc); 10683117bb31SNicolin Chen pm_runtime_enable(&pdev->dev); 1069*7470704dSShengjiu Wang spin_lock_init(&asrc->lock); 10703117bb31SNicolin Chen 10713117bb31SNicolin Chen ret = devm_snd_soc_register_component(&pdev->dev, &fsl_asrc_component, 10723117bb31SNicolin Chen &fsl_asrc_dai, 1); 10733117bb31SNicolin Chen if (ret) { 10743117bb31SNicolin Chen dev_err(&pdev->dev, "failed to register ASoC DAI\n"); 10753117bb31SNicolin Chen return ret; 10763117bb31SNicolin Chen } 10773117bb31SNicolin Chen 10783117bb31SNicolin Chen return 0; 10793117bb31SNicolin Chen } 10803117bb31SNicolin Chen 1081641d334bSRafael J. Wysocki #ifdef CONFIG_PM 10823117bb31SNicolin Chen static int fsl_asrc_runtime_resume(struct device *dev) 10833117bb31SNicolin Chen { 1084*7470704dSShengjiu Wang struct fsl_asrc *asrc = dev_get_drvdata(dev); 1085b1ade0f2SFabio Estevam int i, ret; 10863117bb31SNicolin Chen 1087*7470704dSShengjiu Wang ret = clk_prepare_enable(asrc->mem_clk); 1088b1ade0f2SFabio Estevam if (ret) 1089b1ade0f2SFabio Estevam return ret; 1090*7470704dSShengjiu Wang ret = clk_prepare_enable(asrc->ipg_clk); 1091b1ade0f2SFabio Estevam if (ret) 1092b1ade0f2SFabio Estevam goto disable_mem_clk; 1093*7470704dSShengjiu Wang if (!IS_ERR(asrc->spba_clk)) { 1094*7470704dSShengjiu Wang ret = clk_prepare_enable(asrc->spba_clk); 109513b8a97aSShengjiu Wang if (ret) 109613b8a97aSShengjiu Wang goto disable_ipg_clk; 109713b8a97aSShengjiu Wang } 1098b1ade0f2SFabio Estevam for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { 1099*7470704dSShengjiu Wang ret = clk_prepare_enable(asrc->asrck_clk[i]); 1100b1ade0f2SFabio Estevam if (ret) 1101b1ade0f2SFabio Estevam goto disable_asrck_clk; 1102b1ade0f2SFabio Estevam } 11033117bb31SNicolin Chen 11043117bb31SNicolin Chen return 0; 1105b1ade0f2SFabio Estevam 1106b1ade0f2SFabio Estevam disable_asrck_clk: 1107b1ade0f2SFabio Estevam for (i--; i >= 0; i--) 1108*7470704dSShengjiu Wang clk_disable_unprepare(asrc->asrck_clk[i]); 1109*7470704dSShengjiu Wang if (!IS_ERR(asrc->spba_clk)) 1110*7470704dSShengjiu Wang clk_disable_unprepare(asrc->spba_clk); 111113b8a97aSShengjiu Wang disable_ipg_clk: 1112*7470704dSShengjiu Wang clk_disable_unprepare(asrc->ipg_clk); 1113b1ade0f2SFabio Estevam disable_mem_clk: 1114*7470704dSShengjiu Wang clk_disable_unprepare(asrc->mem_clk); 1115b1ade0f2SFabio Estevam return ret; 11163117bb31SNicolin Chen } 11173117bb31SNicolin Chen 11183117bb31SNicolin Chen static int fsl_asrc_runtime_suspend(struct device *dev) 11193117bb31SNicolin Chen { 1120*7470704dSShengjiu Wang struct fsl_asrc *asrc = dev_get_drvdata(dev); 11213117bb31SNicolin Chen int i; 11223117bb31SNicolin Chen 11233117bb31SNicolin Chen for (i = 0; i < ASRC_CLK_MAX_NUM; i++) 1124*7470704dSShengjiu Wang clk_disable_unprepare(asrc->asrck_clk[i]); 1125*7470704dSShengjiu Wang if (!IS_ERR(asrc->spba_clk)) 1126*7470704dSShengjiu Wang clk_disable_unprepare(asrc->spba_clk); 1127*7470704dSShengjiu Wang clk_disable_unprepare(asrc->ipg_clk); 1128*7470704dSShengjiu Wang clk_disable_unprepare(asrc->mem_clk); 11293117bb31SNicolin Chen 11303117bb31SNicolin Chen return 0; 11313117bb31SNicolin Chen } 1132641d334bSRafael J. Wysocki #endif /* CONFIG_PM */ 11333117bb31SNicolin Chen 1134d3dacda9SFabio Estevam #ifdef CONFIG_PM_SLEEP 11353117bb31SNicolin Chen static int fsl_asrc_suspend(struct device *dev) 11363117bb31SNicolin Chen { 1137*7470704dSShengjiu Wang struct fsl_asrc *asrc = dev_get_drvdata(dev); 11383117bb31SNicolin Chen 1139*7470704dSShengjiu Wang regmap_read(asrc->regmap, REG_ASRCFG, 1140*7470704dSShengjiu Wang &asrc->regcache_cfg); 1141d44c6114SZidan Wang 1142*7470704dSShengjiu Wang regcache_cache_only(asrc->regmap, true); 1143*7470704dSShengjiu Wang regcache_mark_dirty(asrc->regmap); 11443117bb31SNicolin Chen 11453117bb31SNicolin Chen return 0; 11463117bb31SNicolin Chen } 11473117bb31SNicolin Chen 11483117bb31SNicolin Chen static int fsl_asrc_resume(struct device *dev) 11493117bb31SNicolin Chen { 1150*7470704dSShengjiu Wang struct fsl_asrc *asrc = dev_get_drvdata(dev); 11513117bb31SNicolin Chen u32 asrctr; 11523117bb31SNicolin Chen 11533117bb31SNicolin Chen /* Stop all pairs provisionally */ 1154*7470704dSShengjiu Wang regmap_read(asrc->regmap, REG_ASRCTR, &asrctr); 1155*7470704dSShengjiu Wang regmap_update_bits(asrc->regmap, REG_ASRCTR, 11563117bb31SNicolin Chen ASRCTR_ASRCEi_ALL_MASK, 0); 11573117bb31SNicolin Chen 11583117bb31SNicolin Chen /* Restore all registers */ 1159*7470704dSShengjiu Wang regcache_cache_only(asrc->regmap, false); 1160*7470704dSShengjiu Wang regcache_sync(asrc->regmap); 11613117bb31SNicolin Chen 1162*7470704dSShengjiu Wang regmap_update_bits(asrc->regmap, REG_ASRCFG, 1163d44c6114SZidan Wang ASRCFG_NDPRi_ALL_MASK | ASRCFG_POSTMODi_ALL_MASK | 1164*7470704dSShengjiu Wang ASRCFG_PREMODi_ALL_MASK, asrc->regcache_cfg); 1165d44c6114SZidan Wang 11663117bb31SNicolin Chen /* Restart enabled pairs */ 1167*7470704dSShengjiu Wang regmap_update_bits(asrc->regmap, REG_ASRCTR, 11683117bb31SNicolin Chen ASRCTR_ASRCEi_ALL_MASK, asrctr); 11693117bb31SNicolin Chen 11703117bb31SNicolin Chen return 0; 11713117bb31SNicolin Chen } 11723117bb31SNicolin Chen #endif /* CONFIG_PM_SLEEP */ 11733117bb31SNicolin Chen 11743117bb31SNicolin Chen static const struct dev_pm_ops fsl_asrc_pm = { 11753117bb31SNicolin Chen SET_RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL) 11763117bb31SNicolin Chen SET_SYSTEM_SLEEP_PM_OPS(fsl_asrc_suspend, fsl_asrc_resume) 11773117bb31SNicolin Chen }; 11783117bb31SNicolin Chen 1179c05f10f2SShengjiu Wang static const struct fsl_asrc_soc_data fsl_asrc_imx35_data = { 1180c05f10f2SShengjiu Wang .use_edma = false, 1181c05f10f2SShengjiu Wang .channel_bits = 3, 1182c05f10f2SShengjiu Wang }; 1183c05f10f2SShengjiu Wang 1184c05f10f2SShengjiu Wang static const struct fsl_asrc_soc_data fsl_asrc_imx53_data = { 1185c05f10f2SShengjiu Wang .use_edma = false, 1186c05f10f2SShengjiu Wang .channel_bits = 4, 1187c05f10f2SShengjiu Wang }; 1188c05f10f2SShengjiu Wang 1189c05f10f2SShengjiu Wang static const struct fsl_asrc_soc_data fsl_asrc_imx8qm_data = { 1190c05f10f2SShengjiu Wang .use_edma = true, 1191c05f10f2SShengjiu Wang .channel_bits = 4, 1192c05f10f2SShengjiu Wang }; 1193c05f10f2SShengjiu Wang 1194c05f10f2SShengjiu Wang static const struct fsl_asrc_soc_data fsl_asrc_imx8qxp_data = { 1195c05f10f2SShengjiu Wang .use_edma = true, 1196c05f10f2SShengjiu Wang .channel_bits = 4, 1197c05f10f2SShengjiu Wang }; 1198c05f10f2SShengjiu Wang 11993117bb31SNicolin Chen static const struct of_device_id fsl_asrc_ids[] = { 1200c05f10f2SShengjiu Wang { .compatible = "fsl,imx35-asrc", .data = &fsl_asrc_imx35_data }, 1201c05f10f2SShengjiu Wang { .compatible = "fsl,imx53-asrc", .data = &fsl_asrc_imx53_data }, 1202c05f10f2SShengjiu Wang { .compatible = "fsl,imx8qm-asrc", .data = &fsl_asrc_imx8qm_data }, 1203c05f10f2SShengjiu Wang { .compatible = "fsl,imx8qxp-asrc", .data = &fsl_asrc_imx8qxp_data }, 12043117bb31SNicolin Chen {} 12053117bb31SNicolin Chen }; 12063117bb31SNicolin Chen MODULE_DEVICE_TABLE(of, fsl_asrc_ids); 12073117bb31SNicolin Chen 12083117bb31SNicolin Chen static struct platform_driver fsl_asrc_driver = { 12093117bb31SNicolin Chen .probe = fsl_asrc_probe, 12103117bb31SNicolin Chen .driver = { 12113117bb31SNicolin Chen .name = "fsl-asrc", 12123117bb31SNicolin Chen .of_match_table = fsl_asrc_ids, 12133117bb31SNicolin Chen .pm = &fsl_asrc_pm, 12143117bb31SNicolin Chen }, 12153117bb31SNicolin Chen }; 12163117bb31SNicolin Chen module_platform_driver(fsl_asrc_driver); 12173117bb31SNicolin Chen 12183117bb31SNicolin Chen MODULE_DESCRIPTION("Freescale ASRC ASoC driver"); 12193117bb31SNicolin Chen MODULE_AUTHOR("Nicolin Chen <nicoleotsuka@gmail.com>"); 12203117bb31SNicolin Chen MODULE_ALIAS("platform:fsl-asrc"); 12213117bb31SNicolin Chen MODULE_LICENSE("GPL v2"); 1222