diff options
Diffstat (limited to 'sound/soc/fsl')
-rw-r--r-- | sound/soc/fsl/Kconfig | 11 | ||||
-rw-r--r-- | sound/soc/fsl/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/fsl/fsl-asoc-card.c | 6 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_asrc.c | 10 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_asrc.h | 3 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_asrc_dma.c | 14 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_dma.c | 27 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_esai.c | 2 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_ssi.c | 758 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_ssi.h | 3 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_utils.c | 2 | ||||
-rw-r--r-- | sound/soc/fsl/imx-pcm-fiq.c | 6 | ||||
-rw-r--r-- | sound/soc/fsl/imx-wm8962.c | 312 | ||||
-rw-r--r-- | sound/soc/fsl/mpc5200_dma.c | 16 | ||||
-rw-r--r-- | sound/soc/fsl/wm1133-ev1.c | 6 |
15 files changed, 445 insertions, 733 deletions
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 37f9b6201918..6ec19fb4a934 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -231,17 +231,6 @@ config SND_SOC_EUKREA_TLV320 Enable I2S based access to the TLV320AIC23B codec attached to the SSI interface -config SND_SOC_IMX_WM8962 - tristate "SoC Audio support for i.MX boards with wm8962" - depends on OF && I2C && INPUT - select SND_SOC_WM8962 - select SND_SOC_IMX_PCM_DMA - select SND_SOC_IMX_AUDMUX - select SND_SOC_FSL_SSI - help - Say Y if you want to add support for SoC audio on an i.MX board with - a wm8962 codec. - config SND_SOC_IMX_ES8328 tristate "SoC Audio support for i.MX boards with the ES8328 codec" depends on OF && (I2C || SPI) diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index c67bf1139e1e..de94fa057e24 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -55,7 +55,6 @@ snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o snd-soc-wm1133-ev1-objs := wm1133-ev1.o snd-soc-imx-es8328-objs := imx-es8328.o snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o -snd-soc-imx-wm8962-objs := imx-wm8962.o snd-soc-imx-spdif-objs := imx-spdif.o snd-soc-imx-mc13783-objs := imx-mc13783.o @@ -65,6 +64,5 @@ obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o -obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 989be518c4ed..4a6750aa3637 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -91,9 +91,9 @@ struct fsl_asoc_card_priv { struct cpu_priv cpu_priv; struct snd_soc_card card; u32 sample_rate; - u32 sample_format; + snd_pcm_format_t sample_format; u32 asrc_rate; - u32 asrc_format; + snd_pcm_format_t asrc_format; u32 dai_fmt; char name[32]; }; @@ -199,7 +199,7 @@ static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); snd_mask_none(mask); - snd_mask_set(mask, priv->asrc_format); + snd_mask_set(mask, (__force int)priv->asrc_format); return 0; } diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 806d39927318..adfb8135d739 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -582,10 +582,6 @@ static struct snd_soc_dai_driver fsl_asrc_dai = { .ops = &fsl_asrc_dai_ops, }; -static const struct snd_soc_component_driver fsl_asrc_component = { - .name = "fsl-asrc-dai", -}; - static bool fsl_asrc_readable_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -927,12 +923,6 @@ static int fsl_asrc_probe(struct platform_device *pdev) return ret; } - ret = devm_snd_soc_register_platform(&pdev->dev, &fsl_asrc_platform); - if (ret) { - dev_err(&pdev->dev, "failed to register ASoC platform\n"); - return ret; - } - return 0; } diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h index 2c5856ac5bc3..d558dd5499a5 100644 --- a/sound/soc/fsl/fsl_asrc.h +++ b/sound/soc/fsl/fsl_asrc.h @@ -462,6 +462,7 @@ struct fsl_asrc { u32 regcache_cfg; }; -extern struct snd_soc_platform_driver fsl_asrc_platform; +#define DRV_NAME "fsl-asrc-dai" +extern struct snd_soc_component_driver fsl_asrc_component; struct dma_chan *fsl_asrc_get_dma_channel(struct fsl_asrc_pair *pair, bool dir); #endif /* _FSL_ASRC_H */ diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index e1b97e59275a..565e16d8fe85 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -64,7 +64,8 @@ static int fsl_asrc_dma_prepare_and_submit(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_asrc_pair *pair = runtime->private_data; - struct device *dev = rtd->platform->dev; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct device *dev = component->dev; unsigned long flags = DMA_CTRL_ACK; /* Prepare and submit Front-End DMA channel */ @@ -137,12 +138,13 @@ static int fsl_asrc_dma_hw_params(struct snd_pcm_substream *substream, bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; struct snd_dmaengine_dai_dma_data *dma_params_fe = NULL; struct snd_dmaengine_dai_dma_data *dma_params_be = NULL; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_asrc_pair *pair = runtime->private_data; struct fsl_asrc *asrc_priv = pair->asrc_priv; struct dma_slave_config config_fe, config_be; enum asrc_pair_index index = pair->index; - struct device *dev = rtd->platform->dev; + struct device *dev = component->dev; int stream = substream->stream; struct imx_dma_data *tmp_data; struct snd_soc_dpcm *dpcm; @@ -274,7 +276,8 @@ static int fsl_asrc_dma_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; - struct device *dev = rtd->platform->dev; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct device *dev = component->dev; struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); struct fsl_asrc_pair *pair; @@ -381,9 +384,10 @@ static void fsl_asrc_dma_pcm_free(struct snd_pcm *pcm) } } -struct snd_soc_platform_driver fsl_asrc_platform = { +struct snd_soc_component_driver fsl_asrc_component = { + .name = DRV_NAME, .ops = &fsl_asrc_dma_pcm_ops, .pcm_new = fsl_asrc_dma_pcm_new, .pcm_free = fsl_asrc_dma_pcm_free, }; -EXPORT_SYMBOL_GPL(fsl_asrc_platform); +EXPORT_SYMBOL_GPL(fsl_asrc_component); diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 8c2981b70f64..fce2010d3c53 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c @@ -37,6 +37,8 @@ #include "fsl_dma.h" #include "fsl_ssi.h" /* For the offset of stx0 and srx0 */ +#define DRV_NAME "fsl_dma" + /* * The formats that the DMA controller supports, which is anything * that is 8, 16, or 32 bits. @@ -56,7 +58,7 @@ SNDRV_PCM_FMTBIT_U32_LE | \ SNDRV_PCM_FMTBIT_U32_BE) struct dma_object { - struct snd_soc_platform_driver dai; + struct snd_soc_component_driver dai; dma_addr_t ssi_stx_phys; dma_addr_t ssi_srx_phys; unsigned int ssi_fifo_depth; @@ -203,7 +205,8 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id) struct fsl_dma_private *dma_private = dev_id; struct snd_pcm_substream *substream = dma_private->substream; struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct device *dev = rtd->platform->dev; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct device *dev = component->dev; struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; irqreturn_t ret = IRQ_NONE; u32 sr, sr2 = 0; @@ -385,9 +388,10 @@ static int fsl_dma_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct device *dev = rtd->platform->dev; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct device *dev = component->dev; struct dma_object *dma = - container_of(rtd->platform->driver, struct dma_object, dai); + container_of(component->driver, struct dma_object, dai); struct fsl_dma_private *dma_private; struct ccsr_dma_channel __iomem *dma_channel; dma_addr_t ld_buf_phys; @@ -539,7 +543,8 @@ static int fsl_dma_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_dma_private *dma_private = runtime->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct device *dev = rtd->platform->dev; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct device *dev = component->dev; /* Number of bits per sample */ unsigned int sample_bits = @@ -702,7 +707,8 @@ static snd_pcm_uframes_t fsl_dma_pointer(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_dma_private *dma_private = runtime->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct device *dev = rtd->platform->dev; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct device *dev = component->dev; struct ccsr_dma_channel __iomem *dma_channel = dma_private->dma_channel; dma_addr_t position; snd_pcm_uframes_t frames; @@ -799,9 +805,10 @@ static int fsl_dma_close(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_dma_private *dma_private = runtime->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct device *dev = rtd->platform->dev; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct device *dev = component->dev; struct dma_object *dma = - container_of(rtd->platform->driver, struct dma_object, dai); + container_of(component->driver, struct dma_object, dai); if (dma_private) { if (dma_private->irq) @@ -908,6 +915,7 @@ static int fsl_soc_dma_probe(struct platform_device *pdev) return -ENOMEM; } + dma->dai.name = DRV_NAME; dma->dai.ops = &fsl_dma_ops; dma->dai.pcm_new = fsl_dma_new; dma->dai.pcm_free = fsl_dma_free_dma_buffers; @@ -925,7 +933,7 @@ static int fsl_soc_dma_probe(struct platform_device *pdev) of_node_put(ssi_np); - ret = snd_soc_register_platform(&pdev->dev, &dma->dai); + ret = devm_snd_soc_register_component(&pdev->dev, &dma->dai, NULL, 0); if (ret) { dev_err(&pdev->dev, "could not register platform\n"); kfree(dma); @@ -944,7 +952,6 @@ static int fsl_soc_dma_remove(struct platform_device *pdev) { struct dma_object *dma = dev_get_drvdata(&pdev->dev); - snd_soc_unregister_platform(&pdev->dev); iounmap(dma->channel); irq_dispose_mapping(dma->irq); kfree(dma); diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index cef79a1a620b..40a700493f4c 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -788,7 +788,7 @@ static int fsl_esai_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct fsl_esai *esai_priv; struct resource *res; - const uint32_t *iprop; + const __be32 *iprop; void __iomem *regs; int irq, ret; diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index aecd00f7929d..0823b08923b5 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -56,6 +56,10 @@ #include "fsl_ssi.h" #include "imx-pcm.h" +/* Define RX and TX to index ssi->regvals array; Can be 0 or 1 only */ +#define RX 0 +#define TX 1 + /** * FSLSSI_I2S_FORMATS: audio formats supported by the SSI * @@ -86,6 +90,16 @@ SNDRV_PCM_FMTBIT_S24_LE) #endif +/* + * In AC97 mode, TXDIR bit is forced to 0 and TFDIR bit is forced to 1: + * - SSI inputs external bit clock and outputs frame sync clock -- CBM_CFS + * - Also have NB_NF to mark these two clocks will not be inverted + */ +#define FSLSSI_AC97_DAIFMT \ + (SND_SOC_DAIFMT_AC97 | \ + SND_SOC_DAIFMT_CBM_CFS | \ + SND_SOC_DAIFMT_NB_NF) + #define FSLSSI_SIER_DBG_RX_FLAGS \ (SSI_SIER_RFF0_EN | \ SSI_SIER_RLS_EN | \ @@ -201,7 +215,9 @@ struct fsl_ssi_soc_data { * @cpu_dai_drv: CPU DAI driver for this device * * @dai_fmt: DAI configuration this device is currently used with + * @streams: Mask of current active streams: BIT(TX) and BIT(RX) * @i2s_net: I2S and Network mode configurations of SCR register + * @synchronous: Use synchronous mode - both of TX and RX use STCK and SFCK * @use_dma: DMA is used or FIQ with stream filter * @use_dual_fifo: DMA with support for dual FIFO mode * @has_ipg_clk_name: If "ipg" is in the clock name list of device tree @@ -223,8 +239,12 @@ struct fsl_ssi_soc_data { * * @fiq_params: FIQ stream filtering parameters * - * @pdev: Pointer to pdev when using fsl-ssi as sound card (ppc only) - * TODO: Should be replaced with simple-sound-card + * @card_pdev: Platform_device pointer to register a sound card for PowerPC or + * to register a CODEC platform device for AC97 + * @card_name: Platform_device name to register a sound card for PowerPC or + * to register a CODEC platform device for AC97 + * @card_idx: The index of SSI to register a sound card for PowerPC or + * to register a CODEC platform device for AC97 * * @dbg_stats: Debugging statistics * @@ -245,7 +265,9 @@ struct fsl_ssi { struct snd_soc_dai_driver cpu_dai_drv; unsigned int dai_fmt; + u8 streams; u8 i2s_net; + bool synchronous; bool use_dma; bool use_dual_fifo; bool has_ipg_clk_name; @@ -267,7 +289,9 @@ struct fsl_ssi { struct imx_pcm_fiq_params fiq_params; - struct platform_device *pdev; + struct platform_device *card_pdev; + char card_name[32]; + u32 card_idx; struct fsl_ssi_dbg dbg_stats; @@ -376,181 +400,172 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id) } /** - * Enable or disable all rx/tx config flags at once + * Set SCR, SIER, STCR and SRCR registers with cached values in regvals + * + * Notes: + * 1) For offline_config SoCs, enable all necessary bits of both streams + * when 1st stream starts, even if the opposite stream will not start + * 2) It also clears FIFO before setting regvals; SOR is safe to set online */ -static void fsl_ssi_rxtx_config(struct fsl_ssi *ssi, bool enable) +static void fsl_ssi_config_enable(struct fsl_ssi *ssi, bool tx) { - struct regmap *regs = ssi->regs; struct fsl_ssi_regvals *vals = ssi->regvals; + int dir = tx ? TX : RX; + u32 sier, srcr, stcr; + + /* Clear dirty data in the FIFO; It also prevents channel slipping */ + regmap_update_bits(ssi->regs, REG_SSI_SOR, + SSI_SOR_xX_CLR(tx), SSI_SOR_xX_CLR(tx)); + + /* + * On offline_config SoCs, SxCR and SIER are already configured when + * the previous stream started. So skip all SxCR and SIER settings + * to prevent online reconfigurations, then jump to set SCR directly + */ + if (ssi->soc->offline_config && ssi->streams) + goto enable_scr; - if (enable) { - regmap_update_bits(regs, REG_SSI_SIER, - vals[RX].sier | vals[TX].sier, - vals[RX].sier | vals[TX].sier); - regmap_update_bits(regs, REG_SSI_SRCR, - vals[RX].srcr | vals[TX].srcr, - vals[RX].srcr | vals[TX].srcr); - regmap_update_bits(regs, REG_SSI_STCR, - vals[RX].stcr | vals[TX].stcr, - vals[RX].stcr | vals[TX].stcr); + if (ssi->soc->offline_config) { + /* + * Online reconfiguration not supported, so enable all bits for + * both streams at once to avoid necessity of reconfigurations + */ + srcr = vals[RX].srcr | vals[TX].srcr; + stcr = vals[RX].stcr | vals[TX].stcr; + sier = vals[RX].sier | vals[TX].sier; } else { - regmap_update_bits(regs, REG_SSI_SRCR, - vals[RX].srcr | vals[TX].srcr, 0); - regmap_update_bits(regs, REG_SSI_STCR, - vals[RX].stcr | vals[TX].stcr, 0); - regmap_update_bits(regs, REG_SSI_SIER, - vals[RX].sier | vals[TX].sier, 0); + /* Otherwise, only set bits for the current stream */ + srcr = vals[dir].srcr; + stcr = vals[dir].stcr; + sier = vals[dir].sier; } -} -/** - * Clear remaining data in the FIFO to avoid dirty data or channel slipping - */ -static void fsl_ssi_fifo_clear(struct fsl_ssi *ssi, bool is_rx) -{ - bool tx = !is_rx; + /* Configure SRCR, STCR and SIER at once */ + regmap_update_bits(ssi->regs, REG_SSI_SRCR, srcr, srcr); + regmap_update_bits(ssi->regs, REG_SSI_STCR, stcr, stcr); + regmap_update_bits(ssi->regs, REG_SSI_SIER, sier, sier); - regmap_update_bits(ssi->regs, REG_SSI_SOR, - SSI_SOR_xX_CLR(tx), SSI_SOR_xX_CLR(tx)); +enable_scr: + /* + * Start DMA before setting TE to avoid FIFO underrun + * which may cause a channel slip or a channel swap + * + * TODO: FIQ cases might also need this upon testing + */ + if (ssi->use_dma && tx) { + int try = 100; + u32 sfcsr; + + /* Enable SSI first to send TX DMA request */ + regmap_update_bits(ssi->regs, REG_SSI_SCR, + SSI_SCR_SSIEN, SSI_SCR_SSIEN); + + /* Busy wait until TX FIFO not empty -- DMA working */ + do { + regmap_read(ssi->regs, REG_SSI_SFCSR, &sfcsr); + if (SSI_SFCSR_TFCNT0(sfcsr)) + break; + } while (--try); + + /* FIFO still empty -- something might be wrong */ + if (!SSI_SFCSR_TFCNT0(sfcsr)) + dev_warn(ssi->dev, "Timeout waiting TX FIFO filling\n"); + } + /* Enable all remaining bits in SCR */ + regmap_update_bits(ssi->regs, REG_SSI_SCR, + vals[dir].scr, vals[dir].scr); + + /* Log the enabled stream to the mask */ + ssi->streams |= BIT(dir); } /** - * Calculate the bits that have to be disabled for the current stream that is - * getting disabled. This keeps the bits enabled that are necessary for the - * second stream to work if 'stream_active' is true. + * Exclude bits that are used by the opposite stream * - * Detailed calculation: - * These are the values that need to be active after disabling. For non-active - * second stream, this is 0: - * vals_stream * !!stream_active + * When both streams are active, disabling some bits for the current stream + * might break the other stream if these bits are used by it. * - * The following computes the overall differences between the setup for the - * to-disable stream and the active stream, a simple XOR: - * vals_disable ^ (vals_stream * !!(stream_active)) + * @vals : regvals of the current stream + * @avals: regvals of the opposite stream + * @aactive: active state of the opposite stream * - * The full expression adds a mask on all values we care about + * 1) XOR vals and avals to get the differences if the other stream is active; + * Otherwise, return current vals if the other stream is not active + * 2) AND the result of 1) with the current vals */ -#define fsl_ssi_disable_val(vals_disable, vals_stream, stream_active) \ - ((vals_disable) & \ - ((vals_disable) ^ ((vals_stream) * (u32)!!(stream_active)))) +#define _ssi_xor_shared_bits(vals, avals, aactive) \ + ((vals) ^ ((avals) * (aactive))) + +#define ssi_excl_shared_bits(vals, avals, aactive) \ + ((vals) & _ssi_xor_shared_bits(vals, avals, aactive)) /** - * Enable or disable SSI configuration. + * Unset SCR, SIER, STCR and SRCR registers with cached values in regvals + * + * Notes: + * 1) For offline_config SoCs, to avoid online reconfigurations, disable all + * bits of both streams at once when the last stream is abort to end + * 2) It also clears FIFO after unsetting regvals; SOR is safe to set online */ -static void fsl_ssi_config(struct fsl_ssi *ssi, bool enable, - struct fsl_ssi_regvals *vals) +static void fsl_ssi_config_disable(struct fsl_ssi *ssi, bool tx) { - struct regmap *regs = ssi->regs; - struct fsl_ssi_regvals *avals; - int nr_active_streams; - u32 scr; - int keep_active; - - regmap_read(regs, REG_SSI_SCR, &scr); + struct fsl_ssi_regvals *vals, *avals; + u32 sier, srcr, stcr, scr; + int adir = tx ? RX : TX; + int dir = tx ? TX : RX; + bool aactive; - nr_active_streams = !!(scr & SSI_SCR_TE) + !!(scr & SSI_SCR_RE); + /* Check if the opposite stream is active */ + aactive = ssi->streams & BIT(adir); - if (nr_active_streams - 1 > 0) - keep_active = 1; - else - keep_active = 0; + vals = &ssi->regvals[dir]; - /* Get the opposite direction to keep its values untouched */ - if (&ssi->regvals[RX] == vals) - avals = &ssi->regvals[TX]; - else - avals = &ssi->regvals[RX]; - - if (!enable) { - /* - * To keep the other stream safe, exclude shared bits between - * both streams, and get safe bits to disable current stream - */ - u32 scr = fsl_ssi_disable_val(vals->scr, avals->scr, - keep_active); - /* Safely disable SCR register for the stream */ - regmap_update_bits(regs, REG_SSI_SCR, scr, 0); - } + /* Get regvals of the opposite stream to keep opposite stream safe */ + avals = &ssi->regvals[adir]; /* - * For cases where online configuration is not supported, - * 1) Enable all necessary bits of both streams when 1st stream starts - * even if the opposite stream will not start - * 2) Disable all remaining bits of both streams when last stream ends + * To keep the other stream safe, exclude shared bits between + * both streams, and get safe bits to disable current stream */ - if (ssi->soc->offline_config) { - if ((enable && !nr_active_streams) || (!enable && !keep_active)) - fsl_ssi_rxtx_config(ssi, enable); + scr = ssi_excl_shared_bits(vals->scr, avals->scr, aactive); - goto config_done; - } + /* Disable safe bits of SCR register for the current stream */ + regmap_update_bits(ssi->regs, REG_SSI_SCR, scr, 0); - /* Online configure single direction while SSI is running */ - if (enable) { - fsl_ssi_fifo_clear(ssi, vals->scr & SSI_SCR_RE); + /* Log the disabled stream to the mask */ + ssi->streams &= ~BIT(dir); - regmap_update_bits(regs, REG_SSI_SRCR, vals->srcr, vals->srcr); - regmap_update_bits(regs, REG_SSI_STCR, vals->stcr, vals->stcr); - regmap_update_bits(regs, REG_SSI_SIER, vals->sier, vals->sier); - } else { - u32 sier; - u32 srcr; - u32 stcr; + /* + * On offline_config SoCs, if the other stream is active, skip + * SxCR and SIER settings to prevent online reconfigurations + */ + if (ssi->soc->offline_config && aactive) + goto fifo_clear; + if (ssi->soc->offline_config) { + /* Now there is only current stream active, disable all bits */ + srcr = vals->srcr | avals->srcr; + stcr = vals->stcr | avals->stcr; + sier = vals->sier | avals->sier; + } else { /* * To keep the other stream safe, exclude shared bits between * both streams, and get safe bits to disable current stream */ - sier = fsl_ssi_disable_val(vals->sier, avals->sier, - keep_active); - srcr = fsl_ssi_disable_val(vals->srcr, avals->srcr, - keep_active); - stcr = fsl_ssi_disable_val(vals->stcr, avals->stcr, - keep_active); - - /* Safely disable other control registers for the stream */ - regmap_update_bits(regs, REG_SSI_SRCR, srcr, 0); - regmap_update_bits(regs, REG_SSI_STCR, stcr, 0); - regmap_update_bits(regs, REG_SSI_SIER, sier, 0); + sier = ssi_excl_shared_bits(vals->sier, avals->sier, aactive); + srcr = ssi_excl_shared_bits(vals->srcr, avals->srcr, aactive); + stcr = ssi_excl_shared_bits(vals->stcr, avals->stcr, aactive); } -config_done: - /* Enabling of subunits is done after configuration */ - if (enable) { - /* - * Start DMA before setting TE to avoid FIFO underrun - * which may cause a channel slip or a channel swap - * - * TODO: FIQ cases might also need this upon testing - */ - if (ssi->use_dma && (vals->scr & SSI_SCR_TE)) { - int i; - int max_loop = 100; - - /* Enable SSI first to send TX DMA request */ - regmap_update_bits(regs, REG_SSI_SCR, - SSI_SCR_SSIEN, SSI_SCR_SSIEN); - - /* Busy wait until TX FIFO not empty -- DMA working */ - for (i = 0; i < max_loop; i++) { - u32 sfcsr; - regmap_read(regs, REG_SSI_SFCSR, &sfcsr); - if (SSI_SFCSR_TFCNT0(sfcsr)) - break; - } - if (i == max_loop) { - dev_err(ssi->dev, - "Timeout waiting TX FIFO filling\n"); - } - } - /* Enable all remaining bits */ - regmap_update_bits(regs, REG_SSI_SCR, vals->scr, vals->scr); - } -} + /* Clear configurations of SRCR, STCR and SIER at once */ + regmap_update_bits(ssi->regs, REG_SSI_SRCR, srcr, 0); + regmap_update_bits(ssi->regs, REG_SSI_STCR, stcr, 0); + regmap_update_bits(ssi->regs, REG_SSI_SIER, sier, 0); -static void fsl_ssi_rx_config(struct fsl_ssi *ssi, bool enable) -{ - fsl_ssi_config(ssi, enable, &ssi->regvals[RX]); +fifo_clear: + /* Clear remaining data in the FIFO */ + regmap_update_bits(ssi->regs, REG_SSI_SOR, + SSI_SOR_xX_CLR(tx), SSI_SOR_xX_CLR(tx)); } static void fsl_ssi_tx_ac97_saccst_setup(struct fsl_ssi *ssi) @@ -566,21 +581,6 @@ static void fsl_ssi_tx_ac97_saccst_setup(struct fsl_ssi *ssi) } } -static void fsl_ssi_tx_config(struct fsl_ssi *ssi, bool enable) -{ - /* - * SACCST might be modified via AC Link by a CODEC if it sends - * extra bits in their SLOTREQ requests, which'll accidentally - * send valid data to slots other than normal playback slots. - * - * To be safe, configure SACCST right before TX starts. - */ - if (enable && fsl_ssi_is_ac97(ssi)) - fsl_ssi_tx_ac97_saccst_setup(ssi); - - fsl_ssi_config(ssi, enable, &ssi->regvals[TX]); -} - /** * Cache critical bits of SIER, SRCR, STCR and SCR to later set them safely */ @@ -588,17 +588,20 @@ static void fsl_ssi_setup_regvals(struct fsl_ssi *ssi) { struct fsl_ssi_regvals *vals = ssi->regvals; - vals[RX].sier = SSI_SIER_RFF0_EN; + vals[RX].sier = SSI_SIER_RFF0_EN | FSLSSI_SIER_DBG_RX_FLAGS; vals[RX].srcr = SSI_SRCR_RFEN0; - vals[RX].scr = 0; - vals[TX].sier = SSI_SIER_TFE0_EN; + vals[RX].scr = SSI_SCR_SSIEN | SSI_SCR_RE; + vals[TX].sier = SSI_SIER_TFE0_EN | FSLSSI_SIER_DBG_TX_FLAGS; vals[TX].stcr = SSI_STCR_TFEN0; - vals[TX].scr = 0; + vals[TX].scr = SSI_SCR_SSIEN | SSI_SCR_TE; /* AC97 has already enabled SSIEN, RE and TE, so ignore them */ - if (!fsl_ssi_is_ac97(ssi)) { - vals[RX].scr = SSI_SCR_SSIEN | SSI_SCR_RE; - vals[TX].scr = SSI_SCR_SSIEN | SSI_SCR_TE; + if (fsl_ssi_is_ac97(ssi)) + vals[RX].scr = vals[TX].scr = 0; + + if (ssi->use_dual_fifo) { + vals[RX].srcr |= SSI_SRCR_RFEN1; + vals[TX].stcr |= SSI_STCR_TFEN1; } if (ssi->use_dma) { @@ -608,9 +611,6 @@ static void fsl_ssi_setup_regvals(struct fsl_ssi *ssi) vals[RX].sier |= SSI_SIER_RIE; vals[TX].sier |= SSI_SIER_TIE; } - - vals[RX].sier |= FSLSSI_SIER_DBG_RX_FLAGS; - vals[TX].sier |= FSLSSI_SIER_DBG_TX_FLAGS; } static void fsl_ssi_setup_ac97(struct fsl_ssi *ssi) @@ -681,7 +681,6 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, bool tx2, tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); struct regmap *regs = ssi->regs; - int synchronous = ssi->cpu_dai_drv.symmetric_rates, ret; u32 pm = 999, div2, psr, stccr, mask, afreq, factor, i; unsigned long clkrate, baudrate, tmprate; unsigned int slots = params_channels(hw_params); @@ -689,6 +688,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, u64 sub, savesub = 100000; unsigned int freq; bool baudclk_is_used; + int ret; /* Override slots and slot_width if being specifically set... */ if (ssi->slots) @@ -767,7 +767,7 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, mask = SSI_SxCCR_PM_MASK | SSI_SxCCR_DIV2 | SSI_SxCCR_PSR; /* STCCR is used for RX in synchronous mode */ - tx2 = tx || synchronous; + tx2 = tx || ssi->synchronous; regmap_update_bits(regs, REG_SSI_SxCCR(tx2), mask, stccr); if (!baudclk_is_used) { @@ -803,11 +803,6 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, unsigned int sample_size = params_width(hw_params); u32 wl = SSI_SxCCR_WL(sample_size); int ret; - u32 scr; - int enabled; - - regmap_read(regs, REG_SSI_SCR, &scr); - enabled = scr & SSI_SCR_SSIEN; /* * SSI is properly configured if it is enabled and running in @@ -815,7 +810,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, * that should set separate configurations for STCCR and SRCCR * despite running in the synchronous mode. */ - if (enabled && ssi->cpu_dai_drv.symmetric_rates) + if (ssi->streams && ssi->synchronous) return 0; if (fsl_ssi_is_i2s_master(ssi)) { @@ -834,20 +829,20 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, } if (!fsl_ssi_is_ac97(ssi)) { - u8 i2s_net; /* Normal + Network mode to send 16-bit data in 32-bit frames */ if (fsl_ssi_is_i2s_cbm_cfs(ssi) && sample_size == 16) - i2s_net = SSI_SCR_I2S_MODE_NORMAL | SSI_SCR_NET; - else - i2s_net = ssi->i2s_net; + ssi->i2s_net = SSI_SCR_I2S_MODE_NORMAL | SSI_SCR_NET; + + /* Use Normal mode to send mono data at 1st slot of 2 slots */ + if (channels == 1) + ssi->i2s_net = SSI_SCR_I2S_MODE_NORMAL; regmap_update_bits(regs, REG_SSI_SCR, - SSI_SCR_I2S_NET_MASK, - channels == 1 ? 0 : i2s_net); + SSI_SCR_I2S_NET_MASK, ssi->i2s_net); } /* In synchronous mode, the SSI uses STCCR for capture */ - tx2 = tx || ssi->cpu_dai_drv.symmetric_rates; + tx2 = tx || ssi->synchronous; regmap_update_bits(regs, REG_SSI_SxCCR(tx2), SSI_SxCCR_WL_MASK, wl); return 0; @@ -868,45 +863,31 @@ static int fsl_ssi_hw_free(struct snd_pcm_substream *substream, return 0; } -static int _fsl_ssi_set_dai_fmt(struct device *dev, - struct fsl_ssi *ssi, unsigned int fmt) +static int _fsl_ssi_set_dai_fmt(struct fsl_ssi *ssi, unsigned int fmt) { - struct regmap *regs = ssi->regs; - u32 strcr = 0, stcr, srcr, scr, mask; - u8 wm; + u32 strcr = 0, scr = 0, stcr, srcr, mask; ssi->dai_fmt = fmt; - if (fsl_ssi_is_i2s_master(ssi) && IS_ERR(ssi->baudclk)) { - dev_err(dev, "missing baudclk for master mode\n"); - return -EINVAL; - } - - fsl_ssi_setup_regvals(ssi); - - regmap_read(regs, REG_SSI_SCR, &scr); - scr &= ~(SSI_SCR_SYN | SSI_SCR_I2S_MODE_MASK); /* Synchronize frame sync clock for TE to avoid data slipping */ scr |= SSI_SCR_SYNC_TX_FS; - mask = SSI_STCR_TXBIT0 | SSI_STCR_TFDIR | SSI_STCR_TXDIR | - SSI_STCR_TSCKP | SSI_STCR_TFSI | SSI_STCR_TFSL | SSI_STCR_TEFS; - regmap_read(regs, REG_SSI_STCR, &stcr); - regmap_read(regs, REG_SSI_SRCR, &srcr); - stcr &= ~mask; - srcr &= ~mask; + /* Set to default shifting settings: LSB_ALIGNED */ + strcr |= SSI_STCR_TXBIT0; /* Use Network mode as default */ ssi->i2s_net = SSI_SCR_NET; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: - regmap_update_bits(regs, REG_SSI_STCCR, - SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(2)); - regmap_update_bits(regs, REG_SSI_SRCCR, - SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(2)); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFS: case SND_SOC_DAIFMT_CBS_CFS: + if (IS_ERR(ssi->baudclk)) { + dev_err(ssi->dev, + "missing baudclk for master mode\n"); + return -EINVAL; + } + /* fall through */ + case SND_SOC_DAIFMT_CBM_CFS: ssi->i2s_net |= SSI_SCR_I2S_MODE_MASTER; break; case SND_SOC_DAIFMT_CBM_CFM: @@ -916,30 +897,34 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, return -EINVAL; } + regmap_update_bits(ssi->regs, REG_SSI_STCCR, + SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(2)); + regmap_update_bits(ssi->regs, REG_SSI_SRCCR, + SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(2)); + /* Data on rising edge of bclk, frame low, 1clk before data */ - strcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP | - SSI_STCR_TXBIT0 | SSI_STCR_TEFS; + strcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP | SSI_STCR_TEFS; break; case SND_SOC_DAIFMT_LEFT_J: /* Data on rising edge of bclk, frame high */ - strcr |= SSI_STCR_TXBIT0 | SSI_STCR_TSCKP; + strcr |= SSI_STCR_TSCKP; break; case SND_SOC_DAIFMT_DSP_A: /* Data on rising edge of bclk, frame high, 1clk before data */ - strcr |= SSI_STCR_TFSL | SSI_STCR_TSCKP | - SSI_STCR_TXBIT0 | SSI_STCR_TEFS; + strcr |= SSI_STCR_TFSL | SSI_STCR_TSCKP | SSI_STCR_TEFS; break; case SND_SOC_DAIFMT_DSP_B: /* Data on rising edge of bclk, frame high */ - strcr |= SSI_STCR_TFSL | SSI_STCR_TSCKP | SSI_STCR_TXBIT0; + strcr |= SSI_STCR_TFSL | SSI_STCR_TSCKP; break; case SND_SOC_DAIFMT_AC97: /* Data on falling edge of bclk, frame high, 1clk before data */ - ssi->i2s_net |= SSI_SCR_I2S_MODE_NORMAL; + strcr |= SSI_STCR_TEFS; break; default: return -EINVAL; } + scr |= ssi->i2s_net; /* DAI clock inversion */ @@ -973,49 +958,33 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev, break; case SND_SOC_DAIFMT_CBM_CFM: /* Input bit or frame sync clocks */ - scr &= ~SSI_SCR_SYS_CLK_EN; break; case SND_SOC_DAIFMT_CBM_CFS: /* Input bit clock but output frame sync clock */ - strcr &= ~SSI_STCR_TXDIR; strcr |= SSI_STCR_TFDIR; - scr &= ~SSI_SCR_SYS_CLK_EN; break; default: - if (!fsl_ssi_is_ac97(ssi)) - return -EINVAL; + return -EINVAL; } - stcr |= strcr; - srcr |= strcr; + stcr = strcr; + srcr = strcr; /* Set SYN mode and clear RXDIR bit when using SYN or AC97 mode */ - if (ssi->cpu_dai_drv.symmetric_rates || fsl_ssi_is_ac97(ssi)) { + if (ssi->synchronous || fsl_ssi_is_ac97(ssi)) { srcr &= ~SSI_SRCR_RXDIR; scr |= SSI_SCR_SYN; } - regmap_write(regs, REG_SSI_STCR, stcr); - regmap_write(regs, REG_SSI_SRCR, srcr); - regmap_write(regs, REG_SSI_SCR, scr); + mask = SSI_STCR_TFDIR | SSI_STCR_TXDIR | SSI_STCR_TSCKP | + SSI_STCR_TFSL | SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0; - wm = ssi->fifo_watermark; + regmap_update_bits(ssi->regs, REG_SSI_STCR, mask, stcr); + regmap_update_bits(ssi->regs, REG_SSI_SRCR, mask, srcr); - regmap_write(regs, REG_SSI_SFCSR, - SSI_SFCSR_TFWM0(wm) | SSI_SFCSR_RFWM0(wm) | - SSI_SFCSR_TFWM1(wm) | SSI_SFCSR_RFWM1(wm)); - - if (ssi->use_dual_fifo) { - regmap_update_bits(regs, REG_SSI_SRCR, - SSI_SRCR_RFEN1, SSI_SRCR_RFEN1); - regmap_update_bits(regs, REG_SSI_STCR, - SSI_STCR_TFEN1, SSI_STCR_TFEN1); - regmap_update_bits(regs, REG_SSI_SCR, - SSI_SCR_TCH_EN, SSI_SCR_TCH_EN); - } - - if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_AC97) - fsl_ssi_setup_ac97(ssi); + mask = SSI_SCR_SYNC_TX_FS | SSI_SCR_I2S_MODE_MASK | + SSI_SCR_SYS_CLK_EN | SSI_SCR_SYN; + regmap_update_bits(ssi->regs, REG_SSI_SCR, mask, scr); return 0; } @@ -1031,7 +1000,7 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) if (fsl_ssi_is_ac97(ssi)) return 0; - return _fsl_ssi_set_dai_fmt(dai->dev, ssi, fmt); + return _fsl_ssi_set_dai_fmt(ssi, fmt); } /** @@ -1051,9 +1020,7 @@ static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, } /* The slot number should be >= 2 if using Network mode or I2S mode */ - regmap_read(regs, REG_SSI_SCR, &val); - val &= SSI_SCR_I2S_MODE_MASK | SSI_SCR_NET; - if (val && slots < 2) { + if (ssi->i2s_net && slots < 2) { dev_err(dai->dev, "slot number should be >= 2 in I2S or NET\n"); return -EINVAL; } @@ -1063,9 +1030,8 @@ static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, regmap_update_bits(regs, REG_SSI_SRCCR, SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(slots)); - /* Save SSIEN bit of the SCR register */ + /* Save the SCR register value */ regmap_read(regs, REG_SSI_SCR, &val); - val &= SSI_SCR_SSIEN; /* Temporarily enable SSI to allow SxMSKs to be configurable */ regmap_update_bits(regs, REG_SSI_SCR, SSI_SCR_SSIEN, SSI_SCR_SSIEN); @@ -1092,39 +1058,34 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(rtd->cpu_dai); - struct regmap *regs = ssi->regs; + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - fsl_ssi_tx_config(ssi, true); - else - fsl_ssi_rx_config(ssi, true); + /* + * SACCST might be modified via AC Link by a CODEC if it sends + * extra bits in their SLOTREQ requests, which'll accidentally + * send valid data to slots other than normal playback slots. + * + * To be safe, configure SACCST right before TX starts. + */ + if (tx && fsl_ssi_is_ac97(ssi)) + fsl_ssi_tx_ac97_saccst_setup(ssi); + fsl_ssi_config_enable(ssi, tx); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - fsl_ssi_tx_config(ssi, false); - else - fsl_ssi_rx_config(ssi, false); + fsl_ssi_config_disable(ssi, tx); break; default: return -EINVAL; } - /* Clear corresponding FIFO */ - if (fsl_ssi_is_ac97(ssi)) { - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - regmap_write(regs, REG_SSI_SOR, SSI_SOR_TX_CLR); - else - regmap_write(regs, REG_SSI_SOR, SSI_SOR_RX_CLR); - } - return 0; } @@ -1132,10 +1093,9 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai) { struct fsl_ssi *ssi = snd_soc_dai_get_drvdata(dai); - if (ssi->soc->imx && ssi->use_dma) { - dai->playback_dma_data = &ssi->dma_params_tx; - dai->capture_dma_data = &ssi->dma_params_rx; - } + if (ssi->soc->imx && ssi->use_dma) + snd_soc_dai_init_dma_data(dai, &ssi->dma_params_tx, + &ssi->dma_params_rx); return 0; } @@ -1175,6 +1135,7 @@ static const struct snd_soc_component_driver fsl_ssi_component = { static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { .bus_control = true, + .symmetric_channels = 1, .probe = fsl_ssi_dai_probe, .playback = { .stream_name = "AC97 Playback", @@ -1272,6 +1233,53 @@ static struct snd_ac97_bus_ops fsl_ssi_ac97_ops = { }; /** + * Initialize SSI registers + */ +static int fsl_ssi_hw_init(struct fsl_ssi *ssi) +{ + u32 wm = ssi->fifo_watermark; + + /* Initialize regvals */ + fsl_ssi_setup_regvals(ssi); + + /* Set watermarks */ + regmap_write(ssi->regs, REG_SSI_SFCSR, + SSI_SFCSR_TFWM0(wm) | SSI_SFCSR_RFWM0(wm) | + SSI_SFCSR_TFWM1(wm) | SSI_SFCSR_RFWM1(wm)); + + /* Enable Dual FIFO mode */ + if (ssi->use_dual_fifo) + regmap_update_bits(ssi->regs, REG_SSI_SCR, + SSI_SCR_TCH_EN, SSI_SCR_TCH_EN); + + /* AC97 should start earlier to communicate with CODECs */ + if (fsl_ssi_is_ac97(ssi)) { + _fsl_ssi_set_dai_fmt(ssi, ssi->dai_fmt); + fsl_ssi_setup_ac97(ssi); + } + + return 0; +} + +/** + * Clear SSI registers + */ +static void fsl_ssi_hw_clean(struct fsl_ssi *ssi) +{ + /* Disable registers for AC97 */ + if (fsl_ssi_is_ac97(ssi)) { + /* Disable TE and RE bits first */ + regmap_update_bits(ssi->regs, REG_SSI_SCR, + SSI_SCR_TE | SSI_SCR_RE, 0); + /* Disable AC97 mode */ + regmap_write(ssi->regs, REG_SSI_SACNT, 0); + /* Unset WAIT bits */ + regmap_write(ssi->regs, REG_SSI_SOR, 0); + /* Disable SSI -- software reset */ + regmap_update_bits(ssi->regs, REG_SSI_SCR, SSI_SCR_SSIEN, 0); + } +} +/** * Make every character in a string lower-case */ static void make_lowercase(char *s) @@ -1285,9 +1293,7 @@ static void make_lowercase(char *s) static int fsl_ssi_imx_probe(struct platform_device *pdev, struct fsl_ssi *ssi, void __iomem *iomem) { - struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; - u32 dmas[4]; int ret; /* Backward compatible for a DT without ipg clock name assigned */ @@ -1321,14 +1327,8 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, ssi->dma_params_tx.addr = ssi->ssi_phys + REG_SSI_STX0; ssi->dma_params_rx.addr = ssi->ssi_phys + REG_SSI_SRX0; - /* Set to dual FIFO mode according to the SDMA sciprt */ - ret = of_property_read_u32_array(np, "dmas", dmas, 4); - if (ssi->use_dma && !ret && dmas[2] == IMX_DMATYPE_SSI_DUAL) { - ssi->use_dual_fifo = true; - /* - * Use even numbers to avoid channel swap due to SDMA - * script design - */ + /* Use even numbers to avoid channel swap due to SDMA script design */ + if (ssi->use_dual_fifo) { ssi->dma_params_tx.maxburst &= ~0x1; ssi->dma_params_rx.maxburst &= ~0x1; } @@ -1369,41 +1369,109 @@ static void fsl_ssi_imx_clean(struct platform_device *pdev, struct fsl_ssi *ssi) clk_disable_unprepare(ssi->clk); } -static int fsl_ssi_probe(struct platform_device *pdev) +static int fsl_ssi_probe_from_dt(struct fsl_ssi *ssi) { - struct fsl_ssi *ssi; - int ret = 0; - struct device_node *np = pdev->dev.of_node; - struct device *dev = &pdev->dev; + struct device *dev = ssi->dev; + struct device_node *np = dev->of_node; const struct of_device_id *of_id; const char *p, *sprop; - const uint32_t *iprop; - struct resource *res; - void __iomem *iomem; - char name[64]; - struct regmap_config regconfig = fsl_ssi_regconfig; + const __be32 *iprop; + u32 dmas[4]; + int ret; of_id = of_match_device(fsl_ssi_ids, dev); if (!of_id || !of_id->data) return -EINVAL; - ssi = devm_kzalloc(dev, sizeof(*ssi), GFP_KERNEL); - if (!ssi) - return -ENOMEM; - ssi->soc = of_id->data; - ssi->dev = dev; + + ret = of_property_match_string(np, "clock-names", "ipg"); + /* Get error code if not found */ + ssi->has_ipg_clk_name = ret >= 0; /* Check if being used in AC97 mode */ sprop = of_get_property(np, "fsl,mode", NULL); - if (sprop) { - if (!strcmp(sprop, "ac97-slave")) - ssi->dai_fmt = SND_SOC_DAIFMT_AC97; + if (sprop && !strcmp(sprop, "ac97-slave")) { + ssi->dai_fmt = FSLSSI_AC97_DAIFMT; + + ret = of_property_read_u32(np, "cell-index", &ssi->card_idx); + if (ret) { + dev_err(dev, "failed to get SSI index property\n"); + return -EINVAL; + } + strcpy(ssi->card_name, "ac97-codec"); + } else if (!of_find_property(np, "fsl,ssi-asynchronous", NULL)) { + /* + * In synchronous mode, STCK and STFS ports are used by RX + * as well. So the software should limit the sample rates, + * sample bits and channels to be symmetric. + * + * This is exclusive with FSLSSI_AC97_FORMATS as AC97 runs + * in the SSI synchronous mode however it does not have to + * limit symmetric sample rates and sample bits. + */ + ssi->synchronous = true; } /* Select DMA or FIQ */ ssi->use_dma = !of_property_read_bool(np, "fsl,fiq-stream-filter"); + /* Fetch FIFO depth; Set to 8 for older DT without this property */ + iprop = of_get_property(np, "fsl,fifo-depth", NULL); + if (iprop) + ssi->fifo_depth = be32_to_cpup(iprop); + else + ssi->fifo_depth = 8; + + /* Use dual FIFO mode depending on the support from SDMA script */ + ret = of_property_read_u32_array(np, "dmas", dmas, 4); + if (ssi->use_dma && !ret && dmas[2] == IMX_DMATYPE_SSI_DUAL) + ssi->use_dual_fifo = true; + + /* + * Backward compatible for older bindings by manually triggering the + * machine driver's probe(). Use /compatible property, including the + * address of CPU DAI driver structure, as the name of machine driver + * + * If card_name is set by AC97 earlier, bypass here since it uses a + * different name to register the device. + */ + if (!ssi->card_name[0] && of_get_property(np, "codec-handle", NULL)) { + sprop = of_get_property(of_find_node_by_path("/"), + "compatible", NULL); + /* Strip "fsl," in the compatible name if applicable */ + p = strrchr(sprop, ','); + if (p) + sprop = p + 1; + snprintf(ssi->card_name, sizeof(ssi->card_name), + "snd-soc-%s", sprop); + make_lowercase(ssi->card_name); + ssi->card_idx = 0; + } + + return 0; +} + +static int fsl_ssi_probe(struct platform_device *pdev) +{ + struct regmap_config regconfig = fsl_ssi_regconfig; + struct device *dev = &pdev->dev; + struct fsl_ssi *ssi; + struct resource *res; + void __iomem *iomem; + int ret = 0; + + ssi = devm_kzalloc(dev, sizeof(*ssi), GFP_KERNEL); + if (!ssi) + return -ENOMEM; + + ssi->dev = dev; + + /* Probe from DT */ + ret = fsl_ssi_probe_from_dt(ssi); + if (ret) + return ret; + if (fsl_ssi_is_ac97(ssi)) { memcpy(&ssi->cpu_dai_drv, &fsl_ssi_ac97_dai, sizeof(fsl_ssi_ac97_dai)); @@ -1427,15 +1495,11 @@ static int fsl_ssi_probe(struct platform_device *pdev) REG_SSI_SRMSK / sizeof(uint32_t) + 1; } - ret = of_property_match_string(np, "clock-names", "ipg"); - if (ret < 0) { - ssi->has_ipg_clk_name = false; - ssi->regs = devm_regmap_init_mmio(dev, iomem, ®config); - } else { - ssi->has_ipg_clk_name = true; + if (ssi->has_ipg_clk_name) ssi->regs = devm_regmap_init_mmio_clk(dev, "ipg", iomem, ®config); - } + else + ssi->regs = devm_regmap_init_mmio(dev, iomem, ®config); if (IS_ERR(ssi->regs)) { dev_err(dev, "failed to init register map\n"); return PTR_ERR(ssi->regs); @@ -1447,23 +1511,13 @@ static int fsl_ssi_probe(struct platform_device *pdev) return ssi->irq; } - /* Set software limitations for synchronous mode */ - if (!of_find_property(np, "fsl,ssi-asynchronous", NULL)) { - if (!fsl_ssi_is_ac97(ssi)) { - ssi->cpu_dai_drv.symmetric_rates = 1; - ssi->cpu_dai_drv.symmetric_samplebits = 1; - } - + /* Set software limitations for synchronous mode except AC97 */ + if (ssi->synchronous && !fsl_ssi_is_ac97(ssi)) { + ssi->cpu_dai_drv.symmetric_rates = 1; ssi->cpu_dai_drv.symmetric_channels = 1; + ssi->cpu_dai_drv.symmetric_samplebits = 1; } - /* Fetch FIFO depth; Set to 8 for older DT without this property */ - iprop = of_get_property(np, "fsl,fifo-depth", NULL); - if (iprop) - ssi->fifo_depth = be32_to_cpup(iprop); - else - ssi->fifo_depth = 8; - /* * Configure TX and RX DMA watermarks -- when to send a DMA request * @@ -1528,50 +1582,27 @@ static int fsl_ssi_probe(struct platform_device *pdev) if (ret) goto error_asoc_register; - /* Bypass it if using newer DT bindings of ASoC machine drivers */ - if (!of_get_property(np, "codec-handle", NULL)) - goto done; - - /* - * Backward compatible for older bindings by manually triggering the - * machine driver's probe(). Use /compatible property, including the - * address of CPU DAI driver structure, as the name of machine driver. - */ - sprop = of_get_property(of_find_node_by_path("/"), "compatible", NULL); - /* Sometimes the compatible name has a "fsl," prefix, so we strip it. */ - p = strrchr(sprop, ','); - if (p) - sprop = p + 1; - snprintf(name, sizeof(name), "snd-soc-%s", sprop); - make_lowercase(name); - - ssi->pdev = platform_device_register_data(dev, name, 0, NULL, 0); - if (IS_ERR(ssi->pdev)) { - ret = PTR_ERR(ssi->pdev); - dev_err(dev, "failed to register platform: %d\n", ret); - goto error_sound_card; - } - -done: - if (ssi->dai_fmt) - _fsl_ssi_set_dai_fmt(dev, ssi, ssi->dai_fmt); - - if (fsl_ssi_is_ac97(ssi)) { - u32 ssi_idx; + /* Initially configures SSI registers */ + fsl_ssi_hw_init(ssi); - ret = of_property_read_u32(np, "cell-index", &ssi_idx); - if (ret) { - dev_err(dev, "failed to get SSI index property\n"); - goto error_sound_card; - } - - ssi->pdev = platform_device_register_data(NULL, "ac97-codec", - ssi_idx, NULL, 0); - if (IS_ERR(ssi->pdev)) { - ret = PTR_ERR(ssi->pdev); - dev_err(dev, - "failed to register AC97 codec platform: %d\n", - ret); + /* Register a platform device for older bindings or AC97 */ + if (ssi->card_name[0]) { + struct device *parent = dev; + /* + * Do not set SSI dev as the parent of AC97 CODEC device since + * it does not have a DT node. Otherwise ASoC core will assume + * CODEC has the same DT node as the SSI, so it may bypass the + * dai_probe() of SSI and then cause NULL DMA data pointers. + */ + if (fsl_ssi_is_ac97(ssi)) + parent = NULL; + + ssi->card_pdev = platform_device_register_data(parent, + ssi->card_name, ssi->card_idx, NULL, 0); + if (IS_ERR(ssi->card_pdev)) { + ret = PTR_ERR(ssi->card_pdev); + dev_err(dev, "failed to register %s: %d\n", + ssi->card_name, ret); goto error_sound_card; } } @@ -1599,8 +1630,11 @@ static int fsl_ssi_remove(struct platform_device *pdev) fsl_ssi_debugfs_remove(&ssi->dbg_stats); - if (ssi->pdev) - platform_device_unregister(ssi->pdev); + if (ssi->card_pdev) + platform_device_unregister(ssi->card_pdev); + + /* Clean up SSI registers */ + fsl_ssi_hw_clean(ssi); if (ssi->soc->imx) fsl_ssi_imx_clean(pdev, ssi); diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h index de2fdc5db726..18f8dd5209d5 100644 --- a/sound/soc/fsl/fsl_ssi.h +++ b/sound/soc/fsl/fsl_ssi.h @@ -12,9 +12,6 @@ #ifndef _MPC8610_I2S_H #define _MPC8610_I2S_H -#define RX 0 -#define TX 1 - /* -- SSI Register Map -- */ /* SSI Transmit Data Register 0 */ diff --git a/sound/soc/fsl/fsl_utils.c b/sound/soc/fsl/fsl_utils.c index b9e42b503a37..7592b0406370 100644 --- a/sound/soc/fsl/fsl_utils.c +++ b/sound/soc/fsl/fsl_utils.c @@ -36,7 +36,7 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np, { struct resource res; struct device_node *dma_channel_np, *dma_np; - const u32 *iprop; + const __be32 *iprop; int ret; dma_channel_np = of_parse_phandle(ssi_np, name, 0); diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c index 4e5fefee111e..0578f3486847 100644 --- a/sound/soc/fsl/imx-pcm-fiq.c +++ b/sound/soc/fsl/imx-pcm-fiq.c @@ -341,7 +341,7 @@ static void imx_pcm_fiq_free(struct snd_pcm *pcm) imx_pcm_free(pcm); } -static const struct snd_soc_platform_driver imx_soc_platform_fiq = { +static const struct snd_soc_component_driver imx_soc_component_fiq = { .ops = &imx_pcm_ops, .pcm_new = imx_pcm_fiq_new, .pcm_free = imx_pcm_fiq_free, @@ -368,7 +368,8 @@ int imx_pcm_fiq_init(struct platform_device *pdev, params->dma_params_tx->maxburst = 4; params->dma_params_rx->maxburst = 6; - ret = snd_soc_register_platform(&pdev->dev, &imx_soc_platform_fiq); + ret = devm_snd_soc_register_component(&pdev->dev, &imx_soc_component_fiq, + NULL, 0); if (ret) goto failed_register; @@ -384,7 +385,6 @@ EXPORT_SYMBOL_GPL(imx_pcm_fiq_init); void imx_pcm_fiq_exit(struct platform_device *pdev) { - snd_soc_unregister_platform(&pdev->dev); } EXPORT_SYMBOL_GPL(imx_pcm_fiq_exit); diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c deleted file mode 100644 index 206b898e554c..000000000000 --- a/sound/soc/fsl/imx-wm8962.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright 2013 Freescale Semiconductor, Inc. - * - * Based on imx-sgtl5000.c - * Copyright 2012 Freescale Semiconductor, Inc. - * Copyright 2012 Linaro Ltd. - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ - -#include <linux/module.h> -#include <linux/of_platform.h> -#include <linux/i2c.h> -#include <linux/slab.h> -#include <linux/clk.h> -#include <sound/soc.h> -#include <sound/pcm_params.h> -#include <sound/soc-dapm.h> -#include <linux/pinctrl/consumer.h> - -#include "../codecs/wm8962.h" -#include "imx-audmux.h" - -#define DAI_NAME_SIZE 32 - -struct imx_wm8962_data { - struct snd_soc_dai_link dai; - struct snd_soc_card card; - char codec_dai_name[DAI_NAME_SIZE]; - char platform_name[DAI_NAME_SIZE]; - unsigned int clk_frequency; -}; - -struct imx_priv { - struct platform_device *pdev; - int sample_rate; - snd_pcm_format_t sample_format; -}; - -static const struct snd_soc_dapm_widget imx_wm8962_dapm_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_SPK("Ext Spk", NULL), - SND_SOC_DAPM_MIC("AMIC", NULL), - SND_SOC_DAPM_MIC("DMIC", NULL), -}; - -static int imx_hifi_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct imx_priv *priv = snd_soc_card_get_drvdata(rtd->card); - - priv->sample_rate = params_rate(params); - priv->sample_format = params_format(params); - - return 0; -} - -static const struct snd_soc_ops imx_hifi_ops = { - .hw_params = imx_hifi_hw_params, -}; - -static int imx_wm8962_set_bias_level(struct snd_soc_card *card, - struct snd_soc_dapm_context *dapm, - enum snd_soc_bias_level level) -{ - struct snd_soc_pcm_runtime *rtd; - struct snd_soc_dai *codec_dai; - struct imx_priv *priv = snd_soc_card_get_drvdata(card); - struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card); - struct device *dev = &priv->pdev->dev; - unsigned int pll_out; - int ret; - - rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); - codec_dai = rtd->codec_dai; - if (dapm->dev != codec_dai->dev) - return 0; - - switch (level) { - case SND_SOC_BIAS_PREPARE: - if (dapm->bias_level == SND_SOC_BIAS_STANDBY) { - if (priv->sample_format == SNDRV_PCM_FORMAT_S24_LE) - pll_out = priv->sample_rate * 384; - else - pll_out = priv->sample_rate * 256; - - ret = snd_soc_dai_set_pll(codec_dai, WM8962_FLL, - WM8962_FLL_MCLK, data->clk_frequency, - pll_out); - if (ret < 0) { - dev_err(dev, "failed to start FLL: %d\n", ret); - return ret; - } - - ret = snd_soc_dai_set_sysclk(codec_dai, - WM8962_SYSCLK_FLL, pll_out, - SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(dev, "failed to set SYSCLK: %d\n", ret); - return ret; - } - } - break; - - case SND_SOC_BIAS_STANDBY: - if (dapm->bias_level == SND_SOC_BIAS_PREPARE) { - ret = snd_soc_dai_set_sysclk(codec_dai, - WM8962_SYSCLK_MCLK, data->clk_frequency, - SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(dev, - "failed to switch away from FLL: %d\n", - ret); - return ret; - } - - ret = snd_soc_dai_set_pll(codec_dai, WM8962_FLL, - 0, 0, 0); - if (ret < 0) { - dev_err(dev, "failed to stop FLL: %d\n", ret); - return ret; - } - } - break; - - default: - break; - } - - return 0; -} - -static int imx_wm8962_late_probe(struct snd_soc_card *card) -{ - struct snd_soc_pcm_runtime *rtd; - struct snd_soc_dai *codec_dai; - struct imx_priv *priv = snd_soc_card_get_drvdata(card); - struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card); - struct device *dev = &priv->pdev->dev; - int ret; - - rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); - codec_dai = rtd->codec_dai; - ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK, - data->clk_frequency, SND_SOC_CLOCK_IN); - if (ret < 0) - dev_err(dev, "failed to set sysclk in %s\n", __func__); - - return ret; -} - -static int imx_wm8962_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct device_node *ssi_np, *codec_np; - struct platform_device *ssi_pdev; - struct i2c_client *codec_dev; - struct imx_wm8962_data *data; - struct imx_priv *priv; - struct clk *codec_clk; - int int_port, ext_port; - int ret; - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->pdev = pdev; - priv->sample_rate = 44100; - priv->sample_format = SNDRV_PCM_FORMAT_S16_LE; - - ret = of_property_read_u32(np, "mux-int-port", &int_port); - if (ret) { - dev_err(&pdev->dev, "mux-int-port missing or invalid\n"); - return ret; - } - ret = of_property_read_u32(np, "mux-ext-port", &ext_port); - if (ret) { - dev_err(&pdev->dev, "mux-ext-port missing or invalid\n"); - return ret; - } - - /* - * The port numbering in the hardware manual starts at 1, while - * the audmux API expects it starts at 0. - */ - int_port--; - ext_port--; - ret = imx_audmux_v2_configure_port(int_port, - IMX_AUDMUX_V2_PTCR_SYN | - IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) | - IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) | - IMX_AUDMUX_V2_PTCR_TFSDIR | - IMX_AUDMUX_V2_PTCR_TCLKDIR, - IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port)); - if (ret) { - dev_err(&pdev->dev, "audmux internal port setup failed\n"); - return ret; - } - ret = imx_audmux_v2_configure_port(ext_port, - IMX_AUDMUX_V2_PTCR_SYN, - IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)); - if (ret) { - dev_err(&pdev->dev, "audmux external port setup failed\n"); - return ret; - } - - ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0); - codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0); - if (!ssi_np || !codec_np) { - dev_err(&pdev->dev, "phandle missing or invalid\n"); - ret = -EINVAL; - goto fail; - } - - ssi_pdev = of_find_device_by_node(ssi_np); - if (!ssi_pdev) { - dev_err(&pdev->dev, "failed to find SSI platform device\n"); - ret = -EINVAL; - goto fail; - } - codec_dev = of_find_i2c_device_by_node(codec_np); - if (!codec_dev || !codec_dev->dev.driver) { - dev_err(&pdev->dev, "failed to find codec platform device\n"); - ret = -EINVAL; - goto fail; - } - - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) { - ret = -ENOMEM; - goto fail; - } - - codec_clk = clk_get(&codec_dev->dev, NULL); - if (IS_ERR(codec_clk)) { - ret = PTR_ERR(codec_clk); - dev_err(&codec_dev->dev, "failed to get codec clk: %d\n", ret); - goto fail; - } - - data->clk_frequency = clk_get_rate(codec_clk); - clk_put(codec_clk); - - data->dai.name = "HiFi"; - data->dai.stream_name = "HiFi"; - data->dai.codec_dai_name = "wm8962"; - data->dai.codec_of_node = codec_np; - data->dai.cpu_dai_name = dev_name(&ssi_pdev->dev); - data->dai.platform_of_node = ssi_np; - data->dai.ops = &imx_hifi_ops; - data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM; - - data->card.dev = &pdev->dev; - ret = snd_soc_of_parse_card_name(&data->card, "model"); - if (ret) - goto fail; - ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing"); - if (ret) - goto fail; - data->card.num_links = 1; - data->card.owner = THIS_MODULE; - data->card.dai_link = &data->dai; - data->card.dapm_widgets = imx_wm8962_dapm_widgets; - data->card.num_dapm_widgets = ARRAY_SIZE(imx_wm8962_dapm_widgets); - - data->card.late_probe = imx_wm8962_late_probe; - data->card.set_bias_level = imx_wm8962_set_bias_level; - - platform_set_drvdata(pdev, &data->card); - snd_soc_card_set_drvdata(&data->card, data); - - ret = devm_snd_soc_register_card(&pdev->dev, &data->card); - if (ret) { - dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); - goto fail; - } - -fail: - of_node_put(ssi_np); - of_node_put(codec_np); - - return ret; -} - -static const struct of_device_id imx_wm8962_dt_ids[] = { - { .compatible = "fsl,imx-audio-wm8962", }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, imx_wm8962_dt_ids); - -static struct platform_driver imx_wm8962_driver = { - .driver = { - .name = "imx-wm8962", - .pm = &snd_soc_pm_ops, - .of_match_table = imx_wm8962_dt_ids, - }, - .probe = imx_wm8962_probe, -}; -module_platform_driver(imx_wm8962_driver); - -MODULE_AUTHOR("Freescale Semiconductor, Inc."); -MODULE_DESCRIPTION("Freescale i.MX WM8962 ASoC machine driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:imx-wm8962"); diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index e63029f1aabc..c1a4544eb16b 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c @@ -22,6 +22,8 @@ #include "mpc5200_dma.h" +#define DRV_NAME "mpc5200_dma" + /* * Interrupt handlers */ @@ -300,12 +302,13 @@ static const struct snd_pcm_ops psc_dma_ops = { static int psc_dma_new(struct snd_soc_pcm_runtime *rtd) { struct snd_card *card = rtd->card->snd_card; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_soc_dai *dai = rtd->cpu_dai; struct snd_pcm *pcm = rtd->pcm; size_t size = psc_dma_hardware.buffer_bytes_max; int rc; - dev_dbg(rtd->platform->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n", + dev_dbg(component->dev, "psc_dma_new(card=%p, dai=%p, pcm=%p)\n", card, dai, pcm); rc = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32)); @@ -341,10 +344,11 @@ static int psc_dma_new(struct snd_soc_pcm_runtime *rtd) static void psc_dma_free(struct snd_pcm *pcm) { struct snd_soc_pcm_runtime *rtd = pcm->private_data; + struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct snd_pcm_substream *substream; int stream; - dev_dbg(rtd->platform->dev, "psc_dma_free(pcm=%p)\n", pcm); + dev_dbg(component->dev, "psc_dma_free(pcm=%p)\n", pcm); for (stream = 0; stream < 2; stream++) { substream = pcm->streams[stream].substream; @@ -356,7 +360,8 @@ static void psc_dma_free(struct snd_pcm *pcm) } } -static const struct snd_soc_platform_driver mpc5200_audio_dma_platform = { +static const struct snd_soc_component_driver mpc5200_audio_dma_component = { + .name = DRV_NAME, .ops = &psc_dma_ops, .pcm_new = &psc_dma_new, .pcm_free = &psc_dma_free, @@ -468,7 +473,8 @@ int mpc5200_audio_dma_create(struct platform_device *op) dev_set_drvdata(&op->dev, psc_dma); /* Tell the ASoC OF helpers about it */ - return snd_soc_register_platform(&op->dev, &mpc5200_audio_dma_platform); + return devm_snd_soc_register_component(&op->dev, + &mpc5200_audio_dma_component, NULL, 0); out_irq: free_irq(psc_dma->irq, psc_dma); free_irq(psc_dma->capture.irq, &psc_dma->capture); @@ -487,8 +493,6 @@ int mpc5200_audio_dma_destroy(struct platform_device *op) dev_dbg(&op->dev, "mpc5200_audio_dma_destroy()\n"); - snd_soc_unregister_platform(&op->dev); - bcom_gen_bd_rx_release(psc_dma->capture.bcom_task); bcom_gen_bd_tx_release(psc_dma->playback.bcom_task); diff --git a/sound/soc/fsl/wm1133-ev1.c b/sound/soc/fsl/wm1133-ev1.c index cdaf16367b47..2f80b21b2921 100644 --- a/sound/soc/fsl/wm1133-ev1.c +++ b/sound/soc/fsl/wm1133-ev1.c @@ -201,18 +201,18 @@ static struct snd_soc_jack_pin mic_jack_pins[] = { static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_component *component = rtd->codec_dai->component; /* Headphone jack detection */ snd_soc_card_jack_new(rtd->card, "Headphone", SND_JACK_HEADPHONE, &hp_jack, hp_jack_pins, ARRAY_SIZE(hp_jack_pins)); - wm8350_hp_jack_detect(codec, WM8350_JDR, &hp_jack, SND_JACK_HEADPHONE); + wm8350_hp_jack_detect(component, WM8350_JDR, &hp_jack, SND_JACK_HEADPHONE); /* Microphone jack detection */ snd_soc_card_jack_new(rtd->card, "Microphone", SND_JACK_MICROPHONE | SND_JACK_BTN_0, &mic_jack, mic_jack_pins, ARRAY_SIZE(mic_jack_pins)); - wm8350_mic_jack_detect(codec, &mic_jack, SND_JACK_MICROPHONE, + wm8350_mic_jack_detect(component, &mic_jack, SND_JACK_MICROPHONE, SND_JACK_BTN_0); snd_soc_dapm_force_enable_pin(&rtd->card->dapm, "Mic Bias"); |