Загрузка данных
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_constr(const struct snd_pcm_substream *substream,
const struct snd_pcm_hw_constraint_list *channels,
const struct snd_pcm_hw_constraint_list *rates)
{
struct snd_pcm_runtime *rt = substream->runtime;
int ret;
ret = snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
channels);
if (ret < 0)
return ret;
ret = snd_pcm_hw_constraint_list(rt, 0, SNDRV_PCM_HW_PARAM_RATE,
rates);
if (ret < 0)
return ret;
return 0;
}
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 void fsl_xcvr_shutdown(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 mask = 0, val = 0;
int ret;
xcvr->streams &= ~BIT(substream->stream);
/* Enable XCVR controls if there is no stream started */
if (!xcvr->streams) {
if (!xcvr->soc_data->spdif_only) {
struct snd_soc_card *card = dai->component->card;
down_read(&card->snd_card->controls_rwsem);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, true);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name,
(xcvr->mode == FSL_XCVR_MODE_ARC));
fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name,
(xcvr->mode == FSL_XCVR_MODE_EARC));
up_read(&card->snd_card->controls_rwsem);
}
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 set IER0: %d\n", ret);
return;
}
/* clear SPDIF MODE */
if (xcvr->mode == FSL_XCVR_MODE_SPDIF)
mask |= FSL_XCVR_EXT_CTRL_SPDIF_MODE;
}
if (xcvr->mode == FSL_XCVR_MODE_EARC) {
/* set CMDC RESET */
mask |= FSL_XCVR_EXT_CTRL_CMDC_RESET(tx);
val |= FSL_XCVR_EXT_CTRL_CMDC_RESET(tx);
}
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, mask, val);
if (ret < 0) {
dev_err(dai->dev, "Err setting DPATH RESET: %d\n", ret);
return;
}
}