Загрузка данных


#define FSL_XCVR_SPDIF_RX_FREQ	175000000
static int fsl_xcvr_prepare(struct snd_pcm_substream *substream,
			    struct snd_soc_dai *dai)
{
	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
	u32 m_ctl = 0, v_ctl = 0;
	u32 r = substream->runtime->rate, ch = substream->runtime->channels;
	u32 fout = 32 * r * ch * 10;
	int ret = 0;

printk("%s(%d) mode=%d\n",__FUNCTION__,__LINE__,xcvr->mode);
	switch (xcvr->mode) {
	case FSL_XCVR_MODE_SPDIF:
		if (xcvr->soc_data->spdif_only && tx) {
			ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_TX_DPTH_CTRL,
						 FSL_XCVR_TX_DPTH_CTRL_BYPASS_FEM,
						 FSL_XCVR_TX_DPTH_CTRL_BYPASS_FEM);
			if (ret < 0) {
				dev_err(dai->dev, "Failed to set bypass fem: %d\n", ret);
				return ret;
			}
		}
		fallthrough;
	case FSL_XCVR_MODE_ARC:
		if (tx) {
			ret = fsl_xcvr_en_aud_pll(xcvr, fout);
			if (ret < 0) {
				dev_err(dai->dev, "Failed to set TX freq %u: %d\n",
					fout, ret);
				return ret;
			}

			ret = regmap_set_bits(xcvr->regmap, FSL_XCVR_TX_DPTH_CTRL,
					      FSL_XCVR_TX_DPTH_CTRL_FRM_FMT);
			if (ret < 0) {
				dev_err(dai->dev, "Failed to set TX_DPTH: %d\n", ret);
				return ret;
			}

			/**
			 * set SPDIF MODE - this flag is used to gate
			 * SPDIF output, useless for SPDIF RX
			 */
			m_ctl |= FSL_XCVR_EXT_CTRL_SPDIF_MODE;
			v_ctl |= FSL_XCVR_EXT_CTRL_SPDIF_MODE;
		} else {
			/**
			 * Clear RX FIFO, flip RX FIFO bits,
			 * disable eARC related HW mode detects
			 */
			ret = regmap_set_bits(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL,
					      FSL_XCVR_RX_DPTH_CTRL_STORE_FMT |
					      FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO |
					      FSL_XCVR_RX_DPTH_CTRL_COMP |
					      FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL);
			if (ret < 0) {
				dev_err(dai->dev, "Failed to set RX_DPTH: %d\n", ret);
				return ret;
			}

			ret = fsl_xcvr_en_phy_pll(xcvr, FSL_XCVR_SPDIF_RX_FREQ, tx);
			if (ret < 0) {
				dev_err(dai->dev, "Failed to set RX freq %u: %d\n",
					FSL_XCVR_SPDIF_RX_FREQ, ret);
				return ret;
			}
		}
		break;
	case FSL_XCVR_MODE_EARC:
		if (!tx) {
			/** Clear RX FIFO, flip RX FIFO bits */
			ret = regmap_set_bits(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL,
					      FSL_XCVR_RX_DPTH_CTRL_STORE_FMT |
					      FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO);
			if (ret < 0) {
				dev_err(dai->dev, "Failed to set RX_DPTH: %d\n", ret);
				return ret;
			}

			/** Enable eARC related HW mode detects */
			ret = regmap_clear_bits(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL,
						FSL_XCVR_RX_DPTH_CTRL_COMP |
						FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL);
			if (ret < 0) {
				dev_err(dai->dev, "Failed to clr TX_DPTH: %d\n", ret);
				return ret;
			}
		}

		/* clear CMDC RESET */
		m_ctl |= FSL_XCVR_EXT_CTRL_CMDC_RESET(tx);
		/* set TX_RX_MODE */
		m_ctl |= FSL_XCVR_EXT_CTRL_TX_RX_MODE;
		v_ctl |= (tx ? FSL_XCVR_EXT_CTRL_TX_RX_MODE : 0);
		break;
	}

printk("%s(%d) \n",__FUNCTION__,__LINE__);
	ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, m_ctl, v_ctl);
printk("%s(%d) ret=%d\n",__FUNCTION__,__LINE__,ret);
	if (ret < 0) {
		dev_err(dai->dev, "Error while setting EXT_CTRL: %d\n", ret);
		return ret;
	}

	return 0;
}

static int fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd,
			    struct snd_soc_dai *dai)
{
	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
	unsigned long lock_flags;
	int ret = 0;

