Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 76f38451 authored by Nicolin Chen's avatar Nicolin Chen Committed by Mark Brown
Browse files

ASoC: fsl_ssi: Move DT related code to a separate probe()



This patch cleans up probe() function by moving all Device Tree
related code into a separate function. It allows the probe() to
be Device Tree independent. This will be very useful for future
integration of imx-ssi driver which has similar functionalities
while exists only because it supports non-DT cases.

This patch also moves symmetric_channels of AC97 from the probe
to the structure snd_soc_dai_driver for simplification.

Additionally, since PowerPC and AC97 use the same pdev pointer
to register a platform device, this patch also unifies related
code.

Signed-off-by: default avatarNicolin Chen <nicoleotsuka@gmail.com>
Tested-by: default avatarCaleb Crome <caleb@crome.org>
Tested-by: default avatarMaciej S. Szmigiero <mail@maciej.szmigiero.name>
Reviewed-by: default avatarMaciej S. Szmigiero <mail@maciej.szmigiero.name>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent badc9595
Loading
Loading
Loading
Loading
+124 −95
Original line number Diff line number Diff line
@@ -239,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
 *
@@ -285,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;

@@ -1134,6 +1140,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",
@@ -1291,9 +1298,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 */
@@ -1327,14 +1332,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;
	}
@@ -1375,41 +1374,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 __be32 *iprop;
	struct resource *res;
	void __iomem *iomem;
	char name[64];
	struct regmap_config regconfig = fsl_ssi_regconfig;
	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"))
	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));
@@ -1433,15 +1500,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, &regconfig);
	} else {
		ssi->has_ipg_clk_name = true;
	if (ssi->has_ipg_clk_name)
		ssi->regs = devm_regmap_init_mmio_clk(dev, "ipg", iomem,
						      &regconfig);
	}
	else
		ssi->regs = devm_regmap_init_mmio(dev, iomem, &regconfig);
	if (IS_ERR(ssi->regs)) {
		dev_err(dev, "failed to init register map\n");
		return PTR_ERR(ssi->regs);
@@ -1453,24 +1516,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)) {
	/* 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_samplebits = 1;
			ssi->synchronous = true;
		}

		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
	 *
@@ -1535,50 +1587,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:
	/* Initially configures SSI registers */
	fsl_ssi_hw_init(ssi);

	if (fsl_ssi_is_ac97(ssi)) {
		u32 ssi_idx;

		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;
		}
	}
@@ -1606,8 +1635,8 @@ 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);