[alsa-devel] [PATCH] asoc multi-component: mpc8610 hpcd updates

Timur Tabi timur at freescale.com
Wed Jul 28 23:13:03 CEST 2010


Additional updates to the multi-component branch.  Liam, please squash these
in.

Signed-off-by: Timur Tabi <timur at freescale.com>
---
 sound/soc/fsl/fsl_dma.c      |   68 +++++++++++++++--------
 sound/soc/fsl/fsl_dma.h      |    3 -
 sound/soc/fsl/fsl_ssi.c      |   37 +++++++-----
 sound/soc/fsl/mpc8610_hpcd.c |  125 ++++++++++++++++++++++++++---------------
 4 files changed, 144 insertions(+), 89 deletions(-)

diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index 7f87297..d09e194 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -32,6 +32,7 @@
 #include <asm/io.h>
 
 #include "fsl_dma.h"
+#include "fsl_ssi.h"	/* For the offset of stx0 and srx0 */
 
 /*
  * The formats that the DMA controller supports, which is anything
@@ -798,36 +799,35 @@ static void fsl_dma_free_dma_buffers(struct snd_pcm *pcm)
 static LIST_HEAD(dma_list);
 
 /**
- * fsl_soc_dma_to_dai - returning the DAI struct for a given DMA node
- *
- * When a machine driver registers itself with ASoC, it must provide the
- * address of the DAI structures that it wants to connect.  Most drivers simply
- * reference global data structures in the various drivers, but we PowerPC
- * developers are better than that.  This driver keeps a list of every DMA
- * node that it probes, and when the machine driver wants to reference a
- * DMA DAI, this function provides that service.
- *
- * Hopefully one day, ASoC will just want the name of the DMA device, not
- * some obscure pointer, and this function will go away.
+ * find_ssi_node -- returns the SSI node that points to his DMA channel node
+ *
+ * Although this DMA driver attempts to operate independently of the other
+ * devices, it still needs to determine some information about the SSI device
+ * that it's working with.  Unfortunately, the device tree does not contain
+ * a pointer from the DMA channel node to the SSI node -- the pointer goes the
+ * other way.  So we need to scan the device tree for SSI nodes until we find
+ * the one that points to the given DMA channel node.  It's ugly, but at least
+ * it's contained in this one function.
  */
