mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 10:31:46 +09:00
ASoC: rockchip: sai: Add support for RV1126B
* Enhance Frame Integrity Robustness * Support FIFO Interleaved Cfg * Support Data Debug Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com> Change-Id: I1cff642007e3421b49e602ea900832a0d94c58d1
This commit is contained in:
@@ -31,6 +31,7 @@
|
||||
#define FW_RATIO_MAX 8
|
||||
#define FW_RATIO_MIN 1
|
||||
#define MAXBURST_PER_FIFO 8
|
||||
#define FIFO_PER_LANE 32
|
||||
|
||||
#define DEFAULT_FS 48000
|
||||
#define TIMEOUT_US 1000
|
||||
@@ -75,6 +76,7 @@ struct rk_sai_dev {
|
||||
bool is_clk_auto;
|
||||
bool is_mclk_calibrate;
|
||||
bool is_tx_auto_gate; /* auto gate clk when TX FIFO empty */
|
||||
bool is_lane_interleaved;
|
||||
bool no_set_mclk;
|
||||
};
|
||||
|
||||
@@ -281,6 +283,33 @@ err_hclk:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rockchip_sai_fifo_level_wdt(struct rk_sai_dev *sai,
|
||||
int stream, bool en)
|
||||
{
|
||||
if (sai->version < SAI_VER_2411)
|
||||
return;
|
||||
|
||||
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
regmap_update_bits(sai->regmap, SAI_INTCR,
|
||||
SAI_INTCR_TXFLC, SAI_INTCR_TXFLC);
|
||||
regmap_update_bits(sai->regmap, SAI_INTCR,
|
||||
SAI_INTCR_TXFLE_MASK,
|
||||
SAI_INTCR_TXFLE(en));
|
||||
regmap_update_bits(sai->regmap, SAI_TXCR,
|
||||
SAI_XCR_FLE_MASK,
|
||||
SAI_XCR_FLE(en));
|
||||
} else {
|
||||
regmap_update_bits(sai->regmap, SAI_INTCR,
|
||||
SAI_INTCR_RXFLC, SAI_INTCR_RXFLC);
|
||||
regmap_update_bits(sai->regmap, SAI_INTCR,
|
||||
SAI_INTCR_RXFLE_MASK,
|
||||
SAI_INTCR_RXFLE(en));
|
||||
regmap_update_bits(sai->regmap, SAI_RXCR,
|
||||
SAI_XCR_FLE_MASK,
|
||||
SAI_XCR_FLE(en));
|
||||
}
|
||||
}
|
||||
|
||||
static void rockchip_sai_fifo_xrun_detect(struct rk_sai_dev *sai,
|
||||
int stream, bool en)
|
||||
{
|
||||
@@ -408,12 +437,14 @@ static void rockchip_sai_xfer_stop(struct rk_sai_dev *sai, int stream)
|
||||
|
||||
static void rockchip_sai_start(struct rk_sai_dev *sai, int stream)
|
||||
{
|
||||
rockchip_sai_fifo_level_wdt(sai, stream, 1);
|
||||
rockchip_sai_dma_ctrl(sai, stream, 1);
|
||||
rockchip_sai_xfer_start(sai, stream);
|
||||
}
|
||||
|
||||
static void rockchip_sai_stop(struct rk_sai_dev *sai, int stream)
|
||||
{
|
||||
rockchip_sai_fifo_level_wdt(sai, stream, 0);
|
||||
rockchip_sai_dma_ctrl(sai, stream, 0);
|
||||
rockchip_sai_xfer_stop(sai, stream);
|
||||
}
|
||||
@@ -546,6 +577,21 @@ static unsigned int rockchip_sai_lanes_auto(struct snd_pcm_hw_params *params,
|
||||
return lanes;
|
||||
}
|
||||
|
||||
static int rockchip_fifo_cfg(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
if (sai->version < SAI_VER_2411)
|
||||
return 0;
|
||||
|
||||
if (!sai->is_lane_interleaved)
|
||||
regmap_update_bits(sai->regmap, SAI_FIFO_CFG,
|
||||
SAI_FIFO_CHG_MASK, SAI_FIFO_CHG_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
@@ -606,6 +652,8 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
|
||||
slot_width = SAI_XCR_SBW_V(val);
|
||||
ch_per_lane = params_channels(params) / lanes;
|
||||
|
||||
rockchip_fifo_cfg(substream, dai);
|
||||
|
||||
regmap_update_bits(sai->regmap, reg, SAI_XCR_SNB_MASK,
|
||||
SAI_XCR_SNB(ch_per_lane));
|
||||
|
||||
@@ -1072,6 +1120,7 @@ static bool rockchip_sai_wr_reg(struct device *dev, unsigned int reg)
|
||||
case SAI_DMACR:
|
||||
case SAI_INTCR:
|
||||
case SAI_TXDR:
|
||||
case SAI_TXDR2:
|
||||
case SAI_PATH_SEL:
|
||||
case SAI_TX_SLOT_MASK0:
|
||||
case SAI_TX_SLOT_MASK1:
|
||||
@@ -1086,6 +1135,10 @@ static bool rockchip_sai_wr_reg(struct device *dev, unsigned int reg)
|
||||
case SAI_FSXN:
|
||||
case SAI_FS_TIMEOUT:
|
||||
case SAI_LOOPBACK_LR:
|
||||
case SAI_FIFO_CFG:
|
||||
case SAI_TXFL_TIMEOUT:
|
||||
case SAI_RXFL_TIMEOUT:
|
||||
case SAI_DEBUG:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -1109,6 +1162,8 @@ static bool rockchip_sai_rd_reg(struct device *dev, unsigned int reg)
|
||||
case SAI_INTSR:
|
||||
case SAI_TXDR:
|
||||
case SAI_RXDR:
|
||||
case SAI_TXDR2:
|
||||
case SAI_RXDR2:
|
||||
case SAI_PATH_SEL:
|
||||
case SAI_TX_SLOT_MASK0:
|
||||
case SAI_TX_SLOT_MASK1:
|
||||
@@ -1127,6 +1182,11 @@ static bool rockchip_sai_rd_reg(struct device *dev, unsigned int reg)
|
||||
case SAI_FSXN:
|
||||
case SAI_FS_TIMEOUT:
|
||||
case SAI_LOOPBACK_LR:
|
||||
case SAI_FIFO_CFG:
|
||||
case SAI_TXFL_TIMEOUT:
|
||||
case SAI_RXFL_TIMEOUT:
|
||||
case SAI_DEBUG:
|
||||
case SAI_TXDATA0 ... SAI_RXDATA3:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -1144,10 +1204,13 @@ static bool rockchip_sai_volatile_reg(struct device *dev, unsigned int reg)
|
||||
case SAI_RXFIFOLR:
|
||||
case SAI_TXDR:
|
||||
case SAI_RXDR:
|
||||
case SAI_TXDR2:
|
||||
case SAI_RXDR2:
|
||||
case SAI_TX_DATA_CNT:
|
||||
case SAI_RX_DATA_CNT:
|
||||
case SAI_STATUS:
|
||||
case SAI_VERSION:
|
||||
case SAI_TXDATA0 ... SAI_RXDATA3:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -1158,6 +1221,7 @@ static bool rockchip_sai_precious_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case SAI_RXDR:
|
||||
case SAI_RXDR2:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -1175,7 +1239,7 @@ static const struct regmap_config rockchip_sai_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.max_register = SAI_LOOPBACK_LR,
|
||||
.max_register = SAI_RXDR2,
|
||||
.reg_defaults = rockchip_sai_reg_defaults,
|
||||
.num_reg_defaults = ARRAY_SIZE(rockchip_sai_reg_defaults),
|
||||
.writeable_reg = rockchip_sai_wr_reg,
|
||||
@@ -1236,7 +1300,11 @@ static int rockchip_sai_init_dai(struct rk_sai_dev *sai, struct resource *res,
|
||||
SNDRV_PCM_FMTBIT_S32_LE |
|
||||
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
|
||||
|
||||
sai->playback_dma_data.addr = res->start + SAI_TXDR;
|
||||
if (sai->version >= SAI_VER_2411)
|
||||
sai->playback_dma_data.addr = res->start + SAI_TXDR2;
|
||||
else
|
||||
sai->playback_dma_data.addr = res->start + SAI_TXDR;
|
||||
|
||||
sai->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
sai->playback_dma_data.maxburst = MAXBURST_PER_FIFO;
|
||||
}
|
||||
@@ -1252,11 +1320,27 @@ static int rockchip_sai_init_dai(struct rk_sai_dev *sai, struct resource *res,
|
||||
SNDRV_PCM_FMTBIT_S32_LE |
|
||||
SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE;
|
||||
|
||||
sai->capture_dma_data.addr = res->start + SAI_RXDR;
|
||||
if (sai->version >= SAI_VER_2411)
|
||||
sai->capture_dma_data.addr = res->start + SAI_RXDR2;
|
||||
else
|
||||
sai->capture_dma_data.addr = res->start + SAI_RXDR;
|
||||
|
||||
sai->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
sai->capture_dma_data.maxburst = MAXBURST_PER_FIFO;
|
||||
}
|
||||
|
||||
if (sai->version >= SAI_VER_2411) {
|
||||
regmap_update_bits(sai->regmap, SAI_TXCR,
|
||||
SAI_XCR_FPC_MASK | SAI_XCR_SFC_MASK,
|
||||
SAI_XCR_FPC_EN | SAI_XCR_SFC_ONE);
|
||||
regmap_update_bits(sai->regmap, SAI_RXCR,
|
||||
SAI_XCR_FPC_MASK | SAI_XCR_SFC_MASK,
|
||||
SAI_XCR_FPC_EN | SAI_XCR_SFC_ONE);
|
||||
/* The counter is driven by HCLK */
|
||||
regmap_write(sai->regmap, SAI_TXFL_TIMEOUT, 0x1000000);
|
||||
regmap_write(sai->regmap, SAI_RXFL_TIMEOUT, 0x1000000);
|
||||
}
|
||||
|
||||
regmap_update_bits(sai->regmap, SAI_DMACR, SAI_DMACR_TDL_MASK,
|
||||
SAI_DMACR_TDL(16));
|
||||
regmap_update_bits(sai->regmap, SAI_DMACR, SAI_DMACR_RDL_MASK,
|
||||
@@ -1290,6 +1374,7 @@ static const char * const sbw_text[] = {
|
||||
"25", "26", "27", "28", "29", "30", "31", "32", };
|
||||
|
||||
static const char * const mono_text[] = { "Disable", "Enable" };
|
||||
static const char * const dbg_text[] = { "Disable", "Enable" };
|
||||
|
||||
static DECLARE_TLV_DB_SCALE(rmss_tlv, 0, 128, 0);
|
||||
|
||||
@@ -1380,6 +1465,9 @@ static SOC_ENUM_SINGLE_DECL(lp2lr_switch, SAI_LOOPBACK_LR, 2, lplr_text);
|
||||
static SOC_ENUM_SINGLE_DECL(lp1lr_switch, SAI_LOOPBACK_LR, 1, lplr_text);
|
||||
static SOC_ENUM_SINGLE_DECL(lp0lr_switch, SAI_LOOPBACK_LR, 0, lplr_text);
|
||||
|
||||
/* DEBUG */
|
||||
static SOC_ENUM_SINGLE_DECL(__maybe_unused dbg_switch, SAI_DEBUG, 0, dbg_text);
|
||||
|
||||
static int __maybe_unused rockchip_sai_fpw_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
@@ -1702,6 +1790,8 @@ static const struct snd_kcontrol_new rockchip_sai_controls[] = {
|
||||
0, 8192, 0, fs_shift_right_tlv),
|
||||
SOC_SINGLE_TLV("Receive Frame Shift Right Select", SAI_RX_SHIFT,
|
||||
0, 8192, 0, fs_shift_right_tlv),
|
||||
|
||||
SOC_ENUM("Data Debug Switch", dbg_switch),
|
||||
#endif
|
||||
SOC_ENUM("Transmit Start Mode Sel", tsl_enum),
|
||||
SOC_ENUM("Receive Start Mode Sel", rsl_enum),
|
||||
@@ -1811,6 +1901,25 @@ static irqreturn_t rockchip_sai_isr(int irq, void *devid)
|
||||
SAI_INTCR_FSLOST(0));
|
||||
}
|
||||
|
||||
if (val & SAI_INTSR_TXFLI_ACT) {
|
||||
dev_warn_ratelimited(sai->dev, "TX FIFO Level Err\n");
|
||||
regmap_update_bits(sai->regmap, SAI_INTCR,
|
||||
SAI_INTCR_TXFLC, SAI_INTCR_TXFLC);
|
||||
regmap_update_bits(sai->regmap, SAI_INTCR,
|
||||
SAI_INTCR_TXFLE_MASK,
|
||||
SAI_INTCR_TXFLE(0));
|
||||
|
||||
}
|
||||
|
||||
if (val & SAI_INTSR_RXFLI_ACT) {
|
||||
dev_warn_ratelimited(sai->dev, "RX FIFO Level Err\n");
|
||||
regmap_update_bits(sai->regmap, SAI_INTCR,
|
||||
SAI_INTCR_RXFLC, SAI_INTCR_RXFLC);
|
||||
regmap_update_bits(sai->regmap, SAI_INTCR,
|
||||
SAI_INTCR_RXFLE_MASK,
|
||||
SAI_INTCR_RXFLE(0));
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -1962,6 +2071,9 @@ static int rockchip_sai_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
sai->is_lane_interleaved =
|
||||
device_property_read_bool(&pdev->dev, "rockchip,lane-interleaved");
|
||||
|
||||
sai->is_mclk_calibrate =
|
||||
device_property_read_bool(&pdev->dev, "rockchip,mclk-calibrate");
|
||||
if (sai->is_mclk_calibrate) {
|
||||
|
||||
@@ -9,6 +9,14 @@
|
||||
#define _ROCKCHIP_SAI_H
|
||||
|
||||
/* XCR Transmit / Receive Control Register */
|
||||
#define SAI_XCR_FLE_MASK BIT(26)
|
||||
#define SAI_XCR_FLE(x) ((x) << 26)
|
||||
#define SAI_XCR_FPC_MASK BIT(25)
|
||||
#define SAI_XCR_FPC_EN BIT(25)
|
||||
#define SAI_XCR_FPC_DIS 0
|
||||
#define SAI_XCR_SFC_MASK BIT(24)
|
||||
#define SAI_XCR_SFC_ONE BIT(24)
|
||||
#define SAI_XCR_SFC_ALL 0
|
||||
#define SAI_XCR_START_SEL_MASK BIT(23)
|
||||
#define SAI_XCR_START_SEL_CHAINED BIT(23)
|
||||
#define SAI_XCR_START_SEL_STANDALONE 0
|
||||
@@ -128,11 +136,21 @@
|
||||
#define SAI_INTCR_RXOIC BIT(18)
|
||||
#define SAI_INTCR_RXOIE_MASK BIT(17)
|
||||
#define SAI_INTCR_RXOIE(x) ((x) << 17)
|
||||
#define SAI_INTCR_RXFLC BIT(12)
|
||||
#define SAI_INTCR_RXFLE_MASK BIT(11)
|
||||
#define SAI_INTCR_RXFLE(x) ((x) << 11)
|
||||
#define SAI_INTCR_TXFLC BIT(10)
|
||||
#define SAI_INTCR_TXFLE_MASK BIT(9)
|
||||
#define SAI_INTCR_TXFLE(x) ((x) << 9)
|
||||
#define SAI_INTCR_TXUIC BIT(2)
|
||||
#define SAI_INTCR_TXUIE_MASK BIT(1)
|
||||
#define SAI_INTCR_TXUIE(x) ((x) << 1)
|
||||
|
||||
/* INTSR Interrupt Status Register */
|
||||
#define SAI_INTSR_RXFLI_INA 0
|
||||
#define SAI_INTSR_RXFLI_ACT BIT(21)
|
||||
#define SAI_INTSR_TXFLI_INA 0
|
||||
#define SAI_INTSR_TXFLI_ACT BIT(20)
|
||||
#define SAI_INTSR_FSLOSTI_INA 0
|
||||
#define SAI_INTSR_FSLOSTI_ACT BIT(19)
|
||||
#define SAI_INTSR_FSERRI_INA 0
|
||||
@@ -203,11 +221,17 @@
|
||||
*
|
||||
* Support Loopback LR Select (e.g. L:MIC R:LP)
|
||||
*
|
||||
* VERSION >= SAI_VER_2411
|
||||
*
|
||||
* Enhance Frame Integrity Robustness
|
||||
* Support FIFO Interleaved Cfg
|
||||
* Support Data Debug
|
||||
*/
|
||||
#define SAI_VER_2307 0x23073576
|
||||
#define SAI_VER_2311 0x23112118
|
||||
#define SAI_VER_2401 0x24013506
|
||||
#define SAI_VER_2403 0x24031103
|
||||
#define SAI_VER_2411 0x24111126
|
||||
|
||||
/* FS_TIMEOUT: Frame Sync Timeout Register */
|
||||
#define SAI_FS_TIMEOUT_VAL_MASK GENMASK(31, 1)
|
||||
@@ -215,6 +239,11 @@
|
||||
#define SAI_FS_TIMEOUT_EN_MASK BIT(0)
|
||||
#define SAI_FS_TIMEOUT_EN(x) ((x) << 0)
|
||||
|
||||
/* FIFO_CFG: FIFO Config Register */
|
||||
#define SAI_FIFO_CHG_MASK BIT(0)
|
||||
#define SAI_FIFO_CHG_EN BIT(0)
|
||||
#define SAI_FIFO_CHG_DIS 0
|
||||
|
||||
/* SAI Registers */
|
||||
#define SAI_TXCR (0x0000)
|
||||
#define SAI_FSCR (0x0004)
|
||||
@@ -248,5 +277,19 @@
|
||||
#define SAI_FSXN (0x0074)
|
||||
#define SAI_FS_TIMEOUT (0x0078)
|
||||
#define SAI_LOOPBACK_LR (0x007c)
|
||||
#define SAI_FIFO_CFG (0x0080)
|
||||
#define SAI_TXFL_TIMEOUT (0x0084)
|
||||
#define SAI_RXFL_TIMEOUT (0x0088)
|
||||
#define SAI_DEBUG (0x008c)
|
||||
#define SAI_TXDATA0 (0x0090)
|
||||
#define SAI_TXDATA1 (0x0094)
|
||||
#define SAI_TXDATA2 (0x0098)
|
||||
#define SAI_TXDATA3 (0x009c)
|
||||
#define SAI_RXDATA0 (0x00a0)
|
||||
#define SAI_RXDATA1 (0x00a4)
|
||||
#define SAI_RXDATA2 (0x00a8)
|
||||
#define SAI_RXDATA3 (0x00ac)
|
||||
#define SAI_TXDR2 (0x0100)
|
||||
#define SAI_RXDR2 (0x0104)
|
||||
|
||||
#endif /* _ROCKCHIP_SAI_H */
|
||||
|
||||
Reference in New Issue
Block a user