162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// Freescale ASRC ALSA SoC Digital Audio Interface (DAI) driver 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright (C) 2014 Freescale Semiconductor, Inc. 662306a36Sopenharmony_ci// 762306a36Sopenharmony_ci// Author: Nicolin Chen <nicoleotsuka@gmail.com> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/clk.h> 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/of_platform.h> 1462306a36Sopenharmony_ci#include <linux/dma/imx-dma.h> 1562306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1662306a36Sopenharmony_ci#include <sound/dmaengine_pcm.h> 1762306a36Sopenharmony_ci#include <sound/pcm_params.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "fsl_asrc.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define IDEAL_RATIO_DECIMAL_DEPTH 26 2262306a36Sopenharmony_ci#define DIVIDER_NUM 64 2362306a36Sopenharmony_ci#define INIT_RETRY_NUM 50 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define pair_err(fmt, ...) \ 2662306a36Sopenharmony_ci dev_err(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define pair_dbg(fmt, ...) \ 2962306a36Sopenharmony_ci dev_dbg(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define pair_warn(fmt, ...) \ 3262306a36Sopenharmony_ci dev_warn(&asrc->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* Corresponding to process_option */ 3562306a36Sopenharmony_cistatic unsigned int supported_asrc_rate[] = { 3662306a36Sopenharmony_ci 5512, 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 3762306a36Sopenharmony_ci 64000, 88200, 96000, 128000, 176400, 192000, 3862306a36Sopenharmony_ci}; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic struct snd_pcm_hw_constraint_list fsl_asrc_rate_constraints = { 4162306a36Sopenharmony_ci .count = ARRAY_SIZE(supported_asrc_rate), 4262306a36Sopenharmony_ci .list = supported_asrc_rate, 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* 4662306a36Sopenharmony_ci * The following tables map the relationship between asrc_inclk/asrc_outclk in 4762306a36Sopenharmony_ci * fsl_asrc.h and the registers of ASRCSR 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_cistatic unsigned char input_clk_map_imx35[ASRC_CLK_MAP_LEN] = { 5062306a36Sopenharmony_ci 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 5162306a36Sopenharmony_ci 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5262306a36Sopenharmony_ci 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic unsigned char output_clk_map_imx35[ASRC_CLK_MAP_LEN] = { 5662306a36Sopenharmony_ci 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 5762306a36Sopenharmony_ci 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5862306a36Sopenharmony_ci 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* i.MX53 uses the same map for input and output */ 6262306a36Sopenharmony_cistatic unsigned char input_clk_map_imx53[ASRC_CLK_MAP_LEN] = { 6362306a36Sopenharmony_ci/* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf */ 6462306a36Sopenharmony_ci 0x0, 0x1, 0x2, 0x7, 0x4, 0x5, 0x6, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xf, 0xe, 0xd, 6562306a36Sopenharmony_ci 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 6662306a36Sopenharmony_ci 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 6762306a36Sopenharmony_ci}; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic unsigned char output_clk_map_imx53[ASRC_CLK_MAP_LEN] = { 7062306a36Sopenharmony_ci/* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf */ 7162306a36Sopenharmony_ci 0x8, 0x9, 0xa, 0x7, 0xc, 0x5, 0x6, 0xb, 0x0, 0x1, 0x2, 0x3, 0x4, 0xf, 0xe, 0xd, 7262306a36Sopenharmony_ci 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 7362306a36Sopenharmony_ci 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 7462306a36Sopenharmony_ci}; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* 7762306a36Sopenharmony_ci * i.MX8QM/i.MX8QXP uses the same map for input and output. 7862306a36Sopenharmony_ci * clk_map_imx8qm[0] is for i.MX8QM asrc0 7962306a36Sopenharmony_ci * clk_map_imx8qm[1] is for i.MX8QM asrc1 8062306a36Sopenharmony_ci * clk_map_imx8qxp[0] is for i.MX8QXP asrc0 8162306a36Sopenharmony_ci * clk_map_imx8qxp[1] is for i.MX8QXP asrc1 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_cistatic unsigned char clk_map_imx8qm[2][ASRC_CLK_MAP_LEN] = { 8462306a36Sopenharmony_ci { 8562306a36Sopenharmony_ci 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, 8662306a36Sopenharmony_ci 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 8762306a36Sopenharmony_ci 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 8862306a36Sopenharmony_ci }, 8962306a36Sopenharmony_ci { 9062306a36Sopenharmony_ci 0xf, 0xf, 0xf, 0xf, 0xf, 0x7, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, 9162306a36Sopenharmony_ci 0x0, 0x1, 0x2, 0x3, 0xb, 0xc, 0xf, 0xf, 0xd, 0xe, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 9262306a36Sopenharmony_ci 0x4, 0x5, 0x6, 0xf, 0x8, 0x9, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 9362306a36Sopenharmony_ci }, 9462306a36Sopenharmony_ci}; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic unsigned char clk_map_imx8qxp[2][ASRC_CLK_MAP_LEN] = { 9762306a36Sopenharmony_ci { 9862306a36Sopenharmony_ci 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, 9962306a36Sopenharmony_ci 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0xf, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xf, 0xf, 10062306a36Sopenharmony_ci 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 10162306a36Sopenharmony_ci }, 10262306a36Sopenharmony_ci { 10362306a36Sopenharmony_ci 0xf, 0xf, 0xf, 0xf, 0xf, 0x7, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, 10462306a36Sopenharmony_ci 0x0, 0x1, 0x2, 0x3, 0x7, 0x8, 0xf, 0xf, 0x9, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 10562306a36Sopenharmony_ci 0xf, 0xf, 0x6, 0xf, 0xf, 0xf, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 10662306a36Sopenharmony_ci }, 10762306a36Sopenharmony_ci}; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/* 11062306a36Sopenharmony_ci * According to RM, the divider range is 1 ~ 8, 11162306a36Sopenharmony_ci * prescaler is power of 2 from 1 ~ 128. 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_cistatic int asrc_clk_divider[DIVIDER_NUM] = { 11462306a36Sopenharmony_ci 1, 2, 4, 8, 16, 32, 64, 128, /* divider = 1 */ 11562306a36Sopenharmony_ci 2, 4, 8, 16, 32, 64, 128, 256, /* divider = 2 */ 11662306a36Sopenharmony_ci 3, 6, 12, 24, 48, 96, 192, 384, /* divider = 3 */ 11762306a36Sopenharmony_ci 4, 8, 16, 32, 64, 128, 256, 512, /* divider = 4 */ 11862306a36Sopenharmony_ci 5, 10, 20, 40, 80, 160, 320, 640, /* divider = 5 */ 11962306a36Sopenharmony_ci 6, 12, 24, 48, 96, 192, 384, 768, /* divider = 6 */ 12062306a36Sopenharmony_ci 7, 14, 28, 56, 112, 224, 448, 896, /* divider = 7 */ 12162306a36Sopenharmony_ci 8, 16, 32, 64, 128, 256, 512, 1024, /* divider = 8 */ 12262306a36Sopenharmony_ci}; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/* 12562306a36Sopenharmony_ci * Check if the divider is available for internal ratio mode 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_cistatic bool fsl_asrc_divider_avail(int clk_rate, int rate, int *div) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci u32 rem, i; 13062306a36Sopenharmony_ci u64 n; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (div) 13362306a36Sopenharmony_ci *div = 0; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (clk_rate == 0 || rate == 0) 13662306a36Sopenharmony_ci return false; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci n = clk_rate; 13962306a36Sopenharmony_ci rem = do_div(n, rate); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (div) 14262306a36Sopenharmony_ci *div = n; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (rem != 0) 14562306a36Sopenharmony_ci return false; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci for (i = 0; i < DIVIDER_NUM; i++) { 14862306a36Sopenharmony_ci if (n == asrc_clk_divider[i]) 14962306a36Sopenharmony_ci break; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (i == DIVIDER_NUM) 15362306a36Sopenharmony_ci return false; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return true; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci/** 15962306a36Sopenharmony_ci * fsl_asrc_sel_proc - Select the pre-processing and post-processing options 16062306a36Sopenharmony_ci * @inrate: input sample rate 16162306a36Sopenharmony_ci * @outrate: output sample rate 16262306a36Sopenharmony_ci * @pre_proc: return value for pre-processing option 16362306a36Sopenharmony_ci * @post_proc: return value for post-processing option 16462306a36Sopenharmony_ci * 16562306a36Sopenharmony_ci * Make sure to exclude following unsupported cases before 16662306a36Sopenharmony_ci * calling this function: 16762306a36Sopenharmony_ci * 1) inrate > 8.125 * outrate 16862306a36Sopenharmony_ci * 2) inrate > 16.125 * outrate 16962306a36Sopenharmony_ci * 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_cistatic void fsl_asrc_sel_proc(int inrate, int outrate, 17262306a36Sopenharmony_ci int *pre_proc, int *post_proc) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci bool post_proc_cond2; 17562306a36Sopenharmony_ci bool post_proc_cond0; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* select pre_proc between [0, 2] */ 17862306a36Sopenharmony_ci if (inrate * 8 > 33 * outrate) 17962306a36Sopenharmony_ci *pre_proc = 2; 18062306a36Sopenharmony_ci else if (inrate * 8 > 15 * outrate) { 18162306a36Sopenharmony_ci if (inrate > 152000) 18262306a36Sopenharmony_ci *pre_proc = 2; 18362306a36Sopenharmony_ci else 18462306a36Sopenharmony_ci *pre_proc = 1; 18562306a36Sopenharmony_ci } else if (inrate < 76000) 18662306a36Sopenharmony_ci *pre_proc = 0; 18762306a36Sopenharmony_ci else if (inrate > 152000) 18862306a36Sopenharmony_ci *pre_proc = 2; 18962306a36Sopenharmony_ci else 19062306a36Sopenharmony_ci *pre_proc = 1; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* Condition for selection of post-processing */ 19362306a36Sopenharmony_ci post_proc_cond2 = (inrate * 15 > outrate * 16 && outrate < 56000) || 19462306a36Sopenharmony_ci (inrate > 56000 && outrate < 56000); 19562306a36Sopenharmony_ci post_proc_cond0 = inrate * 23 < outrate * 8; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (post_proc_cond2) 19862306a36Sopenharmony_ci *post_proc = 2; 19962306a36Sopenharmony_ci else if (post_proc_cond0) 20062306a36Sopenharmony_ci *post_proc = 0; 20162306a36Sopenharmony_ci else 20262306a36Sopenharmony_ci *post_proc = 1; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci/** 20662306a36Sopenharmony_ci * fsl_asrc_request_pair - Request ASRC pair 20762306a36Sopenharmony_ci * @channels: number of channels 20862306a36Sopenharmony_ci * @pair: pointer to pair 20962306a36Sopenharmony_ci * 21062306a36Sopenharmony_ci * It assigns pair by the order of A->C->B because allocation of pair B, 21162306a36Sopenharmony_ci * within range [ANCA, ANCA+ANCB-1], depends on the channels of pair A 21262306a36Sopenharmony_ci * while pair A and pair C are comparatively independent. 21362306a36Sopenharmony_ci */ 21462306a36Sopenharmony_cistatic int fsl_asrc_request_pair(int channels, struct fsl_asrc_pair *pair) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci enum asrc_pair_index index = ASRC_INVALID_PAIR; 21762306a36Sopenharmony_ci struct fsl_asrc *asrc = pair->asrc; 21862306a36Sopenharmony_ci struct device *dev = &asrc->pdev->dev; 21962306a36Sopenharmony_ci unsigned long lock_flags; 22062306a36Sopenharmony_ci int i, ret = 0; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci spin_lock_irqsave(&asrc->lock, lock_flags); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) { 22562306a36Sopenharmony_ci if (asrc->pair[i] != NULL) 22662306a36Sopenharmony_ci continue; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci index = i; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (i != ASRC_PAIR_B) 23162306a36Sopenharmony_ci break; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (index == ASRC_INVALID_PAIR) { 23562306a36Sopenharmony_ci dev_err(dev, "all pairs are busy now\n"); 23662306a36Sopenharmony_ci ret = -EBUSY; 23762306a36Sopenharmony_ci } else if (asrc->channel_avail < channels) { 23862306a36Sopenharmony_ci dev_err(dev, "can't afford required channels: %d\n", channels); 23962306a36Sopenharmony_ci ret = -EINVAL; 24062306a36Sopenharmony_ci } else { 24162306a36Sopenharmony_ci asrc->channel_avail -= channels; 24262306a36Sopenharmony_ci asrc->pair[index] = pair; 24362306a36Sopenharmony_ci pair->channels = channels; 24462306a36Sopenharmony_ci pair->index = index; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci spin_unlock_irqrestore(&asrc->lock, lock_flags); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci return ret; 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci/** 25362306a36Sopenharmony_ci * fsl_asrc_release_pair - Release ASRC pair 25462306a36Sopenharmony_ci * @pair: pair to release 25562306a36Sopenharmony_ci * 25662306a36Sopenharmony_ci * It clears the resource from asrc and releases the occupied channels. 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_cistatic void fsl_asrc_release_pair(struct fsl_asrc_pair *pair) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci struct fsl_asrc *asrc = pair->asrc; 26162306a36Sopenharmony_ci enum asrc_pair_index index = pair->index; 26262306a36Sopenharmony_ci unsigned long lock_flags; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* Make sure the pair is disabled */ 26562306a36Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCTR, 26662306a36Sopenharmony_ci ASRCTR_ASRCEi_MASK(index), 0); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci spin_lock_irqsave(&asrc->lock, lock_flags); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci asrc->channel_avail += pair->channels; 27162306a36Sopenharmony_ci asrc->pair[index] = NULL; 27262306a36Sopenharmony_ci pair->error = 0; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci spin_unlock_irqrestore(&asrc->lock, lock_flags); 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci/** 27862306a36Sopenharmony_ci * fsl_asrc_set_watermarks- configure input and output thresholds 27962306a36Sopenharmony_ci * @pair: pointer to pair 28062306a36Sopenharmony_ci * @in: input threshold 28162306a36Sopenharmony_ci * @out: output threshold 28262306a36Sopenharmony_ci */ 28362306a36Sopenharmony_cistatic void fsl_asrc_set_watermarks(struct fsl_asrc_pair *pair, u32 in, u32 out) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci struct fsl_asrc *asrc = pair->asrc; 28662306a36Sopenharmony_ci enum asrc_pair_index index = pair->index; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRMCR(index), 28962306a36Sopenharmony_ci ASRMCRi_EXTTHRSHi_MASK | 29062306a36Sopenharmony_ci ASRMCRi_INFIFO_THRESHOLD_MASK | 29162306a36Sopenharmony_ci ASRMCRi_OUTFIFO_THRESHOLD_MASK, 29262306a36Sopenharmony_ci ASRMCRi_EXTTHRSHi | 29362306a36Sopenharmony_ci ASRMCRi_INFIFO_THRESHOLD(in) | 29462306a36Sopenharmony_ci ASRMCRi_OUTFIFO_THRESHOLD(out)); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci/** 29862306a36Sopenharmony_ci * fsl_asrc_cal_asrck_divisor - Calculate the total divisor between asrck clock rate and sample rate 29962306a36Sopenharmony_ci * @pair: pointer to pair 30062306a36Sopenharmony_ci * @div: divider 30162306a36Sopenharmony_ci * 30262306a36Sopenharmony_ci * It follows the formula clk_rate = samplerate * (2 ^ prescaler) * divider 30362306a36Sopenharmony_ci */ 30462306a36Sopenharmony_cistatic u32 fsl_asrc_cal_asrck_divisor(struct fsl_asrc_pair *pair, u32 div) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci u32 ps; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci /* Calculate the divisors: prescaler [2^0, 2^7], divder [1, 8] */ 30962306a36Sopenharmony_ci for (ps = 0; div > 8; ps++) 31062306a36Sopenharmony_ci div >>= 1; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci return ((div - 1) << ASRCDRi_AxCPi_WIDTH) | ps; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci/** 31662306a36Sopenharmony_ci * fsl_asrc_set_ideal_ratio - Calculate and set the ratio for Ideal Ratio mode only 31762306a36Sopenharmony_ci * @pair: pointer to pair 31862306a36Sopenharmony_ci * @inrate: input rate 31962306a36Sopenharmony_ci * @outrate: output rate 32062306a36Sopenharmony_ci * 32162306a36Sopenharmony_ci * The ratio is a 32-bit fixed point value with 26 fractional bits. 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_cistatic int fsl_asrc_set_ideal_ratio(struct fsl_asrc_pair *pair, 32462306a36Sopenharmony_ci int inrate, int outrate) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci struct fsl_asrc *asrc = pair->asrc; 32762306a36Sopenharmony_ci enum asrc_pair_index index = pair->index; 32862306a36Sopenharmony_ci unsigned long ratio; 32962306a36Sopenharmony_ci int i; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (!outrate) { 33262306a36Sopenharmony_ci pair_err("output rate should not be zero\n"); 33362306a36Sopenharmony_ci return -EINVAL; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* Calculate the intergal part of the ratio */ 33762306a36Sopenharmony_ci ratio = (inrate / outrate) << IDEAL_RATIO_DECIMAL_DEPTH; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* ... and then the 26 depth decimal part */ 34062306a36Sopenharmony_ci inrate %= outrate; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci for (i = 1; i <= IDEAL_RATIO_DECIMAL_DEPTH; i++) { 34362306a36Sopenharmony_ci inrate <<= 1; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if (inrate < outrate) 34662306a36Sopenharmony_ci continue; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci ratio |= 1 << (IDEAL_RATIO_DECIMAL_DEPTH - i); 34962306a36Sopenharmony_ci inrate -= outrate; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (!inrate) 35262306a36Sopenharmony_ci break; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRIDRL(index), ratio); 35662306a36Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRIDRH(index), ratio >> 24); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci return 0; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci/** 36262306a36Sopenharmony_ci * fsl_asrc_config_pair - Configure the assigned ASRC pair 36362306a36Sopenharmony_ci * @pair: pointer to pair 36462306a36Sopenharmony_ci * @use_ideal_rate: boolean configuration 36562306a36Sopenharmony_ci * 36662306a36Sopenharmony_ci * It configures those ASRC registers according to a configuration instance 36762306a36Sopenharmony_ci * of struct asrc_config which includes in/output sample rate, width, channel 36862306a36Sopenharmony_ci * and clock settings. 36962306a36Sopenharmony_ci * 37062306a36Sopenharmony_ci * Note: 37162306a36Sopenharmony_ci * The ideal ratio configuration can work with a flexible clock rate setting. 37262306a36Sopenharmony_ci * Using IDEAL_RATIO_RATE gives a faster converting speed but overloads ASRC. 37362306a36Sopenharmony_ci * For a regular audio playback, the clock rate should not be slower than an 37462306a36Sopenharmony_ci * clock rate aligning with the output sample rate; For a use case requiring 37562306a36Sopenharmony_ci * faster conversion, set use_ideal_rate to have the faster speed. 37662306a36Sopenharmony_ci */ 37762306a36Sopenharmony_cistatic int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci struct fsl_asrc_pair_priv *pair_priv = pair->private; 38062306a36Sopenharmony_ci struct asrc_config *config = pair_priv->config; 38162306a36Sopenharmony_ci struct fsl_asrc *asrc = pair->asrc; 38262306a36Sopenharmony_ci struct fsl_asrc_priv *asrc_priv = asrc->private; 38362306a36Sopenharmony_ci enum asrc_pair_index index = pair->index; 38462306a36Sopenharmony_ci enum asrc_word_width input_word_width; 38562306a36Sopenharmony_ci enum asrc_word_width output_word_width; 38662306a36Sopenharmony_ci u32 inrate, outrate, indiv, outdiv; 38762306a36Sopenharmony_ci u32 clk_index[2], div[2]; 38862306a36Sopenharmony_ci u64 clk_rate; 38962306a36Sopenharmony_ci int in, out, channels; 39062306a36Sopenharmony_ci int pre_proc, post_proc; 39162306a36Sopenharmony_ci struct clk *clk; 39262306a36Sopenharmony_ci bool ideal, div_avail; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (!config) { 39562306a36Sopenharmony_ci pair_err("invalid pair config\n"); 39662306a36Sopenharmony_ci return -EINVAL; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* Validate channels */ 40062306a36Sopenharmony_ci if (config->channel_num < 1 || config->channel_num > 10) { 40162306a36Sopenharmony_ci pair_err("does not support %d channels\n", config->channel_num); 40262306a36Sopenharmony_ci return -EINVAL; 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci switch (snd_pcm_format_width(config->input_format)) { 40662306a36Sopenharmony_ci case 8: 40762306a36Sopenharmony_ci input_word_width = ASRC_WIDTH_8_BIT; 40862306a36Sopenharmony_ci break; 40962306a36Sopenharmony_ci case 16: 41062306a36Sopenharmony_ci input_word_width = ASRC_WIDTH_16_BIT; 41162306a36Sopenharmony_ci break; 41262306a36Sopenharmony_ci case 24: 41362306a36Sopenharmony_ci input_word_width = ASRC_WIDTH_24_BIT; 41462306a36Sopenharmony_ci break; 41562306a36Sopenharmony_ci default: 41662306a36Sopenharmony_ci pair_err("does not support this input format, %d\n", 41762306a36Sopenharmony_ci config->input_format); 41862306a36Sopenharmony_ci return -EINVAL; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci switch (snd_pcm_format_width(config->output_format)) { 42262306a36Sopenharmony_ci case 16: 42362306a36Sopenharmony_ci output_word_width = ASRC_WIDTH_16_BIT; 42462306a36Sopenharmony_ci break; 42562306a36Sopenharmony_ci case 24: 42662306a36Sopenharmony_ci output_word_width = ASRC_WIDTH_24_BIT; 42762306a36Sopenharmony_ci break; 42862306a36Sopenharmony_ci default: 42962306a36Sopenharmony_ci pair_err("does not support this output format, %d\n", 43062306a36Sopenharmony_ci config->output_format); 43162306a36Sopenharmony_ci return -EINVAL; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci inrate = config->input_sample_rate; 43562306a36Sopenharmony_ci outrate = config->output_sample_rate; 43662306a36Sopenharmony_ci ideal = config->inclk == INCLK_NONE; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* Validate input and output sample rates */ 43962306a36Sopenharmony_ci for (in = 0; in < ARRAY_SIZE(supported_asrc_rate); in++) 44062306a36Sopenharmony_ci if (inrate == supported_asrc_rate[in]) 44162306a36Sopenharmony_ci break; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (in == ARRAY_SIZE(supported_asrc_rate)) { 44462306a36Sopenharmony_ci pair_err("unsupported input sample rate: %dHz\n", inrate); 44562306a36Sopenharmony_ci return -EINVAL; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci for (out = 0; out < ARRAY_SIZE(supported_asrc_rate); out++) 44962306a36Sopenharmony_ci if (outrate == supported_asrc_rate[out]) 45062306a36Sopenharmony_ci break; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci if (out == ARRAY_SIZE(supported_asrc_rate)) { 45362306a36Sopenharmony_ci pair_err("unsupported output sample rate: %dHz\n", outrate); 45462306a36Sopenharmony_ci return -EINVAL; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if ((outrate >= 5512 && outrate <= 30000) && 45862306a36Sopenharmony_ci (outrate > 24 * inrate || inrate > 8 * outrate)) { 45962306a36Sopenharmony_ci pair_err("exceed supported ratio range [1/24, 8] for \ 46062306a36Sopenharmony_ci inrate/outrate: %d/%d\n", inrate, outrate); 46162306a36Sopenharmony_ci return -EINVAL; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci /* Validate input and output clock sources */ 46562306a36Sopenharmony_ci clk_index[IN] = asrc_priv->clk_map[IN][config->inclk]; 46662306a36Sopenharmony_ci clk_index[OUT] = asrc_priv->clk_map[OUT][config->outclk]; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* We only have output clock for ideal ratio mode */ 46962306a36Sopenharmony_ci clk = asrc_priv->asrck_clk[clk_index[ideal ? OUT : IN]]; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci clk_rate = clk_get_rate(clk); 47262306a36Sopenharmony_ci div_avail = fsl_asrc_divider_avail(clk_rate, inrate, &div[IN]); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci /* 47562306a36Sopenharmony_ci * The divider range is [1, 1024], defined by the hardware. For non- 47662306a36Sopenharmony_ci * ideal ratio configuration, clock rate has to be strictly aligned 47762306a36Sopenharmony_ci * with the sample rate. For ideal ratio configuration, clock rates 47862306a36Sopenharmony_ci * only result in different converting speeds. So remainder does not 47962306a36Sopenharmony_ci * matter, as long as we keep the divider within its valid range. 48062306a36Sopenharmony_ci */ 48162306a36Sopenharmony_ci if (div[IN] == 0 || (!ideal && !div_avail)) { 48262306a36Sopenharmony_ci pair_err("failed to support input sample rate %dHz by asrck_%x\n", 48362306a36Sopenharmony_ci inrate, clk_index[ideal ? OUT : IN]); 48462306a36Sopenharmony_ci return -EINVAL; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci div[IN] = min_t(u32, 1024, div[IN]); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci clk = asrc_priv->asrck_clk[clk_index[OUT]]; 49062306a36Sopenharmony_ci clk_rate = clk_get_rate(clk); 49162306a36Sopenharmony_ci if (ideal && use_ideal_rate) 49262306a36Sopenharmony_ci div_avail = fsl_asrc_divider_avail(clk_rate, IDEAL_RATIO_RATE, &div[OUT]); 49362306a36Sopenharmony_ci else 49462306a36Sopenharmony_ci div_avail = fsl_asrc_divider_avail(clk_rate, outrate, &div[OUT]); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci /* Output divider has the same limitation as the input one */ 49762306a36Sopenharmony_ci if (div[OUT] == 0 || (!ideal && !div_avail)) { 49862306a36Sopenharmony_ci pair_err("failed to support output sample rate %dHz by asrck_%x\n", 49962306a36Sopenharmony_ci outrate, clk_index[OUT]); 50062306a36Sopenharmony_ci return -EINVAL; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci div[OUT] = min_t(u32, 1024, div[OUT]); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* Set the channel number */ 50662306a36Sopenharmony_ci channels = config->channel_num; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (asrc_priv->soc->channel_bits < 4) 50962306a36Sopenharmony_ci channels /= 2; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci /* Update channels for current pair */ 51262306a36Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCNCR, 51362306a36Sopenharmony_ci ASRCNCR_ANCi_MASK(index, asrc_priv->soc->channel_bits), 51462306a36Sopenharmony_ci ASRCNCR_ANCi(index, channels, asrc_priv->soc->channel_bits)); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci /* Default setting: Automatic selection for processing mode */ 51762306a36Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCTR, 51862306a36Sopenharmony_ci ASRCTR_ATSi_MASK(index), ASRCTR_ATS(index)); 51962306a36Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCTR, 52062306a36Sopenharmony_ci ASRCTR_USRi_MASK(index), 0); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* Set the input and output clock sources */ 52362306a36Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCSR, 52462306a36Sopenharmony_ci ASRCSR_AICSi_MASK(index) | ASRCSR_AOCSi_MASK(index), 52562306a36Sopenharmony_ci ASRCSR_AICS(index, clk_index[IN]) | 52662306a36Sopenharmony_ci ASRCSR_AOCS(index, clk_index[OUT])); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci /* Calculate the input clock divisors */ 52962306a36Sopenharmony_ci indiv = fsl_asrc_cal_asrck_divisor(pair, div[IN]); 53062306a36Sopenharmony_ci outdiv = fsl_asrc_cal_asrck_divisor(pair, div[OUT]); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci /* Suppose indiv and outdiv includes prescaler, so add its MASK too */ 53362306a36Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCDR(index), 53462306a36Sopenharmony_ci ASRCDRi_AOCPi_MASK(index) | ASRCDRi_AICPi_MASK(index) | 53562306a36Sopenharmony_ci ASRCDRi_AOCDi_MASK(index) | ASRCDRi_AICDi_MASK(index), 53662306a36Sopenharmony_ci ASRCDRi_AOCP(index, outdiv) | ASRCDRi_AICP(index, indiv)); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci /* Implement word_width configurations */ 53962306a36Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRMCR1(index), 54062306a36Sopenharmony_ci ASRMCR1i_OW16_MASK | ASRMCR1i_IWD_MASK, 54162306a36Sopenharmony_ci ASRMCR1i_OW16(output_word_width) | 54262306a36Sopenharmony_ci ASRMCR1i_IWD(input_word_width)); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci /* Enable BUFFER STALL */ 54562306a36Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRMCR(index), 54662306a36Sopenharmony_ci ASRMCRi_BUFSTALLi_MASK, ASRMCRi_BUFSTALLi); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci /* Set default thresholds for input and output FIFO */ 54962306a36Sopenharmony_ci fsl_asrc_set_watermarks(pair, ASRC_INPUTFIFO_THRESHOLD, 55062306a36Sopenharmony_ci ASRC_INPUTFIFO_THRESHOLD); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci /* Configure the following only for Ideal Ratio mode */ 55362306a36Sopenharmony_ci if (!ideal) 55462306a36Sopenharmony_ci return 0; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci /* Clear ASTSx bit to use Ideal Ratio mode */ 55762306a36Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCTR, 55862306a36Sopenharmony_ci ASRCTR_ATSi_MASK(index), 0); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci /* Enable Ideal Ratio mode */ 56162306a36Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCTR, 56262306a36Sopenharmony_ci ASRCTR_IDRi_MASK(index) | ASRCTR_USRi_MASK(index), 56362306a36Sopenharmony_ci ASRCTR_IDR(index) | ASRCTR_USR(index)); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci fsl_asrc_sel_proc(inrate, outrate, &pre_proc, &post_proc); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci /* Apply configurations for pre- and post-processing */ 56862306a36Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCFG, 56962306a36Sopenharmony_ci ASRCFG_PREMODi_MASK(index) | ASRCFG_POSTMODi_MASK(index), 57062306a36Sopenharmony_ci ASRCFG_PREMOD(index, pre_proc) | 57162306a36Sopenharmony_ci ASRCFG_POSTMOD(index, post_proc)); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci return fsl_asrc_set_ideal_ratio(pair, inrate, outrate); 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci/** 57762306a36Sopenharmony_ci * fsl_asrc_start_pair - Start the assigned ASRC pair 57862306a36Sopenharmony_ci * @pair: pointer to pair 57962306a36Sopenharmony_ci * 58062306a36Sopenharmony_ci * It enables the assigned pair and makes it stopped at the stall level. 58162306a36Sopenharmony_ci */ 58262306a36Sopenharmony_cistatic void fsl_asrc_start_pair(struct fsl_asrc_pair *pair) 58362306a36Sopenharmony_ci{ 58462306a36Sopenharmony_ci struct fsl_asrc *asrc = pair->asrc; 58562306a36Sopenharmony_ci enum asrc_pair_index index = pair->index; 58662306a36Sopenharmony_ci int reg, retry = INIT_RETRY_NUM, i; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* Enable the current pair */ 58962306a36Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCTR, 59062306a36Sopenharmony_ci ASRCTR_ASRCEi_MASK(index), ASRCTR_ASRCE(index)); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci /* Wait for status of initialization */ 59362306a36Sopenharmony_ci do { 59462306a36Sopenharmony_ci udelay(5); 59562306a36Sopenharmony_ci regmap_read(asrc->regmap, REG_ASRCFG, ®); 59662306a36Sopenharmony_ci reg &= ASRCFG_INIRQi_MASK(index); 59762306a36Sopenharmony_ci } while (!reg && --retry); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci /* NOTE: Doesn't treat initialization timeout as an error */ 60062306a36Sopenharmony_ci if (!retry) 60162306a36Sopenharmony_ci pair_warn("initialization isn't finished\n"); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci /* Make the input fifo to ASRC STALL level */ 60462306a36Sopenharmony_ci regmap_read(asrc->regmap, REG_ASRCNCR, ®); 60562306a36Sopenharmony_ci for (i = 0; i < pair->channels * 4; i++) 60662306a36Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRDI(index), 0); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci /* Enable overload interrupt */ 60962306a36Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRIER, ASRIER_AOLIE); 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci/** 61362306a36Sopenharmony_ci * fsl_asrc_stop_pair - Stop the assigned ASRC pair 61462306a36Sopenharmony_ci * @pair: pointer to pair 61562306a36Sopenharmony_ci */ 61662306a36Sopenharmony_cistatic void fsl_asrc_stop_pair(struct fsl_asrc_pair *pair) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci struct fsl_asrc *asrc = pair->asrc; 61962306a36Sopenharmony_ci enum asrc_pair_index index = pair->index; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci /* Stop the current pair */ 62262306a36Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCTR, 62362306a36Sopenharmony_ci ASRCTR_ASRCEi_MASK(index), 0); 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci/** 62762306a36Sopenharmony_ci * fsl_asrc_get_dma_channel- Get DMA channel according to the pair and direction. 62862306a36Sopenharmony_ci * @pair: pointer to pair 62962306a36Sopenharmony_ci * @dir: DMA direction 63062306a36Sopenharmony_ci */ 63162306a36Sopenharmony_cistatic struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, 63262306a36Sopenharmony_ci bool dir) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci struct fsl_asrc *asrc = pair->asrc; 63562306a36Sopenharmony_ci enum asrc_pair_index index = pair->index; 63662306a36Sopenharmony_ci char name[4]; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci sprintf(name, "%cx%c", dir == IN ? 'r' : 't', index + 'a'); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci return dma_request_slave_channel(&asrc->pdev->dev, name); 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cistatic int fsl_asrc_dai_startup(struct snd_pcm_substream *substream, 64462306a36Sopenharmony_ci struct snd_soc_dai *dai) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); 64762306a36Sopenharmony_ci struct fsl_asrc_priv *asrc_priv = asrc->private; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci /* Odd channel number is not valid for older ASRC (channel_bits==3) */ 65062306a36Sopenharmony_ci if (asrc_priv->soc->channel_bits == 3) 65162306a36Sopenharmony_ci snd_pcm_hw_constraint_step(substream->runtime, 0, 65262306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, 2); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci return snd_pcm_hw_constraint_list(substream->runtime, 0, 65662306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, &fsl_asrc_rate_constraints); 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci/* Select proper clock source for internal ratio mode */ 66062306a36Sopenharmony_cistatic void fsl_asrc_select_clk(struct fsl_asrc_priv *asrc_priv, 66162306a36Sopenharmony_ci struct fsl_asrc_pair *pair, 66262306a36Sopenharmony_ci int in_rate, 66362306a36Sopenharmony_ci int out_rate) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci struct fsl_asrc_pair_priv *pair_priv = pair->private; 66662306a36Sopenharmony_ci struct asrc_config *config = pair_priv->config; 66762306a36Sopenharmony_ci int rate[2], select_clk[2]; /* Array size 2 means IN and OUT */ 66862306a36Sopenharmony_ci int clk_rate, clk_index; 66962306a36Sopenharmony_ci int i, j; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci rate[IN] = in_rate; 67262306a36Sopenharmony_ci rate[OUT] = out_rate; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci /* Select proper clock source for internal ratio mode */ 67562306a36Sopenharmony_ci for (j = 0; j < 2; j++) { 67662306a36Sopenharmony_ci for (i = 0; i < ASRC_CLK_MAP_LEN; i++) { 67762306a36Sopenharmony_ci clk_index = asrc_priv->clk_map[j][i]; 67862306a36Sopenharmony_ci clk_rate = clk_get_rate(asrc_priv->asrck_clk[clk_index]); 67962306a36Sopenharmony_ci /* Only match a perfect clock source with no remainder */ 68062306a36Sopenharmony_ci if (fsl_asrc_divider_avail(clk_rate, rate[j], NULL)) 68162306a36Sopenharmony_ci break; 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci select_clk[j] = i; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci /* Switch to ideal ratio mode if there is no proper clock source */ 68862306a36Sopenharmony_ci if (select_clk[IN] == ASRC_CLK_MAP_LEN || select_clk[OUT] == ASRC_CLK_MAP_LEN) { 68962306a36Sopenharmony_ci select_clk[IN] = INCLK_NONE; 69062306a36Sopenharmony_ci select_clk[OUT] = OUTCLK_ASRCK1_CLK; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci config->inclk = select_clk[IN]; 69462306a36Sopenharmony_ci config->outclk = select_clk[OUT]; 69562306a36Sopenharmony_ci} 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_cistatic int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream, 69862306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 69962306a36Sopenharmony_ci struct snd_soc_dai *dai) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); 70262306a36Sopenharmony_ci struct fsl_asrc_priv *asrc_priv = asrc->private; 70362306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 70462306a36Sopenharmony_ci struct fsl_asrc_pair *pair = runtime->private_data; 70562306a36Sopenharmony_ci struct fsl_asrc_pair_priv *pair_priv = pair->private; 70662306a36Sopenharmony_ci unsigned int channels = params_channels(params); 70762306a36Sopenharmony_ci unsigned int rate = params_rate(params); 70862306a36Sopenharmony_ci struct asrc_config config; 70962306a36Sopenharmony_ci int ret; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci ret = fsl_asrc_request_pair(channels, pair); 71262306a36Sopenharmony_ci if (ret) { 71362306a36Sopenharmony_ci dev_err(dai->dev, "fail to request asrc pair\n"); 71462306a36Sopenharmony_ci return ret; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci pair_priv->config = &config; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci config.pair = pair->index; 72062306a36Sopenharmony_ci config.channel_num = channels; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 72362306a36Sopenharmony_ci config.input_format = params_format(params); 72462306a36Sopenharmony_ci config.output_format = asrc->asrc_format; 72562306a36Sopenharmony_ci config.input_sample_rate = rate; 72662306a36Sopenharmony_ci config.output_sample_rate = asrc->asrc_rate; 72762306a36Sopenharmony_ci } else { 72862306a36Sopenharmony_ci config.input_format = asrc->asrc_format; 72962306a36Sopenharmony_ci config.output_format = params_format(params); 73062306a36Sopenharmony_ci config.input_sample_rate = asrc->asrc_rate; 73162306a36Sopenharmony_ci config.output_sample_rate = rate; 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci fsl_asrc_select_clk(asrc_priv, pair, 73562306a36Sopenharmony_ci config.input_sample_rate, 73662306a36Sopenharmony_ci config.output_sample_rate); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci ret = fsl_asrc_config_pair(pair, false); 73962306a36Sopenharmony_ci if (ret) { 74062306a36Sopenharmony_ci dev_err(dai->dev, "fail to config asrc pair\n"); 74162306a36Sopenharmony_ci return ret; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci return 0; 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cistatic int fsl_asrc_dai_hw_free(struct snd_pcm_substream *substream, 74862306a36Sopenharmony_ci struct snd_soc_dai *dai) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 75162306a36Sopenharmony_ci struct fsl_asrc_pair *pair = runtime->private_data; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci if (pair) 75462306a36Sopenharmony_ci fsl_asrc_release_pair(pair); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci return 0; 75762306a36Sopenharmony_ci} 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_cistatic int fsl_asrc_dai_trigger(struct snd_pcm_substream *substream, int cmd, 76062306a36Sopenharmony_ci struct snd_soc_dai *dai) 76162306a36Sopenharmony_ci{ 76262306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 76362306a36Sopenharmony_ci struct fsl_asrc_pair *pair = runtime->private_data; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci switch (cmd) { 76662306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 76762306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 76862306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 76962306a36Sopenharmony_ci fsl_asrc_start_pair(pair); 77062306a36Sopenharmony_ci break; 77162306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 77262306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 77362306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 77462306a36Sopenharmony_ci fsl_asrc_stop_pair(pair); 77562306a36Sopenharmony_ci break; 77662306a36Sopenharmony_ci default: 77762306a36Sopenharmony_ci return -EINVAL; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci return 0; 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_cistatic int fsl_asrc_dai_probe(struct snd_soc_dai *dai) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci struct fsl_asrc *asrc = snd_soc_dai_get_drvdata(dai); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci snd_soc_dai_init_dma_data(dai, &asrc->dma_params_tx, 78862306a36Sopenharmony_ci &asrc->dma_params_rx); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci return 0; 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistatic const struct snd_soc_dai_ops fsl_asrc_dai_ops = { 79462306a36Sopenharmony_ci .probe = fsl_asrc_dai_probe, 79562306a36Sopenharmony_ci .startup = fsl_asrc_dai_startup, 79662306a36Sopenharmony_ci .hw_params = fsl_asrc_dai_hw_params, 79762306a36Sopenharmony_ci .hw_free = fsl_asrc_dai_hw_free, 79862306a36Sopenharmony_ci .trigger = fsl_asrc_dai_trigger, 79962306a36Sopenharmony_ci}; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci#define FSL_ASRC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \ 80262306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S16_LE | \ 80362306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_3LE) 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_cistatic struct snd_soc_dai_driver fsl_asrc_dai = { 80662306a36Sopenharmony_ci .playback = { 80762306a36Sopenharmony_ci .stream_name = "ASRC-Playback", 80862306a36Sopenharmony_ci .channels_min = 1, 80962306a36Sopenharmony_ci .channels_max = 10, 81062306a36Sopenharmony_ci .rate_min = 5512, 81162306a36Sopenharmony_ci .rate_max = 192000, 81262306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_KNOT, 81362306a36Sopenharmony_ci .formats = FSL_ASRC_FORMATS | 81462306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S8, 81562306a36Sopenharmony_ci }, 81662306a36Sopenharmony_ci .capture = { 81762306a36Sopenharmony_ci .stream_name = "ASRC-Capture", 81862306a36Sopenharmony_ci .channels_min = 1, 81962306a36Sopenharmony_ci .channels_max = 10, 82062306a36Sopenharmony_ci .rate_min = 5512, 82162306a36Sopenharmony_ci .rate_max = 192000, 82262306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_KNOT, 82362306a36Sopenharmony_ci .formats = FSL_ASRC_FORMATS, 82462306a36Sopenharmony_ci }, 82562306a36Sopenharmony_ci .ops = &fsl_asrc_dai_ops, 82662306a36Sopenharmony_ci}; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_cistatic bool fsl_asrc_readable_reg(struct device *dev, unsigned int reg) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci switch (reg) { 83162306a36Sopenharmony_ci case REG_ASRCTR: 83262306a36Sopenharmony_ci case REG_ASRIER: 83362306a36Sopenharmony_ci case REG_ASRCNCR: 83462306a36Sopenharmony_ci case REG_ASRCFG: 83562306a36Sopenharmony_ci case REG_ASRCSR: 83662306a36Sopenharmony_ci case REG_ASRCDR1: 83762306a36Sopenharmony_ci case REG_ASRCDR2: 83862306a36Sopenharmony_ci case REG_ASRSTR: 83962306a36Sopenharmony_ci case REG_ASRPM1: 84062306a36Sopenharmony_ci case REG_ASRPM2: 84162306a36Sopenharmony_ci case REG_ASRPM3: 84262306a36Sopenharmony_ci case REG_ASRPM4: 84362306a36Sopenharmony_ci case REG_ASRPM5: 84462306a36Sopenharmony_ci case REG_ASRTFR1: 84562306a36Sopenharmony_ci case REG_ASRCCR: 84662306a36Sopenharmony_ci case REG_ASRDOA: 84762306a36Sopenharmony_ci case REG_ASRDOB: 84862306a36Sopenharmony_ci case REG_ASRDOC: 84962306a36Sopenharmony_ci case REG_ASRIDRHA: 85062306a36Sopenharmony_ci case REG_ASRIDRLA: 85162306a36Sopenharmony_ci case REG_ASRIDRHB: 85262306a36Sopenharmony_ci case REG_ASRIDRLB: 85362306a36Sopenharmony_ci case REG_ASRIDRHC: 85462306a36Sopenharmony_ci case REG_ASRIDRLC: 85562306a36Sopenharmony_ci case REG_ASR76K: 85662306a36Sopenharmony_ci case REG_ASR56K: 85762306a36Sopenharmony_ci case REG_ASRMCRA: 85862306a36Sopenharmony_ci case REG_ASRFSTA: 85962306a36Sopenharmony_ci case REG_ASRMCRB: 86062306a36Sopenharmony_ci case REG_ASRFSTB: 86162306a36Sopenharmony_ci case REG_ASRMCRC: 86262306a36Sopenharmony_ci case REG_ASRFSTC: 86362306a36Sopenharmony_ci case REG_ASRMCR1A: 86462306a36Sopenharmony_ci case REG_ASRMCR1B: 86562306a36Sopenharmony_ci case REG_ASRMCR1C: 86662306a36Sopenharmony_ci return true; 86762306a36Sopenharmony_ci default: 86862306a36Sopenharmony_ci return false; 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci} 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_cistatic bool fsl_asrc_volatile_reg(struct device *dev, unsigned int reg) 87362306a36Sopenharmony_ci{ 87462306a36Sopenharmony_ci switch (reg) { 87562306a36Sopenharmony_ci case REG_ASRSTR: 87662306a36Sopenharmony_ci case REG_ASRDIA: 87762306a36Sopenharmony_ci case REG_ASRDIB: 87862306a36Sopenharmony_ci case REG_ASRDIC: 87962306a36Sopenharmony_ci case REG_ASRDOA: 88062306a36Sopenharmony_ci case REG_ASRDOB: 88162306a36Sopenharmony_ci case REG_ASRDOC: 88262306a36Sopenharmony_ci case REG_ASRFSTA: 88362306a36Sopenharmony_ci case REG_ASRFSTB: 88462306a36Sopenharmony_ci case REG_ASRFSTC: 88562306a36Sopenharmony_ci case REG_ASRCFG: 88662306a36Sopenharmony_ci return true; 88762306a36Sopenharmony_ci default: 88862306a36Sopenharmony_ci return false; 88962306a36Sopenharmony_ci } 89062306a36Sopenharmony_ci} 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_cistatic bool fsl_asrc_writeable_reg(struct device *dev, unsigned int reg) 89362306a36Sopenharmony_ci{ 89462306a36Sopenharmony_ci switch (reg) { 89562306a36Sopenharmony_ci case REG_ASRCTR: 89662306a36Sopenharmony_ci case REG_ASRIER: 89762306a36Sopenharmony_ci case REG_ASRCNCR: 89862306a36Sopenharmony_ci case REG_ASRCFG: 89962306a36Sopenharmony_ci case REG_ASRCSR: 90062306a36Sopenharmony_ci case REG_ASRCDR1: 90162306a36Sopenharmony_ci case REG_ASRCDR2: 90262306a36Sopenharmony_ci case REG_ASRSTR: 90362306a36Sopenharmony_ci case REG_ASRPM1: 90462306a36Sopenharmony_ci case REG_ASRPM2: 90562306a36Sopenharmony_ci case REG_ASRPM3: 90662306a36Sopenharmony_ci case REG_ASRPM4: 90762306a36Sopenharmony_ci case REG_ASRPM5: 90862306a36Sopenharmony_ci case REG_ASRTFR1: 90962306a36Sopenharmony_ci case REG_ASRCCR: 91062306a36Sopenharmony_ci case REG_ASRDIA: 91162306a36Sopenharmony_ci case REG_ASRDIB: 91262306a36Sopenharmony_ci case REG_ASRDIC: 91362306a36Sopenharmony_ci case REG_ASRIDRHA: 91462306a36Sopenharmony_ci case REG_ASRIDRLA: 91562306a36Sopenharmony_ci case REG_ASRIDRHB: 91662306a36Sopenharmony_ci case REG_ASRIDRLB: 91762306a36Sopenharmony_ci case REG_ASRIDRHC: 91862306a36Sopenharmony_ci case REG_ASRIDRLC: 91962306a36Sopenharmony_ci case REG_ASR76K: 92062306a36Sopenharmony_ci case REG_ASR56K: 92162306a36Sopenharmony_ci case REG_ASRMCRA: 92262306a36Sopenharmony_ci case REG_ASRMCRB: 92362306a36Sopenharmony_ci case REG_ASRMCRC: 92462306a36Sopenharmony_ci case REG_ASRMCR1A: 92562306a36Sopenharmony_ci case REG_ASRMCR1B: 92662306a36Sopenharmony_ci case REG_ASRMCR1C: 92762306a36Sopenharmony_ci return true; 92862306a36Sopenharmony_ci default: 92962306a36Sopenharmony_ci return false; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci} 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_cistatic struct reg_default fsl_asrc_reg[] = { 93462306a36Sopenharmony_ci { REG_ASRCTR, 0x0000 }, { REG_ASRIER, 0x0000 }, 93562306a36Sopenharmony_ci { REG_ASRCNCR, 0x0000 }, { REG_ASRCFG, 0x0000 }, 93662306a36Sopenharmony_ci { REG_ASRCSR, 0x0000 }, { REG_ASRCDR1, 0x0000 }, 93762306a36Sopenharmony_ci { REG_ASRCDR2, 0x0000 }, { REG_ASRSTR, 0x0000 }, 93862306a36Sopenharmony_ci { REG_ASRRA, 0x0000 }, { REG_ASRRB, 0x0000 }, 93962306a36Sopenharmony_ci { REG_ASRRC, 0x0000 }, { REG_ASRPM1, 0x0000 }, 94062306a36Sopenharmony_ci { REG_ASRPM2, 0x0000 }, { REG_ASRPM3, 0x0000 }, 94162306a36Sopenharmony_ci { REG_ASRPM4, 0x0000 }, { REG_ASRPM5, 0x0000 }, 94262306a36Sopenharmony_ci { REG_ASRTFR1, 0x0000 }, { REG_ASRCCR, 0x0000 }, 94362306a36Sopenharmony_ci { REG_ASRDIA, 0x0000 }, { REG_ASRDOA, 0x0000 }, 94462306a36Sopenharmony_ci { REG_ASRDIB, 0x0000 }, { REG_ASRDOB, 0x0000 }, 94562306a36Sopenharmony_ci { REG_ASRDIC, 0x0000 }, { REG_ASRDOC, 0x0000 }, 94662306a36Sopenharmony_ci { REG_ASRIDRHA, 0x0000 }, { REG_ASRIDRLA, 0x0000 }, 94762306a36Sopenharmony_ci { REG_ASRIDRHB, 0x0000 }, { REG_ASRIDRLB, 0x0000 }, 94862306a36Sopenharmony_ci { REG_ASRIDRHC, 0x0000 }, { REG_ASRIDRLC, 0x0000 }, 94962306a36Sopenharmony_ci { REG_ASR76K, 0x0A47 }, { REG_ASR56K, 0x0DF3 }, 95062306a36Sopenharmony_ci { REG_ASRMCRA, 0x0000 }, { REG_ASRFSTA, 0x0000 }, 95162306a36Sopenharmony_ci { REG_ASRMCRB, 0x0000 }, { REG_ASRFSTB, 0x0000 }, 95262306a36Sopenharmony_ci { REG_ASRMCRC, 0x0000 }, { REG_ASRFSTC, 0x0000 }, 95362306a36Sopenharmony_ci { REG_ASRMCR1A, 0x0000 }, { REG_ASRMCR1B, 0x0000 }, 95462306a36Sopenharmony_ci { REG_ASRMCR1C, 0x0000 }, 95562306a36Sopenharmony_ci}; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_cistatic const struct regmap_config fsl_asrc_regmap_config = { 95862306a36Sopenharmony_ci .reg_bits = 32, 95962306a36Sopenharmony_ci .reg_stride = 4, 96062306a36Sopenharmony_ci .val_bits = 32, 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci .max_register = REG_ASRMCR1C, 96362306a36Sopenharmony_ci .reg_defaults = fsl_asrc_reg, 96462306a36Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(fsl_asrc_reg), 96562306a36Sopenharmony_ci .readable_reg = fsl_asrc_readable_reg, 96662306a36Sopenharmony_ci .volatile_reg = fsl_asrc_volatile_reg, 96762306a36Sopenharmony_ci .writeable_reg = fsl_asrc_writeable_reg, 96862306a36Sopenharmony_ci .cache_type = REGCACHE_FLAT, 96962306a36Sopenharmony_ci}; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci/** 97262306a36Sopenharmony_ci * fsl_asrc_init - Initialize ASRC registers with a default configuration 97362306a36Sopenharmony_ci * @asrc: ASRC context 97462306a36Sopenharmony_ci */ 97562306a36Sopenharmony_cistatic int fsl_asrc_init(struct fsl_asrc *asrc) 97662306a36Sopenharmony_ci{ 97762306a36Sopenharmony_ci unsigned long ipg_rate; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci /* Halt ASRC internal FP when input FIFO needs data for pair A, B, C */ 98062306a36Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRCTR, ASRCTR_ASRCEN); 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci /* Disable interrupt by default */ 98362306a36Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRIER, 0x0); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci /* Apply recommended settings for parameters from Reference Manual */ 98662306a36Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRPM1, 0x7fffff); 98762306a36Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRPM2, 0x255555); 98862306a36Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRPM3, 0xff7280); 98962306a36Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRPM4, 0xff7280); 99062306a36Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRPM5, 0xff7280); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci /* Base address for task queue FIFO. Set to 0x7C */ 99362306a36Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRTFR1, 99462306a36Sopenharmony_ci ASRTFR1_TF_BASE_MASK, ASRTFR1_TF_BASE(0xfc)); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci /* 99762306a36Sopenharmony_ci * Set the period of the 76KHz and 56KHz sampling clocks based on 99862306a36Sopenharmony_ci * the ASRC processing clock. 99962306a36Sopenharmony_ci * On iMX6, ipg_clk = 133MHz, REG_ASR76K = 0x06D6, REG_ASR56K = 0x0947 100062306a36Sopenharmony_ci */ 100162306a36Sopenharmony_ci ipg_rate = clk_get_rate(asrc->ipg_clk); 100262306a36Sopenharmony_ci regmap_write(asrc->regmap, REG_ASR76K, ipg_rate / 76000); 100362306a36Sopenharmony_ci return regmap_write(asrc->regmap, REG_ASR56K, ipg_rate / 56000); 100462306a36Sopenharmony_ci} 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci/** 100762306a36Sopenharmony_ci * fsl_asrc_isr- Interrupt handler for ASRC 100862306a36Sopenharmony_ci * @irq: irq number 100962306a36Sopenharmony_ci * @dev_id: ASRC context 101062306a36Sopenharmony_ci */ 101162306a36Sopenharmony_cistatic irqreturn_t fsl_asrc_isr(int irq, void *dev_id) 101262306a36Sopenharmony_ci{ 101362306a36Sopenharmony_ci struct fsl_asrc *asrc = (struct fsl_asrc *)dev_id; 101462306a36Sopenharmony_ci struct device *dev = &asrc->pdev->dev; 101562306a36Sopenharmony_ci enum asrc_pair_index index; 101662306a36Sopenharmony_ci u32 status; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci regmap_read(asrc->regmap, REG_ASRSTR, &status); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci /* Clean overload error */ 102162306a36Sopenharmony_ci regmap_write(asrc->regmap, REG_ASRSTR, ASRSTR_AOLE); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci /* 102462306a36Sopenharmony_ci * We here use dev_dbg() for all exceptions because ASRC itself does 102562306a36Sopenharmony_ci * not care if FIFO overflowed or underrun while a warning in the 102662306a36Sopenharmony_ci * interrupt would result a ridged conversion. 102762306a36Sopenharmony_ci */ 102862306a36Sopenharmony_ci for (index = ASRC_PAIR_A; index < ASRC_PAIR_MAX_NUM; index++) { 102962306a36Sopenharmony_ci if (!asrc->pair[index]) 103062306a36Sopenharmony_ci continue; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci if (status & ASRSTR_ATQOL) { 103362306a36Sopenharmony_ci asrc->pair[index]->error |= ASRC_TASK_Q_OVERLOAD; 103462306a36Sopenharmony_ci dev_dbg(dev, "ASRC Task Queue FIFO overload\n"); 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci if (status & ASRSTR_AOOL(index)) { 103862306a36Sopenharmony_ci asrc->pair[index]->error |= ASRC_OUTPUT_TASK_OVERLOAD; 103962306a36Sopenharmony_ci pair_dbg("Output Task Overload\n"); 104062306a36Sopenharmony_ci } 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci if (status & ASRSTR_AIOL(index)) { 104362306a36Sopenharmony_ci asrc->pair[index]->error |= ASRC_INPUT_TASK_OVERLOAD; 104462306a36Sopenharmony_ci pair_dbg("Input Task Overload\n"); 104562306a36Sopenharmony_ci } 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci if (status & ASRSTR_AODO(index)) { 104862306a36Sopenharmony_ci asrc->pair[index]->error |= ASRC_OUTPUT_BUFFER_OVERFLOW; 104962306a36Sopenharmony_ci pair_dbg("Output Data Buffer has overflowed\n"); 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if (status & ASRSTR_AIDU(index)) { 105362306a36Sopenharmony_ci asrc->pair[index]->error |= ASRC_INPUT_BUFFER_UNDERRUN; 105462306a36Sopenharmony_ci pair_dbg("Input Data Buffer has underflowed\n"); 105562306a36Sopenharmony_ci } 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci return IRQ_HANDLED; 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cistatic int fsl_asrc_get_fifo_addr(u8 dir, enum asrc_pair_index index) 106262306a36Sopenharmony_ci{ 106362306a36Sopenharmony_ci return REG_ASRDx(dir, index); 106462306a36Sopenharmony_ci} 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_cistatic int fsl_asrc_runtime_resume(struct device *dev); 106762306a36Sopenharmony_cistatic int fsl_asrc_runtime_suspend(struct device *dev); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_cistatic int fsl_asrc_probe(struct platform_device *pdev) 107062306a36Sopenharmony_ci{ 107162306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 107262306a36Sopenharmony_ci struct fsl_asrc_priv *asrc_priv; 107362306a36Sopenharmony_ci struct fsl_asrc *asrc; 107462306a36Sopenharmony_ci struct resource *res; 107562306a36Sopenharmony_ci void __iomem *regs; 107662306a36Sopenharmony_ci int irq, ret, i; 107762306a36Sopenharmony_ci u32 asrc_fmt = 0; 107862306a36Sopenharmony_ci u32 map_idx; 107962306a36Sopenharmony_ci char tmp[16]; 108062306a36Sopenharmony_ci u32 width; 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci asrc = devm_kzalloc(&pdev->dev, sizeof(*asrc), GFP_KERNEL); 108362306a36Sopenharmony_ci if (!asrc) 108462306a36Sopenharmony_ci return -ENOMEM; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci asrc_priv = devm_kzalloc(&pdev->dev, sizeof(*asrc_priv), GFP_KERNEL); 108762306a36Sopenharmony_ci if (!asrc_priv) 108862306a36Sopenharmony_ci return -ENOMEM; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci asrc->pdev = pdev; 109162306a36Sopenharmony_ci asrc->private = asrc_priv; 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci /* Get the addresses and IRQ */ 109462306a36Sopenharmony_ci regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 109562306a36Sopenharmony_ci if (IS_ERR(regs)) 109662306a36Sopenharmony_ci return PTR_ERR(regs); 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci asrc->paddr = res->start; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci asrc->regmap = devm_regmap_init_mmio(&pdev->dev, regs, &fsl_asrc_regmap_config); 110162306a36Sopenharmony_ci if (IS_ERR(asrc->regmap)) { 110262306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to init regmap\n"); 110362306a36Sopenharmony_ci return PTR_ERR(asrc->regmap); 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 110762306a36Sopenharmony_ci if (irq < 0) 110862306a36Sopenharmony_ci return irq; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, fsl_asrc_isr, 0, 111162306a36Sopenharmony_ci dev_name(&pdev->dev), asrc); 111262306a36Sopenharmony_ci if (ret) { 111362306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to claim irq %u: %d\n", irq, ret); 111462306a36Sopenharmony_ci return ret; 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci asrc->mem_clk = devm_clk_get(&pdev->dev, "mem"); 111862306a36Sopenharmony_ci if (IS_ERR(asrc->mem_clk)) { 111962306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to get mem clock\n"); 112062306a36Sopenharmony_ci return PTR_ERR(asrc->mem_clk); 112162306a36Sopenharmony_ci } 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci asrc->ipg_clk = devm_clk_get(&pdev->dev, "ipg"); 112462306a36Sopenharmony_ci if (IS_ERR(asrc->ipg_clk)) { 112562306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to get ipg clock\n"); 112662306a36Sopenharmony_ci return PTR_ERR(asrc->ipg_clk); 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci asrc->spba_clk = devm_clk_get(&pdev->dev, "spba"); 113062306a36Sopenharmony_ci if (IS_ERR(asrc->spba_clk)) 113162306a36Sopenharmony_ci dev_warn(&pdev->dev, "failed to get spba clock\n"); 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { 113462306a36Sopenharmony_ci sprintf(tmp, "asrck_%x", i); 113562306a36Sopenharmony_ci asrc_priv->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp); 113662306a36Sopenharmony_ci if (IS_ERR(asrc_priv->asrck_clk[i])) { 113762306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to get %s clock\n", tmp); 113862306a36Sopenharmony_ci return PTR_ERR(asrc_priv->asrck_clk[i]); 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci asrc_priv->soc = of_device_get_match_data(&pdev->dev); 114362306a36Sopenharmony_ci asrc->use_edma = asrc_priv->soc->use_edma; 114462306a36Sopenharmony_ci asrc->get_dma_channel = fsl_asrc_get_dma_channel; 114562306a36Sopenharmony_ci asrc->request_pair = fsl_asrc_request_pair; 114662306a36Sopenharmony_ci asrc->release_pair = fsl_asrc_release_pair; 114762306a36Sopenharmony_ci asrc->get_fifo_addr = fsl_asrc_get_fifo_addr; 114862306a36Sopenharmony_ci asrc->pair_priv_size = sizeof(struct fsl_asrc_pair_priv); 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci if (of_device_is_compatible(np, "fsl,imx35-asrc")) { 115162306a36Sopenharmony_ci asrc_priv->clk_map[IN] = input_clk_map_imx35; 115262306a36Sopenharmony_ci asrc_priv->clk_map[OUT] = output_clk_map_imx35; 115362306a36Sopenharmony_ci } else if (of_device_is_compatible(np, "fsl,imx53-asrc")) { 115462306a36Sopenharmony_ci asrc_priv->clk_map[IN] = input_clk_map_imx53; 115562306a36Sopenharmony_ci asrc_priv->clk_map[OUT] = output_clk_map_imx53; 115662306a36Sopenharmony_ci } else if (of_device_is_compatible(np, "fsl,imx8qm-asrc") || 115762306a36Sopenharmony_ci of_device_is_compatible(np, "fsl,imx8qxp-asrc")) { 115862306a36Sopenharmony_ci ret = of_property_read_u32(np, "fsl,asrc-clk-map", &map_idx); 115962306a36Sopenharmony_ci if (ret) { 116062306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to get clk map index\n"); 116162306a36Sopenharmony_ci return ret; 116262306a36Sopenharmony_ci } 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci if (map_idx > 1) { 116562306a36Sopenharmony_ci dev_err(&pdev->dev, "unsupported clk map index\n"); 116662306a36Sopenharmony_ci return -EINVAL; 116762306a36Sopenharmony_ci } 116862306a36Sopenharmony_ci if (of_device_is_compatible(np, "fsl,imx8qm-asrc")) { 116962306a36Sopenharmony_ci asrc_priv->clk_map[IN] = clk_map_imx8qm[map_idx]; 117062306a36Sopenharmony_ci asrc_priv->clk_map[OUT] = clk_map_imx8qm[map_idx]; 117162306a36Sopenharmony_ci } else { 117262306a36Sopenharmony_ci asrc_priv->clk_map[IN] = clk_map_imx8qxp[map_idx]; 117362306a36Sopenharmony_ci asrc_priv->clk_map[OUT] = clk_map_imx8qxp[map_idx]; 117462306a36Sopenharmony_ci } 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci asrc->channel_avail = 10; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci ret = of_property_read_u32(np, "fsl,asrc-rate", 118062306a36Sopenharmony_ci &asrc->asrc_rate); 118162306a36Sopenharmony_ci if (ret) { 118262306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to get output rate\n"); 118362306a36Sopenharmony_ci return ret; 118462306a36Sopenharmony_ci } 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci ret = of_property_read_u32(np, "fsl,asrc-format", &asrc_fmt); 118762306a36Sopenharmony_ci asrc->asrc_format = (__force snd_pcm_format_t)asrc_fmt; 118862306a36Sopenharmony_ci if (ret) { 118962306a36Sopenharmony_ci ret = of_property_read_u32(np, "fsl,asrc-width", &width); 119062306a36Sopenharmony_ci if (ret) { 119162306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to decide output format\n"); 119262306a36Sopenharmony_ci return ret; 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci switch (width) { 119662306a36Sopenharmony_ci case 16: 119762306a36Sopenharmony_ci asrc->asrc_format = SNDRV_PCM_FORMAT_S16_LE; 119862306a36Sopenharmony_ci break; 119962306a36Sopenharmony_ci case 24: 120062306a36Sopenharmony_ci asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE; 120162306a36Sopenharmony_ci break; 120262306a36Sopenharmony_ci default: 120362306a36Sopenharmony_ci dev_warn(&pdev->dev, 120462306a36Sopenharmony_ci "unsupported width, use default S24_LE\n"); 120562306a36Sopenharmony_ci asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE; 120662306a36Sopenharmony_ci break; 120762306a36Sopenharmony_ci } 120862306a36Sopenharmony_ci } 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci if (!(FSL_ASRC_FORMATS & pcm_format_to_bits(asrc->asrc_format))) { 121162306a36Sopenharmony_ci dev_warn(&pdev->dev, "unsupported width, use default S24_LE\n"); 121262306a36Sopenharmony_ci asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE; 121362306a36Sopenharmony_ci } 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci platform_set_drvdata(pdev, asrc); 121662306a36Sopenharmony_ci spin_lock_init(&asrc->lock); 121762306a36Sopenharmony_ci pm_runtime_enable(&pdev->dev); 121862306a36Sopenharmony_ci if (!pm_runtime_enabled(&pdev->dev)) { 121962306a36Sopenharmony_ci ret = fsl_asrc_runtime_resume(&pdev->dev); 122062306a36Sopenharmony_ci if (ret) 122162306a36Sopenharmony_ci goto err_pm_disable; 122262306a36Sopenharmony_ci } 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(&pdev->dev); 122562306a36Sopenharmony_ci if (ret < 0) 122662306a36Sopenharmony_ci goto err_pm_get_sync; 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci ret = fsl_asrc_init(asrc); 122962306a36Sopenharmony_ci if (ret) { 123062306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to init asrc %d\n", ret); 123162306a36Sopenharmony_ci goto err_pm_get_sync; 123262306a36Sopenharmony_ci } 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci ret = pm_runtime_put_sync(&pdev->dev); 123562306a36Sopenharmony_ci if (ret < 0 && ret != -ENOSYS) 123662306a36Sopenharmony_ci goto err_pm_get_sync; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, &fsl_asrc_component, 123962306a36Sopenharmony_ci &fsl_asrc_dai, 1); 124062306a36Sopenharmony_ci if (ret) { 124162306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to register ASoC DAI\n"); 124262306a36Sopenharmony_ci goto err_pm_get_sync; 124362306a36Sopenharmony_ci } 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci return 0; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_cierr_pm_get_sync: 124862306a36Sopenharmony_ci if (!pm_runtime_status_suspended(&pdev->dev)) 124962306a36Sopenharmony_ci fsl_asrc_runtime_suspend(&pdev->dev); 125062306a36Sopenharmony_cierr_pm_disable: 125162306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 125262306a36Sopenharmony_ci return ret; 125362306a36Sopenharmony_ci} 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_cistatic void fsl_asrc_remove(struct platform_device *pdev) 125662306a36Sopenharmony_ci{ 125762306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 125862306a36Sopenharmony_ci if (!pm_runtime_status_suspended(&pdev->dev)) 125962306a36Sopenharmony_ci fsl_asrc_runtime_suspend(&pdev->dev); 126062306a36Sopenharmony_ci} 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_cistatic int fsl_asrc_runtime_resume(struct device *dev) 126362306a36Sopenharmony_ci{ 126462306a36Sopenharmony_ci struct fsl_asrc *asrc = dev_get_drvdata(dev); 126562306a36Sopenharmony_ci struct fsl_asrc_priv *asrc_priv = asrc->private; 126662306a36Sopenharmony_ci int reg, retry = INIT_RETRY_NUM; 126762306a36Sopenharmony_ci int i, ret; 126862306a36Sopenharmony_ci u32 asrctr; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci ret = clk_prepare_enable(asrc->mem_clk); 127162306a36Sopenharmony_ci if (ret) 127262306a36Sopenharmony_ci return ret; 127362306a36Sopenharmony_ci ret = clk_prepare_enable(asrc->ipg_clk); 127462306a36Sopenharmony_ci if (ret) 127562306a36Sopenharmony_ci goto disable_mem_clk; 127662306a36Sopenharmony_ci if (!IS_ERR(asrc->spba_clk)) { 127762306a36Sopenharmony_ci ret = clk_prepare_enable(asrc->spba_clk); 127862306a36Sopenharmony_ci if (ret) 127962306a36Sopenharmony_ci goto disable_ipg_clk; 128062306a36Sopenharmony_ci } 128162306a36Sopenharmony_ci for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { 128262306a36Sopenharmony_ci ret = clk_prepare_enable(asrc_priv->asrck_clk[i]); 128362306a36Sopenharmony_ci if (ret) 128462306a36Sopenharmony_ci goto disable_asrck_clk; 128562306a36Sopenharmony_ci } 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci /* Stop all pairs provisionally */ 128862306a36Sopenharmony_ci regmap_read(asrc->regmap, REG_ASRCTR, &asrctr); 128962306a36Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCTR, 129062306a36Sopenharmony_ci ASRCTR_ASRCEi_ALL_MASK, 0); 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci /* Restore all registers */ 129362306a36Sopenharmony_ci regcache_cache_only(asrc->regmap, false); 129462306a36Sopenharmony_ci regcache_mark_dirty(asrc->regmap); 129562306a36Sopenharmony_ci regcache_sync(asrc->regmap); 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCFG, 129862306a36Sopenharmony_ci ASRCFG_NDPRi_ALL_MASK | ASRCFG_POSTMODi_ALL_MASK | 129962306a36Sopenharmony_ci ASRCFG_PREMODi_ALL_MASK, asrc_priv->regcache_cfg); 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci /* Restart enabled pairs */ 130262306a36Sopenharmony_ci regmap_update_bits(asrc->regmap, REG_ASRCTR, 130362306a36Sopenharmony_ci ASRCTR_ASRCEi_ALL_MASK, asrctr); 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci /* Wait for status of initialization for all enabled pairs */ 130662306a36Sopenharmony_ci do { 130762306a36Sopenharmony_ci udelay(5); 130862306a36Sopenharmony_ci regmap_read(asrc->regmap, REG_ASRCFG, ®); 130962306a36Sopenharmony_ci reg = (reg >> ASRCFG_INIRQi_SHIFT(0)) & 0x7; 131062306a36Sopenharmony_ci } while ((reg != ((asrctr >> ASRCTR_ASRCEi_SHIFT(0)) & 0x7)) && --retry); 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci /* 131362306a36Sopenharmony_ci * NOTE: Doesn't treat initialization timeout as an error 131462306a36Sopenharmony_ci * Some of the pairs may success, then still can continue. 131562306a36Sopenharmony_ci */ 131662306a36Sopenharmony_ci if (!retry) { 131762306a36Sopenharmony_ci for (i = ASRC_PAIR_A; i < ASRC_PAIR_MAX_NUM; i++) { 131862306a36Sopenharmony_ci if ((asrctr & ASRCTR_ASRCEi_MASK(i)) && !(reg & (1 << i))) 131962306a36Sopenharmony_ci dev_warn(dev, "Pair %c initialization isn't finished\n", 'A' + i); 132062306a36Sopenharmony_ci } 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci return 0; 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_cidisable_asrck_clk: 132662306a36Sopenharmony_ci for (i--; i >= 0; i--) 132762306a36Sopenharmony_ci clk_disable_unprepare(asrc_priv->asrck_clk[i]); 132862306a36Sopenharmony_ci if (!IS_ERR(asrc->spba_clk)) 132962306a36Sopenharmony_ci clk_disable_unprepare(asrc->spba_clk); 133062306a36Sopenharmony_cidisable_ipg_clk: 133162306a36Sopenharmony_ci clk_disable_unprepare(asrc->ipg_clk); 133262306a36Sopenharmony_cidisable_mem_clk: 133362306a36Sopenharmony_ci clk_disable_unprepare(asrc->mem_clk); 133462306a36Sopenharmony_ci return ret; 133562306a36Sopenharmony_ci} 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_cistatic int fsl_asrc_runtime_suspend(struct device *dev) 133862306a36Sopenharmony_ci{ 133962306a36Sopenharmony_ci struct fsl_asrc *asrc = dev_get_drvdata(dev); 134062306a36Sopenharmony_ci struct fsl_asrc_priv *asrc_priv = asrc->private; 134162306a36Sopenharmony_ci int i; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci regmap_read(asrc->regmap, REG_ASRCFG, 134462306a36Sopenharmony_ci &asrc_priv->regcache_cfg); 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci regcache_cache_only(asrc->regmap, true); 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci for (i = 0; i < ASRC_CLK_MAX_NUM; i++) 134962306a36Sopenharmony_ci clk_disable_unprepare(asrc_priv->asrck_clk[i]); 135062306a36Sopenharmony_ci if (!IS_ERR(asrc->spba_clk)) 135162306a36Sopenharmony_ci clk_disable_unprepare(asrc->spba_clk); 135262306a36Sopenharmony_ci clk_disable_unprepare(asrc->ipg_clk); 135362306a36Sopenharmony_ci clk_disable_unprepare(asrc->mem_clk); 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci return 0; 135662306a36Sopenharmony_ci} 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_cistatic const struct dev_pm_ops fsl_asrc_pm = { 135962306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(fsl_asrc_runtime_suspend, fsl_asrc_runtime_resume, NULL) 136062306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 136162306a36Sopenharmony_ci pm_runtime_force_resume) 136262306a36Sopenharmony_ci}; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_cistatic const struct fsl_asrc_soc_data fsl_asrc_imx35_data = { 136562306a36Sopenharmony_ci .use_edma = false, 136662306a36Sopenharmony_ci .channel_bits = 3, 136762306a36Sopenharmony_ci}; 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_cistatic const struct fsl_asrc_soc_data fsl_asrc_imx53_data = { 137062306a36Sopenharmony_ci .use_edma = false, 137162306a36Sopenharmony_ci .channel_bits = 4, 137262306a36Sopenharmony_ci}; 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_cistatic const struct fsl_asrc_soc_data fsl_asrc_imx8qm_data = { 137562306a36Sopenharmony_ci .use_edma = true, 137662306a36Sopenharmony_ci .channel_bits = 4, 137762306a36Sopenharmony_ci}; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_cistatic const struct fsl_asrc_soc_data fsl_asrc_imx8qxp_data = { 138062306a36Sopenharmony_ci .use_edma = true, 138162306a36Sopenharmony_ci .channel_bits = 4, 138262306a36Sopenharmony_ci}; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_cistatic const struct of_device_id fsl_asrc_ids[] = { 138562306a36Sopenharmony_ci { .compatible = "fsl,imx35-asrc", .data = &fsl_asrc_imx35_data }, 138662306a36Sopenharmony_ci { .compatible = "fsl,imx53-asrc", .data = &fsl_asrc_imx53_data }, 138762306a36Sopenharmony_ci { .compatible = "fsl,imx8qm-asrc", .data = &fsl_asrc_imx8qm_data }, 138862306a36Sopenharmony_ci { .compatible = "fsl,imx8qxp-asrc", .data = &fsl_asrc_imx8qxp_data }, 138962306a36Sopenharmony_ci {} 139062306a36Sopenharmony_ci}; 139162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, fsl_asrc_ids); 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_cistatic struct platform_driver fsl_asrc_driver = { 139462306a36Sopenharmony_ci .probe = fsl_asrc_probe, 139562306a36Sopenharmony_ci .remove_new = fsl_asrc_remove, 139662306a36Sopenharmony_ci .driver = { 139762306a36Sopenharmony_ci .name = "fsl-asrc", 139862306a36Sopenharmony_ci .of_match_table = fsl_asrc_ids, 139962306a36Sopenharmony_ci .pm = &fsl_asrc_pm, 140062306a36Sopenharmony_ci }, 140162306a36Sopenharmony_ci}; 140262306a36Sopenharmony_cimodule_platform_driver(fsl_asrc_driver); 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ciMODULE_DESCRIPTION("Freescale ASRC ASoC driver"); 140562306a36Sopenharmony_ciMODULE_AUTHOR("Nicolin Chen <nicoleotsuka@gmail.com>"); 140662306a36Sopenharmony_ciMODULE_ALIAS("platform:fsl-asrc"); 140762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1408