1*2ba28053SFabio Estevam // SPDX-License-Identifier: GPL-2.0 2*2ba28053SFabio Estevam // 3*2ba28053SFabio Estevam // Freescale ASRC ALSA SoC Digital Audio Interface (DAI) driver 4*2ba28053SFabio Estevam // 5*2ba28053SFabio Estevam // Copyright (C) 2014 Freescale Semiconductor, Inc. 6*2ba28053SFabio Estevam // 7*2ba28053SFabio 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 /* Sample rates are aligned with that defined in pcm.h file */ 30fff6e03cSZidan Wang static const u8 process_option[][12][2] = { 31fff6e03cSZidan Wang /* 8kHz 11.025kHz 16kHz 22.05kHz 32kHz 44.1kHz 48kHz 64kHz 88.2kHz 96kHz 176kHz 192kHz */ 32fff6e03cSZidan Wang {{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 5512Hz */ 33fff6e03cSZidan Wang {{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 8kHz */ 34fff6e03cSZidan Wang {{0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 11025Hz */ 35fff6e03cSZidan Wang {{1, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 16kHz */ 36fff6e03cSZidan Wang {{1, 2}, {1, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 22050Hz */ 37fff6e03cSZidan Wang {{1, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0},}, /* 32kHz */ 38fff6e03cSZidan Wang {{2, 2}, {2, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 44.1kHz */ 39fff6e03cSZidan Wang {{2, 2}, {2, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 48kHz */ 40fff6e03cSZidan Wang {{2, 2}, {2, 2}, {2, 2}, {2, 1}, {1, 2}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0},}, /* 64kHz */ 41fff6e03cSZidan Wang {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 88.2kHz */ 42fff6e03cSZidan Wang {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 96kHz */ 43fff6e03cSZidan Wang {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 176kHz */ 44fff6e03cSZidan Wang {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 192kHz */ 453117bb31SNicolin Chen }; 463117bb31SNicolin Chen 473117bb31SNicolin Chen /* Corresponding to process_option */ 483117bb31SNicolin Chen static int supported_input_rate[] = { 493117bb31SNicolin Chen 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 503117bb31SNicolin Chen 96000, 176400, 192000, 513117bb31SNicolin Chen }; 523117bb31SNicolin Chen 533117bb31SNicolin Chen static int supported_asrc_rate[] = { 54fff6e03cSZidan Wang 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000, 553117bb31SNicolin Chen }; 563117bb31SNicolin Chen 573117bb31SNicolin Chen /** 583117bb31SNicolin Chen * The following tables map the relationship between asrc_inclk/asrc_outclk in 593117bb31SNicolin Chen * fsl_asrc.h and the registers of ASRCSR 603117bb31SNicolin Chen */ 613117bb31SNicolin Chen static unsigned char input_clk_map_imx35[] = { 623117bb31SNicolin Chen 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 633117bb31SNicolin Chen }; 643117bb31SNicolin Chen 653117bb31SNicolin Chen static unsigned char output_clk_map_imx35[] = { 663117bb31SNicolin Chen 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 673117bb31SNicolin Chen }; 683117bb31SNicolin Chen 693117bb31SNicolin Chen /* i.MX53 uses the same map for input and output */ 703117bb31SNicolin Chen static unsigned char input_clk_map_imx53[] = { 713117bb31SNicolin Chen /* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf */ 723117bb31SNicolin Chen 0x0, 0x1, 0x2, 0x7, 0x4, 0x5, 0x6, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xf, 0xe, 0xd, 733117bb31SNicolin Chen }; 743117bb31SNicolin Chen 753117bb31SNicolin Chen static unsigned char output_clk_map_imx53[] = { 763117bb31SNicolin Chen /* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf */ 773117bb31SNicolin Chen 0x8, 0x9, 0xa, 0x7, 0xc, 0x5, 0x6, 0xb, 0x0, 0x1, 0x2, 0x3, 0x4, 0xf, 0xe, 0xd, 783117bb31SNicolin Chen }; 793117bb31SNicolin Chen 803117bb31SNicolin Chen static unsigned char *clk_map[2]; 813117bb31SNicolin Chen 823117bb31SNicolin Chen /** 833117bb31SNicolin Chen * Request ASRC pair 843117bb31SNicolin Chen * 853117bb31SNicolin Chen * It assigns pair by the order of A->C->B because allocation of pair B, 863117bb31SNicolin Chen * within range [ANCA, ANCA+ANCB-1], depends on the channels of pair A 873117bb31SNicolin Chen * while pair A and pair C are comparatively independent. 883117bb31SNicolin Chen */ 893117bb31SNicolin Chen static int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair) 903117bb31SNicolin Chen { 913117bb31SNicolin Chen enum asrc_pair_index index = ASRC_INVALID_PAIR; 923117bb31SNicolin Chen struct fsl_asrc *asrc_priv = pair->asrc_priv; 933117bb31SNicolin Chen struct device *dev = &asrc_priv->pdev->dev; 943117bb31SNicolin Chen unsigned long lock_flags; 953117bb31SNicolin Chen int i, ret = 0; 963117bb31SNicolin Chen 973117bb31SNicolin Chen spin_lock_irqsave(&asrc_priv->lock, lock_flags); 983117bb31SNicolin Chen 993117bb31SNicolin Chen for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) { 1003117bb31SNicolin Chen if (asrc_priv->pair[i] != NULL) 1013117bb31SNicolin Chen continue; 1023117bb31SNicolin Chen 1033117bb31SNicolin Chen index = i; 1043117bb31SNicolin Chen 1053117bb31SNicolin Chen if (i != ASRC_PAIR_B) 1063117bb31SNicolin Chen break; 1073117bb31SNicolin Chen } 1083117bb31SNicolin Chen 1093117bb31SNicolin Chen if (index == ASRC_INVALID_PAIR) { 1103117bb31SNicolin Chen dev_err(dev, "all pairs are busy now\n"); 1113117bb31SNicolin Chen ret = -EBUSY; 1123117bb31SNicolin Chen } else if (asrc_priv->channel_avail < channels) { 1133117bb31SNicolin Chen dev_err(dev, "can't afford required channels: %d\n", channels); 1143117bb31SNicolin Chen ret = -EINVAL; 1153117bb31SNicolin Chen } else { 1163117bb31SNicolin Chen asrc_priv->channel_avail -= channels; 1173117bb31SNicolin Chen asrc_priv->pair[index] = pair; 1183117bb31SNicolin Chen pair->channels = channels; 1193117bb31SNicolin Chen pair->index = index; 1203117bb31SNicolin Chen } 1213117bb31SNicolin Chen 1223117bb31SNicolin Chen spin_unlock_irqrestore(&asrc_priv->lock, lock_flags); 1233117bb31SNicolin Chen 1243117bb31SNicolin Chen return ret; 1253117bb31SNicolin Chen } 1263117bb31SNicolin Chen 1273117bb31SNicolin Chen /** 1283117bb31SNicolin Chen * Release ASRC pair 1293117bb31SNicolin Chen * 1303117bb31SNicolin Chen * It clears the resource from asrc_priv and releases the occupied channels. 1313117bb31SNicolin Chen */ 1323117bb31SNicolin Chen static void fsl_asrc_release_pair(struct fsl_asrc_pair *pair) 1333117bb31SNicolin Chen { 1343117bb31SNicolin Chen struct fsl_asrc *asrc_priv = pair->asrc_priv; 1353117bb31SNicolin Chen enum asrc_pair_index index = pair->index; 1363117bb31SNicolin Chen unsigned long lock_flags; 1373117bb31SNicolin Chen 1383117bb31SNicolin Chen /* Make sure the pair is disabled */ 1393117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, 1403117bb31SNicolin Chen ASRCTR_ASRCEi_MASK(index), 0); 1413117bb31SNicolin Chen 1423117bb31SNicolin Chen spin_lock_irqsave(&asrc_priv->lock, lock_flags); 1433117bb31SNicolin Chen 1443117bb31SNicolin Chen asrc_priv->channel_avail += pair->channels; 1453117bb31SNicolin Chen asrc_priv->pair[index] = NULL; 1463117bb31SNicolin Chen pair->error = 0; 1473117bb31SNicolin Chen 1483117bb31SNicolin Chen spin_unlock_irqrestore(&asrc_priv->lock, lock_flags); 1493117bb31SNicolin Chen } 1503117bb31SNicolin Chen 1513117bb31SNicolin Chen /** 1523117bb31SNicolin Chen * Configure input and output thresholds 1533117bb31SNicolin Chen */ 1543117bb31SNicolin Chen static void fsl_asrc_set_watermarks(struct fsl_asrc_pair *pair, u32 in, u32 out) 1553117bb31SNicolin Chen { 1563117bb31SNicolin Chen struct fsl_asrc *asrc_priv = pair->asrc_priv; 1573117bb31SNicolin Chen enum asrc_pair_index index = pair->index; 1583117bb31SNicolin Chen 1593117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRMCR(index), 1603117bb31SNicolin Chen ASRMCRi_EXTTHRSHi_MASK | 1613117bb31SNicolin Chen ASRMCRi_INFIFO_THRESHOLD_MASK | 1623117bb31SNicolin Chen ASRMCRi_OUTFIFO_THRESHOLD_MASK, 1633117bb31SNicolin Chen ASRMCRi_EXTTHRSHi | 1643117bb31SNicolin Chen ASRMCRi_INFIFO_THRESHOLD(in) | 1653117bb31SNicolin Chen ASRMCRi_OUTFIFO_THRESHOLD(out)); 1663117bb31SNicolin Chen } 1673117bb31SNicolin Chen 1683117bb31SNicolin Chen /** 1693117bb31SNicolin Chen * Calculate the total divisor between asrck clock rate and sample rate 1703117bb31SNicolin Chen * 1713117bb31SNicolin Chen * It follows the formula clk_rate = samplerate * (2 ^ prescaler) * divider 1723117bb31SNicolin Chen */ 1733117bb31SNicolin Chen static u32 fsl_asrc_cal_asrck_divisor(struct fsl_asrc_pair *pair, u32 div) 1743117bb31SNicolin Chen { 1753117bb31SNicolin Chen u32 ps; 1763117bb31SNicolin Chen 1773117bb31SNicolin Chen /* Calculate the divisors: prescaler [2^0, 2^7], divder [1, 8] */ 1783117bb31SNicolin Chen for (ps = 0; div > 8; ps++) 1793117bb31SNicolin Chen div >>= 1; 1803117bb31SNicolin Chen 1813117bb31SNicolin Chen return ((div - 1) << ASRCDRi_AxCPi_WIDTH) | ps; 1823117bb31SNicolin Chen } 1833117bb31SNicolin Chen 1843117bb31SNicolin Chen /** 1853117bb31SNicolin Chen * Calculate and set the ratio for Ideal Ratio mode only 1863117bb31SNicolin Chen * 1873117bb31SNicolin Chen * The ratio is a 32-bit fixed point value with 26 fractional bits. 1883117bb31SNicolin Chen */ 1893117bb31SNicolin Chen static int fsl_asrc_set_ideal_ratio(struct fsl_asrc_pair *pair, 1903117bb31SNicolin Chen int inrate, int outrate) 1913117bb31SNicolin Chen { 1923117bb31SNicolin Chen struct fsl_asrc *asrc_priv = pair->asrc_priv; 1933117bb31SNicolin Chen enum asrc_pair_index index = pair->index; 1943117bb31SNicolin Chen unsigned long ratio; 1953117bb31SNicolin Chen int i; 1963117bb31SNicolin Chen 1973117bb31SNicolin Chen if (!outrate) { 1983117bb31SNicolin Chen pair_err("output rate should not be zero\n"); 1993117bb31SNicolin Chen return -EINVAL; 2003117bb31SNicolin Chen } 2013117bb31SNicolin Chen 2023117bb31SNicolin Chen /* Calculate the intergal part of the ratio */ 2033117bb31SNicolin Chen ratio = (inrate / outrate) << IDEAL_RATIO_DECIMAL_DEPTH; 2043117bb31SNicolin Chen 2053117bb31SNicolin Chen /* ... and then the 26 depth decimal part */ 2063117bb31SNicolin Chen inrate %= outrate; 2073117bb31SNicolin Chen 2083117bb31SNicolin Chen for (i = 1; i <= IDEAL_RATIO_DECIMAL_DEPTH; i++) { 2093117bb31SNicolin Chen inrate <<= 1; 2103117bb31SNicolin Chen 2113117bb31SNicolin Chen if (inrate < outrate) 2123117bb31SNicolin Chen continue; 2133117bb31SNicolin Chen 2143117bb31SNicolin Chen ratio |= 1 << (IDEAL_RATIO_DECIMAL_DEPTH - i); 2153117bb31SNicolin Chen inrate -= outrate; 2163117bb31SNicolin Chen 2173117bb31SNicolin Chen if (!inrate) 2183117bb31SNicolin Chen break; 2193117bb31SNicolin Chen } 2203117bb31SNicolin Chen 2213117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRIDRL(index), ratio); 2223117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRIDRH(index), ratio >> 24); 2233117bb31SNicolin Chen 2243117bb31SNicolin Chen return 0; 2253117bb31SNicolin Chen } 2263117bb31SNicolin Chen 2273117bb31SNicolin Chen /** 2283117bb31SNicolin Chen * Configure the assigned ASRC pair 2293117bb31SNicolin Chen * 2303117bb31SNicolin Chen * It configures those ASRC registers according to a configuration instance 2313117bb31SNicolin Chen * of struct asrc_config which includes in/output sample rate, width, channel 2323117bb31SNicolin Chen * and clock settings. 2333117bb31SNicolin Chen */ 2343117bb31SNicolin Chen static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair) 2353117bb31SNicolin Chen { 2363117bb31SNicolin Chen struct asrc_config *config = pair->config; 2373117bb31SNicolin Chen struct fsl_asrc *asrc_priv = pair->asrc_priv; 2383117bb31SNicolin Chen enum asrc_pair_index index = pair->index; 2394e13eb72SNicolin Chen u32 inrate, outrate, indiv, outdiv; 2403117bb31SNicolin Chen u32 clk_index[2], div[2]; 2413117bb31SNicolin Chen int in, out, channels; 2423117bb31SNicolin Chen struct clk *clk; 2434e13eb72SNicolin Chen bool ideal; 2443117bb31SNicolin Chen 2453117bb31SNicolin Chen if (!config) { 2463117bb31SNicolin Chen pair_err("invalid pair config\n"); 2473117bb31SNicolin Chen return -EINVAL; 2483117bb31SNicolin Chen } 2493117bb31SNicolin Chen 2503117bb31SNicolin Chen /* Validate channels */ 2513117bb31SNicolin Chen if (config->channel_num < 1 || config->channel_num > 10) { 2523117bb31SNicolin Chen pair_err("does not support %d channels\n", config->channel_num); 2533117bb31SNicolin Chen return -EINVAL; 2543117bb31SNicolin Chen } 2553117bb31SNicolin Chen 2563117bb31SNicolin Chen /* Validate output width */ 2573117bb31SNicolin Chen if (config->output_word_width == ASRC_WIDTH_8_BIT) { 2583117bb31SNicolin Chen pair_err("does not support 8bit width output\n"); 2593117bb31SNicolin Chen return -EINVAL; 2603117bb31SNicolin Chen } 2613117bb31SNicolin Chen 2624e13eb72SNicolin Chen inrate = config->input_sample_rate; 2634e13eb72SNicolin Chen outrate = config->output_sample_rate; 2644e13eb72SNicolin Chen ideal = config->inclk == INCLK_NONE; 2654e13eb72SNicolin Chen 2663117bb31SNicolin Chen /* Validate input and output sample rates */ 2673117bb31SNicolin Chen for (in = 0; in < ARRAY_SIZE(supported_input_rate); in++) 2683117bb31SNicolin Chen if (inrate == supported_input_rate[in]) 2693117bb31SNicolin Chen break; 2703117bb31SNicolin Chen 2713117bb31SNicolin Chen if (in == ARRAY_SIZE(supported_input_rate)) { 2723117bb31SNicolin Chen pair_err("unsupported input sample rate: %dHz\n", inrate); 2733117bb31SNicolin Chen return -EINVAL; 2743117bb31SNicolin Chen } 2753117bb31SNicolin Chen 2763117bb31SNicolin Chen for (out = 0; out < ARRAY_SIZE(supported_asrc_rate); out++) 2773117bb31SNicolin Chen if (outrate == supported_asrc_rate[out]) 2783117bb31SNicolin Chen break; 2793117bb31SNicolin Chen 2803117bb31SNicolin Chen if (out == ARRAY_SIZE(supported_asrc_rate)) { 2813117bb31SNicolin Chen pair_err("unsupported output sample rate: %dHz\n", outrate); 2823117bb31SNicolin Chen return -EINVAL; 2833117bb31SNicolin Chen } 2843117bb31SNicolin Chen 285fff6e03cSZidan Wang if ((outrate > 8000 && outrate < 30000) && 286fff6e03cSZidan Wang (outrate/inrate > 24 || inrate/outrate > 8)) { 287fff6e03cSZidan Wang pair_err("exceed supported ratio range [1/24, 8] for \ 288fff6e03cSZidan Wang inrate/outrate: %d/%d\n", inrate, outrate); 289fff6e03cSZidan Wang return -EINVAL; 290fff6e03cSZidan Wang } 291fff6e03cSZidan Wang 2923117bb31SNicolin Chen /* Validate input and output clock sources */ 2933117bb31SNicolin Chen clk_index[IN] = clk_map[IN][config->inclk]; 2943117bb31SNicolin Chen clk_index[OUT] = clk_map[OUT][config->outclk]; 2953117bb31SNicolin Chen 2963117bb31SNicolin Chen /* We only have output clock for ideal ratio mode */ 2973117bb31SNicolin Chen clk = asrc_priv->asrck_clk[clk_index[ideal ? OUT : IN]]; 2983117bb31SNicolin Chen 2993117bb31SNicolin Chen div[IN] = clk_get_rate(clk) / inrate; 3003117bb31SNicolin Chen if (div[IN] == 0) { 3013117bb31SNicolin Chen pair_err("failed to support input sample rate %dHz by asrck_%x\n", 3023117bb31SNicolin Chen inrate, clk_index[ideal ? OUT : IN]); 3033117bb31SNicolin Chen return -EINVAL; 3043117bb31SNicolin Chen } 3053117bb31SNicolin Chen 3063117bb31SNicolin Chen clk = asrc_priv->asrck_clk[clk_index[OUT]]; 3073117bb31SNicolin Chen 3083117bb31SNicolin Chen /* Use fixed output rate for Ideal Ratio mode (INCLK_NONE) */ 3093117bb31SNicolin Chen if (ideal) 3103117bb31SNicolin Chen div[OUT] = clk_get_rate(clk) / IDEAL_RATIO_RATE; 3113117bb31SNicolin Chen else 3123117bb31SNicolin Chen div[OUT] = clk_get_rate(clk) / outrate; 3133117bb31SNicolin Chen 3143117bb31SNicolin Chen if (div[OUT] == 0) { 3153117bb31SNicolin Chen pair_err("failed to support output sample rate %dHz by asrck_%x\n", 3163117bb31SNicolin Chen outrate, clk_index[OUT]); 3173117bb31SNicolin Chen return -EINVAL; 3183117bb31SNicolin Chen } 3193117bb31SNicolin Chen 3203117bb31SNicolin Chen /* Set the channel number */ 3213117bb31SNicolin Chen channels = config->channel_num; 3223117bb31SNicolin Chen 3233117bb31SNicolin Chen if (asrc_priv->channel_bits < 4) 3243117bb31SNicolin Chen channels /= 2; 3253117bb31SNicolin Chen 3263117bb31SNicolin Chen /* Update channels for current pair */ 3273117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCNCR, 3283117bb31SNicolin Chen ASRCNCR_ANCi_MASK(index, asrc_priv->channel_bits), 3293117bb31SNicolin Chen ASRCNCR_ANCi(index, channels, asrc_priv->channel_bits)); 3303117bb31SNicolin Chen 3313117bb31SNicolin Chen /* Default setting: Automatic selection for processing mode */ 3323117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, 3333117bb31SNicolin Chen ASRCTR_ATSi_MASK(index), ASRCTR_ATS(index)); 3343117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, 3353117bb31SNicolin Chen ASRCTR_USRi_MASK(index), 0); 3363117bb31SNicolin Chen 3373117bb31SNicolin Chen /* Set the input and output clock sources */ 3383117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCSR, 3393117bb31SNicolin Chen ASRCSR_AICSi_MASK(index) | ASRCSR_AOCSi_MASK(index), 3403117bb31SNicolin Chen ASRCSR_AICS(index, clk_index[IN]) | 3413117bb31SNicolin Chen ASRCSR_AOCS(index, clk_index[OUT])); 3423117bb31SNicolin Chen 3433117bb31SNicolin Chen /* Calculate the input clock divisors */ 3443117bb31SNicolin Chen indiv = fsl_asrc_cal_asrck_divisor(pair, div[IN]); 3453117bb31SNicolin Chen outdiv = fsl_asrc_cal_asrck_divisor(pair, div[OUT]); 3463117bb31SNicolin Chen 3473117bb31SNicolin Chen /* Suppose indiv and outdiv includes prescaler, so add its MASK too */ 3483117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCDR(index), 3493117bb31SNicolin Chen ASRCDRi_AOCPi_MASK(index) | ASRCDRi_AICPi_MASK(index) | 3503117bb31SNicolin Chen ASRCDRi_AOCDi_MASK(index) | ASRCDRi_AICDi_MASK(index), 3513117bb31SNicolin Chen ASRCDRi_AOCP(index, outdiv) | ASRCDRi_AICP(index, indiv)); 3523117bb31SNicolin Chen 3533117bb31SNicolin Chen /* Implement word_width configurations */ 3543117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRMCR1(index), 3553117bb31SNicolin Chen ASRMCR1i_OW16_MASK | ASRMCR1i_IWD_MASK, 3563117bb31SNicolin Chen ASRMCR1i_OW16(config->output_word_width) | 3573117bb31SNicolin Chen ASRMCR1i_IWD(config->input_word_width)); 3583117bb31SNicolin Chen 3593117bb31SNicolin Chen /* Enable BUFFER STALL */ 3603117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRMCR(index), 3613117bb31SNicolin Chen ASRMCRi_BUFSTALLi_MASK, ASRMCRi_BUFSTALLi); 3623117bb31SNicolin Chen 3633117bb31SNicolin Chen /* Set default thresholds for input and output FIFO */ 3643117bb31SNicolin Chen fsl_asrc_set_watermarks(pair, ASRC_INPUTFIFO_THRESHOLD, 3653117bb31SNicolin Chen ASRC_INPUTFIFO_THRESHOLD); 3663117bb31SNicolin Chen 3674091fb95SMasahiro Yamada /* Configure the following only for Ideal Ratio mode */ 3683117bb31SNicolin Chen if (!ideal) 3693117bb31SNicolin Chen return 0; 3703117bb31SNicolin Chen 3713117bb31SNicolin Chen /* Clear ASTSx bit to use Ideal Ratio mode */ 3723117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, 3733117bb31SNicolin Chen ASRCTR_ATSi_MASK(index), 0); 3743117bb31SNicolin Chen 3753117bb31SNicolin Chen /* Enable Ideal Ratio mode */ 3763117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, 3773117bb31SNicolin Chen ASRCTR_IDRi_MASK(index) | ASRCTR_USRi_MASK(index), 3783117bb31SNicolin Chen ASRCTR_IDR(index) | ASRCTR_USR(index)); 3793117bb31SNicolin Chen 3803117bb31SNicolin Chen /* Apply configurations for pre- and post-processing */ 3813117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCFG, 3823117bb31SNicolin Chen ASRCFG_PREMODi_MASK(index) | ASRCFG_POSTMODi_MASK(index), 3833117bb31SNicolin Chen ASRCFG_PREMOD(index, process_option[in][out][0]) | 3843117bb31SNicolin Chen ASRCFG_POSTMOD(index, process_option[in][out][1])); 3853117bb31SNicolin Chen 3863117bb31SNicolin Chen return fsl_asrc_set_ideal_ratio(pair, inrate, outrate); 3873117bb31SNicolin Chen } 3883117bb31SNicolin Chen 3893117bb31SNicolin Chen /** 3903117bb31SNicolin Chen * Start the assigned ASRC pair 3913117bb31SNicolin Chen * 3923117bb31SNicolin Chen * It enables the assigned pair and makes it stopped at the stall level. 3933117bb31SNicolin Chen */ 3943117bb31SNicolin Chen static void fsl_asrc_start_pair(struct fsl_asrc_pair *pair) 3953117bb31SNicolin Chen { 3963117bb31SNicolin Chen struct fsl_asrc *asrc_priv = pair->asrc_priv; 3973117bb31SNicolin Chen enum asrc_pair_index index = pair->index; 3983117bb31SNicolin Chen int reg, retry = 10, i; 3993117bb31SNicolin Chen 4003117bb31SNicolin Chen /* Enable the current pair */ 4013117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, 4023117bb31SNicolin Chen ASRCTR_ASRCEi_MASK(index), ASRCTR_ASRCE(index)); 4033117bb31SNicolin Chen 4043117bb31SNicolin Chen /* Wait for status of initialization */ 4053117bb31SNicolin Chen do { 4063117bb31SNicolin Chen udelay(5); 4073117bb31SNicolin Chen regmap_read(asrc_priv->regmap, REG_ASRCFG, ®); 4083117bb31SNicolin Chen reg &= ASRCFG_INIRQi_MASK(index); 4093117bb31SNicolin Chen } while (!reg && --retry); 4103117bb31SNicolin Chen 4113117bb31SNicolin Chen /* Make the input fifo to ASRC STALL level */ 4123117bb31SNicolin Chen regmap_read(asrc_priv->regmap, REG_ASRCNCR, ®); 4133117bb31SNicolin Chen for (i = 0; i < pair->channels * 4; i++) 4143117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRDI(index), 0); 4153117bb31SNicolin Chen 4163117bb31SNicolin Chen /* Enable overload interrupt */ 4173117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRIER, ASRIER_AOLIE); 4183117bb31SNicolin Chen } 4193117bb31SNicolin Chen 4203117bb31SNicolin Chen /** 4213117bb31SNicolin Chen * Stop the assigned ASRC pair 4223117bb31SNicolin Chen */ 4233117bb31SNicolin Chen static void fsl_asrc_stop_pair(struct fsl_asrc_pair *pair) 4243117bb31SNicolin Chen { 4253117bb31SNicolin Chen struct fsl_asrc *asrc_priv = pair->asrc_priv; 4263117bb31SNicolin Chen enum asrc_pair_index index = pair->index; 4273117bb31SNicolin Chen 4283117bb31SNicolin Chen /* Stop the current pair */ 4293117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, 4303117bb31SNicolin Chen ASRCTR_ASRCEi_MASK(index), 0); 4313117bb31SNicolin Chen } 4323117bb31SNicolin Chen 4333117bb31SNicolin Chen /** 4343117bb31SNicolin Chen * Get DMA channel according to the pair and direction. 4353117bb31SNicolin Chen */ 4363117bb31SNicolin Chen struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, bool dir) 4373117bb31SNicolin Chen { 4383117bb31SNicolin Chen struct fsl_asrc *asrc_priv = pair->asrc_priv; 4393117bb31SNicolin Chen enum asrc_pair_index index = pair->index; 4403117bb31SNicolin Chen char name[4]; 4413117bb31SNicolin Chen 4423117bb31SNicolin Chen sprintf(name, "%cx%c", dir == IN ? 'r' : 't', index + 'a'); 4433117bb31SNicolin Chen 4443117bb31SNicolin Chen return dma_request_slave_channel(&asrc_priv->pdev->dev, name); 4453117bb31SNicolin Chen } 4463117bb31SNicolin Chen EXPORT_SYMBOL_GPL(fsl_asrc_get_dma_channel); 4473117bb31SNicolin Chen 4483117bb31SNicolin Chen static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream, 4493117bb31SNicolin Chen struct snd_pcm_hw_params *params, 4503117bb31SNicolin Chen struct snd_soc_dai *dai) 4513117bb31SNicolin Chen { 4523117bb31SNicolin Chen struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai); 4534ca73043SZidan Wang int width = params_width(params); 4543117bb31SNicolin Chen struct snd_pcm_runtime *runtime = substream->runtime; 4553117bb31SNicolin Chen struct fsl_asrc_pair *pair = runtime->private_data; 4563117bb31SNicolin Chen unsigned int channels = params_channels(params); 4573117bb31SNicolin Chen unsigned int rate = params_rate(params); 4583117bb31SNicolin Chen struct asrc_config config; 4593117bb31SNicolin Chen int word_width, ret; 4603117bb31SNicolin Chen 4613117bb31SNicolin Chen ret = fsl_asrc_request_pair(channels, pair); 4623117bb31SNicolin Chen if (ret) { 4633117bb31SNicolin Chen dev_err(dai->dev, "fail to request asrc pair\n"); 4643117bb31SNicolin Chen return ret; 4653117bb31SNicolin Chen } 4663117bb31SNicolin Chen 4673117bb31SNicolin Chen pair->config = &config; 4683117bb31SNicolin Chen 4693117bb31SNicolin Chen if (width == 16) 4703117bb31SNicolin Chen width = ASRC_WIDTH_16_BIT; 4713117bb31SNicolin Chen else 4723117bb31SNicolin Chen width = ASRC_WIDTH_24_BIT; 4733117bb31SNicolin Chen 4743117bb31SNicolin Chen if (asrc_priv->asrc_width == 16) 4753117bb31SNicolin Chen word_width = ASRC_WIDTH_16_BIT; 4763117bb31SNicolin Chen else 4773117bb31SNicolin Chen word_width = ASRC_WIDTH_24_BIT; 4783117bb31SNicolin Chen 4793117bb31SNicolin Chen config.pair = pair->index; 4803117bb31SNicolin Chen config.channel_num = channels; 4813117bb31SNicolin Chen config.inclk = INCLK_NONE; 4823117bb31SNicolin Chen config.outclk = OUTCLK_ASRCK1_CLK; 4833117bb31SNicolin Chen 4843117bb31SNicolin Chen if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 4853117bb31SNicolin Chen config.input_word_width = width; 4863117bb31SNicolin Chen config.output_word_width = word_width; 4873117bb31SNicolin Chen config.input_sample_rate = rate; 4883117bb31SNicolin Chen config.output_sample_rate = asrc_priv->asrc_rate; 4893117bb31SNicolin Chen } else { 4903117bb31SNicolin Chen config.input_word_width = word_width; 4913117bb31SNicolin Chen config.output_word_width = width; 4923117bb31SNicolin Chen config.input_sample_rate = asrc_priv->asrc_rate; 4933117bb31SNicolin Chen config.output_sample_rate = rate; 4943117bb31SNicolin Chen } 4953117bb31SNicolin Chen 4963117bb31SNicolin Chen ret = fsl_asrc_config_pair(pair); 4973117bb31SNicolin Chen if (ret) { 4983117bb31SNicolin Chen dev_err(dai->dev, "fail to config asrc pair\n"); 4993117bb31SNicolin Chen return ret; 5003117bb31SNicolin Chen } 5013117bb31SNicolin Chen 5023117bb31SNicolin Chen return 0; 5033117bb31SNicolin Chen } 5043117bb31SNicolin Chen 5053117bb31SNicolin Chen static int fsl_asrc_dai_hw_free(struct snd_pcm_substream *substream, 5063117bb31SNicolin Chen struct snd_soc_dai *dai) 5073117bb31SNicolin Chen { 5083117bb31SNicolin Chen struct snd_pcm_runtime *runtime = substream->runtime; 5093117bb31SNicolin Chen struct fsl_asrc_pair *pair = runtime->private_data; 5103117bb31SNicolin Chen 5113117bb31SNicolin Chen if (pair) 5123117bb31SNicolin Chen fsl_asrc_release_pair(pair); 5133117bb31SNicolin Chen 5143117bb31SNicolin Chen return 0; 5153117bb31SNicolin Chen } 5163117bb31SNicolin Chen 5173117bb31SNicolin Chen static int fsl_asrc_dai_trigger(struct snd_pcm_substream *substream, int cmd, 5183117bb31SNicolin Chen struct snd_soc_dai *dai) 5193117bb31SNicolin Chen { 5203117bb31SNicolin Chen struct snd_pcm_runtime *runtime = substream->runtime; 5213117bb31SNicolin Chen struct fsl_asrc_pair *pair = runtime->private_data; 5223117bb31SNicolin Chen 5233117bb31SNicolin Chen switch (cmd) { 5243117bb31SNicolin Chen case SNDRV_PCM_TRIGGER_START: 5253117bb31SNicolin Chen case SNDRV_PCM_TRIGGER_RESUME: 5263117bb31SNicolin Chen case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 5273117bb31SNicolin Chen fsl_asrc_start_pair(pair); 5283117bb31SNicolin Chen break; 5293117bb31SNicolin Chen case SNDRV_PCM_TRIGGER_STOP: 5303117bb31SNicolin Chen case SNDRV_PCM_TRIGGER_SUSPEND: 5313117bb31SNicolin Chen case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 5323117bb31SNicolin Chen fsl_asrc_stop_pair(pair); 5333117bb31SNicolin Chen break; 5343117bb31SNicolin Chen default: 5353117bb31SNicolin Chen return -EINVAL; 5363117bb31SNicolin Chen } 5373117bb31SNicolin Chen 5383117bb31SNicolin Chen return 0; 5393117bb31SNicolin Chen } 5403117bb31SNicolin Chen 54129a22ebfSGustavo A. R. Silva static const struct snd_soc_dai_ops fsl_asrc_dai_ops = { 5423117bb31SNicolin Chen .hw_params = fsl_asrc_dai_hw_params, 5433117bb31SNicolin Chen .hw_free = fsl_asrc_dai_hw_free, 5443117bb31SNicolin Chen .trigger = fsl_asrc_dai_trigger, 5453117bb31SNicolin Chen }; 5463117bb31SNicolin Chen 5473117bb31SNicolin Chen static int fsl_asrc_dai_probe(struct snd_soc_dai *dai) 5483117bb31SNicolin Chen { 5493117bb31SNicolin Chen struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai); 5503117bb31SNicolin Chen 5513117bb31SNicolin Chen snd_soc_dai_init_dma_data(dai, &asrc_priv->dma_params_tx, 5523117bb31SNicolin Chen &asrc_priv->dma_params_rx); 5533117bb31SNicolin Chen 5543117bb31SNicolin Chen return 0; 5553117bb31SNicolin Chen } 5563117bb31SNicolin Chen 5573117bb31SNicolin Chen #define FSL_ASRC_RATES SNDRV_PCM_RATE_8000_192000 5583117bb31SNicolin Chen #define FSL_ASRC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \ 5593117bb31SNicolin Chen SNDRV_PCM_FMTBIT_S16_LE | \ 560d526416cSNicolin Chen SNDRV_PCM_FMTBIT_S20_3LE) 5613117bb31SNicolin Chen 5623117bb31SNicolin Chen static struct snd_soc_dai_driver fsl_asrc_dai = { 5633117bb31SNicolin Chen .probe = fsl_asrc_dai_probe, 5643117bb31SNicolin Chen .playback = { 5653117bb31SNicolin Chen .stream_name = "ASRC-Playback", 5663117bb31SNicolin Chen .channels_min = 1, 5673117bb31SNicolin Chen .channels_max = 10, 5683117bb31SNicolin Chen .rates = FSL_ASRC_RATES, 5693117bb31SNicolin Chen .formats = FSL_ASRC_FORMATS, 5703117bb31SNicolin Chen }, 5713117bb31SNicolin Chen .capture = { 5723117bb31SNicolin Chen .stream_name = "ASRC-Capture", 5733117bb31SNicolin Chen .channels_min = 1, 5743117bb31SNicolin Chen .channels_max = 10, 5753117bb31SNicolin Chen .rates = FSL_ASRC_RATES, 5763117bb31SNicolin Chen .formats = FSL_ASRC_FORMATS, 5773117bb31SNicolin Chen }, 5783117bb31SNicolin Chen .ops = &fsl_asrc_dai_ops, 5793117bb31SNicolin Chen }; 5803117bb31SNicolin Chen 5813117bb31SNicolin Chen static bool fsl_asrc_readable_reg(struct device *dev, unsigned int reg) 5823117bb31SNicolin Chen { 5833117bb31SNicolin Chen switch (reg) { 5843117bb31SNicolin Chen case REG_ASRCTR: 5853117bb31SNicolin Chen case REG_ASRIER: 5863117bb31SNicolin Chen case REG_ASRCNCR: 5873117bb31SNicolin Chen case REG_ASRCFG: 5883117bb31SNicolin Chen case REG_ASRCSR: 5893117bb31SNicolin Chen case REG_ASRCDR1: 5903117bb31SNicolin Chen case REG_ASRCDR2: 5913117bb31SNicolin Chen case REG_ASRSTR: 5923117bb31SNicolin Chen case REG_ASRPM1: 5933117bb31SNicolin Chen case REG_ASRPM2: 5943117bb31SNicolin Chen case REG_ASRPM3: 5953117bb31SNicolin Chen case REG_ASRPM4: 5963117bb31SNicolin Chen case REG_ASRPM5: 5973117bb31SNicolin Chen case REG_ASRTFR1: 5983117bb31SNicolin Chen case REG_ASRCCR: 5993117bb31SNicolin Chen case REG_ASRDOA: 6003117bb31SNicolin Chen case REG_ASRDOB: 6013117bb31SNicolin Chen case REG_ASRDOC: 6023117bb31SNicolin Chen case REG_ASRIDRHA: 6033117bb31SNicolin Chen case REG_ASRIDRLA: 6043117bb31SNicolin Chen case REG_ASRIDRHB: 6053117bb31SNicolin Chen case REG_ASRIDRLB: 6063117bb31SNicolin Chen case REG_ASRIDRHC: 6073117bb31SNicolin Chen case REG_ASRIDRLC: 6083117bb31SNicolin Chen case REG_ASR76K: 6093117bb31SNicolin Chen case REG_ASR56K: 6103117bb31SNicolin Chen case REG_ASRMCRA: 6113117bb31SNicolin Chen case REG_ASRFSTA: 6123117bb31SNicolin Chen case REG_ASRMCRB: 6133117bb31SNicolin Chen case REG_ASRFSTB: 6143117bb31SNicolin Chen case REG_ASRMCRC: 6153117bb31SNicolin Chen case REG_ASRFSTC: 6163117bb31SNicolin Chen case REG_ASRMCR1A: 6173117bb31SNicolin Chen case REG_ASRMCR1B: 6183117bb31SNicolin Chen case REG_ASRMCR1C: 6193117bb31SNicolin Chen return true; 6203117bb31SNicolin Chen default: 6213117bb31SNicolin Chen return false; 6223117bb31SNicolin Chen } 6233117bb31SNicolin Chen } 6243117bb31SNicolin Chen 6253117bb31SNicolin Chen static bool fsl_asrc_volatile_reg(struct device *dev, unsigned int reg) 6263117bb31SNicolin Chen { 6273117bb31SNicolin Chen switch (reg) { 6283117bb31SNicolin Chen case REG_ASRSTR: 6293117bb31SNicolin Chen case REG_ASRDIA: 6303117bb31SNicolin Chen case REG_ASRDIB: 6313117bb31SNicolin Chen case REG_ASRDIC: 6323117bb31SNicolin Chen case REG_ASRDOA: 6333117bb31SNicolin Chen case REG_ASRDOB: 6343117bb31SNicolin Chen case REG_ASRDOC: 6353117bb31SNicolin Chen case REG_ASRFSTA: 6363117bb31SNicolin Chen case REG_ASRFSTB: 6373117bb31SNicolin Chen case REG_ASRFSTC: 6383117bb31SNicolin Chen case REG_ASRCFG: 6393117bb31SNicolin Chen return true; 6403117bb31SNicolin Chen default: 6413117bb31SNicolin Chen return false; 6423117bb31SNicolin Chen } 6433117bb31SNicolin Chen } 6443117bb31SNicolin Chen 6453117bb31SNicolin Chen static bool fsl_asrc_writeable_reg(struct device *dev, unsigned int reg) 6463117bb31SNicolin Chen { 6473117bb31SNicolin Chen switch (reg) { 6483117bb31SNicolin Chen case REG_ASRCTR: 6493117bb31SNicolin Chen case REG_ASRIER: 6503117bb31SNicolin Chen case REG_ASRCNCR: 6513117bb31SNicolin Chen case REG_ASRCFG: 6523117bb31SNicolin Chen case REG_ASRCSR: 6533117bb31SNicolin Chen case REG_ASRCDR1: 6543117bb31SNicolin Chen case REG_ASRCDR2: 6553117bb31SNicolin Chen case REG_ASRSTR: 6563117bb31SNicolin Chen case REG_ASRPM1: 6573117bb31SNicolin Chen case REG_ASRPM2: 6583117bb31SNicolin Chen case REG_ASRPM3: 6593117bb31SNicolin Chen case REG_ASRPM4: 6603117bb31SNicolin Chen case REG_ASRPM5: 6613117bb31SNicolin Chen case REG_ASRTFR1: 6623117bb31SNicolin Chen case REG_ASRCCR: 6633117bb31SNicolin Chen case REG_ASRDIA: 6643117bb31SNicolin Chen case REG_ASRDIB: 6653117bb31SNicolin Chen case REG_ASRDIC: 6663117bb31SNicolin Chen case REG_ASRIDRHA: 6673117bb31SNicolin Chen case REG_ASRIDRLA: 6683117bb31SNicolin Chen case REG_ASRIDRHB: 6693117bb31SNicolin Chen case REG_ASRIDRLB: 6703117bb31SNicolin Chen case REG_ASRIDRHC: 6713117bb31SNicolin Chen case REG_ASRIDRLC: 6723117bb31SNicolin Chen case REG_ASR76K: 6733117bb31SNicolin Chen case REG_ASR56K: 6743117bb31SNicolin Chen case REG_ASRMCRA: 6753117bb31SNicolin Chen case REG_ASRMCRB: 6763117bb31SNicolin Chen case REG_ASRMCRC: 6773117bb31SNicolin Chen case REG_ASRMCR1A: 6783117bb31SNicolin Chen case REG_ASRMCR1B: 6793117bb31SNicolin Chen case REG_ASRMCR1C: 6803117bb31SNicolin Chen return true; 6813117bb31SNicolin Chen default: 6823117bb31SNicolin Chen return false; 6833117bb31SNicolin Chen } 6843117bb31SNicolin Chen } 6853117bb31SNicolin Chen 68686a570c5SNicolin Chen static struct reg_default fsl_asrc_reg[] = { 68786a570c5SNicolin Chen { REG_ASRCTR, 0x0000 }, { REG_ASRIER, 0x0000 }, 68886a570c5SNicolin Chen { REG_ASRCNCR, 0x0000 }, { REG_ASRCFG, 0x0000 }, 68986a570c5SNicolin Chen { REG_ASRCSR, 0x0000 }, { REG_ASRCDR1, 0x0000 }, 69086a570c5SNicolin Chen { REG_ASRCDR2, 0x0000 }, { REG_ASRSTR, 0x0000 }, 69186a570c5SNicolin Chen { REG_ASRRA, 0x0000 }, { REG_ASRRB, 0x0000 }, 69286a570c5SNicolin Chen { REG_ASRRC, 0x0000 }, { REG_ASRPM1, 0x0000 }, 69386a570c5SNicolin Chen { REG_ASRPM2, 0x0000 }, { REG_ASRPM3, 0x0000 }, 69486a570c5SNicolin Chen { REG_ASRPM4, 0x0000 }, { REG_ASRPM5, 0x0000 }, 69586a570c5SNicolin Chen { REG_ASRTFR1, 0x0000 }, { REG_ASRCCR, 0x0000 }, 69686a570c5SNicolin Chen { REG_ASRDIA, 0x0000 }, { REG_ASRDOA, 0x0000 }, 69786a570c5SNicolin Chen { REG_ASRDIB, 0x0000 }, { REG_ASRDOB, 0x0000 }, 69886a570c5SNicolin Chen { REG_ASRDIC, 0x0000 }, { REG_ASRDOC, 0x0000 }, 69986a570c5SNicolin Chen { REG_ASRIDRHA, 0x0000 }, { REG_ASRIDRLA, 0x0000 }, 70086a570c5SNicolin Chen { REG_ASRIDRHB, 0x0000 }, { REG_ASRIDRLB, 0x0000 }, 70186a570c5SNicolin Chen { REG_ASRIDRHC, 0x0000 }, { REG_ASRIDRLC, 0x0000 }, 70286a570c5SNicolin Chen { REG_ASR76K, 0x0A47 }, { REG_ASR56K, 0x0DF3 }, 70386a570c5SNicolin Chen { REG_ASRMCRA, 0x0000 }, { REG_ASRFSTA, 0x0000 }, 70486a570c5SNicolin Chen { REG_ASRMCRB, 0x0000 }, { REG_ASRFSTB, 0x0000 }, 70586a570c5SNicolin Chen { REG_ASRMCRC, 0x0000 }, { REG_ASRFSTC, 0x0000 }, 70686a570c5SNicolin Chen { REG_ASRMCR1A, 0x0000 }, { REG_ASRMCR1B, 0x0000 }, 70786a570c5SNicolin Chen { REG_ASRMCR1C, 0x0000 }, 70886a570c5SNicolin Chen }; 70986a570c5SNicolin Chen 710bf16d883SXiubo Li static const struct regmap_config fsl_asrc_regmap_config = { 7113117bb31SNicolin Chen .reg_bits = 32, 7123117bb31SNicolin Chen .reg_stride = 4, 7133117bb31SNicolin Chen .val_bits = 32, 7143117bb31SNicolin Chen 7153117bb31SNicolin Chen .max_register = REG_ASRMCR1C, 71686a570c5SNicolin Chen .reg_defaults = fsl_asrc_reg, 71786a570c5SNicolin Chen .num_reg_defaults = ARRAY_SIZE(fsl_asrc_reg), 7183117bb31SNicolin Chen .readable_reg = fsl_asrc_readable_reg, 7193117bb31SNicolin Chen .volatile_reg = fsl_asrc_volatile_reg, 7203117bb31SNicolin Chen .writeable_reg = fsl_asrc_writeable_reg, 721b4138868SMarek Vasut .cache_type = REGCACHE_FLAT, 7223117bb31SNicolin Chen }; 7233117bb31SNicolin Chen 7243117bb31SNicolin Chen /** 7253117bb31SNicolin Chen * Initialize ASRC registers with a default configurations 7263117bb31SNicolin Chen */ 7273117bb31SNicolin Chen static int fsl_asrc_init(struct fsl_asrc *asrc_priv) 7283117bb31SNicolin Chen { 7293117bb31SNicolin Chen /* Halt ASRC internal FP when input FIFO needs data for pair A, B, C */ 7303117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRCTR, ASRCTR_ASRCEN); 7313117bb31SNicolin Chen 7323117bb31SNicolin Chen /* Disable interrupt by default */ 7333117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRIER, 0x0); 7343117bb31SNicolin Chen 7353117bb31SNicolin Chen /* Apply recommended settings for parameters from Reference Manual */ 7363117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRPM1, 0x7fffff); 7373117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRPM2, 0x255555); 7383117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRPM3, 0xff7280); 7393117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRPM4, 0xff7280); 7403117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRPM5, 0xff7280); 7413117bb31SNicolin Chen 7423117bb31SNicolin Chen /* Base address for task queue FIFO. Set to 0x7C */ 7433117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRTFR1, 7443117bb31SNicolin Chen ASRTFR1_TF_BASE_MASK, ASRTFR1_TF_BASE(0xfc)); 7453117bb31SNicolin Chen 7463117bb31SNicolin Chen /* Set the processing clock for 76KHz to 133M */ 7473117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASR76K, 0x06D6); 7483117bb31SNicolin Chen 7493117bb31SNicolin Chen /* Set the processing clock for 56KHz to 133M */ 7503117bb31SNicolin Chen return regmap_write(asrc_priv->regmap, REG_ASR56K, 0x0947); 7513117bb31SNicolin Chen } 7523117bb31SNicolin Chen 7533117bb31SNicolin Chen /** 7543117bb31SNicolin Chen * Interrupt handler for ASRC 7553117bb31SNicolin Chen */ 7563117bb31SNicolin Chen static irqreturn_t fsl_asrc_isr(int irq, void *dev_id) 7573117bb31SNicolin Chen { 7583117bb31SNicolin Chen struct fsl_asrc *asrc_priv = (struct fsl_asrc *)dev_id; 7593117bb31SNicolin Chen struct device *dev = &asrc_priv->pdev->dev; 7603117bb31SNicolin Chen enum asrc_pair_index index; 7613117bb31SNicolin Chen u32 status; 7623117bb31SNicolin Chen 7633117bb31SNicolin Chen regmap_read(asrc_priv->regmap, REG_ASRSTR, &status); 7643117bb31SNicolin Chen 7653117bb31SNicolin Chen /* Clean overload error */ 7663117bb31SNicolin Chen regmap_write(asrc_priv->regmap, REG_ASRSTR, ASRSTR_AOLE); 7673117bb31SNicolin Chen 7683117bb31SNicolin Chen /* 7693117bb31SNicolin Chen * We here use dev_dbg() for all exceptions because ASRC itself does 7703117bb31SNicolin Chen * not care if FIFO overflowed or underrun while a warning in the 7713117bb31SNicolin Chen * interrupt would result a ridged conversion. 7723117bb31SNicolin Chen */ 7733117bb31SNicolin Chen for (index = ASRC_PAIR_A; index < ASRC_PAIR_MAX_NUM; index++) { 7743117bb31SNicolin Chen if (!asrc_priv->pair[index]) 7753117bb31SNicolin Chen continue; 7763117bb31SNicolin Chen 7773117bb31SNicolin Chen if (status & ASRSTR_ATQOL) { 7783117bb31SNicolin Chen asrc_priv->pair[index]->error |= ASRC_TASK_Q_OVERLOAD; 7793117bb31SNicolin Chen dev_dbg(dev, "ASRC Task Queue FIFO overload\n"); 7803117bb31SNicolin Chen } 7813117bb31SNicolin Chen 7823117bb31SNicolin Chen if (status & ASRSTR_AOOL(index)) { 7833117bb31SNicolin Chen asrc_priv->pair[index]->error |= ASRC_OUTPUT_TASK_OVERLOAD; 7843117bb31SNicolin Chen pair_dbg("Output Task Overload\n"); 7853117bb31SNicolin Chen } 7863117bb31SNicolin Chen 7873117bb31SNicolin Chen if (status & ASRSTR_AIOL(index)) { 7883117bb31SNicolin Chen asrc_priv->pair[index]->error |= ASRC_INPUT_TASK_OVERLOAD; 7893117bb31SNicolin Chen pair_dbg("Input Task Overload\n"); 7903117bb31SNicolin Chen } 7913117bb31SNicolin Chen 7923117bb31SNicolin Chen if (status & ASRSTR_AODO(index)) { 7933117bb31SNicolin Chen asrc_priv->pair[index]->error |= ASRC_OUTPUT_BUFFER_OVERFLOW; 7943117bb31SNicolin Chen pair_dbg("Output Data Buffer has overflowed\n"); 7953117bb31SNicolin Chen } 7963117bb31SNicolin Chen 7973117bb31SNicolin Chen if (status & ASRSTR_AIDU(index)) { 7983117bb31SNicolin Chen asrc_priv->pair[index]->error |= ASRC_INPUT_BUFFER_UNDERRUN; 7993117bb31SNicolin Chen pair_dbg("Input Data Buffer has underflowed\n"); 8003117bb31SNicolin Chen } 8013117bb31SNicolin Chen } 8023117bb31SNicolin Chen 8033117bb31SNicolin Chen return IRQ_HANDLED; 8043117bb31SNicolin Chen } 8053117bb31SNicolin Chen 8063117bb31SNicolin Chen static int fsl_asrc_probe(struct platform_device *pdev) 8073117bb31SNicolin Chen { 8083117bb31SNicolin Chen struct device_node *np = pdev->dev.of_node; 8093117bb31SNicolin Chen struct fsl_asrc *asrc_priv; 8103117bb31SNicolin Chen struct resource *res; 8113117bb31SNicolin Chen void __iomem *regs; 8123117bb31SNicolin Chen int irq, ret, i; 8133117bb31SNicolin Chen char tmp[16]; 8143117bb31SNicolin Chen 8153117bb31SNicolin Chen asrc_priv = devm_kzalloc(&pdev->dev, sizeof(*asrc_priv), GFP_KERNEL); 8163117bb31SNicolin Chen if (!asrc_priv) 8173117bb31SNicolin Chen return -ENOMEM; 8183117bb31SNicolin Chen 8193117bb31SNicolin Chen asrc_priv->pdev = pdev; 8203117bb31SNicolin Chen 8213117bb31SNicolin Chen /* Get the addresses and IRQ */ 8223117bb31SNicolin Chen res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 8233117bb31SNicolin Chen regs = devm_ioremap_resource(&pdev->dev, res); 8243117bb31SNicolin Chen if (IS_ERR(regs)) 8253117bb31SNicolin Chen return PTR_ERR(regs); 8263117bb31SNicolin Chen 8273117bb31SNicolin Chen asrc_priv->paddr = res->start; 8283117bb31SNicolin Chen 8293117bb31SNicolin Chen asrc_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs, 8303117bb31SNicolin Chen &fsl_asrc_regmap_config); 8313117bb31SNicolin Chen if (IS_ERR(asrc_priv->regmap)) { 8323117bb31SNicolin Chen dev_err(&pdev->dev, "failed to init regmap\n"); 8333117bb31SNicolin Chen return PTR_ERR(asrc_priv->regmap); 8343117bb31SNicolin Chen } 8353117bb31SNicolin Chen 8363117bb31SNicolin Chen irq = platform_get_irq(pdev, 0); 8373117bb31SNicolin Chen if (irq < 0) { 838f03038e5SFabio Estevam dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); 8393117bb31SNicolin Chen return irq; 8403117bb31SNicolin Chen } 8413117bb31SNicolin Chen 8423117bb31SNicolin Chen ret = devm_request_irq(&pdev->dev, irq, fsl_asrc_isr, 0, 843888c819dSFabio Estevam dev_name(&pdev->dev), asrc_priv); 8443117bb31SNicolin Chen if (ret) { 8453117bb31SNicolin Chen dev_err(&pdev->dev, "failed to claim irq %u: %d\n", irq, ret); 8463117bb31SNicolin Chen return ret; 8473117bb31SNicolin Chen } 8483117bb31SNicolin Chen 8493117bb31SNicolin Chen asrc_priv->mem_clk = devm_clk_get(&pdev->dev, "mem"); 8503117bb31SNicolin Chen if (IS_ERR(asrc_priv->mem_clk)) { 8513117bb31SNicolin Chen dev_err(&pdev->dev, "failed to get mem clock\n"); 852d387dd08SDan Carpenter return PTR_ERR(asrc_priv->mem_clk); 8533117bb31SNicolin Chen } 8543117bb31SNicolin Chen 8553117bb31SNicolin Chen asrc_priv->ipg_clk = devm_clk_get(&pdev->dev, "ipg"); 8563117bb31SNicolin Chen if (IS_ERR(asrc_priv->ipg_clk)) { 8573117bb31SNicolin Chen dev_err(&pdev->dev, "failed to get ipg clock\n"); 8583117bb31SNicolin Chen return PTR_ERR(asrc_priv->ipg_clk); 8593117bb31SNicolin Chen } 8603117bb31SNicolin Chen 86113b8a97aSShengjiu Wang asrc_priv->spba_clk = devm_clk_get(&pdev->dev, "spba"); 86213b8a97aSShengjiu Wang if (IS_ERR(asrc_priv->spba_clk)) 86313b8a97aSShengjiu Wang dev_warn(&pdev->dev, "failed to get spba clock\n"); 86413b8a97aSShengjiu Wang 8653117bb31SNicolin Chen for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { 8663117bb31SNicolin Chen sprintf(tmp, "asrck_%x", i); 8673117bb31SNicolin Chen asrc_priv->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp); 8683117bb31SNicolin Chen if (IS_ERR(asrc_priv->asrck_clk[i])) { 8693117bb31SNicolin Chen dev_err(&pdev->dev, "failed to get %s clock\n", tmp); 8703117bb31SNicolin Chen return PTR_ERR(asrc_priv->asrck_clk[i]); 8713117bb31SNicolin Chen } 8723117bb31SNicolin Chen } 8733117bb31SNicolin Chen 874f3d8ac8cSFabio Estevam if (of_device_is_compatible(np, "fsl,imx35-asrc")) { 8753117bb31SNicolin Chen asrc_priv->channel_bits = 3; 8763117bb31SNicolin Chen clk_map[IN] = input_clk_map_imx35; 8773117bb31SNicolin Chen clk_map[OUT] = output_clk_map_imx35; 8783117bb31SNicolin Chen } else { 8793117bb31SNicolin Chen asrc_priv->channel_bits = 4; 8803117bb31SNicolin Chen clk_map[IN] = input_clk_map_imx53; 8813117bb31SNicolin Chen clk_map[OUT] = output_clk_map_imx53; 8823117bb31SNicolin Chen } 8833117bb31SNicolin Chen 8843117bb31SNicolin Chen ret = fsl_asrc_init(asrc_priv); 8853117bb31SNicolin Chen if (ret) { 8863117bb31SNicolin Chen dev_err(&pdev->dev, "failed to init asrc %d\n", ret); 887c0296950SFabio Estevam return ret; 8883117bb31SNicolin Chen } 8893117bb31SNicolin Chen 8903117bb31SNicolin Chen asrc_priv->channel_avail = 10; 8913117bb31SNicolin Chen 8923117bb31SNicolin Chen ret = of_property_read_u32(np, "fsl,asrc-rate", 8933117bb31SNicolin Chen &asrc_priv->asrc_rate); 8943117bb31SNicolin Chen if (ret) { 8953117bb31SNicolin Chen dev_err(&pdev->dev, "failed to get output rate\n"); 896c0296950SFabio Estevam return ret; 8973117bb31SNicolin Chen } 8983117bb31SNicolin Chen 8993117bb31SNicolin Chen ret = of_property_read_u32(np, "fsl,asrc-width", 9003117bb31SNicolin Chen &asrc_priv->asrc_width); 9013117bb31SNicolin Chen if (ret) { 9023117bb31SNicolin Chen dev_err(&pdev->dev, "failed to get output width\n"); 903c0296950SFabio Estevam return ret; 9043117bb31SNicolin Chen } 9053117bb31SNicolin Chen 9063117bb31SNicolin Chen if (asrc_priv->asrc_width != 16 && asrc_priv->asrc_width != 24) { 9073117bb31SNicolin Chen dev_warn(&pdev->dev, "unsupported width, switching to 24bit\n"); 9083117bb31SNicolin Chen asrc_priv->asrc_width = 24; 9093117bb31SNicolin Chen } 9103117bb31SNicolin Chen 9113117bb31SNicolin Chen platform_set_drvdata(pdev, asrc_priv); 9123117bb31SNicolin Chen pm_runtime_enable(&pdev->dev); 9133117bb31SNicolin Chen spin_lock_init(&asrc_priv->lock); 9143117bb31SNicolin Chen 9153117bb31SNicolin Chen ret = devm_snd_soc_register_component(&pdev->dev, &fsl_asrc_component, 9163117bb31SNicolin Chen &fsl_asrc_dai, 1); 9173117bb31SNicolin Chen if (ret) { 9183117bb31SNicolin Chen dev_err(&pdev->dev, "failed to register ASoC DAI\n"); 9193117bb31SNicolin Chen return ret; 9203117bb31SNicolin Chen } 9213117bb31SNicolin Chen 9223117bb31SNicolin Chen return 0; 9233117bb31SNicolin Chen } 9243117bb31SNicolin Chen 925641d334bSRafael J. Wysocki #ifdef CONFIG_PM 9263117bb31SNicolin Chen static int fsl_asrc_runtime_resume(struct device *dev) 9273117bb31SNicolin Chen { 9283117bb31SNicolin Chen struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); 929b1ade0f2SFabio Estevam int i, ret; 9303117bb31SNicolin Chen 931b1ade0f2SFabio Estevam ret = clk_prepare_enable(asrc_priv->mem_clk); 932b1ade0f2SFabio Estevam if (ret) 933b1ade0f2SFabio Estevam return ret; 934b1ade0f2SFabio Estevam ret = clk_prepare_enable(asrc_priv->ipg_clk); 935b1ade0f2SFabio Estevam if (ret) 936b1ade0f2SFabio Estevam goto disable_mem_clk; 93713b8a97aSShengjiu Wang if (!IS_ERR(asrc_priv->spba_clk)) { 93813b8a97aSShengjiu Wang ret = clk_prepare_enable(asrc_priv->spba_clk); 93913b8a97aSShengjiu Wang if (ret) 94013b8a97aSShengjiu Wang goto disable_ipg_clk; 94113b8a97aSShengjiu Wang } 942b1ade0f2SFabio Estevam for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { 943b1ade0f2SFabio Estevam ret = clk_prepare_enable(asrc_priv->asrck_clk[i]); 944b1ade0f2SFabio Estevam if (ret) 945b1ade0f2SFabio Estevam goto disable_asrck_clk; 946b1ade0f2SFabio Estevam } 9473117bb31SNicolin Chen 9483117bb31SNicolin Chen return 0; 949b1ade0f2SFabio Estevam 950b1ade0f2SFabio Estevam disable_asrck_clk: 951b1ade0f2SFabio Estevam for (i--; i >= 0; i--) 952b1ade0f2SFabio Estevam clk_disable_unprepare(asrc_priv->asrck_clk[i]); 95313b8a97aSShengjiu Wang if (!IS_ERR(asrc_priv->spba_clk)) 95413b8a97aSShengjiu Wang clk_disable_unprepare(asrc_priv->spba_clk); 95513b8a97aSShengjiu Wang disable_ipg_clk: 956b1ade0f2SFabio Estevam clk_disable_unprepare(asrc_priv->ipg_clk); 957b1ade0f2SFabio Estevam disable_mem_clk: 958b1ade0f2SFabio Estevam clk_disable_unprepare(asrc_priv->mem_clk); 959b1ade0f2SFabio Estevam return ret; 9603117bb31SNicolin Chen } 9613117bb31SNicolin Chen 9623117bb31SNicolin Chen static int fsl_asrc_runtime_suspend(struct device *dev) 9633117bb31SNicolin Chen { 9643117bb31SNicolin Chen struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); 9653117bb31SNicolin Chen int i; 9663117bb31SNicolin Chen 9673117bb31SNicolin Chen for (i = 0; i < ASRC_CLK_MAX_NUM; i++) 9683117bb31SNicolin Chen clk_disable_unprepare(asrc_priv->asrck_clk[i]); 96913b8a97aSShengjiu Wang if (!IS_ERR(asrc_priv->spba_clk)) 97013b8a97aSShengjiu Wang clk_disable_unprepare(asrc_priv->spba_clk); 9713117bb31SNicolin Chen clk_disable_unprepare(asrc_priv->ipg_clk); 9723117bb31SNicolin Chen clk_disable_unprepare(asrc_priv->mem_clk); 9733117bb31SNicolin Chen 9743117bb31SNicolin Chen return 0; 9753117bb31SNicolin Chen } 976641d334bSRafael J. Wysocki #endif /* CONFIG_PM */ 9773117bb31SNicolin Chen 978d3dacda9SFabio Estevam #ifdef CONFIG_PM_SLEEP 9793117bb31SNicolin Chen static int fsl_asrc_suspend(struct device *dev) 9803117bb31SNicolin Chen { 9813117bb31SNicolin Chen struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); 9823117bb31SNicolin Chen 983d44c6114SZidan Wang regmap_read(asrc_priv->regmap, REG_ASRCFG, 984d44c6114SZidan Wang &asrc_priv->regcache_cfg); 985d44c6114SZidan Wang 9863117bb31SNicolin Chen regcache_cache_only(asrc_priv->regmap, true); 9873117bb31SNicolin Chen regcache_mark_dirty(asrc_priv->regmap); 9883117bb31SNicolin Chen 9893117bb31SNicolin Chen return 0; 9903117bb31SNicolin Chen } 9913117bb31SNicolin Chen 9923117bb31SNicolin Chen static int fsl_asrc_resume(struct device *dev) 9933117bb31SNicolin Chen { 9943117bb31SNicolin Chen struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); 9953117bb31SNicolin Chen u32 asrctr; 9963117bb31SNicolin Chen 9973117bb31SNicolin Chen /* Stop all pairs provisionally */ 9983117bb31SNicolin Chen regmap_read(asrc_priv->regmap, REG_ASRCTR, &asrctr); 9993117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, 10003117bb31SNicolin Chen ASRCTR_ASRCEi_ALL_MASK, 0); 10013117bb31SNicolin Chen 10023117bb31SNicolin Chen /* Restore all registers */ 10033117bb31SNicolin Chen regcache_cache_only(asrc_priv->regmap, false); 10043117bb31SNicolin Chen regcache_sync(asrc_priv->regmap); 10053117bb31SNicolin Chen 1006d44c6114SZidan Wang regmap_update_bits(asrc_priv->regmap, REG_ASRCFG, 1007d44c6114SZidan Wang ASRCFG_NDPRi_ALL_MASK | ASRCFG_POSTMODi_ALL_MASK | 1008d44c6114SZidan Wang ASRCFG_PREMODi_ALL_MASK, asrc_priv->regcache_cfg); 1009d44c6114SZidan Wang 10103117bb31SNicolin Chen /* Restart enabled pairs */ 10113117bb31SNicolin Chen regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, 10123117bb31SNicolin Chen ASRCTR_ASRCEi_ALL_MASK, asrctr); 10133117bb31SNicolin Chen 10143117bb31SNicolin Chen return 0; 10153117bb31SNicolin Chen } 10163117bb31SNicolin Chen #endif /* CONFIG_PM_SLEEP */ 10173117bb31SNicolin Chen 10183117bb31SNicolin Chen static const struct dev_pm_ops fsl_asrc_pm = { 10193117bb31SNicolin Chen SET_RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL) 10203117bb31SNicolin Chen SET_SYSTEM_SLEEP_PM_OPS(fsl_asrc_suspend, fsl_asrc_resume) 10213117bb31SNicolin Chen }; 10223117bb31SNicolin Chen 10233117bb31SNicolin Chen static const struct of_device_id fsl_asrc_ids[] = { 10243117bb31SNicolin Chen { .compatible = "fsl,imx35-asrc", }, 10253117bb31SNicolin Chen { .compatible = "fsl,imx53-asrc", }, 10263117bb31SNicolin Chen {} 10273117bb31SNicolin Chen }; 10283117bb31SNicolin Chen MODULE_DEVICE_TABLE(of, fsl_asrc_ids); 10293117bb31SNicolin Chen 10303117bb31SNicolin Chen static struct platform_driver fsl_asrc_driver = { 10313117bb31SNicolin Chen .probe = fsl_asrc_probe, 10323117bb31SNicolin Chen .driver = { 10333117bb31SNicolin Chen .name = "fsl-asrc", 10343117bb31SNicolin Chen .of_match_table = fsl_asrc_ids, 10353117bb31SNicolin Chen .pm = &fsl_asrc_pm, 10363117bb31SNicolin Chen }, 10373117bb31SNicolin Chen }; 10383117bb31SNicolin Chen module_platform_driver(fsl_asrc_driver); 10393117bb31SNicolin Chen 10403117bb31SNicolin Chen MODULE_DESCRIPTION("Freescale ASRC ASoC driver"); 10413117bb31SNicolin Chen MODULE_AUTHOR("Nicolin Chen <nicoleotsuka@gmail.com>"); 10423117bb31SNicolin Chen MODULE_ALIAS("platform:fsl-asrc"); 10433117bb31SNicolin Chen MODULE_LICENSE("GPL v2"); 1044