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