diff options
author | Viorel Suman <viorel.suman@nxp.com> | 2020-03-31 10:16:56 +0300 |
---|---|---|
committer | Viorel Suman <viorel.suman@nxp.com> | 2020-04-02 11:57:02 +0300 |
commit | 2513444554dc5519512710da930530edbb993a6a (patch) | |
tree | 798b748a97d50d4566c07c29fc64157861ac20b0 /sound/soc/fsl | |
parent | ca5fccb261bcd67f87562a622946d2c1f7448a12 (diff) |
MLK-23732: fsl_xcvr: implement eARC RX fallback mode
There are 2 configurable options for eARC RX fallback
to ARC mode: "ARC single ended" or "ARC common".
Add amixer control in order to allow setting it
from userspace.
Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
Reviewed-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Diffstat (limited to 'sound/soc/fsl')
-rw-r--r-- | sound/soc/fsl/fsl_xcvr.c | 54 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_xcvr.h | 22 |
2 files changed, 74 insertions, 2 deletions
diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index 315f5b9a329e..6fbbf64c6f01 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -25,6 +25,7 @@ struct fsl_xcvr { const char *fw_name; u8 streams; u32 mode; + u32 arc_mode_idx; void __iomem *ram_addr; struct snd_dmaengine_dai_dma_data dma_prms_rx; struct snd_dmaengine_dai_dma_data dma_prms_tx; @@ -50,6 +51,17 @@ static const struct snd_pcm_hw_constraint_list fsl_xcvr_earc_rates_constr = { static const u32 fsl_xcvr_spdif_channels[] = { 2, }; +static const int fsl_xcvr_arc_mode_ints[] = { + FSL_XCVR_ISR_SET_ARC_SE_INT, FSL_XCVR_ISR_SET_ARC_CM_INT, +}; + +static const char * const fsl_xcvr_arc_mode[] = { + "ARC Single Ended", "ARC Common", +}; + +static const struct soc_enum fsl_xcvr_arc_mode_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(fsl_xcvr_arc_mode), fsl_xcvr_arc_mode); + /* * pll_phy: pll 0; phy 1; */ @@ -105,6 +117,8 @@ static int fsl_xcvr_prepare(struct snd_pcm_substream *substream, break; case FSL_XCVR_AMODE_ARC: /* Enable ISR */ + m_isr |= fsl_xcvr_arc_mode_ints[xcvr->arc_mode_idx]; + v_isr |= fsl_xcvr_arc_mode_ints[xcvr->arc_mode_idx]; break; case FSL_XCVR_AMODE_EARC: /* clear CMDC RESET */ @@ -125,7 +139,7 @@ static int fsl_xcvr_prepare(struct snd_pcm_substream *substream, ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_ISR_SET, m_isr, v_isr); if (ret < 0) { - dev_err(dai->dev, "Error while setting MO ISR: %d\n", ret); + dev_err(dai->dev, "Error while setting M0 ISR: %d\n", ret); return ret; } @@ -554,6 +568,31 @@ static int fsl_xcvr_tx_cs_put(struct snd_kcontrol *kcontrol, return 0; } +static int fsl_xcvr_arc_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + unsigned int *item = ucontrol->value.enumerated.item; + int val = snd_soc_enum_item_to_val(e, item[0]); + + xcvr->arc_mode_idx = val; + + return 0; +} + +static int fsl_xcvr_arc_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); + struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); + + ucontrol->value.enumerated.item[0] = xcvr->arc_mode_idx; + + return 0; +} + static struct snd_kcontrol_new fsl_xcvr_rx_ctls[] = { /* Channel status controller */ { @@ -571,6 +610,8 @@ static struct snd_kcontrol_new fsl_xcvr_rx_ctls[] = { .info = fsl_xcvr_type_bytes_info, .get = fsl_xcvr_rx_cs_get, }, + SOC_ENUM_EXT("ARC Mode", fsl_xcvr_arc_mode_enum, + fsl_xcvr_arc_mode_get, fsl_xcvr_arc_mode_put), }; static struct snd_kcontrol_new fsl_xcvr_tx_ctls[] = { @@ -817,6 +858,17 @@ static irqreturn_t irq0_isr(int irq, void *devid) dev_dbg(dev, "RX/TX FIFO full/empty\n"); if (isr & FSL_XCVR_IRQ_ARC_MODE) dev_dbg(dev, "CMDC SM falls out of eARC mode\n"); + if (isr & FSL_XCVR_IRQ_CMDC_STATUS_UPD) { + dev_dbg(dev, "CMDC status update\n"); + regmap_read(regmap, FSL_XCVR_EXT_STATUS, &val); + if (val & FSL_XCVR_EXT_STUS_RX_CMDC_COTO) { + dev_dbg(dev, "RX CMDC comma timeout\n"); + /* Set eARC fallback mode*/ + val = fsl_xcvr_arc_mode_ints[xcvr->arc_mode_idx]; + regmap_update_bits(xcvr->regmap, FSL_XCVR_ISR_SET, + val, val); + } + } if (isr & FSL_XCVR_IRQ_DMA_RD_REQ) dev_dbg(dev, "DMA read request\n"); if (isr & FSL_XCVR_IRQ_DMA_WR_REQ) diff --git a/sound/soc/fsl/fsl_xcvr.h b/sound/soc/fsl/fsl_xcvr.h index 424f6572747f..c51c88a6c69d 100644 --- a/sound/soc/fsl/fsl_xcvr.h +++ b/sound/soc/fsl/fsl_xcvr.h @@ -104,6 +104,21 @@ #define FSL_XCVR_EXT_CTRL_PAGE(i) (((i) << FSL_XCVR_EXT_CTRL_PAGE_SHFT) \ & FSL_XCVR_EXT_CTRL_PAGE_MASK) +#define FSL_XCVR_EXT_STUS_NT_FIFO_ENTR GENMASK(7, 0) +#define FSL_XCVR_EXT_STUS_NR_FIFO_ENTR GENMASK(15, 8) +#define FSL_XCVR_EXT_STUS_CM0_SLEEPING BIT(16) +#define FSL_XCVR_EXT_STUS_CM0_DEEP_SLP BIT(17) +#define FSL_XCVR_EXT_STUS_CM0_SLP_HACK BIT(18) +#define FSL_XCVR_EXT_STUS_RX_CMDC_RSTO BIT(23) +#define FSL_XCVR_EXT_STUS_TX_CMDC_RSTO BIT(24) +#define FSL_XCVR_EXT_STUS_RX_CMDC_COTO BIT(25) +#define FSL_XCVR_EXT_STUS_TX_CMDC_COTO BIT(26) +#define FSL_XCVR_EXT_STUS_HB_STATUS BIT(27) +#define FSL_XCVR_EXT_STUS_NEW_UD4_REC BIT(28) +#define FSL_XCVR_EXT_STUS_NEW_UD5_REC BIT(29) +#define FSL_XCVR_EXT_STUS_NEW_UD6_REC BIT(30) +#define FSL_XCVR_EXT_STUS_HPD_INPUT BIT(31) + #define FSL_XCVR_IRQ_NEW_CS BIT(0) #define FSL_XCVR_IRQ_NEW_UD BIT(1) #define FSL_XCVR_IRQ_MUTE BIT(2) @@ -132,12 +147,17 @@ FSL_XCVR_IRQ_MUTE | \ FSL_XCVR_IRQ_FIFO_UOFL_ERR | \ FSL_XCVR_IRQ_HOST_WAKEUP | \ + FSL_XCVR_IRQ_CMDC_STATUS_UPD | \ FSL_XCVR_IRQ_ARC_MODE #define FSL_XCVR_ISR_CMDC_TX_EN BIT(3) #define FSL_XCVR_ISR_HPD_TGL BIT(15) -#define FSL_XCVR_ISR_SET_SPDIF_MODE(t) (t ? BIT(21) : BIT(20)) #define FSL_XCVR_ISR_DMAC_SPARE_INT BIT(19) +#define FSL_XCVR_ISR_SET_SPDIF_RX_INT BIT(20) +#define FSL_XCVR_ISR_SET_SPDIF_TX_INT BIT(21) +#define FSL_XCVR_ISR_SET_SPDIF_MODE(t) (t ? BIT(21) : BIT(20)) +#define FSL_XCVR_ISR_SET_ARC_CM_INT BIT(22) +#define FSL_XCVR_ISR_SET_ARC_SE_INT BIT(23) #define FSL_XCVR_PHY_AI_ADDR_MASK GENMASK(7, 0) #define FSL_XCVR_PHY_AI_RESETN BIT(15) |