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