-struct snd_soc_platform_driver *fsl_soc_dma_to_dai(const char *path,
-	dma_addr_t ssi_stx_phys, dma_addr_t ssi_srx_phys)
+static struct device_node *find_ssi_node(struct device_node *dma_channel_np)
 {
-	struct list_head *ptr;
-	struct dma_object *dma;
+	struct device_node *ssi_np, *np;
 
-	list_for_each(ptr, &dma_list) {
-		dma = list_entry(ptr, struct dma_object, list);
-		if (strcmp(path, dma->path) == 0) {
-			dma->ssi_stx_phys = ssi_stx_phys;
-			dma->ssi_srx_phys = ssi_srx_phys;
-			return &dma->dai;
-		}
+	for_each_compatible_node(ssi_np, NULL, "fsl,mpc8610-ssi") {
+		/* Check each DMA phandle to see if it points to us.  We
+		 * assume that device_node pointers are a valid comparison.
+		 */
+		np = of_parse_phandle(ssi_np, "fsl,playback-dma", 0);
+		if (np == dma_channel_np)
+			return ssi_np;
+
+		np = of_parse_phandle(ssi_np, "fsl,capture-dma", 0);
+		if (np == dma_channel_np)
+			return ssi_np;
 	}
 
 	return NULL;
 }
-EXPORT_SYMBOL(fsl_soc_dma_to_dai);
 
 static struct snd_pcm_ops fsl_dma_ops = {
 	.open   	= fsl_dma_open,
@@ -843,8 +843,24 @@ static int __devinit fsl_soc_dma_probe(struct of_device *of_dev,
  {
 	struct dma_object *dma;
 	struct device_node *np = of_dev->dev.of_node;
+	struct device_node *ssi_np;
+	struct resource res;
 	int ret;
 
+	/* Find the SSI node that points to us. */
+	ssi_np = find_ssi_node(np);
+	if (!ssi_np) {
+		dev_err(&of_dev->dev, "cannot find parent SSI node\n");
+		return -ENODEV;
+	}
+
+	ret = of_address_to_resource(ssi_np, 0, &res);
+	of_node_put(ssi_np);
+	if (ret) {
+		dev_err(&of_dev->dev, "could not determine device resources\n");
+		return ret;
+	}
+
 	dma = kzalloc(sizeof(*dma) + strlen(np->full_name), GFP_KERNEL);
 	if (!dma) {
 		dev_err(&of_dev->dev, "could not allocate dma object\n");
@@ -856,6 +872,10 @@ static int __devinit fsl_soc_dma_probe(struct of_device *of_dev,
 	dma->dai.pcm_new = fsl_dma_new;
 	dma->dai.pcm_free = fsl_dma_free_dma_buffers;
 
+	/* Store the SSI-specific information that we need */
+	dma->ssi_stx_phys = res.start + offsetof(struct ccsr_ssi, stx0);
+	dma->ssi_srx_phys = res.start + offsetof(struct ccsr_ssi, srx0);
+
 	ret = snd_soc_register_platform(&of_dev->dev, &dma->dai);
 	if (ret) {
 		dev_err(&of_dev->dev, "could not register platform\n");
@@ -921,7 +941,7 @@ static void __exit fsl_soc_dma_exit(void)
  * will already have been probed.  The easiest way to do that is to make the
  * __init function called via arch_initcall().
  */
-arch_initcall(fsl_soc_dma_init);
+module_init(fsl_soc_dma_init);
 module_exit(fsl_soc_dma_exit);
 
 MODULE_AUTHOR("Timur Tabi <timur at freescale.com>");
diff --git a/sound/soc/fsl/fsl_dma.h b/sound/soc/fsl/fsl_dma.h
index e152bc6..78fee97 100644
--- a/sound/soc/fsl/fsl_dma.h
+++ b/sound/soc/fsl/fsl_dma.h
@@ -126,7 +126,4 @@ struct fsl_dma_link_descriptor {
 	u8 res[4];      /* Reserved */
 } __attribute__ ((aligned(32), packed));
 
-struct snd_soc_platform_driver *fsl_soc_dma_to_dai(const char *path,
-	dma_addr_t ssi_stx_phys, dma_addr_t ssi_srx_phys);
-
 #endif
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 2388484..51b089f 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -292,8 +292,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
 
 		/* The 'name' should not have any slashes in it. */
 		ret = request_irq(ssi_private->irq, fsl_ssi_isr, 0,
-				  strrchr(ssi_private->name, '/') + 1,
-				  ssi_private);
+				  ssi_private->name, ssi_private);
 		if (ret < 0) {
 			dev_err(substream->pcm->card->dev,
 				"could not claim irq %u\n", ssi_private->irq);
@@ -622,11 +621,9 @@ static int __devinit fsl_ssi_probe(struct of_device *of_dev,
 	int ret = 0;
 	struct device_attribute *dev_attr;
 	struct device_node *np = of_dev->dev.of_node;
-	const char *sprop;
+	const char *p, *sprop;
 	struct resource res;
 	char name[64];
-	struct platform_device *pdev;
-	void *platform_data;
 
 	/* We are only interested in SSIs with a codec phandle in them, so let's
 	 * make sure this SSI has one.
@@ -641,21 +638,22 @@ static int __devinit fsl_ssi_probe(struct of_device *of_dev,
 		return -ENODEV;
 	}
 
-	ssi_private = kzalloc(sizeof(struct fsl_ssi_private) +
-			      strlen(np->full_name), GFP_KERNEL);
+	/* The DAI name is the last part of the full name of the node. */
+	p = strrchr(np->full_name, '/') + 1;
+	ssi_private = kzalloc(sizeof(struct fsl_ssi_private) + strlen(p),
+			      GFP_KERNEL);
 	if (!ssi_private) {
 		dev_err(&of_dev->dev, "could not allocate DAI object\n");
 		return -ENOMEM;
 	}
 
+	strcpy(ssi_private->name, p);
+
 	/* Initialize this copy of the CPU DAI driver structure */
 	memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template,
 	       sizeof(fsl_ssi_dai_template));
 	ssi_private->cpu_dai_drv.name = ssi_private->name;
 
-	/* The name we register with ASoC is the full node name */
-	strlcpy(ssi_private->name, np->full_name, sizeof(ssi_private->name));
-
 	/* Get the addresses and IRQ */
 	ret = of_address_to_resource(np, 0, &res);
 	if (ret) {
@@ -698,19 +696,26 @@ static int __devinit fsl_ssi_probe(struct of_device *of_dev,
 	}
 
 	/* Trigger the machine driver's probe function.  The platform driver
-	 * name of the machine driver is taken from the /model node of the
+	 * name of the machine driver is taken from the /model property of the
 	 * device tree.  We also pass the address of the CPU DAI driver
 	 * structure.
 	 */
 	sprop = of_get_property(of_find_node_by_path("/"), "model", NULL);
+	/* Sometimes the model name has a "fsl," prefix, so we strip that. */
+	p = strrchr(sprop, ',');
+	if (p)
+		sprop = p + 1;
 	snprintf(name, sizeof(name), "snd-soc-%s", sprop);
 	make_lowercase(name);
 
-	platform_data = &ssi_private->cpu_dai_drv;
-	pdev = platform_device_register_data(&of_dev->dev, name,
-		0, &platform_data, sizeof(void *));
-
-	ssi_private->pdev = pdev;
+	ssi_private->pdev =
+		platform_device_register_data(&of_dev->dev, name, 0, NULL, 0);
+	if (IS_ERR(ssi_private->pdev)) {
+		ret = PTR_ERR(ssi_private->pdev);
+		dev_err(&of_dev->dev, "failed to register platform: %d\n", ret);
+		kfree(ssi_private);
+		return ret;
+	}
 
 	return 0;
 }
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index e87cd1e..38339c1 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -22,6 +22,8 @@
 /* There's only one global utilities register */
 static phys_addr_t guts_phys;
 
+#define DAI_NAME_SIZE	32
+
 /**
  * mpc8610_hpcd_data: machine-specific ASoC device data
  *
@@ -38,7 +40,9 @@ struct mpc8610_hpcd_data {
 	unsigned int ssi_id;		/* 0 = SSI1, 1 = SSI2, etc */
 	unsigned int dma_id[2];		/* 0 = DMA1, 1 = DMA2, etc */
 	unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/
-	char dai_name[32];
+	char codec_dai_name[DAI_NAME_SIZE];
+	char codec_name[DAI_NAME_SIZE];
+	char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
 };
 
 /**
@@ -233,25 +237,68 @@ static int get_parent_cell_index(struct device_node *np)
 	return *iprop;
 }
 
+/**
+ * codec_node_dev_name - determine the dev_name for a codec node
+ *
+ * This function determines the dev_name for an I2C node.  This is the name
+ * that would be returned by dev_name() if this device_node were part of a
+ * 'struct device'  It's ugly and hackish, but it works.
+ *
+ * The dev_name for such devices include the bus number and I2C address. For
+ * example, "cs4270-codec.0-004f".
+ */
+static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
+{
+	const u32 *iprop;
+	int bus, addr;
+	char temp[DAI_NAME_SIZE];
+
+	of_modalias_node(np, temp, DAI_NAME_SIZE);
+
+	iprop = of_get_property(np, "reg", NULL);
+	if (!iprop)
+		return -EINVAL;
+
+	addr = *iprop;
+
+	bus = get_parent_cell_index(np);
+	if (bus < 0)
+		return bus;
+
+	snprintf(buf, len, "%s-codec.%u-%04x", temp, bus, addr);
+
+	return 0;
+}
+
 static int get_dma_channel(struct device_node *ssi_np,
 			   const char *compatible,
-			   dma_addr_t ssi_stx_phys,
-			   dma_addr_t ssi_srx_phys,
 			   struct snd_soc_dai_link *dai,
 			   unsigned int *dma_channel_id,
 			   unsigned int *dma_id)
 {
+	struct resource res;
 	struct device_node *dma_channel_np;
 	const u32 *iprop;
+	int ret;
 
 	dma_channel_np = get_node_by_phandle_name(ssi_np, compatible,
 						  "fsl,ssi-dma-channel");
 	if (!dma_channel_np)
 		return -EINVAL;
 
-	// FIXME: change this to get the OF device name
-	dai->platform_name = fsl_soc_dma_to_dai(dma_channel_np->full_name,
-					       ssi_stx_phys, ssi_srx_phys);
+	/* Determine the dev_name for the device_node.  This code mimics the
+	 * behavior of of_device_make_bus_id(). We need this because ASoC uses
+	 * the dev_name() of the device to match the platform (DMA) device with
+	 * the CPU (SSI) device.  It's all ugly and hackish, but it works (for
+	 * now).
+	 *
+	 * dai->platform name should already point to an allocated buffer.
+	 */
+	ret = of_address_to_resource(dma_channel_np, 0, &res);
+	if (ret)
+		return ret;
+	snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
+		 (unsigned long long) res.start, dma_channel_np->name);
 
 	iprop = of_get_property(dma_channel_np, "cell-index", NULL);
 	if (!iprop) {
@@ -265,6 +312,7 @@ static int get_dma_channel(struct device_node *ssi_np,
 
 	return 0;
 }
+
 /**
  * mpc8610_hpcd_probe: platform probe function for the machine driver
  *
@@ -274,22 +322,16 @@ static int get_dma_channel(struct device_node *ssi_np,
  */
 static int mpc8610_hpcd_probe(struct platform_device *pdev)
 {
-	struct snd_soc_dai_driver **platform_data = pdev->dev.platform_data;
 	struct device *dev = pdev->dev.parent;
+	/* of_dev is the OF device for the SSI node that probed us */
 	struct of_device *of_dev = container_of(dev, struct of_device, dev);
 	struct device_node *np = of_dev->dev.of_node;
 	struct device_node *codec_np = NULL;
-	struct device_node *dma_np = NULL;
-	struct device_node *dma_channel_np = NULL;
 	struct platform_device *sound_device = NULL;
 	struct mpc8610_hpcd_data *machine_data;
-	int id;
-	dma_addr_t ssi_stx_phys;
-	dma_addr_t ssi_srx_phys;
 	int ret = -ENODEV;
 	const char *sprop;
 	const u32 *iprop;
-	struct resource res;
 
 	/* We are only interested in SSIs with a codec phandle in them,
 	 * so let's make sure this SSI has one. The MPC8610 HPCD only
@@ -306,20 +348,27 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
 	if (!machine_data)
 		return -ENOMEM;
 
-	machine_data->dai[0].name = machine_data->dai_name;
+	machine_data->dai[0].cpu_dai_name = dev_name(&of_dev->dev);
+	machine_data->dai[0].ops = &mpc8610_hpcd_ops;
 
-	/* FIXME: Timur, do we need to append .0 or .1 suffix here ? */
-	machine_data->dai[0].cpu_dai_name = "fsl-ssi-dai";
-	machine_data->dai[0].platform_name = "fsl-pcm-audio";
+	/* Determine the codec name, it will be used as the codec DAI name */
+	ret = codec_node_dev_name(codec_np, machine_data->codec_name,
+				  DAI_NAME_SIZE);
+	if (ret) {
+		dev_err(&pdev->dev, "invalid codec node %s\n",
+			codec_np->full_name);
+		ret = -EINVAL;
+		goto error;
+	}
+	machine_data->dai[0].codec_name = machine_data->codec_name;
 
+	/* The DAI name from the codec (snd_soc_dai_driver.name) */
 	machine_data->dai[0].codec_dai_name = "cs4270-hifi";
-	machine_data->dai[0].codec_name = "cs4270-codec";
-	machine_data->dai[0].ops = &mpc8610_hpcd_ops;
-
-	/* Store the codec name, it will be used as the codec DAI name */
-	of_modalias_node(codec_np, machine_data->dai_name,
-			 sizeof(machine_data->dai_name));
 
+	/* We register two DAIs per SSI, one for playback and the other for
+	 * capture.  Currently, we only support codecs that have one DAI for
+	 * both playback and capture.
+	 */
 	memcpy(&machine_data->dai[1], &machine_data->dai[0],
 	       sizeof(struct snd_soc_dai_link));
 
@@ -331,7 +380,6 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
 		goto error;
 	}
 	machine_data->ssi_id = *iprop;
-	id = *iprop;
 
 	/* Get the serial format and clock direction. */
 	sprop = of_get_property(np, "fsl,mode", NULL);
@@ -399,18 +447,9 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
 		goto error;
 	}
 
-	/* Read the SSI information from the device tree */
-	ret = of_address_to_resource(np, 0, &res);
-	if (ret || !res.start) {
-		dev_err(&pdev->dev, "could not obtain SSI address\n");
-		goto error;
-	}
-	ssi_stx_phys = res.start + offsetof(struct ccsr_ssi, stx0);
-	ssi_srx_phys = res.start + offsetof(struct ccsr_ssi, srx0);
-
 	/* Find the playback DMA channel to use. */
-	ret = get_dma_channel(np, "fsl,playback-dma", ssi_stx_phys,
-			      ssi_srx_phys, &machine_data->dai[0],
+	machine_data->dai[0].platform_name = machine_data->platform_name[0];
+	ret = get_dma_channel(np, "fsl,playback-dma", &machine_data->dai[0],
 			      &machine_data->dma_channel_id[0],
 			      &machine_data->dma_id[0]);
 	if (ret) {
@@ -419,8 +458,8 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
 	}
 
 	/* Find the capture DMA channel to use. */
-	ret = get_dma_channel(np, "fsl,capture-dma", ssi_stx_phys,
-			      ssi_srx_phys, &machine_data->dai[1],
+	machine_data->dai[1].platform_name = machine_data->platform_name[1];
+	ret = get_dma_channel(np, "fsl,capture-dma", &machine_data->dai[1],
 			      &machine_data->dma_channel_id[1],
 			      &machine_data->dma_id[1]);
 	if (ret) {
@@ -429,18 +468,14 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
 	}
 
 	/* Initialize our DAI data structure.  */
-	iprop = of_get_property(codec_np, "reg", NULL);
-	if (!iprop) {
-		dev_err(&pdev->dev, "codec node is missing 'reg' property\n");
-		goto error;
-	}
-
 	machine_data->dai[0].stream_name = "playback";
 	machine_data->dai[1].stream_name = "capture";
+	machine_data->dai[0].name = machine_data->dai[0].stream_name;
+	machine_data->dai[1].name = machine_data->dai[1].stream_name;
 
 	machine_data->card.probe = mpc8610_hpcd_machine_probe;
 	machine_data->card.remove = mpc8610_hpcd_machine_remove;
-	machine_data->card.name = "MPC8610 HPCD";
+	machine_data->card.name = pdev->name; /* The platform driver name */
 	machine_data->card.num_links = 2;
 	machine_data->card.dai_link = machine_data->dai;
 
@@ -468,8 +503,6 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
 
 error:
 	of_node_put(codec_np);
-	of_node_put(dma_np);
-	of_node_put(dma_channel_np);
 
 	if (sound_device)
 		platform_device_unregister(sound_device);
-- 
1.7.0.1




More information about the Alsa-devel mailing list