Merge remote-tracking branch 'asoc/for-5.10' into asoc-next
This commit is contained in:
@ -324,7 +324,7 @@ config SND_SOC_FSL_ASOC_CARD
|
||||
help
|
||||
ALSA SoC Audio support with ASRC feature for Freescale SoCs that have
|
||||
ESAI/SAI/SSI and connect with external CODECs such as WM8962, CS42888,
|
||||
CS4271, CS4272 and SGTL5000.
|
||||
CS4271, CS4272, SGTL5000 and TLV320AIC32x4.
|
||||
Say Y if you want to add support for Freescale Generic ASoC Sound Card.
|
||||
|
||||
config SND_SOC_IMX_AUDMIX
|
||||
|
@ -617,6 +617,9 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
|
||||
codec_dai_name = "sgtl5000";
|
||||
priv->codec_priv.mclk_id = SGTL5000_SYSCLK;
|
||||
priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
|
||||
} else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic32x4")) {
|
||||
codec_dai_name = "tlv320aic32x4-hifi";
|
||||
priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
|
||||
} else if (of_device_is_compatible(np, "fsl,imx-audio-wm8962")) {
|
||||
codec_dai_name = "wm8962";
|
||||
priv->codec_priv.mclk_id = WM8962_SYSCLK_MCLK;
|
||||
@ -696,6 +699,17 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
|
||||
goto asrc_fail;
|
||||
}
|
||||
} else if (of_node_name_eq(cpu_np, "esai")) {
|
||||
struct clk *esai_clk = clk_get(&cpu_pdev->dev, "extal");
|
||||
|
||||
if (!IS_ERR(esai_clk)) {
|
||||
priv->cpu_priv.sysclk_freq[TX] = clk_get_rate(esai_clk);
|
||||
priv->cpu_priv.sysclk_freq[RX] = clk_get_rate(esai_clk);
|
||||
clk_put(esai_clk);
|
||||
} else if (PTR_ERR(esai_clk) == -EPROBE_DEFER) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto asrc_fail;
|
||||
}
|
||||
|
||||
priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL;
|
||||
priv->cpu_priv.sysclk_id[0] = ESAI_HCKR_EXTAL;
|
||||
} else if (of_node_name_eq(cpu_np, "sai")) {
|
||||
@ -849,6 +863,7 @@ static const struct of_device_id fsl_asoc_card_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx-audio-ac97", },
|
||||
{ .compatible = "fsl,imx-audio-cs42888", },
|
||||
{ .compatible = "fsl,imx-audio-cs427x", },
|
||||
{ .compatible = "fsl,imx-audio-tlv320aic32x4", },
|
||||
{ .compatible = "fsl,imx-audio-sgtl5000", },
|
||||
{ .compatible = "fsl,imx-audio-wm8962", },
|
||||
{ .compatible = "fsl,imx-audio-wm8960", },
|
||||
|
@ -154,7 +154,7 @@ static void fsl_dma_abort_stream(struct snd_pcm_substream *substream)
|
||||
/**
|
||||
* fsl_dma_update_pointers - update LD pointers to point to the next period
|
||||
*
|
||||
* As each period is completed, this function changes the the link
|
||||
* As each period is completed, this function changes the link
|
||||
* descriptor pointers for that period to point to the next period.
|
||||
*/
|
||||
static void fsl_dma_update_pointers(struct fsl_dma_private *dma_private)
|
||||
|
@ -41,7 +41,7 @@ struct fsl_esai_soc_data {
|
||||
* @extalclk: esai clock source to derive HCK, SCK and FS
|
||||
* @fsysclk: system clock source to derive HCK, SCK and FS
|
||||
* @spbaclk: SPBA clock (optional, depending on SoC design)
|
||||
* @task: tasklet to handle the reset operation
|
||||
* @work: work to handle the reset operation
|
||||
* @soc: soc specific data
|
||||
* @lock: spin lock between hw_reset() and trigger()
|
||||
* @fifo_depth: depth of tx/rx FIFO
|
||||
@ -67,7 +67,7 @@ struct fsl_esai {
|
||||
struct clk *extalclk;
|
||||
struct clk *fsysclk;
|
||||
struct clk *spbaclk;
|
||||
struct tasklet_struct task;
|
||||
struct work_struct work;
|
||||
const struct fsl_esai_soc_data *soc;
|
||||
spinlock_t lock; /* Protect hw_reset and trigger */
|
||||
u32 fifo_depth;
|
||||
@ -117,7 +117,7 @@ static irqreturn_t esai_isr(int irq, void *devid)
|
||||
ESAI_xCR_xEIE_MASK, 0);
|
||||
regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR,
|
||||
ESAI_xCR_xEIE_MASK, 0);
|
||||
tasklet_schedule(&esai_priv->task);
|
||||
schedule_work(&esai_priv->work);
|
||||
}
|
||||
|
||||
if (esr & ESAI_ESR_TINIT_MASK)
|
||||
@ -708,9 +708,9 @@ static void fsl_esai_trigger_stop(struct fsl_esai *esai_priv, bool tx)
|
||||
ESAI_xFCR_xFR, 0);
|
||||
}
|
||||
|
||||
static void fsl_esai_hw_reset(struct tasklet_struct *t)
|
||||
static void fsl_esai_hw_reset(struct work_struct *work)
|
||||
{
|
||||
struct fsl_esai *esai_priv = from_tasklet(esai_priv, t, task);
|
||||
struct fsl_esai *esai_priv = container_of(work, struct fsl_esai, work);
|
||||
bool tx = true, rx = false, enabled[2];
|
||||
unsigned long lock_flags;
|
||||
u32 tfcr, rfcr;
|
||||
@ -1070,7 +1070,7 @@ static int fsl_esai_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
tasklet_setup(&esai_priv->task, fsl_esai_hw_reset);
|
||||
INIT_WORK(&esai_priv->work, fsl_esai_hw_reset);
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
@ -1088,7 +1088,7 @@ static int fsl_esai_remove(struct platform_device *pdev)
|
||||
struct fsl_esai *esai_priv = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
tasklet_kill(&esai_priv->task);
|
||||
cancel_work_sync(&esai_priv->work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -37,6 +37,24 @@ static const struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = {
|
||||
.list = fsl_sai_rates,
|
||||
};
|
||||
|
||||
/**
|
||||
* fsl_sai_dir_is_synced - Check if stream is synced by the opposite stream
|
||||
*
|
||||
* SAI supports synchronous mode using bit/frame clocks of either Transmitter's
|
||||
* or Receiver's for both streams. This function is used to check if clocks of
|
||||
* the stream's are synced by the opposite stream.
|
||||
*
|
||||
* @sai: SAI context
|
||||
* @dir: stream direction
|
||||
*/
|
||||
static inline bool fsl_sai_dir_is_synced(struct fsl_sai *sai, int dir)
|
||||
{
|
||||
int adir = (dir == TX) ? RX : TX;
|
||||
|
||||
/* current dir in async mode while opposite dir in sync mode */
|
||||
return !sai->synchronous[dir] && sai->synchronous[adir];
|
||||
}
|
||||
|
||||
static irqreturn_t fsl_sai_isr(int irq, void *devid)
|
||||
{
|
||||
struct fsl_sai *sai = (struct fsl_sai *)devid;
|
||||
@ -332,6 +350,8 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
|
||||
unsigned int ofs = sai->soc_data->reg_offset;
|
||||
unsigned long clk_rate;
|
||||
u32 savediv = 0, ratio, savesub = freq;
|
||||
int adir = tx ? RX : TX;
|
||||
int dir = tx ? TX : RX;
|
||||
u32 id;
|
||||
int ret = 0;
|
||||
|
||||
@ -390,19 +410,17 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
|
||||
* 4) For Tx and Rx are both Synchronous with another SAI, we just
|
||||
* ignore it.
|
||||
*/
|
||||
if ((sai->synchronous[TX] && !sai->synchronous[RX]) ||
|
||||
(!tx && !sai->synchronous[RX])) {
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_RCR2(ofs),
|
||||
if (fsl_sai_dir_is_synced(sai, adir)) {
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_xCR2(!tx, ofs),
|
||||
FSL_SAI_CR2_MSEL_MASK,
|
||||
FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_RCR2(ofs),
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_xCR2(!tx, ofs),
|
||||
FSL_SAI_CR2_DIV_MASK, savediv - 1);
|
||||
} else if ((sai->synchronous[RX] && !sai->synchronous[TX]) ||
|
||||
(tx && !sai->synchronous[TX])) {
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_TCR2(ofs),
|
||||
} else if (!sai->synchronous[dir]) {
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs),
|
||||
FSL_SAI_CR2_MSEL_MASK,
|
||||
FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_TCR2(ofs),
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs),
|
||||
FSL_SAI_CR2_DIV_MASK, savediv - 1);
|
||||
}
|
||||
|
||||
@ -424,6 +442,8 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
|
||||
u32 val_cr4 = 0, val_cr5 = 0;
|
||||
u32 slots = (channels == 1) ? 2 : channels;
|
||||
u32 slot_width = word_width;
|
||||
int adir = tx ? RX : TX;
|
||||
u32 pins;
|
||||
int ret;
|
||||
|
||||
if (sai->slots)
|
||||
@ -432,6 +452,8 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
|
||||
if (sai->slot_width)
|
||||
slot_width = sai->slot_width;
|
||||
|
||||
pins = DIV_ROUND_UP(channels, slots);
|
||||
|
||||
if (!sai->is_slave_mode) {
|
||||
if (sai->bclk_ratio)
|
||||
ret = fsl_sai_set_bclk(cpu_dai, tx,
|
||||
@ -467,42 +489,38 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
|
||||
|
||||
val_cr4 |= FSL_SAI_CR4_FRSZ(slots);
|
||||
|
||||
/* Set to output mode to avoid tri-stated data pins */
|
||||
if (tx)
|
||||
val_cr4 |= FSL_SAI_CR4_CHMOD;
|
||||
|
||||
/*
|
||||
* For SAI master mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will
|
||||
* generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4),
|
||||
* RCR5(TCR5) and RMR(TMR) for playback(capture), or there will be sync
|
||||
* error.
|
||||
* RCR5(TCR5) for playback(capture), or there will be sync error.
|
||||
*/
|
||||
|
||||
if (!sai->is_slave_mode) {
|
||||
if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) {
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_TCR4(ofs),
|
||||
FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
|
||||
val_cr4);
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_TCR5(ofs),
|
||||
FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
|
||||
FSL_SAI_CR5_FBT_MASK, val_cr5);
|
||||
regmap_write(sai->regmap, FSL_SAI_TMR,
|
||||
~0UL - ((1 << channels) - 1));
|
||||
} else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) {
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_RCR4(ofs),
|
||||
FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
|
||||
val_cr4);
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_RCR5(ofs),
|
||||
FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
|
||||
FSL_SAI_CR5_FBT_MASK, val_cr5);
|
||||
regmap_write(sai->regmap, FSL_SAI_RMR,
|
||||
~0UL - ((1 << channels) - 1));
|
||||
}
|
||||
if (!sai->is_slave_mode && fsl_sai_dir_is_synced(sai, adir)) {
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_xCR4(!tx, ofs),
|
||||
FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
|
||||
FSL_SAI_CR4_CHMOD_MASK,
|
||||
val_cr4);
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_xCR5(!tx, ofs),
|
||||
FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
|
||||
FSL_SAI_CR5_FBT_MASK, val_cr5);
|
||||
}
|
||||
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs),
|
||||
FSL_SAI_CR3_TRCE_MASK,
|
||||
FSL_SAI_CR3_TRCE((1 << pins) - 1));
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
|
||||
FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
|
||||
FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
|
||||
FSL_SAI_CR4_CHMOD_MASK,
|
||||
val_cr4);
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_xCR5(tx, ofs),
|
||||
FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
|
||||
FSL_SAI_CR5_FBT_MASK, val_cr5);
|
||||
regmap_write(sai->regmap, FSL_SAI_xMR(tx), ~0UL - ((1 << channels) - 1));
|
||||
regmap_write(sai->regmap, FSL_SAI_xMR(tx),
|
||||
~0UL - ((1 << min(channels, slots)) - 1));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -512,6 +530,10 @@ static int fsl_sai_hw_free(struct snd_pcm_substream *substream,
|
||||
{
|
||||
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
||||
unsigned int ofs = sai->soc_data->reg_offset;
|
||||
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs),
|
||||
FSL_SAI_CR3_TRCE_MASK, 0);
|
||||
|
||||
if (!sai->is_slave_mode &&
|
||||
sai->mclk_streams & BIT(substream->stream)) {
|
||||
@ -522,6 +544,38 @@ static int fsl_sai_hw_free(struct snd_pcm_substream *substream,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fsl_sai_config_disable(struct fsl_sai *sai, int dir)
|
||||
{
|
||||
unsigned int ofs = sai->soc_data->reg_offset;
|
||||
bool tx = dir == TX;
|
||||
u32 xcsr, count = 100;
|
||||
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
|
||||
FSL_SAI_CSR_TERE, 0);
|
||||
|
||||
/* TERE will remain set till the end of current frame */
|
||||
do {
|
||||
udelay(10);
|
||||
regmap_read(sai->regmap, FSL_SAI_xCSR(tx, ofs), &xcsr);
|
||||
} while (--count && xcsr & FSL_SAI_CSR_TERE);
|
||||
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
|
||||
FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);
|
||||
|
||||
/*
|
||||
* For sai master mode, after several open/close sai,
|
||||
* there will be no frame clock, and can't recover
|
||||
* anymore. Add software reset to fix this issue.
|
||||
* This is a hardware bug, and will be fix in the
|
||||
* next sai version.
|
||||
*/
|
||||
if (!sai->is_slave_mode) {
|
||||
/* Software Reset */
|
||||
regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR);
|
||||
/* Clear SR bit to finish the reset */
|
||||
regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
struct snd_soc_dai *cpu_dai)
|
||||
@ -530,7 +584,9 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
unsigned int ofs = sai->soc_data->reg_offset;
|
||||
|
||||
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
||||
u32 xcsr, count = 100;
|
||||
int adir = tx ? RX : TX;
|
||||
int dir = tx ? TX : RX;
|
||||
u32 xcsr;
|
||||
|
||||
/*
|
||||
* Asynchronous mode: Clear SYNC for both Tx and Rx.
|
||||
@ -553,10 +609,22 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
|
||||
FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE);
|
||||
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs),
|
||||
FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs),
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
|
||||
FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
|
||||
/*
|
||||
* Enable the opposite direction for synchronous mode
|
||||
* 1. Tx sync with Rx: only set RE for Rx; set TE & RE for Tx
|
||||
* 2. Rx sync with Tx: only set TE for Tx; set RE & TE for Rx
|
||||
*
|
||||
* RM recommends to enable RE after TE for case 1 and to enable
|
||||
* TE after RE for case 2, but we here may not always guarantee
|
||||
* that happens: "arecord 1.wav; aplay 2.wav" in case 1 enables
|
||||
* TE after RE, which is against what RM recommends but should
|
||||
* be safe to do, judging by years of testing results.
|
||||
*/
|
||||
if (fsl_sai_dir_is_synced(sai, adir))
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_xCSR((!tx), ofs),
|
||||
FSL_SAI_CSR_TERE, FSL_SAI_CSR_TERE);
|
||||
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, ofs),
|
||||
FSL_SAI_CSR_xIE_MASK, FSL_SAI_FLAGS);
|
||||
@ -571,43 +639,23 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
|
||||
/* Check if the opposite FRDE is also disabled */
|
||||
regmap_read(sai->regmap, FSL_SAI_xCSR(!tx, ofs), &xcsr);
|
||||
if (!(xcsr & FSL_SAI_CSR_FRDE)) {
|
||||
/* Disable both directions and reset their FIFOs */
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs),
|
||||
FSL_SAI_CSR_TERE, 0);
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs),
|
||||
FSL_SAI_CSR_TERE, 0);
|
||||
|
||||
/* TERE will remain set till the end of current frame */
|
||||
do {
|
||||
udelay(10);
|
||||
regmap_read(sai->regmap,
|
||||
FSL_SAI_xCSR(tx, ofs), &xcsr);
|
||||
} while (--count && xcsr & FSL_SAI_CSR_TERE);
|
||||
/*
|
||||
* If opposite stream provides clocks for synchronous mode and
|
||||
* it is inactive, disable it before disabling the current one
|
||||
*/
|
||||
if (fsl_sai_dir_is_synced(sai, adir) && !(xcsr & FSL_SAI_CSR_FRDE))
|
||||
fsl_sai_config_disable(sai, adir);
|
||||
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_TCSR(ofs),
|
||||
FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_RCSR(ofs),
|
||||
FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);
|
||||
/*
|
||||
* Disable current stream if either of:
|
||||
* 1. current stream doesn't provide clocks for synchronous mode
|
||||
* 2. current stream provides clocks for synchronous mode but no
|
||||
* more stream is active.
|
||||
*/
|
||||
if (!fsl_sai_dir_is_synced(sai, dir) || !(xcsr & FSL_SAI_CSR_FRDE))
|
||||
fsl_sai_config_disable(sai, dir);
|
||||
|
||||
/*
|
||||
* For sai master mode, after several open/close sai,
|
||||
* there will be no frame clock, and can't recover
|
||||
* anymore. Add software reset to fix this issue.
|
||||
* This is a hardware bug, and will be fix in the
|
||||
* next sai version.
|
||||
*/
|
||||
if (!sai->is_slave_mode) {
|
||||
/* Software Reset for both Tx and Rx */
|
||||
regmap_write(sai->regmap, FSL_SAI_TCSR(ofs),
|
||||
FSL_SAI_CSR_SR);
|
||||
regmap_write(sai->regmap, FSL_SAI_RCSR(ofs),
|
||||
FSL_SAI_CSR_SR);
|
||||
/* Clear SR bit to finish the reset */
|
||||
regmap_write(sai->regmap, FSL_SAI_TCSR(ofs), 0);
|
||||
regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -620,14 +668,9 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *cpu_dai)
|
||||
{
|
||||
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
unsigned int ofs = sai->soc_data->reg_offset;
|
||||
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
||||
int ret;
|
||||
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs),
|
||||
FSL_SAI_CR3_TRCE_MASK,
|
||||
FSL_SAI_CR3_TRCE);
|
||||
|
||||
/*
|
||||
* EDMA controller needs period size to be a multiple of
|
||||
* tx/rx maxburst
|
||||
@ -644,17 +687,6 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *cpu_dai)
|
||||
{
|
||||
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
unsigned int ofs = sai->soc_data->reg_offset;
|
||||
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
||||
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs),
|
||||
FSL_SAI_CR3_TRCE_MASK, 0);
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
|
||||
.set_bclk_ratio = fsl_sai_set_dai_bclk_ratio,
|
||||
.set_sysclk = fsl_sai_set_dai_sysclk,
|
||||
@ -664,7 +696,6 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
|
||||
.hw_free = fsl_sai_hw_free,
|
||||
.trigger = fsl_sai_trigger,
|
||||
.startup = fsl_sai_startup,
|
||||
.shutdown = fsl_sai_shutdown,
|
||||
};
|
||||
|
||||
static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
|
||||
@ -765,6 +796,8 @@ static struct reg_default fsl_sai_reg_defaults_ofs8[] = {
|
||||
{FSL_SAI_RCR4(8), 0},
|
||||
{FSL_SAI_RCR5(8), 0},
|
||||
{FSL_SAI_RMR, 0},
|
||||
{FSL_SAI_MCTL, 0},
|
||||
{FSL_SAI_MDIV, 0},
|
||||
};
|
||||
|
||||
static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
|
||||
@ -805,6 +838,18 @@ static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg)
|
||||
case FSL_SAI_RFR6:
|
||||
case FSL_SAI_RFR7:
|
||||
case FSL_SAI_RMR:
|
||||
case FSL_SAI_MCTL:
|
||||
case FSL_SAI_MDIV:
|
||||
case FSL_SAI_VERID:
|
||||
case FSL_SAI_PARAM:
|
||||
case FSL_SAI_TTCTN:
|
||||
case FSL_SAI_RTCTN:
|
||||
case FSL_SAI_TTCTL:
|
||||
case FSL_SAI_TBCTN:
|
||||
case FSL_SAI_TTCAP:
|
||||
case FSL_SAI_RTCTL:
|
||||
case FSL_SAI_RBCTN:
|
||||
case FSL_SAI_RTCAP:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -819,6 +864,10 @@ static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg)
|
||||
if (reg == FSL_SAI_TCSR(ofs) || reg == FSL_SAI_RCSR(ofs))
|
||||
return true;
|
||||
|
||||
/* Set VERID and PARAM be volatile for reading value in probe */
|
||||
if (ofs == 8 && (reg == FSL_SAI_VERID || reg == FSL_SAI_PARAM))
|
||||
return true;
|
||||
|
||||
switch (reg) {
|
||||
case FSL_SAI_TFR0:
|
||||
case FSL_SAI_TFR1:
|
||||
@ -872,6 +921,10 @@ static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg)
|
||||
case FSL_SAI_TDR7:
|
||||
case FSL_SAI_TMR:
|
||||
case FSL_SAI_RMR:
|
||||
case FSL_SAI_MCTL:
|
||||
case FSL_SAI_MDIV:
|
||||
case FSL_SAI_TTCTL:
|
||||
case FSL_SAI_RTCTL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -893,6 +946,48 @@ static struct regmap_config fsl_sai_regmap_config = {
|
||||
.cache_type = REGCACHE_FLAT,
|
||||
};
|
||||
|
||||
static int fsl_sai_check_version(struct device *dev)
|
||||
{
|
||||
struct fsl_sai *sai = dev_get_drvdata(dev);
|
||||
unsigned char ofs = sai->soc_data->reg_offset;
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
if (FSL_SAI_TCSR(ofs) == FSL_SAI_VERID)
|
||||
return 0;
|
||||
|
||||
ret = regmap_read(sai->regmap, FSL_SAI_VERID, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev_dbg(dev, "VERID: 0x%016X\n", val);
|
||||
|
||||
sai->verid.major = (val & FSL_SAI_VERID_MAJOR_MASK) >>
|
||||
FSL_SAI_VERID_MAJOR_SHIFT;
|
||||
sai->verid.minor = (val & FSL_SAI_VERID_MINOR_MASK) >>
|
||||
FSL_SAI_VERID_MINOR_SHIFT;
|
||||
sai->verid.feature = val & FSL_SAI_VERID_FEATURE_MASK;
|
||||
|
||||
ret = regmap_read(sai->regmap, FSL_SAI_PARAM, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev_dbg(dev, "PARAM: 0x%016X\n", val);
|
||||
|
||||
/* Max slots per frame, power of 2 */
|
||||
sai->param.slot_num = 1 <<
|
||||
((val & FSL_SAI_PARAM_SPF_MASK) >> FSL_SAI_PARAM_SPF_SHIFT);
|
||||
|
||||
/* Words per fifo, power of 2 */
|
||||
sai->param.fifo_depth = 1 <<
|
||||
((val & FSL_SAI_PARAM_WPF_MASK) >> FSL_SAI_PARAM_WPF_SHIFT);
|
||||
|
||||
/* Number of datalines implemented */
|
||||
sai->param.dataline = val & FSL_SAI_PARAM_DLN_MASK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_sai_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
@ -920,6 +1015,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
|
||||
|
||||
if (sai->soc_data->reg_offset == 8) {
|
||||
fsl_sai_regmap_config.reg_defaults = fsl_sai_reg_defaults_ofs8;
|
||||
fsl_sai_regmap_config.max_register = FSL_SAI_MDIV;
|
||||
fsl_sai_regmap_config.num_reg_defaults =
|
||||
ARRAY_SIZE(fsl_sai_reg_defaults_ofs8);
|
||||
}
|
||||
@ -928,7 +1024,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
|
||||
"bus", base, &fsl_sai_regmap_config);
|
||||
|
||||
/* Compatible with old DTB cases */
|
||||
if (IS_ERR(sai->regmap))
|
||||
if (IS_ERR(sai->regmap) && PTR_ERR(sai->regmap) != -EPROBE_DEFER)
|
||||
sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
|
||||
"sai", base, &fsl_sai_regmap_config);
|
||||
if (IS_ERR(sai->regmap)) {
|
||||
@ -1019,6 +1115,18 @@ static int fsl_sai_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, sai);
|
||||
|
||||
/* Get sai version */
|
||||
ret = fsl_sai_check_version(&pdev->dev);
|
||||
if (ret < 0)
|
||||
dev_warn(&pdev->dev, "Error reading SAI version: %d\n", ret);
|
||||
|
||||
/* Select MCLK direction */
|
||||
if (of_find_property(np, "fsl,sai-mclk-direction-output", NULL) &&
|
||||
sai->verid.major >= 3 && sai->verid.minor >= 1) {
|
||||
regmap_update_bits(sai->regmap, FSL_SAI_MCTL,
|
||||
FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN);
|
||||
}
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
regcache_cache_only(sai->regmap, true);
|
||||
|
||||
|
@ -14,6 +14,8 @@
|
||||
SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
/* SAI Register Map Register */
|
||||
#define FSL_SAI_VERID 0x00 /* SAI Version ID Register */
|
||||
#define FSL_SAI_PARAM 0x04 /* SAI Parameter Register */
|
||||
#define FSL_SAI_TCSR(ofs) (0x00 + ofs) /* SAI Transmit Control */
|
||||
#define FSL_SAI_TCR1(ofs) (0x04 + ofs) /* SAI Transmit Configuration 1 */
|
||||
#define FSL_SAI_TCR2(ofs) (0x08 + ofs) /* SAI Transmit Configuration 2 */
|
||||
@ -37,6 +39,10 @@
|
||||
#define FSL_SAI_TFR6 0x58 /* SAI Transmit FIFO 6 */
|
||||
#define FSL_SAI_TFR7 0x5C /* SAI Transmit FIFO 7 */
|
||||
#define FSL_SAI_TMR 0x60 /* SAI Transmit Mask */
|
||||
#define FSL_SAI_TTCTL 0x70 /* SAI Transmit Timestamp Control Register */
|
||||
#define FSL_SAI_TTCTN 0x74 /* SAI Transmit Timestamp Counter Register */
|
||||
#define FSL_SAI_TBCTN 0x78 /* SAI Transmit Bit Counter Register */
|
||||
#define FSL_SAI_TTCAP 0x7C /* SAI Transmit Timestamp Capture */
|
||||
#define FSL_SAI_RCSR(ofs) (0x80 + ofs) /* SAI Receive Control */
|
||||
#define FSL_SAI_RCR1(ofs) (0x84 + ofs)/* SAI Receive Configuration 1 */
|
||||
#define FSL_SAI_RCR2(ofs) (0x88 + ofs) /* SAI Receive Configuration 2 */
|
||||
@ -60,6 +66,13 @@
|
||||
#define FSL_SAI_RFR6 0xd8 /* SAI Receive FIFO 6 */
|
||||
#define FSL_SAI_RFR7 0xdc /* SAI Receive FIFO 7 */
|
||||
#define FSL_SAI_RMR 0xe0 /* SAI Receive Mask */
|
||||
#define FSL_SAI_RTCTL 0xf0 /* SAI Receive Timestamp Control Register */
|
||||
#define FSL_SAI_RTCTN 0xf4 /* SAI Receive Timestamp Counter Register */
|
||||
#define FSL_SAI_RBCTN 0xf8 /* SAI Receive Bit Counter Register */
|
||||
#define FSL_SAI_RTCAP 0xfc /* SAI Receive Timestamp Capture */
|
||||
|
||||
#define FSL_SAI_MCTL 0x100 /* SAI MCLK Control Register */
|
||||
#define FSL_SAI_MDIV 0x104 /* SAI MCLK Divide Register */
|
||||
|
||||
#define FSL_SAI_xCSR(tx, ofs) (tx ? FSL_SAI_TCSR(ofs) : FSL_SAI_RCSR(ofs))
|
||||
#define FSL_SAI_xCR1(tx, ofs) (tx ? FSL_SAI_TCR1(ofs) : FSL_SAI_RCR1(ofs))
|
||||
@ -73,6 +86,7 @@
|
||||
|
||||
/* SAI Transmit/Receive Control Register */
|
||||
#define FSL_SAI_CSR_TERE BIT(31)
|
||||
#define FSL_SAI_CSR_SE BIT(30)
|
||||
#define FSL_SAI_CSR_FR BIT(25)
|
||||
#define FSL_SAI_CSR_SR BIT(24)
|
||||
#define FSL_SAI_CSR_xF_SHIFT 16
|
||||
@ -106,19 +120,29 @@
|
||||
#define FSL_SAI_CR2_MSEL(ID) ((ID) << 26)
|
||||
#define FSL_SAI_CR2_BCP BIT(25)
|
||||
#define FSL_SAI_CR2_BCD_MSTR BIT(24)
|
||||
#define FSL_SAI_CR2_BYP BIT(23) /* BCLK bypass */
|
||||
#define FSL_SAI_CR2_DIV_MASK 0xff
|
||||
|
||||
/* SAI Transmit and Receive Configuration 3 Register */
|
||||
#define FSL_SAI_CR3_TRCE BIT(16)
|
||||
#define FSL_SAI_CR3_TRCE(x) ((x) << 16)
|
||||
#define FSL_SAI_CR3_TRCE_MASK GENMASK(23, 16)
|
||||
#define FSL_SAI_CR3_WDFL(x) (x)
|
||||
#define FSL_SAI_CR3_WDFL_MASK 0x1f
|
||||
|
||||
/* SAI Transmit and Receive Configuration 4 Register */
|
||||
|
||||
#define FSL_SAI_CR4_FCONT BIT(28)
|
||||
#define FSL_SAI_CR4_FCOMB_SHIFT BIT(26)
|
||||
#define FSL_SAI_CR4_FCOMB_SOFT BIT(27)
|
||||
#define FSL_SAI_CR4_FCOMB_MASK (0x3 << 26)
|
||||
#define FSL_SAI_CR4_FPACK_8 (0x2 << 24)
|
||||
#define FSL_SAI_CR4_FPACK_16 (0x3 << 24)
|
||||
#define FSL_SAI_CR4_FRSZ(x) (((x) - 1) << 16)
|
||||
#define FSL_SAI_CR4_FRSZ_MASK (0x1f << 16)
|
||||
#define FSL_SAI_CR4_SYWD(x) (((x) - 1) << 8)
|
||||
#define FSL_SAI_CR4_SYWD_MASK (0x1f << 8)
|
||||
#define FSL_SAI_CR4_CHMOD BIT(5)
|
||||
#define FSL_SAI_CR4_CHMOD_MASK BIT(5)
|
||||
#define FSL_SAI_CR4_MF BIT(4)
|
||||
#define FSL_SAI_CR4_FSE BIT(3)
|
||||
#define FSL_SAI_CR4_FSP BIT(1)
|
||||
@ -132,6 +156,43 @@
|
||||
#define FSL_SAI_CR5_FBT(x) ((x) << 8)
|
||||
#define FSL_SAI_CR5_FBT_MASK (0x1f << 8)
|
||||
|
||||
/* SAI MCLK Control Register */
|
||||
#define FSL_SAI_MCTL_MCLK_EN BIT(30) /* MCLK Enable */
|
||||
#define FSL_SAI_MCTL_MSEL_MASK (0x3 << 24)
|
||||
#define FSL_SAI_MCTL_MSEL(ID) ((ID) << 24)
|
||||
#define FSL_SAI_MCTL_MSEL_BUS 0
|
||||
#define FSL_SAI_MCTL_MSEL_MCLK1 BIT(24)
|
||||
#define FSL_SAI_MCTL_MSEL_MCLK2 BIT(25)
|
||||
#define FSL_SAI_MCTL_MSEL_MCLK3 (BIT(24) | BIT(25))
|
||||
#define FSL_SAI_MCTL_DIV_EN BIT(23)
|
||||
#define FSL_SAI_MCTL_DIV_MASK 0xFF
|
||||
|
||||
/* SAI VERID Register */
|
||||
#define FSL_SAI_VERID_MAJOR_SHIFT 24
|
||||
#define FSL_SAI_VERID_MAJOR_MASK GENMASK(31, 24)
|
||||
#define FSL_SAI_VERID_MINOR_SHIFT 16
|
||||
#define FSL_SAI_VERID_MINOR_MASK GENMASK(23, 16)
|
||||
#define FSL_SAI_VERID_FEATURE_SHIFT 0
|
||||
#define FSL_SAI_VERID_FEATURE_MASK GENMASK(15, 0)
|
||||
#define FSL_SAI_VERID_EFIFO_EN BIT(0)
|
||||
#define FSL_SAI_VERID_TSTMP_EN BIT(1)
|
||||
|
||||
/* SAI PARAM Register */
|
||||
#define FSL_SAI_PARAM_SPF_SHIFT 16
|
||||
#define FSL_SAI_PARAM_SPF_MASK GENMASK(19, 16)
|
||||
#define FSL_SAI_PARAM_WPF_SHIFT 8
|
||||
#define FSL_SAI_PARAM_WPF_MASK GENMASK(11, 8)
|
||||
#define FSL_SAI_PARAM_DLN_MASK GENMASK(3, 0)
|
||||
|
||||
/* SAI MCLK Divide Register */
|
||||
#define FSL_SAI_MDIV_MASK 0xFFFFF
|
||||
|
||||
/* SAI timestamp and bitcounter */
|
||||
#define FSL_SAI_xTCTL_TSEN BIT(0)
|
||||
#define FSL_SAI_xTCTL_TSINC BIT(1)
|
||||
#define FSL_SAI_xTCTL_RTSC BIT(8)
|
||||
#define FSL_SAI_xTCTL_RBC BIT(9)
|
||||
|
||||
/* SAI type */
|
||||
#define FSL_SAI_DMA BIT(0)
|
||||
#define FSL_SAI_USE_AC97 BIT(1)
|
||||
@ -162,6 +223,32 @@ struct fsl_sai_soc_data {
|
||||
unsigned int reg_offset;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct fsl_sai_verid - version id data
|
||||
* @major: major version number
|
||||
* @minor: minor version number
|
||||
* @feature: feature specification number
|
||||
* 0000000000000000b - Standard feature set
|
||||
* 0000000000000000b - Standard feature set
|
||||
*/
|
||||
struct fsl_sai_verid {
|
||||
u32 major;
|
||||
u32 minor;
|
||||
u32 feature;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct fsl_sai_param - parameter data
|
||||
* @slot_num: The maximum number of slots per frame
|
||||
* @fifo_depth: The number of words in each FIFO (depth)
|
||||
* @dataline: The number of datalines implemented
|
||||
*/
|
||||
struct fsl_sai_param {
|
||||
u32 slot_num;
|
||||
u32 fifo_depth;
|
||||
u32 dataline;
|
||||
};
|
||||
|
||||
struct fsl_sai {
|
||||
struct platform_device *pdev;
|
||||
struct regmap *regmap;
|
||||
@ -183,6 +270,8 @@ struct fsl_sai {
|
||||
struct snd_soc_dai_driver cpu_dai_drv;
|
||||
struct snd_dmaengine_dai_dma_data dma_params_rx;
|
||||
struct snd_dmaengine_dai_dma_data dma_params_tx;
|
||||
struct fsl_sai_verid verid;
|
||||
struct fsl_sai_param param;
|
||||
};
|
||||
|
||||
#define TX 1
|
||||
|
@ -1252,16 +1252,12 @@ static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
|
||||
|
||||
static int fsl_spdif_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct fsl_spdif_priv *spdif_priv;
|
||||
struct spdif_mixer_control *ctrl;
|
||||
struct resource *res;
|
||||
void __iomem *regs;
|
||||
int irq, ret, i;
|
||||
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
spdif_priv = devm_kzalloc(&pdev->dev, sizeof(*spdif_priv), GFP_KERNEL);
|
||||
if (!spdif_priv)
|
||||
return -ENOMEM;
|
||||
|
@ -185,20 +185,20 @@ static int imx_audmix_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->num_dai = 2 * num_dai;
|
||||
priv->dai = devm_kzalloc(&pdev->dev, priv->num_dai *
|
||||
priv->dai = devm_kcalloc(&pdev->dev, priv->num_dai,
|
||||
sizeof(struct snd_soc_dai_link), GFP_KERNEL);
|
||||
if (!priv->dai)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->num_dai_conf = num_dai;
|
||||
priv->dai_conf = devm_kzalloc(&pdev->dev, priv->num_dai_conf *
|
||||
priv->dai_conf = devm_kcalloc(&pdev->dev, priv->num_dai_conf,
|
||||
sizeof(struct snd_soc_codec_conf),
|
||||
GFP_KERNEL);
|
||||
if (!priv->dai_conf)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->num_dapm_routes = 3 * num_dai;
|
||||
priv->dapm_routes = devm_kzalloc(&pdev->dev, priv->num_dapm_routes *
|
||||
priv->dapm_routes = devm_kcalloc(&pdev->dev, priv->num_dapm_routes,
|
||||
sizeof(struct snd_soc_dapm_route),
|
||||
GFP_KERNEL);
|
||||
if (!priv->dapm_routes)
|
||||
@ -208,7 +208,7 @@ static int imx_audmix_probe(struct platform_device *pdev)
|
||||
struct snd_soc_dai_link_component *dlc;
|
||||
|
||||
/* for CPU/Codec/Platform x 2 */
|
||||
dlc = devm_kzalloc(&pdev->dev, 6 * sizeof(*dlc), GFP_KERNEL);
|
||||
dlc = devm_kcalloc(&pdev->dev, 6, sizeof(*dlc), GFP_KERNEL);
|
||||
if (!dlc) {
|
||||
dev_err(&pdev->dev, "failed to allocate dai_link\n");
|
||||
return -ENOMEM;
|
||||
|
@ -145,13 +145,13 @@ static int imx_es8328_probe(struct platform_device *pdev)
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
goto put_device;
|
||||
}
|
||||
|
||||
comp = devm_kzalloc(dev, 3 * sizeof(*comp), GFP_KERNEL);
|
||||
if (!comp) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
goto put_device;
|
||||
}
|
||||
|
||||
data->dev = dev;
|
||||
@ -182,12 +182,12 @@ static int imx_es8328_probe(struct platform_device *pdev)
|
||||
ret = snd_soc_of_parse_card_name(&data->card, "model");
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to parse card name\n");
|
||||
goto fail;
|
||||
goto put_device;
|
||||
}
|
||||
ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing");
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to parse routing: %d\n", ret);
|
||||
goto fail;
|
||||
goto put_device;
|
||||
}
|
||||
data->card.num_links = 1;
|
||||
data->card.owner = THIS_MODULE;
|
||||
@ -196,10 +196,12 @@ static int imx_es8328_probe(struct platform_device *pdev)
|
||||
ret = snd_soc_register_card(&data->card);
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to register: %d\n", ret);
|
||||
goto fail;
|
||||
goto put_device;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, data);
|
||||
put_device:
|
||||
put_device(&ssi_pdev->dev);
|
||||
fail:
|
||||
of_node_put(ssi_np);
|
||||
of_node_put(codec_np);
|
||||
|
@ -96,7 +96,7 @@ static int imx_mc13783_probe(struct platform_device *pdev)
|
||||
|
||||
imx_mc13783.dev = &pdev->dev;
|
||||
|
||||
ret = snd_soc_register_card(&imx_mc13783);
|
||||
ret = devm_snd_soc_register_card(&pdev->dev, &imx_mc13783);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
|
||||
ret);
|
||||
@ -140,19 +140,11 @@ static int imx_mc13783_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx_mc13783_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_card(&imx_mc13783);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver imx_mc13783_audio_driver = {
|
||||
.driver = {
|
||||
.name = "imx_mc13783",
|
||||
},
|
||||
.probe = imx_mc13783_probe,
|
||||
.remove = imx_mc13783_remove
|
||||
};
|
||||
|
||||
module_platform_driver(imx_mc13783_audio_driver);
|
||||
|
@ -176,7 +176,7 @@ static int mx27vis_aic32x4_probe(struct platform_device *pdev)
|
||||
mx27vis_amp_muter_gpio = pdata->amp_muter_gpio;
|
||||
|
||||
mx27vis_aic32x4.dev = &pdev->dev;
|
||||
ret = snd_soc_register_card(&mx27vis_aic32x4);
|
||||
ret = devm_snd_soc_register_card(&pdev->dev, &mx27vis_aic32x4);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
|
||||
ret);
|
||||
@ -199,19 +199,11 @@ static int mx27vis_aic32x4_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mx27vis_aic32x4_remove(struct platform_device *pdev)
|
||||
{
|
||||
snd_soc_unregister_card(&mx27vis_aic32x4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver mx27vis_aic32x4_audio_driver = {
|
||||
.driver = {
|
||||
.name = "mx27vis",
|
||||
},
|
||||
.probe = mx27vis_aic32x4_probe,
|
||||
.remove = mx27vis_aic32x4_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(mx27vis_aic32x4_audio_driver);
|
||||
|
Reference in New Issue
Block a user