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, ...) \ 243117bb31SNicolin Chen dev_err(&asrc_priv->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) 253117bb31SNicolin Chen 263117bb31SNicolin Chen #define pair_dbg(fmt, ...) \ 273117bb31SNicolin Chen dev_dbg(&asrc_priv->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) 283117bb31SNicolin Chen 293117bb31SNicolin Chen /* Corresponding to process_option */ 303117bb31SNicolin Chen static int supported_input_rate[] = { 313117bb31SNicolin Chen 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 323117bb31SNicolin Chen 96000, 176400, 192000, 333117bb31SNicolin Chen }; 343117bb31SNicolin Chen 353117bb31SNicolin Chen static int supported_asrc_rate[] = { 36fff6e03cSZidan Wang 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000, 373117bb31SNicolin Chen }; 383117bb31SNicolin Chen 393117bb31SNicolin Chen /** 403117bb31SNicolin Chen * The following tables map the relationship between asrc_inclk/asrc_outclk in 413117bb31SNicolin Chen * fsl_asrc.h and the registers of ASRCSR 423117bb31SNicolin Chen */ 433117bb31SNicolin Chen static unsigned char input_clk_map_imx35[] = { 443117bb31SNicolin Chen 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 453117bb31SNicolin Chen }; 463117bb31SNicolin Chen 473117bb31SNicolin Chen static unsigned char output_clk_map_imx35[] = { 483117bb31SNicolin Chen 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 493117bb31SNicolin Chen }; 503117bb31SNicolin Chen 513117bb31SNicolin Chen /* i.MX53 uses the same map for input and output */ 523117bb31SNicolin Chen static unsigned char input_clk_map_imx53[] = { 533117bb31SNicolin Chen /* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf */ 543117bb31SNicolin Chen 0x0, 0x1, 0x2, 0x7, 0x4, 0x5, 0x6, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xf, 0xe, 0xd, 553117bb31SNicolin Chen }; 563117bb31SNicolin Chen 573117bb31SNicolin Chen static unsigned char output_clk_map_imx53[] = { 583117bb31SNicolin Chen /* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf */ 593117bb31SNicolin Chen 0x8, 0x9, 0xa, 0x7, 0xc, 0x5, 0x6, 0xb, 0x0, 0x1, 0x2, 0x3, 0x4, 0xf, 0xe, 0xd, 603117bb31SNicolin Chen }; 613117bb31SNicolin Chen 623117bb31SNicolin Chen static unsigned char *clk_map[2]; 633117bb31SNicolin Chen 643117bb31SNicolin Chen /** 65*4aecaa0aSS.j. Wang * Select the pre-processing and post-processing options 66*4aecaa0aSS.j. Wang * Make sure to exclude following unsupported cases before 67*4aecaa0aSS.j. Wang * calling this function: 68*4aecaa0aSS.j. Wang * 1) inrate > 8.125 * outrate 69*4aecaa0aSS.j. Wang * 2) inrate > 16.125 * outrate 70*4aecaa0aSS.j. Wang * 71*4aecaa0aSS.j. Wang * inrate: input sample rate 72*4aecaa0aSS.j. Wang * outrate: output sample rate 73*4aecaa0aSS.j. Wang * pre_proc: return value for pre-processing option 74*4aecaa0aSS.j. Wang * post_proc: return value for post-processing option 75*4aecaa0aSS.j. Wang */ 76*4aecaa0aSS.j. Wang static void fsl_asrc_sel_proc(int inrate, int outrate, 77*4aecaa0aSS.j. Wang int *pre_proc, int *post_proc) 78*4aecaa0aSS.j. Wang { 79*4aecaa0aSS.j. Wang bool post_proc_cond2; 80*4aecaa0aSS.j. Wang bool post_proc_cond0; 81*4aecaa0aSS.j. Wang 82*4aecaa0aSS.j. Wang /* select pre_proc between [0, 2] */ 83*4aecaa0aSS.j. Wang if (inrate * 8 > 33 * outrate) 84*4aecaa0aSS.j. Wang *pre_proc = 2; 85*4aecaa0aSS.j. Wang else if (inrate * 8 > 15 * outrate) { 86*4aecaa0aSS.j. Wang if (inrate > 152000) 87*4aecaa0aSS.j. Wang *pre_proc = 2; 88*4aecaa0aSS.j. Wang else 89*4aecaa0aSS.j. Wang *pre_proc = 1; 90*4aecaa0aSS.j. Wang } else if (inrate < 76000) 91*4aecaa0aSS.j. Wang *pre_proc = 0; 92*4aecaa0aSS.j. Wang else if (inrate > 152000) 93*4aecaa0aSS.j. Wang *pre_proc = 2; 94*4aecaa0aSS.j. Wang else 95*4aecaa0aSS.j. Wang *pre_proc = 1; 96*4aecaa0aSS.j. Wang 97*4aecaa0aSS.j. Wang /* Condition for selection of post-processing */ 98*4aecaa0aSS.j. Wang post_proc_cond2 = (inrate * 15 > outrate * 16 && outrate < 56000) || 99*4aecaa0aSS.j. Wang (inrate > 56000 && outrate < 56000); 100*4aecaa0aSS.j. Wang post_proc_cond0 = inrate * 23 < outrate * 8; 101*4aecaa0aSS.j. Wang 102*4aecaa0aSS.j. Wang if (post_proc_cond2) 103*4aecaa0aSS.j. Wang *post_proc = 2; 104*4aecaa0aSS.j. Wang else if (post_proc_cond0) 105*4aecaa0aSS.j. Wang *post_proc = 0; 106*4aecaa0aSS.j. Wang else 107*4aecaa0aSS.j. Wang *post_proc = 1; 108*4aecaa0aSS.j. Wang } 109*4aecaa0aSS.j. Wang 110*4aecaa0aSS.j. Wang /** 1113117bb31SNicolin Chen * Request ASRC pair 1123117bb31SNicolin Chen * 1133117bb31SNicolin Chen * It assigns pair by the order of A->C->B because allocation of pair B, 1143117bb31SNicolin Chen * within range [ANCA, ANCA+ANCB-1], depends on the channels of pair A 1153117bb31SNicolin Chen * while pair A and pair C are comparatively independent. 1163117bb31SNicolin Chen */ 1173117bb31SNicolin Chen static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair) 1183117bb31SNicolin Chen { 1193117bb31SNicolin Chen enum asrc_pair_index index = ASRC_INVALID_PAIR; 1203117bb31SNicolin Chen struct fsl_asrc *asrc_priv = pair->asrc_priv; 1213117bb31SNicolin Chen struct device *dev = &asrc_priv->pdev->dev; 1223117bb31SNicolin Chen unsigned long lock_flags; 1233117bb31SNicolin Chen int i, ret = 0; 1243117bb31SNicolin Chen 1253117bb31SNicolin Chen spin_lock_irqsave(&asrc_priv->lock, lock_flags); 1263117bb31SNicolin Chen 1273117bb31SNicolin Chen for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) { 1283117bb31SNicolin Chen if (asrc_priv->pair[i] != NULL) 1293117bb31SNicolin Chen continue; 1303117bb31SNicolin Chen 1313117bb31SNicolin Chen index = i; 1323117bb31SNicolin Chen 1333117bb31SNicolin Chen if (i != ASRC_PAIR_B) 1343117bb31SNicolin Chen break; 1353117bb31SNicolin Chen } 1363117bb31SNicolin Chen 1373117bb31SNicolin Chen if (index == ASRC_INVALID_PAIR) { 1383117bb31SNicolin Chen dev_err(dev, "all pairs are busy now\n"); 1393117bb31SNicolin Chen ret = -EBUSY; 1403117bb31SNicolin Chen } else if (asrc_priv->channel_avail < channels) { 1413117bb31SNicolin Chen dev_err(dev, "can't afford required channels: %d\n", channels); 1423117bb31SNicolin Chen ret = -EINVAL; 1433117bb31SNicolin Chen } else { 1443117bb31SNicolin Chen asrc_priv->channel_avail -= channels; 1453117bb31SNicolin Chen asrc_priv->pair[index] = pair; 1463117bb31SNicolin Chen pair->channels = channels; 1473117bb31SNicolin Chen pair->index = index; 1483117bb31SNicolin Chen } 1493117bb31SNicolin Chen 1503117bb31SNicolin Chen spin_unlock_irqrestore(&asrc_priv->lock, lock_flags); 1513117bb31SNicolin Chen 1523117bb31SNicolin Chen return ret; 1533117bb31SNicolin Chen } 1543117bb31SNicolin Chen 1553117bb31SNicolin Chen /** 1563117bb31SNicolin Chen * Release ASRC pair 1573117bb31SNicolin Chen * 1583117bb31SNicolin Chen * It clears the resource from asrc_priv and releases the occupied channels. 1593117bb31SNicolin Chen */ 1603117bb31SNicolin Chen static void fsl_asrc_release_pair(struct fsl_asrc_pair *pair) 1613117bb31SNicolin Chen { 1623117bb31SNicolin Chen struct fsl_asrc *asrc_priv = pair->asrc_priv; 1633117bb31SNicolin Chen enum asrc_pair_index index = pair->index; 1643117bb31SNicolin Chen unsigned long lock_flags; 1653117bb31SNicolin Chen 1663117bb31SNicolin Chen /* Make sure the pair is disabled */ 1673117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, 1683117bb31SNicolin Chen ASRCTR_ASRCEi_MASK(index), 0); 1693117bb31SNicolin Chen 1703117bb31SNicolin Chen spin_lock_irqsave(&asrc_priv->lock, lock_flags); 1713117bb31SNicolin Chen 1723117bb31SNicolin Chen asrc_priv->channel_avail += pair->channels; 1733117bb31SNicolin Chen asrc_priv->pair[index] = NULL; 1743117bb31SNicolin Chen pair->error = 0; 1753117bb31SNicolin Chen 1763117bb31SNicolin Chen spin_unlock_irqrestore(&asrc_priv->lock, lock_flags); 1773117bb31SNicolin Chen } 1783117bb31SNicolin Chen 1793117bb31SNicolin Chen /** 1803117bb31SNicolin Chen * Configure input and output thresholds 1813117bb31SNicolin Chen */ 1823117bb31SNicolin Chen static void fsl_asrc_set_watermarks(struct fsl_asrc_pair *pair, u32 in, u32 out) 1833117bb31SNicolin Chen { 1843117bb31SNicolin Chen struct fsl_asrc *asrc_priv = pair->asrc_priv; 1853117bb31SNicolin Chen enum asrc_pair_index index = pair->index; 1863117bb31SNicolin Chen 1873117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRMCR(index), 1883117bb31SNicolin Chen ASRMCRi_EXTTHRSHi_MASK | 1893117bb31SNicolin Chen ASRMCRi_INFIFO_THRESHOLD_MASK | 1903117bb31SNicolin Chen ASRMCRi_OUTFIFO_THRESHOLD_MASK, 1913117bb31SNicolin Chen ASRMCRi_EXTTHRSHi | 1923117bb31SNicolin Chen ASRMCRi_INFIFO_THRESHOLD(in) | 1933117bb31SNicolin Chen ASRMCRi_OUTFIFO_THRESHOLD(out)); 1943117bb31SNicolin Chen } 1953117bb31SNicolin Chen 1963117bb31SNicolin Chen /** 1973117bb31SNicolin Chen * Calculate the total divisor between asrck clock rate and sample rate 1983117bb31SNicolin Chen * 1993117bb31SNicolin Chen * It follows the formula clk_rate = samplerate * (2 ^ prescaler) * divider 2003117bb31SNicolin Chen */ 2013117bb31SNicolin Chen static u32 fsl_asrc_cal_asrck_divisor(struct fsl_asrc_pair *pair, u32 div) 2023117bb31SNicolin Chen { 2033117bb31SNicolin Chen u32 ps; 2043117bb31SNicolin Chen 2053117bb31SNicolin Chen /* Calculate the divisors: prescaler [2^0, 2^7], divder [1, 8] */ 2063117bb31SNicolin Chen for (ps = 0; div > 8; ps++) 2073117bb31SNicolin Chen div >>= 1; 2083117bb31SNicolin Chen 2093117bb31SNicolin Chen return ((div - 1) << ASRCDRi_AxCPi_WIDTH) | ps; 2103117bb31SNicolin Chen } 2113117bb31SNicolin Chen 2123117bb31SNicolin Chen /** 2133117bb31SNicolin Chen * Calculate and set the ratio for Ideal Ratio mode only 2143117bb31SNicolin Chen * 2153117bb31SNicolin Chen * The ratio is a 32-bit fixed point value with 26 fractional bits. 2163117bb31SNicolin Chen */ 2173117bb31SNicolin Chen static int fsl_asrc_set_ideal_ratio(struct fsl_asrc_pair *pair, 2183117bb31SNicolin Chen int inrate, int outrate) 2193117bb31SNicolin Chen { 2203117bb31SNicolin Chen struct fsl_asrc *asrc_priv = pair->asrc_priv; 2213117bb31SNicolin Chen enum asrc_pair_index index = pair->index; 2223117bb31SNicolin Chen unsigned long ratio; 2233117bb31SNicolin Chen int i; 2243117bb31SNicolin Chen 2253117bb31SNicolin Chen if (!outrate) { 2263117bb31SNicolin Chen pair_err("output rate should not be zero\n"); 2273117bb31SNicolin Chen return -EINVAL; 2283117bb31SNicolin Chen } 2293117bb31SNicolin Chen 2303117bb31SNicolin Chen /* Calculate the intergal part of the ratio */ 2313117bb31SNicolin Chen ratio = (inrate / outrate) << IDEAL_RATIO_DECIMAL_DEPTH; 2323117bb31SNicolin Chen 2333117bb31SNicolin Chen /* ... and then the 26 depth decimal part */ 2343117bb31SNicolin Chen inrate %= outrate; 2353117bb31SNicolin Chen 2363117bb31SNicolin Chen for (i = 1; i <= IDEAL_RATIO_DECIMAL_DEPTH; i++) { 2373117bb31SNicolin Chen inrate <<= 1; 2383117bb31SNicolin Chen 2393117bb31SNicolin Chen if (inrate < outrate) 2403117bb31SNicolin Chen continue; 2413117bb31SNicolin Chen 2423117bb31SNicolin Chen ratio |= 1 << (IDEAL_RATIO_DECIMAL_DEPTH - i); 2433117bb31SNicolin Chen inrate -= outrate; 2443117bb31SNicolin Chen 2453117bb31SNicolin Chen if (!inrate) 2463117bb31SNicolin Chen break; 2473117bb31SNicolin Chen } 2483117bb31SNicolin Chen 2493117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRIDRL(index), ratio); 2503117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRIDRH(index), ratio >> 24); 2513117bb31SNicolin Chen 2523117bb31SNicolin Chen return 0; 2533117bb31SNicolin Chen } 2543117bb31SNicolin Chen 2553117bb31SNicolin Chen /** 2563117bb31SNicolin Chen * Configure the assigned ASRC pair 2573117bb31SNicolin Chen * 2583117bb31SNicolin Chen * It configures those ASRC registers according to a configuration instance 2593117bb31SNicolin Chen * of struct asrc_config which includes in/output sample rate, width, channel 2603117bb31SNicolin Chen * and clock settings. 2613117bb31SNicolin Chen */ 2623117bb31SNicolin Chen static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair) 2633117bb31SNicolin Chen { 2643117bb31SNicolin Chen struct asrc_config *config = pair->config; 2653117bb31SNicolin Chen struct fsl_asrc *asrc_priv = pair->asrc_priv; 2663117bb31SNicolin Chen enum asrc_pair_index index = pair->index; 2674e13eb72SNicolin Chen u32 inrate, outrate, indiv, outdiv; 2683117bb31SNicolin Chen u32 clk_index[2], div[2]; 2693117bb31SNicolin Chen int in, out, channels; 270*4aecaa0aSS.j. Wang int pre_proc, post_proc; 2713117bb31SNicolin Chen struct clk *clk; 2724e13eb72SNicolin Chen bool ideal; 2733117bb31SNicolin Chen 2743117bb31SNicolin Chen if (!config) { 2753117bb31SNicolin Chen pair_err("invalid pair config\n"); 2763117bb31SNicolin Chen return -EINVAL; 2773117bb31SNicolin Chen } 2783117bb31SNicolin Chen 2793117bb31SNicolin Chen /* Validate channels */ 2803117bb31SNicolin Chen if (config->channel_num < 1 || config->channel_num > 10) { 2813117bb31SNicolin Chen pair_err("does not support %d channels\n", config->channel_num); 2823117bb31SNicolin Chen return -EINVAL; 2833117bb31SNicolin Chen } 2843117bb31SNicolin Chen 2853117bb31SNicolin Chen /* Validate output width */ 2863117bb31SNicolin Chen if (config->output_word_width == ASRC_WIDTH_8_BIT) { 2873117bb31SNicolin Chen pair_err("does not support 8bit width output\n"); 2883117bb31SNicolin Chen return -EINVAL; 2893117bb31SNicolin Chen } 2903117bb31SNicolin Chen 2914e13eb72SNicolin Chen inrate = config->input_sample_rate; 2924e13eb72SNicolin Chen outrate = config->output_sample_rate; 2934e13eb72SNicolin Chen ideal = config->inclk == INCLK_NONE; 2944e13eb72SNicolin Chen 2953117bb31SNicolin Chen /* Validate input and output sample rates */ 2963117bb31SNicolin Chen for (in = 0; in < ARRAY_SIZE(supported_input_rate); in++) 2973117bb31SNicolin Chen if (inrate == supported_input_rate[in]) 2983117bb31SNicolin Chen break; 2993117bb31SNicolin Chen 3003117bb31SNicolin Chen if (in == ARRAY_SIZE(supported_input_rate)) { 3013117bb31SNicolin Chen pair_err("unsupported input sample rate: %dHz\n", inrate); 3023117bb31SNicolin Chen return -EINVAL; 3033117bb31SNicolin Chen } 3043117bb31SNicolin Chen 3053117bb31SNicolin Chen for (out = 0; out < ARRAY_SIZE(supported_asrc_rate); out++) 3063117bb31SNicolin Chen if (outrate == supported_asrc_rate[out]) 3073117bb31SNicolin Chen break; 3083117bb31SNicolin Chen 3093117bb31SNicolin Chen if (out == ARRAY_SIZE(supported_asrc_rate)) { 3103117bb31SNicolin Chen pair_err("unsupported output sample rate: %dHz\n", outrate); 3113117bb31SNicolin Chen return -EINVAL; 3123117bb31SNicolin Chen } 3133117bb31SNicolin Chen 314fff6e03cSZidan Wang if ((outrate > 8000 && outrate < 30000) && 315fff6e03cSZidan Wang (outrate/inrate > 24 || inrate/outrate > 8)) { 316fff6e03cSZidan Wang pair_err("exceed supported ratio range [1/24, 8] for \ 317fff6e03cSZidan Wang inrate/outrate: %d/%d\n", inrate, outrate); 318fff6e03cSZidan Wang return -EINVAL; 319fff6e03cSZidan Wang } 320fff6e03cSZidan Wang 3213117bb31SNicolin Chen /* Validate input and output clock sources */ 3223117bb31SNicolin Chen clk_index[IN] = clk_map[IN][config->inclk]; 3233117bb31SNicolin Chen clk_index[OUT] = clk_map[OUT][config->outclk]; 3243117bb31SNicolin Chen 3253117bb31SNicolin Chen /* We only have output clock for ideal ratio mode */ 3263117bb31SNicolin Chen clk = asrc_priv->asrck_clk[clk_index[ideal ? OUT : IN]]; 3273117bb31SNicolin Chen 3283117bb31SNicolin Chen div[IN] = clk_get_rate(clk) / inrate; 3293117bb31SNicolin Chen if (div[IN] == 0) { 3303117bb31SNicolin Chen pair_err("failed to support input sample rate %dHz by asrck_%x\n", 3313117bb31SNicolin Chen inrate, clk_index[ideal ? OUT : IN]); 3323117bb31SNicolin Chen return -EINVAL; 3333117bb31SNicolin Chen } 3343117bb31SNicolin Chen 3353117bb31SNicolin Chen clk = asrc_priv->asrck_clk[clk_index[OUT]]; 3363117bb31SNicolin Chen 3373117bb31SNicolin Chen /* Use fixed output rate for Ideal Ratio mode (INCLK_NONE) */ 3383117bb31SNicolin Chen if (ideal) 3393117bb31SNicolin Chen div[OUT] = clk_get_rate(clk) / IDEAL_RATIO_RATE; 3403117bb31SNicolin Chen else 3413117bb31SNicolin Chen div[OUT] = clk_get_rate(clk) / outrate; 3423117bb31SNicolin Chen 3433117bb31SNicolin Chen if (div[OUT] == 0) { 3443117bb31SNicolin Chen pair_err("failed to support output sample rate %dHz by asrck_%x\n", 3453117bb31SNicolin Chen outrate, clk_index[OUT]); 3463117bb31SNicolin Chen return -EINVAL; 3473117bb31SNicolin Chen } 3483117bb31SNicolin Chen 3493117bb31SNicolin Chen /* Set the channel number */ 3503117bb31SNicolin Chen channels = config->channel_num; 3513117bb31SNicolin Chen 3523117bb31SNicolin Chen if (asrc_priv->channel_bits < 4) 3533117bb31SNicolin Chen channels /= 2; 3543117bb31SNicolin Chen 3553117bb31SNicolin Chen /* Update channels for current pair */ 3563117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCNCR, 3573117bb31SNicolin Chen ASRCNCR_ANCi_MASK(index, asrc_priv->channel_bits), 3583117bb31SNicolin Chen ASRCNCR_ANCi(index, channels, asrc_priv->channel_bits)); 3593117bb31SNicolin Chen 3603117bb31SNicolin Chen /* Default setting: Automatic selection for processing mode */ 3613117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, 3623117bb31SNicolin Chen ASRCTR_ATSi_MASK(index), ASRCTR_ATS(index)); 3633117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, 3643117bb31SNicolin Chen ASRCTR_USRi_MASK(index), 0); 3653117bb31SNicolin Chen 3663117bb31SNicolin Chen /* Set the input and output clock sources */ 3673117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCSR, 3683117bb31SNicolin Chen ASRCSR_AICSi_MASK(index) | ASRCSR_AOCSi_MASK(index), 3693117bb31SNicolin Chen ASRCSR_AICS(index, clk_index[IN]) | 3703117bb31SNicolin Chen ASRCSR_AOCS(index, clk_index[OUT])); 3713117bb31SNicolin Chen 3723117bb31SNicolin Chen /* Calculate the input clock divisors */ 3733117bb31SNicolin Chen indiv = fsl_asrc_cal_asrck_divisor(pair, div[IN]); 3743117bb31SNicolin Chen outdiv = fsl_asrc_cal_asrck_divisor(pair, div[OUT]); 3753117bb31SNicolin Chen 3763117bb31SNicolin Chen /* Suppose indiv and outdiv includes prescaler, so add its MASK too */ 3773117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCDR(index), 3783117bb31SNicolin Chen ASRCDRi_AOCPi_MASK(index) | ASRCDRi_AICPi_MASK(index) | 3793117bb31SNicolin Chen ASRCDRi_AOCDi_MASK(index) | ASRCDRi_AICDi_MASK(index), 3803117bb31SNicolin Chen ASRCDRi_AOCP(index, outdiv) | ASRCDRi_AICP(index, indiv)); 3813117bb31SNicolin Chen 3823117bb31SNicolin Chen /* Implement word_width configurations */ 3833117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRMCR1(index), 3843117bb31SNicolin Chen ASRMCR1i_OW16_MASK | ASRMCR1i_IWD_MASK, 3853117bb31SNicolin Chen ASRMCR1i_OW16(config->output_word_width) | 3863117bb31SNicolin Chen ASRMCR1i_IWD(config->input_word_width)); 3873117bb31SNicolin Chen 3883117bb31SNicolin Chen /* Enable BUFFER STALL */ 3893117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRMCR(index), 3903117bb31SNicolin Chen ASRMCRi_BUFSTALLi_MASK, ASRMCRi_BUFSTALLi); 3913117bb31SNicolin Chen 3923117bb31SNicolin Chen /* Set default thresholds for input and output FIFO */ 3933117bb31SNicolin Chen fsl_asrc_set_watermarks(pair, ASRC_INPUTFIFO_THRESHOLD, 3943117bb31SNicolin Chen ASRC_INPUTFIFO_THRESHOLD); 3953117bb31SNicolin Chen 3964091fb95SMasahiro Yamada /* Configure the following only for Ideal Ratio mode */ 3973117bb31SNicolin Chen if (!ideal) 3983117bb31SNicolin Chen return 0; 3993117bb31SNicolin Chen 4003117bb31SNicolin Chen /* Clear ASTSx bit to use Ideal Ratio mode */ 4013117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, 4023117bb31SNicolin Chen ASRCTR_ATSi_MASK(index), 0); 4033117bb31SNicolin Chen 4043117bb31SNicolin Chen /* Enable Ideal Ratio mode */ 4053117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, 4063117bb31SNicolin Chen ASRCTR_IDRi_MASK(index) | ASRCTR_USRi_MASK(index), 4073117bb31SNicolin Chen ASRCTR_IDR(index) | ASRCTR_USR(index)); 4083117bb31SNicolin Chen 409*4aecaa0aSS.j. Wang fsl_asrc_sel_proc(inrate, outrate, &pre_proc, &post_proc); 410*4aecaa0aSS.j. Wang 4113117bb31SNicolin Chen /* Apply configurations for pre- and post-processing */ 4123117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCFG, 4133117bb31SNicolin Chen ASRCFG_PREMODi_MASK(index) | ASRCFG_POSTMODi_MASK(index), 414*4aecaa0aSS.j. Wang ASRCFG_PREMOD(index, pre_proc) | 415*4aecaa0aSS.j. Wang ASRCFG_POSTMOD(index, post_proc)); 4163117bb31SNicolin Chen 4173117bb31SNicolin Chen return fsl_asrc_set_ideal_ratio(pair, inrate, outrate); 4183117bb31SNicolin Chen } 4193117bb31SNicolin Chen 4203117bb31SNicolin Chen /** 4213117bb31SNicolin Chen * Start the assigned ASRC pair 4223117bb31SNicolin Chen * 4233117bb31SNicolin Chen * It enables the assigned pair and makes it stopped at the stall level. 4243117bb31SNicolin Chen */ 4253117bb31SNicolin Chen static void fsl_asrc_start_pair(struct fsl_asrc_pair *pair) 4263117bb31SNicolin Chen { 4273117bb31SNicolin Chen struct fsl_asrc *asrc_priv = pair->asrc_priv; 4283117bb31SNicolin Chen enum asrc_pair_index index = pair->index; 4293117bb31SNicolin Chen int reg, retry = 10, i; 4303117bb31SNicolin Chen 4313117bb31SNicolin Chen /* Enable the current pair */ 4323117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, 4333117bb31SNicolin Chen ASRCTR_ASRCEi_MASK(index), ASRCTR_ASRCE(index)); 4343117bb31SNicolin Chen 4353117bb31SNicolin Chen /* Wait for status of initialization */ 4363117bb31SNicolin Chen do { 4373117bb31SNicolin Chen udelay(5); 4383117bb31SNicolin Chen regmap_read(asrc_priv->regmap, REG_ASRCFG, ®); 4393117bb31SNicolin Chen reg &= ASRCFG_INIRQi_MASK(index); 4403117bb31SNicolin Chen } while (!reg && --retry); 4413117bb31SNicolin Chen 4423117bb31SNicolin Chen /* Make the input fifo to ASRC STALL level */ 4433117bb31SNicolin Chen regmap_read(asrc_priv->regmap, REG_ASRCNCR, ®); 4443117bb31SNicolin Chen for (i = 0; i < pair->channels * 4; i++) 4453117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRDI(index), 0); 4463117bb31SNicolin Chen 4473117bb31SNicolin Chen /* Enable overload interrupt */ 4483117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRIER, ASRIER_AOLIE); 4493117bb31SNicolin Chen } 4503117bb31SNicolin Chen 4513117bb31SNicolin Chen /** 4523117bb31SNicolin Chen * Stop the assigned ASRC pair 4533117bb31SNicolin Chen */ 4543117bb31SNicolin Chen static void fsl_asrc_stop_pair(struct fsl_asrc_pair *pair) 4553117bb31SNicolin Chen { 4563117bb31SNicolin Chen struct fsl_asrc *asrc_priv = pair->asrc_priv; 4573117bb31SNicolin Chen enum asrc_pair_index index = pair->index; 4583117bb31SNicolin Chen 4593117bb31SNicolin Chen /* Stop the current pair */ 4603117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, 4613117bb31SNicolin Chen ASRCTR_ASRCEi_MASK(index), 0); 4623117bb31SNicolin Chen } 4633117bb31SNicolin Chen 4643117bb31SNicolin Chen /** 4653117bb31SNicolin Chen * Get DMA channel according to the pair and direction. 4663117bb31SNicolin Chen */ 4673117bb31SNicolin Chen struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, bool dir) 4683117bb31SNicolin Chen { 4693117bb31SNicolin Chen struct fsl_asrc *asrc_priv = pair->asrc_priv; 4703117bb31SNicolin Chen enum asrc_pair_index index = pair->index; 4713117bb31SNicolin Chen char name[4]; 4723117bb31SNicolin Chen 4733117bb31SNicolin Chen sprintf(name, "%cx%c", dir == IN ? 'r' : 't', index + 'a'); 4743117bb31SNicolin Chen 4753117bb31SNicolin Chen return dma_request_slave_channel(&asrc_priv->pdev->dev, name); 4763117bb31SNicolin Chen } 4773117bb31SNicolin Chen EXPORT_SYMBOL_GPL(fsl_asrc_get_dma_channel); 4783117bb31SNicolin Chen 47953f67a78SS.j. Wang static int fsl_asrc_dai_startup(struct snd_pcm_substream *substream, 48053f67a78SS.j. Wang struct snd_soc_dai *dai) 48153f67a78SS.j. Wang { 48253f67a78SS.j. Wang struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai); 48353f67a78SS.j. Wang 48453f67a78SS.j. Wang /* Odd channel number is not valid for older ASRC (channel_bits==3) */ 48553f67a78SS.j. Wang if (asrc_priv->channel_bits == 3) 48653f67a78SS.j. Wang snd_pcm_hw_constraint_step(substream->runtime, 0, 48753f67a78SS.j. Wang SNDRV_PCM_HW_PARAM_CHANNELS, 2); 48853f67a78SS.j. Wang 48953f67a78SS.j. Wang return 0; 49053f67a78SS.j. Wang } 49153f67a78SS.j. Wang 4923117bb31SNicolin Chen static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream, 4933117bb31SNicolin Chen struct snd_pcm_hw_params *params, 4943117bb31SNicolin Chen struct snd_soc_dai *dai) 4953117bb31SNicolin Chen { 4963117bb31SNicolin Chen struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai); 4974ca73043SZidan Wang int width = params_width(params); 4983117bb31SNicolin Chen struct snd_pcm_runtime *runtime = substream->runtime; 4993117bb31SNicolin Chen struct fsl_asrc_pair *pair = runtime->private_data; 5003117bb31SNicolin Chen unsigned int channels = params_channels(params); 5013117bb31SNicolin Chen unsigned int rate = params_rate(params); 5023117bb31SNicolin Chen struct asrc_config config; 5033117bb31SNicolin Chen int word_width, ret; 5043117bb31SNicolin Chen 5053117bb31SNicolin Chen ret = fsl_asrc_request_pair(channels, pair); 5063117bb31SNicolin Chen if (ret) { 5073117bb31SNicolin Chen dev_err(dai->dev, "fail to request asrc pair\n"); 5083117bb31SNicolin Chen return ret; 5093117bb31SNicolin Chen } 5103117bb31SNicolin Chen 5113117bb31SNicolin Chen pair->config = &config; 5123117bb31SNicolin Chen 5133117bb31SNicolin Chen if (width == 16) 5143117bb31SNicolin Chen width = ASRC_WIDTH_16_BIT; 5153117bb31SNicolin Chen else 5163117bb31SNicolin Chen width = ASRC_WIDTH_24_BIT; 5173117bb31SNicolin Chen 5183117bb31SNicolin Chen if (asrc_priv->asrc_width == 16) 5193117bb31SNicolin Chen word_width = ASRC_WIDTH_16_BIT; 5203117bb31SNicolin Chen else 5213117bb31SNicolin Chen word_width = ASRC_WIDTH_24_BIT; 5223117bb31SNicolin Chen 5233117bb31SNicolin Chen config.pair = pair->index; 5243117bb31SNicolin Chen config.channel_num = channels; 5253117bb31SNicolin Chen config.inclk = INCLK_NONE; 5263117bb31SNicolin Chen config.outclk = OUTCLK_ASRCK1_CLK; 5273117bb31SNicolin Chen 5283117bb31SNicolin Chen if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 5293117bb31SNicolin Chen config.input_word_width = width; 5303117bb31SNicolin Chen config.output_word_width = word_width; 5313117bb31SNicolin Chen config.input_sample_rate = rate; 5323117bb31SNicolin Chen config.output_sample_rate = asrc_priv->asrc_rate; 5333117bb31SNicolin Chen } else { 5343117bb31SNicolin Chen config.input_word_width = word_width; 5353117bb31SNicolin Chen config.output_word_width = width; 5363117bb31SNicolin Chen config.input_sample_rate = asrc_priv->asrc_rate; 5373117bb31SNicolin Chen config.output_sample_rate = rate; 5383117bb31SNicolin Chen } 5393117bb31SNicolin Chen 5403117bb31SNicolin Chen ret = fsl_asrc_config_pair(pair); 5413117bb31SNicolin Chen if (ret) { 5423117bb31SNicolin Chen dev_err(dai->dev, "fail to config asrc pair\n"); 5433117bb31SNicolin Chen return ret; 5443117bb31SNicolin Chen } 5453117bb31SNicolin Chen 5463117bb31SNicolin Chen return 0; 5473117bb31SNicolin Chen } 5483117bb31SNicolin Chen 5493117bb31SNicolin Chen static int fsl_asrc_dai_hw_free(struct snd_pcm_substream *substream, 5503117bb31SNicolin Chen struct snd_soc_dai *dai) 5513117bb31SNicolin Chen { 5523117bb31SNicolin Chen struct snd_pcm_runtime *runtime = substream->runtime; 5533117bb31SNicolin Chen struct fsl_asrc_pair *pair = runtime->private_data; 5543117bb31SNicolin Chen 5553117bb31SNicolin Chen if (pair) 5563117bb31SNicolin Chen fsl_asrc_release_pair(pair); 5573117bb31SNicolin Chen 5583117bb31SNicolin Chen return 0; 5593117bb31SNicolin Chen } 5603117bb31SNicolin Chen 5613117bb31SNicolin Chen static int fsl_asrc_dai_trigger(struct snd_pcm_substream *substream, int cmd, 5623117bb31SNicolin Chen struct snd_soc_dai *dai) 5633117bb31SNicolin Chen { 5643117bb31SNicolin Chen struct snd_pcm_runtime *runtime = substream->runtime; 5653117bb31SNicolin Chen struct fsl_asrc_pair *pair = runtime->private_data; 5663117bb31SNicolin Chen 5673117bb31SNicolin Chen switch (cmd) { 5683117bb31SNicolin Chen case SNDRV_PCM_TRIGGER_START: 5693117bb31SNicolin Chen case SNDRV_PCM_TRIGGER_RESUME: 5703117bb31SNicolin Chen case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 5713117bb31SNicolin Chen fsl_asrc_start_pair(pair); 5723117bb31SNicolin Chen break; 5733117bb31SNicolin Chen case SNDRV_PCM_TRIGGER_STOP: 5743117bb31SNicolin Chen case SNDRV_PCM_TRIGGER_SUSPEND: 5753117bb31SNicolin Chen case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 5763117bb31SNicolin Chen fsl_asrc_stop_pair(pair); 5773117bb31SNicolin Chen break; 5783117bb31SNicolin Chen default: 5793117bb31SNicolin Chen return -EINVAL; 5803117bb31SNicolin Chen } 5813117bb31SNicolin Chen 5823117bb31SNicolin Chen return 0; 5833117bb31SNicolin Chen } 5843117bb31SNicolin Chen 58529a22ebfSGustavo A. R. Silva static const struct snd_soc_dai_ops fsl_asrc_dai_ops = { 58653f67a78SS.j. Wang .startup = fsl_asrc_dai_startup, 5873117bb31SNicolin Chen .hw_params = fsl_asrc_dai_hw_params, 5883117bb31SNicolin Chen .hw_free = fsl_asrc_dai_hw_free, 5893117bb31SNicolin Chen .trigger = fsl_asrc_dai_trigger, 5903117bb31SNicolin Chen }; 5913117bb31SNicolin Chen 5923117bb31SNicolin Chen static int fsl_asrc_dai_probe(struct snd_soc_dai *dai) 5933117bb31SNicolin Chen { 5943117bb31SNicolin Chen struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai); 5953117bb31SNicolin Chen 5963117bb31SNicolin Chen snd_soc_dai_init_dma_data(dai, &asrc_priv->dma_params_tx, 5973117bb31SNicolin Chen &asrc_priv->dma_params_rx); 5983117bb31SNicolin Chen 5993117bb31SNicolin Chen return 0; 6003117bb31SNicolin Chen } 6013117bb31SNicolin Chen 6023117bb31SNicolin Chen #define FSL_ASRC_RATES SNDRV_PCM_RATE_8000_192000 6033117bb31SNicolin Chen #define FSL_ASRC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \ 6043117bb31SNicolin Chen SNDRV_PCM_FMTBIT_S16_LE | \ 605d526416cSNicolin Chen SNDRV_PCM_FMTBIT_S20_3LE) 6063117bb31SNicolin Chen 6073117bb31SNicolin Chen static struct snd_soc_dai_driver fsl_asrc_dai = { 6083117bb31SNicolin Chen .probe = fsl_asrc_dai_probe, 6093117bb31SNicolin Chen .playback = { 6103117bb31SNicolin Chen .stream_name = "ASRC-Playback", 6113117bb31SNicolin Chen .channels_min = 1, 6123117bb31SNicolin Chen .channels_max = 10, 6133117bb31SNicolin Chen .rates = FSL_ASRC_RATES, 6143117bb31SNicolin Chen .formats = FSL_ASRC_FORMATS, 6153117bb31SNicolin Chen }, 6163117bb31SNicolin Chen .capture = { 6173117bb31SNicolin Chen .stream_name = "ASRC-Capture", 6183117bb31SNicolin Chen .channels_min = 1, 6193117bb31SNicolin Chen .channels_max = 10, 6203117bb31SNicolin Chen .rates = FSL_ASRC_RATES, 6213117bb31SNicolin Chen .formats = FSL_ASRC_FORMATS, 6223117bb31SNicolin Chen }, 6233117bb31SNicolin Chen .ops = &fsl_asrc_dai_ops, 6243117bb31SNicolin Chen }; 6253117bb31SNicolin Chen 6263117bb31SNicolin Chen static bool fsl_asrc_readable_reg(struct device *dev, unsigned int reg) 6273117bb31SNicolin Chen { 6283117bb31SNicolin Chen switch (reg) { 6293117bb31SNicolin Chen case REG_ASRCTR: 6303117bb31SNicolin Chen case REG_ASRIER: 6313117bb31SNicolin Chen case REG_ASRCNCR: 6323117bb31SNicolin Chen case REG_ASRCFG: 6333117bb31SNicolin Chen case REG_ASRCSR: 6343117bb31SNicolin Chen case REG_ASRCDR1: 6353117bb31SNicolin Chen case REG_ASRCDR2: 6363117bb31SNicolin Chen case REG_ASRSTR: 6373117bb31SNicolin Chen case REG_ASRPM1: 6383117bb31SNicolin Chen case REG_ASRPM2: 6393117bb31SNicolin Chen case REG_ASRPM3: 6403117bb31SNicolin Chen case REG_ASRPM4: 6413117bb31SNicolin Chen case REG_ASRPM5: 6423117bb31SNicolin Chen case REG_ASRTFR1: 6433117bb31SNicolin Chen case REG_ASRCCR: 6443117bb31SNicolin Chen case REG_ASRDOA: 6453117bb31SNicolin Chen case REG_ASRDOB: 6463117bb31SNicolin Chen case REG_ASRDOC: 6473117bb31SNicolin Chen case REG_ASRIDRHA: 6483117bb31SNicolin Chen case REG_ASRIDRLA: 6493117bb31SNicolin Chen case REG_ASRIDRHB: 6503117bb31SNicolin Chen case REG_ASRIDRLB: 6513117bb31SNicolin Chen case REG_ASRIDRHC: 6523117bb31SNicolin Chen case REG_ASRIDRLC: 6533117bb31SNicolin Chen case REG_ASR76K: 6543117bb31SNicolin Chen case REG_ASR56K: 6553117bb31SNicolin Chen case REG_ASRMCRA: 6563117bb31SNicolin Chen case REG_ASRFSTA: 6573117bb31SNicolin Chen case REG_ASRMCRB: 6583117bb31SNicolin Chen case REG_ASRFSTB: 6593117bb31SNicolin Chen case REG_ASRMCRC: 6603117bb31SNicolin Chen case REG_ASRFSTC: 6613117bb31SNicolin Chen case REG_ASRMCR1A: 6623117bb31SNicolin Chen case REG_ASRMCR1B: 6633117bb31SNicolin Chen case REG_ASRMCR1C: 6643117bb31SNicolin Chen return true; 6653117bb31SNicolin Chen default: 6663117bb31SNicolin Chen return false; 6673117bb31SNicolin Chen } 6683117bb31SNicolin Chen } 6693117bb31SNicolin Chen 6703117bb31SNicolin Chen static bool fsl_asrc_volatile_reg(struct device *dev, unsigned int reg) 6713117bb31SNicolin Chen { 6723117bb31SNicolin Chen switch (reg) { 6733117bb31SNicolin Chen case REG_ASRSTR: 6743117bb31SNicolin Chen case REG_ASRDIA: 6753117bb31SNicolin Chen case REG_ASRDIB: 6763117bb31SNicolin Chen case REG_ASRDIC: 6773117bb31SNicolin Chen case REG_ASRDOA: 6783117bb31SNicolin Chen case REG_ASRDOB: 6793117bb31SNicolin Chen case REG_ASRDOC: 6803117bb31SNicolin Chen case REG_ASRFSTA: 6813117bb31SNicolin Chen case REG_ASRFSTB: 6823117bb31SNicolin Chen case REG_ASRFSTC: 6833117bb31SNicolin Chen case REG_ASRCFG: 6843117bb31SNicolin Chen return true; 6853117bb31SNicolin Chen default: 6863117bb31SNicolin Chen return false; 6873117bb31SNicolin Chen } 6883117bb31SNicolin Chen } 6893117bb31SNicolin Chen 6903117bb31SNicolin Chen static bool fsl_asrc_writeable_reg(struct device *dev, unsigned int reg) 6913117bb31SNicolin Chen { 6923117bb31SNicolin Chen switch (reg) { 6933117bb31SNicolin Chen case REG_ASRCTR: 6943117bb31SNicolin Chen case REG_ASRIER: 6953117bb31SNicolin Chen case REG_ASRCNCR: 6963117bb31SNicolin Chen case REG_ASRCFG: 6973117bb31SNicolin Chen case REG_ASRCSR: 6983117bb31SNicolin Chen case REG_ASRCDR1: 6993117bb31SNicolin Chen case REG_ASRCDR2: 7003117bb31SNicolin Chen case REG_ASRSTR: 7013117bb31SNicolin Chen case REG_ASRPM1: 7023117bb31SNicolin Chen case REG_ASRPM2: 7033117bb31SNicolin Chen case REG_ASRPM3: 7043117bb31SNicolin Chen case REG_ASRPM4: 7053117bb31SNicolin Chen case REG_ASRPM5: 7063117bb31SNicolin Chen case REG_ASRTFR1: 7073117bb31SNicolin Chen case REG_ASRCCR: 7083117bb31SNicolin Chen case REG_ASRDIA: 7093117bb31SNicolin Chen case REG_ASRDIB: 7103117bb31SNicolin Chen case REG_ASRDIC: 7113117bb31SNicolin Chen case REG_ASRIDRHA: 7123117bb31SNicolin Chen case REG_ASRIDRLA: 7133117bb31SNicolin Chen case REG_ASRIDRHB: 7143117bb31SNicolin Chen case REG_ASRIDRLB: 7153117bb31SNicolin Chen case REG_ASRIDRHC: 7163117bb31SNicolin Chen case REG_ASRIDRLC: 7173117bb31SNicolin Chen case REG_ASR76K: 7183117bb31SNicolin Chen case REG_ASR56K: 7193117bb31SNicolin Chen case REG_ASRMCRA: 7203117bb31SNicolin Chen case REG_ASRMCRB: 7213117bb31SNicolin Chen case REG_ASRMCRC: 7223117bb31SNicolin Chen case REG_ASRMCR1A: 7233117bb31SNicolin Chen case REG_ASRMCR1B: 7243117bb31SNicolin Chen case REG_ASRMCR1C: 7253117bb31SNicolin Chen return true; 7263117bb31SNicolin Chen default: 7273117bb31SNicolin Chen return false; 7283117bb31SNicolin Chen } 7293117bb31SNicolin Chen } 7303117bb31SNicolin Chen 73186a570c5SNicolin Chen static struct reg_default fsl_asrc_reg[] = { 73286a570c5SNicolin Chen { REG_ASRCTR, 0x0000 }, { REG_ASRIER, 0x0000 }, 73386a570c5SNicolin Chen { REG_ASRCNCR, 0x0000 }, { REG_ASRCFG, 0x0000 }, 73486a570c5SNicolin Chen { REG_ASRCSR, 0x0000 }, { REG_ASRCDR1, 0x0000 }, 73586a570c5SNicolin Chen { REG_ASRCDR2, 0x0000 }, { REG_ASRSTR, 0x0000 }, 73686a570c5SNicolin Chen { REG_ASRRA, 0x0000 }, { REG_ASRRB, 0x0000 }, 73786a570c5SNicolin Chen { REG_ASRRC, 0x0000 }, { REG_ASRPM1, 0x0000 }, 73886a570c5SNicolin Chen { REG_ASRPM2, 0x0000 }, { REG_ASRPM3, 0x0000 }, 73986a570c5SNicolin Chen { REG_ASRPM4, 0x0000 }, { REG_ASRPM5, 0x0000 }, 74086a570c5SNicolin Chen { REG_ASRTFR1, 0x0000 }, { REG_ASRCCR, 0x0000 }, 74186a570c5SNicolin Chen { REG_ASRDIA, 0x0000 }, { REG_ASRDOA, 0x0000 }, 74286a570c5SNicolin Chen { REG_ASRDIB, 0x0000 }, { REG_ASRDOB, 0x0000 }, 74386a570c5SNicolin Chen { REG_ASRDIC, 0x0000 }, { REG_ASRDOC, 0x0000 }, 74486a570c5SNicolin Chen { REG_ASRIDRHA, 0x0000 }, { REG_ASRIDRLA, 0x0000 }, 74586a570c5SNicolin Chen { REG_ASRIDRHB, 0x0000 }, { REG_ASRIDRLB, 0x0000 }, 74686a570c5SNicolin Chen { REG_ASRIDRHC, 0x0000 }, { REG_ASRIDRLC, 0x0000 }, 74786a570c5SNicolin Chen { REG_ASR76K, 0x0A47 }, { REG_ASR56K, 0x0DF3 }, 74886a570c5SNicolin Chen { REG_ASRMCRA, 0x0000 }, { REG_ASRFSTA, 0x0000 }, 74986a570c5SNicolin Chen { REG_ASRMCRB, 0x0000 }, { REG_ASRFSTB, 0x0000 }, 75086a570c5SNicolin Chen { REG_ASRMCRC, 0x0000 }, { REG_ASRFSTC, 0x0000 }, 75186a570c5SNicolin Chen { REG_ASRMCR1A, 0x0000 }, { REG_ASRMCR1B, 0x0000 }, 75286a570c5SNicolin Chen { REG_ASRMCR1C, 0x0000 }, 75386a570c5SNicolin Chen }; 75486a570c5SNicolin Chen 755bf16d883SXiubo Li static const struct regmap_config fsl_asrc_regmap_config = { 7563117bb31SNicolin Chen .reg_bits = 32, 7573117bb31SNicolin Chen .reg_stride = 4, 7583117bb31SNicolin Chen .val_bits = 32, 7593117bb31SNicolin Chen 7603117bb31SNicolin Chen .max_register = REG_ASRMCR1C, 76186a570c5SNicolin Chen .reg_defaults = fsl_asrc_reg, 76286a570c5SNicolin Chen .num_reg_defaults = ARRAY_SIZE(fsl_asrc_reg), 7633117bb31SNicolin Chen .readable_reg = fsl_asrc_readable_reg, 7643117bb31SNicolin Chen .volatile_reg = fsl_asrc_volatile_reg, 7653117bb31SNicolin Chen .writeable_reg = fsl_asrc_writeable_reg, 766b4138868SMarek Vasut .cache_type = REGCACHE_FLAT, 7673117bb31SNicolin Chen }; 7683117bb31SNicolin Chen 7693117bb31SNicolin Chen /** 7703117bb31SNicolin Chen * Initialize ASRC registers with a default configurations 7713117bb31SNicolin Chen */ 7723117bb31SNicolin Chen static int fsl_asrc_init(struct fsl_asrc *asrc_priv) 7733117bb31SNicolin Chen { 7743117bb31SNicolin Chen /* Halt ASRC internal FP when input FIFO needs data for pair A, B, C */ 7753117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRCTR, ASRCTR_ASRCEN); 7763117bb31SNicolin Chen 7773117bb31SNicolin Chen /* Disable interrupt by default */ 7783117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRIER, 0x0); 7793117bb31SNicolin Chen 7803117bb31SNicolin Chen /* Apply recommended settings for parameters from Reference Manual */ 7813117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRPM1, 0x7fffff); 7823117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRPM2, 0x255555); 7833117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRPM3, 0xff7280); 7843117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRPM4, 0xff7280); 7853117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRPM5, 0xff7280); 7863117bb31SNicolin Chen 7873117bb31SNicolin Chen /* Base address for task queue FIFO. Set to 0x7C */ 7883117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRTFR1, 7893117bb31SNicolin Chen ASRTFR1_TF_BASE_MASK, ASRTFR1_TF_BASE(0xfc)); 7903117bb31SNicolin Chen 7913117bb31SNicolin Chen /* Set the processing clock for 76KHz to 133M */ 7923117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASR76K, 0x06D6); 7933117bb31SNicolin Chen 7943117bb31SNicolin Chen /* Set the processing clock for 56KHz to 133M */ 7953117bb31SNicolin Chen return regmap_write(asrc_priv->regmap, REG_ASR56K, 0x0947); 7963117bb31SNicolin Chen } 7973117bb31SNicolin Chen 7983117bb31SNicolin Chen /** 7993117bb31SNicolin Chen * Interrupt handler for ASRC 8003117bb31SNicolin Chen */ 8013117bb31SNicolin Chen static irqreturn_t fsl_asrc_isr(int irq, void *dev_id) 8023117bb31SNicolin Chen { 8033117bb31SNicolin Chen struct fsl_asrc *asrc_priv = (struct fsl_asrc *)dev_id; 8043117bb31SNicolin Chen struct device *dev = &asrc_priv->pdev->dev; 8053117bb31SNicolin Chen enum asrc_pair_index index; 8063117bb31SNicolin Chen u32 status; 8073117bb31SNicolin Chen 8083117bb31SNicolin Chen regmap_read(asrc_priv->regmap, REG_ASRSTR, &status); 8093117bb31SNicolin Chen 8103117bb31SNicolin Chen /* Clean overload error */ 8113117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRSTR, ASRSTR_AOLE); 8123117bb31SNicolin Chen 8133117bb31SNicolin Chen /* 8143117bb31SNicolin Chen * We here use dev_dbg() for all exceptions because ASRC itself does 8153117bb31SNicolin Chen * not care if FIFO overflowed or underrun while a warning in the 8163117bb31SNicolin Chen * interrupt would result a ridged conversion. 8173117bb31SNicolin Chen */ 8183117bb31SNicolin Chen for (index = ASRC_PAIR_A; index < ASRC_PAIR_MAX_NUM; index++) { 8193117bb31SNicolin Chen if (!asrc_priv->pair[index]) 8203117bb31SNicolin Chen continue; 8213117bb31SNicolin Chen 8223117bb31SNicolin Chen if (status & ASRSTR_ATQOL) { 8233117bb31SNicolin Chen asrc_priv->pair[index]->error |= ASRC_TASK_Q_OVERLOAD; 8243117bb31SNicolin Chen dev_dbg(dev, "ASRC Task Queue FIFO overload\n"); 8253117bb31SNicolin Chen } 8263117bb31SNicolin Chen 8273117bb31SNicolin Chen if (status & ASRSTR_AOOL(index)) { 8283117bb31SNicolin Chen asrc_priv->pair[index]->error |= ASRC_OUTPUT_TASK_OVERLOAD; 8293117bb31SNicolin Chen pair_dbg("Output Task Overload\n"); 8303117bb31SNicolin Chen } 8313117bb31SNicolin Chen 8323117bb31SNicolin Chen if (status & ASRSTR_AIOL(index)) { 8333117bb31SNicolin Chen asrc_priv->pair[index]->error |= ASRC_INPUT_TASK_OVERLOAD; 8343117bb31SNicolin Chen pair_dbg("Input Task Overload\n"); 8353117bb31SNicolin Chen } 8363117bb31SNicolin Chen 8373117bb31SNicolin Chen if (status & ASRSTR_AODO(index)) { 8383117bb31SNicolin Chen asrc_priv->pair[index]->error |= ASRC_OUTPUT_BUFFER_OVERFLOW; 8393117bb31SNicolin Chen pair_dbg("Output Data Buffer has overflowed\n"); 8403117bb31SNicolin Chen } 8413117bb31SNicolin Chen 8423117bb31SNicolin Chen if (status & ASRSTR_AIDU(index)) { 8433117bb31SNicolin Chen asrc_priv->pair[index]->error |= ASRC_INPUT_BUFFER_UNDERRUN; 8443117bb31SNicolin Chen pair_dbg("Input Data Buffer has underflowed\n"); 8453117bb31SNicolin Chen } 8463117bb31SNicolin Chen } 8473117bb31SNicolin Chen 8483117bb31SNicolin Chen return IRQ_HANDLED; 8493117bb31SNicolin Chen } 8503117bb31SNicolin Chen 8513117bb31SNicolin Chen static int fsl_asrc_probe(struct platform_device *pdev) 8523117bb31SNicolin Chen { 8533117bb31SNicolin Chen struct device_node *np = pdev->dev.of_node; 8543117bb31SNicolin Chen struct fsl_asrc *asrc_priv; 8553117bb31SNicolin Chen struct resource *res; 8563117bb31SNicolin Chen void __iomem *regs; 8573117bb31SNicolin Chen int irq, ret, i; 8583117bb31SNicolin Chen char tmp[16]; 8593117bb31SNicolin Chen 8603117bb31SNicolin Chen asrc_priv = devm_kzalloc(&pdev->dev, sizeof(*asrc_priv), GFP_KERNEL); 8613117bb31SNicolin Chen if (!asrc_priv) 8623117bb31SNicolin Chen return -ENOMEM; 8633117bb31SNicolin Chen 8643117bb31SNicolin Chen asrc_priv->pdev = pdev; 8653117bb31SNicolin Chen 8663117bb31SNicolin Chen /* Get the addresses and IRQ */ 8673117bb31SNicolin Chen res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 8683117bb31SNicolin Chen regs = devm_ioremap_resource(&pdev->dev, res); 8693117bb31SNicolin Chen if (IS_ERR(regs)) 8703117bb31SNicolin Chen return PTR_ERR(regs); 8713117bb31SNicolin Chen 8723117bb31SNicolin Chen asrc_priv->paddr = res->start; 8733117bb31SNicolin Chen 8743117bb31SNicolin Chen asrc_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs, 8753117bb31SNicolin Chen &fsl_asrc_regmap_config); 8763117bb31SNicolin Chen if (IS_ERR(asrc_priv->regmap)) { 8773117bb31SNicolin Chen dev_err(&pdev->dev, "failed to init regmap\n"); 8783117bb31SNicolin Chen return PTR_ERR(asrc_priv->regmap); 8793117bb31SNicolin Chen } 8803117bb31SNicolin Chen 8813117bb31SNicolin Chen irq = platform_get_irq(pdev, 0); 8823117bb31SNicolin Chen if (irq < 0) { 883f03038e5SFabio Estevam dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); 8843117bb31SNicolin Chen return irq; 8853117bb31SNicolin Chen } 8863117bb31SNicolin Chen 8873117bb31SNicolin Chen ret = devm_request_irq(&pdev->dev, irq, fsl_asrc_isr, 0, 888888c819dSFabio Estevam dev_name(&pdev->dev), asrc_priv); 8893117bb31SNicolin Chen if (ret) { 8903117bb31SNicolin Chen dev_err(&pdev->dev, "failed to claim irq %u: %d\n", irq, ret); 8913117bb31SNicolin Chen return ret; 8923117bb31SNicolin Chen } 8933117bb31SNicolin Chen 8943117bb31SNicolin Chen asrc_priv->mem_clk = devm_clk_get(&pdev->dev, "mem"); 8953117bb31SNicolin Chen if (IS_ERR(asrc_priv->mem_clk)) { 8963117bb31SNicolin Chen dev_err(&pdev->dev, "failed to get mem clock\n"); 897d387dd08SDan Carpenter return PTR_ERR(asrc_priv->mem_clk); 8983117bb31SNicolin Chen } 8993117bb31SNicolin Chen 9003117bb31SNicolin Chen asrc_priv->ipg_clk = devm_clk_get(&pdev->dev, "ipg"); 9013117bb31SNicolin Chen if (IS_ERR(asrc_priv->ipg_clk)) { 9023117bb31SNicolin Chen dev_err(&pdev->dev, "failed to get ipg clock\n"); 9033117bb31SNicolin Chen return PTR_ERR(asrc_priv->ipg_clk); 9043117bb31SNicolin Chen } 9053117bb31SNicolin Chen 90613b8a97aSShengjiu Wang asrc_priv->spba_clk = devm_clk_get(&pdev->dev, "spba"); 90713b8a97aSShengjiu Wang if (IS_ERR(asrc_priv->spba_clk)) 90813b8a97aSShengjiu Wang dev_warn(&pdev->dev, "failed to get spba clock\n"); 90913b8a97aSShengjiu Wang 9103117bb31SNicolin Chen for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { 9113117bb31SNicolin Chen sprintf(tmp, "asrck_%x", i); 9123117bb31SNicolin Chen asrc_priv->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp); 9133117bb31SNicolin Chen if (IS_ERR(asrc_priv->asrck_clk[i])) { 9143117bb31SNicolin Chen dev_err(&pdev->dev, "failed to get %s clock\n", tmp); 9153117bb31SNicolin Chen return PTR_ERR(asrc_priv->asrck_clk[i]); 9163117bb31SNicolin Chen } 9173117bb31SNicolin Chen } 9183117bb31SNicolin Chen 919f3d8ac8cSFabio Estevam if (of_device_is_compatible(np, "fsl,imx35-asrc")) { 9203117bb31SNicolin Chen asrc_priv->channel_bits = 3; 9213117bb31SNicolin Chen clk_map[IN] = input_clk_map_imx35; 9223117bb31SNicolin Chen clk_map[OUT] = output_clk_map_imx35; 9233117bb31SNicolin Chen } else { 9243117bb31SNicolin Chen asrc_priv->channel_bits = 4; 9253117bb31SNicolin Chen clk_map[IN] = input_clk_map_imx53; 9263117bb31SNicolin Chen clk_map[OUT] = output_clk_map_imx53; 9273117bb31SNicolin Chen } 9283117bb31SNicolin Chen 9293117bb31SNicolin Chen ret = fsl_asrc_init(asrc_priv); 9303117bb31SNicolin Chen if (ret) { 9313117bb31SNicolin Chen dev_err(&pdev->dev, "failed to init asrc %d\n", ret); 932c0296950SFabio Estevam return ret; 9333117bb31SNicolin Chen } 9343117bb31SNicolin Chen 9353117bb31SNicolin Chen asrc_priv->channel_avail = 10; 9363117bb31SNicolin Chen 9373117bb31SNicolin Chen ret = of_property_read_u32(np, "fsl,asrc-rate", 9383117bb31SNicolin Chen &asrc_priv->asrc_rate); 9393117bb31SNicolin Chen if (ret) { 9403117bb31SNicolin Chen dev_err(&pdev->dev, "failed to get output rate\n"); 941c0296950SFabio Estevam return ret; 9423117bb31SNicolin Chen } 9433117bb31SNicolin Chen 9443117bb31SNicolin Chen ret = of_property_read_u32(np, "fsl,asrc-width", 9453117bb31SNicolin Chen &asrc_priv->asrc_width); 9463117bb31SNicolin Chen if (ret) { 9473117bb31SNicolin Chen dev_err(&pdev->dev, "failed to get output width\n"); 948c0296950SFabio Estevam return ret; 9493117bb31SNicolin Chen } 9503117bb31SNicolin Chen 9513117bb31SNicolin Chen if (asrc_priv->asrc_width != 16 && asrc_priv->asrc_width != 24) { 9523117bb31SNicolin Chen dev_warn(&pdev->dev, "unsupported width, switching to 24bit\n"); 9533117bb31SNicolin Chen asrc_priv->asrc_width = 24; 9543117bb31SNicolin Chen } 9553117bb31SNicolin Chen 9563117bb31SNicolin Chen platform_set_drvdata(pdev, asrc_priv); 9573117bb31SNicolin Chen pm_runtime_enable(&pdev->dev); 9583117bb31SNicolin Chen spin_lock_init(&asrc_priv->lock); 9593117bb31SNicolin Chen 9603117bb31SNicolin Chen ret = devm_snd_soc_register_component(&pdev->dev, &fsl_asrc_component, 9613117bb31SNicolin Chen &fsl_asrc_dai, 1); 9623117bb31SNicolin Chen if (ret) { 9633117bb31SNicolin Chen dev_err(&pdev->dev, "failed to register ASoC DAI\n"); 9643117bb31SNicolin Chen return ret; 9653117bb31SNicolin Chen } 9663117bb31SNicolin Chen 9673117bb31SNicolin Chen return 0; 9683117bb31SNicolin Chen } 9693117bb31SNicolin Chen 970641d334bSRafael J. Wysocki #ifdef CONFIG_PM 9713117bb31SNicolin Chen static int fsl_asrc_runtime_resume(struct device *dev) 9723117bb31SNicolin Chen { 9733117bb31SNicolin Chen struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); 974b1ade0f2SFabio Estevam int i, ret; 9753117bb31SNicolin Chen 976b1ade0f2SFabio Estevam ret = clk_prepare_enable(asrc_priv->mem_clk); 977b1ade0f2SFabio Estevam if (ret) 978b1ade0f2SFabio Estevam return ret; 979b1ade0f2SFabio Estevam ret = clk_prepare_enable(asrc_priv->ipg_clk); 980b1ade0f2SFabio Estevam if (ret) 981b1ade0f2SFabio Estevam goto disable_mem_clk; 98213b8a97aSShengjiu Wang if (!IS_ERR(asrc_priv->spba_clk)) { 98313b8a97aSShengjiu Wang ret = clk_prepare_enable(asrc_priv->spba_clk); 98413b8a97aSShengjiu Wang if (ret) 98513b8a97aSShengjiu Wang goto disable_ipg_clk; 98613b8a97aSShengjiu Wang } 987b1ade0f2SFabio Estevam for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { 988b1ade0f2SFabio Estevam ret = clk_prepare_enable(asrc_priv->asrck_clk[i]); 989b1ade0f2SFabio Estevam if (ret) 990b1ade0f2SFabio Estevam goto disable_asrck_clk; 991b1ade0f2SFabio Estevam } 9923117bb31SNicolin Chen 9933117bb31SNicolin Chen return 0; 994b1ade0f2SFabio Estevam 995b1ade0f2SFabio Estevam disable_asrck_clk: 996b1ade0f2SFabio Estevam for (i--; i >= 0; i--) 997b1ade0f2SFabio Estevam clk_disable_unprepare(asrc_priv->asrck_clk[i]); 99813b8a97aSShengjiu Wang if (!IS_ERR(asrc_priv->spba_clk)) 99913b8a97aSShengjiu Wang clk_disable_unprepare(asrc_priv->spba_clk); 100013b8a97aSShengjiu Wang disable_ipg_clk: 1001b1ade0f2SFabio Estevam clk_disable_unprepare(asrc_priv->ipg_clk); 1002b1ade0f2SFabio Estevam disable_mem_clk: 1003b1ade0f2SFabio Estevam clk_disable_unprepare(asrc_priv->mem_clk); 1004b1ade0f2SFabio Estevam return ret; 10053117bb31SNicolin Chen } 10063117bb31SNicolin Chen 10073117bb31SNicolin Chen static int fsl_asrc_runtime_suspend(struct device *dev) 10083117bb31SNicolin Chen { 10093117bb31SNicolin Chen struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); 10103117bb31SNicolin Chen int i; 10113117bb31SNicolin Chen 10123117bb31SNicolin Chen for (i = 0; i < ASRC_CLK_MAX_NUM; i++) 10133117bb31SNicolin Chen clk_disable_unprepare(asrc_priv->asrck_clk[i]); 101413b8a97aSShengjiu Wang if (!IS_ERR(asrc_priv->spba_clk)) 101513b8a97aSShengjiu Wang clk_disable_unprepare(asrc_priv->spba_clk); 10163117bb31SNicolin Chen clk_disable_unprepare(asrc_priv->ipg_clk); 10173117bb31SNicolin Chen clk_disable_unprepare(asrc_priv->mem_clk); 10183117bb31SNicolin Chen 10193117bb31SNicolin Chen return 0; 10203117bb31SNicolin Chen } 1021641d334bSRafael J. Wysocki #endif /* CONFIG_PM */ 10223117bb31SNicolin Chen 1023d3dacda9SFabio Estevam #ifdef CONFIG_PM_SLEEP 10243117bb31SNicolin Chen static int fsl_asrc_suspend(struct device *dev) 10253117bb31SNicolin Chen { 10263117bb31SNicolin Chen struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); 10273117bb31SNicolin Chen 1028d44c6114SZidan Wang regmap_read(asrc_priv->regmap, REG_ASRCFG, 1029d44c6114SZidan Wang &asrc_priv->regcache_cfg); 1030d44c6114SZidan Wang 10313117bb31SNicolin Chen regcache_cache_only(asrc_priv->regmap, true); 10323117bb31SNicolin Chen regcache_mark_dirty(asrc_priv->regmap); 10333117bb31SNicolin Chen 10343117bb31SNicolin Chen return 0; 10353117bb31SNicolin Chen } 10363117bb31SNicolin Chen 10373117bb31SNicolin Chen static int fsl_asrc_resume(struct device *dev) 10383117bb31SNicolin Chen { 10393117bb31SNicolin Chen struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); 10403117bb31SNicolin Chen u32 asrctr; 10413117bb31SNicolin Chen 10423117bb31SNicolin Chen /* Stop all pairs provisionally */ 10433117bb31SNicolin Chen regmap_read(asrc_priv->regmap, REG_ASRCTR, &asrctr); 10443117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, 10453117bb31SNicolin Chen ASRCTR_ASRCEi_ALL_MASK, 0); 10463117bb31SNicolin Chen 10473117bb31SNicolin Chen /* Restore all registers */ 10483117bb31SNicolin Chen regcache_cache_only(asrc_priv->regmap, false); 10493117bb31SNicolin Chen regcache_sync(asrc_priv->regmap); 10503117bb31SNicolin Chen 1051d44c6114SZidan Wang regmap_update_bits(asrc_priv->regmap, REG_ASRCFG, 1052d44c6114SZidan Wang ASRCFG_NDPRi_ALL_MASK | ASRCFG_POSTMODi_ALL_MASK | 1053d44c6114SZidan Wang ASRCFG_PREMODi_ALL_MASK, asrc_priv->regcache_cfg); 1054d44c6114SZidan Wang 10553117bb31SNicolin Chen /* Restart enabled pairs */ 10563117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, 10573117bb31SNicolin Chen ASRCTR_ASRCEi_ALL_MASK, asrctr); 10583117bb31SNicolin Chen 10593117bb31SNicolin Chen return 0; 10603117bb31SNicolin Chen } 10613117bb31SNicolin Chen #endif /* CONFIG_PM_SLEEP */ 10623117bb31SNicolin Chen 10633117bb31SNicolin Chen static const struct dev_pm_ops fsl_asrc_pm = { 10643117bb31SNicolin Chen SET_RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL) 10653117bb31SNicolin Chen SET_SYSTEM_SLEEP_PM_OPS(fsl_asrc_suspend, fsl_asrc_resume) 10663117bb31SNicolin Chen }; 10673117bb31SNicolin Chen 10683117bb31SNicolin Chen static const struct of_device_id fsl_asrc_ids[] = { 10693117bb31SNicolin Chen { .compatible = "fsl,imx35-asrc", }, 10703117bb31SNicolin Chen { .compatible = "fsl,imx53-asrc", }, 10713117bb31SNicolin Chen {} 10723117bb31SNicolin Chen }; 10733117bb31SNicolin Chen MODULE_DEVICE_TABLE(of, fsl_asrc_ids); 10743117bb31SNicolin Chen 10753117bb31SNicolin Chen static struct platform_driver fsl_asrc_driver = { 10763117bb31SNicolin Chen .probe = fsl_asrc_probe, 10773117bb31SNicolin Chen .driver = { 10783117bb31SNicolin Chen .name = "fsl-asrc", 10793117bb31SNicolin Chen .of_match_table = fsl_asrc_ids, 10803117bb31SNicolin Chen .pm = &fsl_asrc_pm, 10813117bb31SNicolin Chen }, 10823117bb31SNicolin Chen }; 10833117bb31SNicolin Chen module_platform_driver(fsl_asrc_driver); 10843117bb31SNicolin Chen 10853117bb31SNicolin Chen MODULE_DESCRIPTION("Freescale ASRC ASoC driver"); 10863117bb31SNicolin Chen MODULE_AUTHOR("Nicolin Chen <nicoleotsuka@gmail.com>"); 10873117bb31SNicolin Chen MODULE_ALIAS("platform:fsl-asrc"); 10883117bb31SNicolin Chen MODULE_LICENSE("GPL v2"); 1089