	spin_lock_irqsave(&xcvr->lock, lock_flags);

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_RESUME:
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
		/* set DPATH RESET */
		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
					 FSL_XCVR_EXT_CTRL_DPTH_RESET(tx),
					 FSL_XCVR_EXT_CTRL_DPTH_RESET(tx));
		if (ret < 0) {
			dev_err(dai->dev, "Failed to set DPATH RESET: %d\n", ret);
			goto release_lock;
		}

		if (tx) {
			switch (xcvr->mode) {
			case FSL_XCVR_MODE_EARC:
				/* set isr_cmdc_tx_en, w1c */
				ret = regmap_write(xcvr->regmap,
						   FSL_XCVR_ISR_SET,
						   FSL_XCVR_ISR_CMDC_TX_EN);
				if (ret < 0) {
					dev_err(dai->dev, "err updating isr %d\n", ret);
					goto release_lock;
				}
				fallthrough;
			case FSL_XCVR_MODE_SPDIF:
				ret = regmap_set_bits(xcvr->regmap,
						      FSL_XCVR_TX_DPTH_CTRL,
						      FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX);
				if (ret < 0) {
					dev_err(dai->dev, "Failed to start DATA_TX: %d\n", ret);
					goto release_lock;
				}
				break;
			}
		}

		/* enable DMA RD/WR */
		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
					 FSL_XCVR_EXT_CTRL_DMA_DIS(tx), 0);
		if (ret < 0) {
			dev_err(dai->dev, "Failed to enable DMA: %d\n", ret);
			goto release_lock;
		}

		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
					 FSL_XCVR_IRQ_EARC_ALL, FSL_XCVR_IRQ_EARC_ALL);
		if (ret < 0) {
			dev_err(dai->dev, "Error while setting IER0: %d\n", ret);
			goto release_lock;
		}

		/* clear DPATH RESET */
		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
					 FSL_XCVR_EXT_CTRL_DPTH_RESET(tx),
					 0);
		if (ret < 0) {
			dev_err(dai->dev, "Failed to clear DPATH RESET: %d\n", ret);
			goto release_lock;
		}

		break;
	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_SUSPEND:
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
		/* disable DMA RD/WR */
		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
					 FSL_XCVR_EXT_CTRL_DMA_DIS(tx),
					 FSL_XCVR_EXT_CTRL_DMA_DIS(tx));
		if (ret < 0) {
			dev_err(dai->dev, "Failed to disable DMA: %d\n", ret);
			goto release_lock;
		}

		ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
					 FSL_XCVR_IRQ_EARC_ALL, 0);
		if (ret < 0) {
			dev_err(dai->dev, "Failed to clear IER0: %d\n", ret);
			goto release_lock;
		}

		if (tx) {
			switch (xcvr->mode) {
			case FSL_XCVR_MODE_SPDIF:
				ret = regmap_clear_bits(xcvr->regmap,
							FSL_XCVR_TX_DPTH_CTRL,
							FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX);
				if (ret < 0) {
					dev_err(dai->dev, "Failed to stop DATA_TX: %d\n", ret);
					goto release_lock;
				}
				if (xcvr->soc_data->spdif_only)
					break;
				else
					fallthrough;
			case FSL_XCVR_MODE_EARC:
				/* clear ISR_CMDC_TX_EN, W1C */
				ret = regmap_write(xcvr->regmap,
						   FSL_XCVR_ISR_CLR,
						   FSL_XCVR_ISR_CMDC_TX_EN);
				if (ret < 0) {
					dev_err(dai->dev,
						"Err updating ISR %d\n", ret);
					goto release_lock;
				}
				break;
			}
		}
		break;
	default:
		ret = -EINVAL;
		break;
	}

release_lock:
	spin_unlock_irqrestore(&xcvr->lock, lock_flags);
	return ret;
}

static int fsl_xcvr_startup(struct snd_pcm_substream *substream,
			    struct snd_soc_dai *dai)
{
	struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai);
	bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
	int ret = 0;

printk("%s(%d)\n",__FUNCTION__,__LINE__);
	if (xcvr->streams & BIT(substream->stream)) {
		dev_err(dai->dev, "%sX busy\n", tx ? "T" : "R");
		return -EBUSY;
	}

printk("%s(%d)\n",__FUNCTION__,__LINE__);
	/*
	 * EDMA controller needs period size to be a multiple of
	 * tx/rx maxburst
	 */
	if (xcvr->soc_data->use_edma)
		snd_pcm_hw_constraint_step(substream->runtime, 0,
					   SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
					   tx ? xcvr->dma_prms_tx.maxburst :
					   xcvr->dma_prms_rx.maxburst);

	switch (xcvr->mode) {
	case FSL_XCVR_MODE_SPDIF:
	case FSL_XCVR_MODE_ARC:
		if (xcvr->soc_data->spdif_only && tx)
			ret = fsl_xcvr_constr(substream, &fsl_xcvr_spdif_channels_constr,
					      &xcvr->spdif_constr_rates);
		else
			ret = fsl_xcvr_constr(substream, &fsl_xcvr_spdif_channels_constr,
					      &fsl_xcvr_spdif_rates_constr);
		break;
	case FSL_XCVR_MODE_EARC:
		ret = fsl_xcvr_constr(substream, &fsl_xcvr_earc_channels_constr,
				      &fsl_xcvr_earc_rates_constr);
		break;
	}
printk("%s(%d) mode=%d ret=%d\n",__FUNCTION__,__LINE__,xcvr->mode,ret);
	if (ret < 0)
		return ret;

	xcvr->streams |= BIT(substream->stream);

printk("%s(%d)\n",__FUNCTION__,__LINE__);
	if (!xcvr->soc_data->spdif_only) {
		struct snd_soc_card *card = dai->component->card;

		/* Disable XCVR controls if there is stream started */
		down_read(&card->snd_card->controls_rwsem);
		fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, false);
		fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, false);
		fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name, false);
		up_read(&card->snd_card->controls_rwsem);
	}

printk("%s(%d)\n",__FUNCTION__,__LINE__);
	return 0;
}

static const struct fsl_xcvr_soc_data fsl_xcvr_imx95_data = {
	.fw_name = "imx/xcvr/xcvr-imx95.bin",
	.spdif_only = true,
	.use_phy = true,
	.use_edma = true,
	.pll_ver = PLL_MX95,
};