diff options
Diffstat (limited to 'sound/soc/fsl/p1022_ds.c')
| -rw-r--r-- | sound/soc/fsl/p1022_ds.c | 246 | 
1 files changed, 49 insertions, 197 deletions
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c index 63b9eaa1ebc..f75c3cf0e6d 100644 --- a/sound/soc/fsl/p1022_ds.c +++ b/sound/soc/fsl/p1022_ds.c @@ -12,6 +12,7 @@  #include <linux/module.h>  #include <linux/interrupt.h> +#include <linux/of_address.h>  #include <linux/of_device.h>  #include <linux/slab.h>  #include <sound/soc.h> @@ -19,6 +20,7 @@  #include "fsl_dma.h"  #include "fsl_ssi.h" +#include "fsl_utils.h"  /* P1022-specific PMUXCR and DMUXCR bit definitions */ @@ -45,7 +47,7 @@   * ch: The channel on the DMA controller (0, 1, 2, or 3)   * device: The device to set as the target (CCSR_GUTS_DMUXCR_xxx)   */ -static inline void guts_set_dmuxcr(struct ccsr_guts_85xx __iomem *guts, +static inline void guts_set_dmuxcr(struct ccsr_guts __iomem *guts,  	unsigned int co, unsigned int ch, unsigned int device)  {  	unsigned int shift = 16 + (8 * (1 - co) + 2 * (3 - ch)); @@ -56,8 +58,6 @@ static inline void guts_set_dmuxcr(struct ccsr_guts_85xx __iomem *guts,  /* There's only one global utilities register */  static phys_addr_t guts_phys; -#define DAI_NAME_SIZE	32 -  /**   * machine_data: machine-specific ASoC device data   * @@ -74,7 +74,6 @@ struct machine_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 codec_name[DAI_NAME_SIZE];  	char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */  }; @@ -85,14 +84,13 @@ struct machine_data {   *   * Here we program the DMACR and PMUXCR registers.   */ -static int p1022_ds_machine_probe(struct platform_device *sound_device) +static int p1022_ds_machine_probe(struct snd_soc_card *card)  { -	struct snd_soc_card *card = platform_get_drvdata(sound_device);  	struct machine_data *mdata =  		container_of(card, struct machine_data, card); -	struct ccsr_guts_85xx __iomem *guts; +	struct ccsr_guts __iomem *guts; -	guts = ioremap(guts_phys, sizeof(struct ccsr_guts_85xx)); +	guts = ioremap(guts_phys, sizeof(struct ccsr_guts));  	if (!guts) {  		dev_err(card->dev, "could not map global utilities\n");  		return -ENOMEM; @@ -160,14 +158,13 @@ static int p1022_ds_startup(struct snd_pcm_substream *substream)   * This function is called to remove the sound device for one SSI.  We   * de-program the DMACR and PMUXCR register.   */ -static int p1022_ds_machine_remove(struct platform_device *sound_device) +static int p1022_ds_machine_remove(struct snd_soc_card *card)  { -	struct snd_soc_card *card = platform_get_drvdata(sound_device);  	struct machine_data *mdata =  		container_of(card, struct machine_data, card); -	struct ccsr_guts_85xx __iomem *guts; +	struct ccsr_guts __iomem *guts; -	guts = ioremap(guts_phys, sizeof(struct ccsr_guts_85xx)); +	guts = ioremap(guts_phys, sizeof(struct ccsr_guts));  	if (!guts) {  		dev_err(card->dev, "could not map global utilities\n");  		return -ENOMEM; @@ -192,132 +189,6 @@ static struct snd_soc_ops p1022_ds_ops = {  };  /** - * get_node_by_phandle_name - get a node by its phandle name - * - * This function takes a node, the name of a property in that node, and a - * compatible string.  Assuming the property is a phandle to another node, - * it returns that node, (optionally) if that node is compatible. - * - * If the property is not a phandle, or the node it points to is not compatible - * with the specific string, then NULL is returned. - */ -static struct device_node *get_node_by_phandle_name(struct device_node *np, -	const char *name, const char *compatible) -{ -	np = of_parse_phandle(np, name, 0); -	if (!np) -		return NULL; - -	if (!of_device_is_compatible(np, compatible)) { -		of_node_put(np); -		return NULL; -	} - -	return np; -} - -/** - * get_parent_cell_index -- return the cell-index of the parent of a node - * - * Return the value of the cell-index property of the parent of the given - * node.  This is used for DMA channel nodes that need to know the DMA ID - * of the controller they are on. - */ -static int get_parent_cell_index(struct device_node *np) -{ -	struct device_node *parent = of_get_parent(np); -	const u32 *iprop; -	int ret = -1; - -	if (!parent) -		return -1; - -	iprop = of_get_property(parent, "cell-index", NULL); -	if (iprop) -		ret = *iprop; - -	of_node_put(parent); - -	return ret; -} - -/** - * 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, -			   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; - -	/* 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) { -		of_node_put(dma_channel_np); -		return -EINVAL; -	} - -	*dma_channel_id = *iprop; -	*dma_id = get_parent_cell_index(dma_channel_np); -	of_node_put(dma_channel_np); - -	return 0; -} - -/**   * p1022_ds_probe: platform probe function for the machine driver   *   * Although this is a machine driver, the SSI node is the "master" node with @@ -332,7 +203,6 @@ static int p1022_ds_probe(struct platform_device *pdev)  		container_of(dev, struct platform_device, dev);  	struct device_node *np = ssi_pdev->dev.of_node;  	struct device_node *codec_np = NULL; -	struct platform_device *sound_device = NULL;  	struct machine_data *mdata;  	int ret = -ENODEV;  	const char *sprop; @@ -354,15 +224,8 @@ static int p1022_ds_probe(struct platform_device *pdev)  	mdata->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev);  	mdata->dai[0].ops = &p1022_ds_ops; -	/* Determine the codec name, it will be used as the codec DAI name */ -	ret = codec_node_dev_name(codec_np, mdata->codec_name, DAI_NAME_SIZE); -	if (ret) { -		dev_err(&pdev->dev, "invalid codec node %s\n", -			codec_np->full_name); -		ret = -EINVAL; -		goto error; -	} -	mdata->dai[0].codec_name = mdata->codec_name; +	/* ASoC core can match codec with device node */ +	mdata->dai[0].codec_of_node = codec_np;  	/* We register two DAIs per SSI, one for playback and the other for  	 * capture.  We support codecs that have separate DAIs for both playback @@ -381,7 +244,7 @@ static int p1022_ds_probe(struct platform_device *pdev)  		ret = -EINVAL;  		goto error;  	} -	mdata->ssi_id = *iprop; +	mdata->ssi_id = be32_to_cpup(iprop);  	/* Get the serial format and clock direction. */  	sprop = of_get_property(np, "fsl,mode", NULL); @@ -392,7 +255,8 @@ static int p1022_ds_probe(struct platform_device *pdev)  	}  	if (strcasecmp(sprop, "i2s-slave") == 0) { -		mdata->dai_format = SND_SOC_DAIFMT_I2S; +		mdata->dai_format = SND_SOC_DAIFMT_NB_NF | +			SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM;  		mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;  		mdata->cpu_clk_direction = SND_SOC_CLOCK_IN; @@ -407,33 +271,40 @@ static int p1022_ds_probe(struct platform_device *pdev)  			ret = -EINVAL;  			goto error;  		} -		mdata->clk_frequency = *iprop; +		mdata->clk_frequency = be32_to_cpup(iprop);  	} else if (strcasecmp(sprop, "i2s-master") == 0) { -		mdata->dai_format = SND_SOC_DAIFMT_I2S; +		mdata->dai_format = SND_SOC_DAIFMT_NB_NF | +			SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS;  		mdata->codec_clk_direction = SND_SOC_CLOCK_IN;  		mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;  	} else if (strcasecmp(sprop, "lj-slave") == 0) { -		mdata->dai_format = SND_SOC_DAIFMT_LEFT_J; +		mdata->dai_format = SND_SOC_DAIFMT_NB_NF | +			SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM;  		mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;  		mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;  	} else if (strcasecmp(sprop, "lj-master") == 0) { -		mdata->dai_format = SND_SOC_DAIFMT_LEFT_J; +		mdata->dai_format = SND_SOC_DAIFMT_NB_NF | +			SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBS_CFS;  		mdata->codec_clk_direction = SND_SOC_CLOCK_IN;  		mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;  	} else if (strcasecmp(sprop, "rj-slave") == 0) { -		mdata->dai_format = SND_SOC_DAIFMT_RIGHT_J; +		mdata->dai_format = SND_SOC_DAIFMT_NB_NF | +			SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBM_CFM;  		mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;  		mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;  	} else if (strcasecmp(sprop, "rj-master") == 0) { -		mdata->dai_format = SND_SOC_DAIFMT_RIGHT_J; +		mdata->dai_format = SND_SOC_DAIFMT_NB_NF | +			SND_SOC_DAIFMT_RIGHT_J | SND_SOC_DAIFMT_CBS_CFS;  		mdata->codec_clk_direction = SND_SOC_CLOCK_IN;  		mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;  	} else if (strcasecmp(sprop, "ac97-slave") == 0) { -		mdata->dai_format = SND_SOC_DAIFMT_AC97; +		mdata->dai_format = SND_SOC_DAIFMT_NB_NF | +			SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBM_CFM;  		mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;  		mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;  	} else if (strcasecmp(sprop, "ac97-master") == 0) { -		mdata->dai_format = SND_SOC_DAIFMT_AC97; +		mdata->dai_format = SND_SOC_DAIFMT_NB_NF | +			SND_SOC_DAIFMT_AC97 | SND_SOC_DAIFMT_CBS_CFS;  		mdata->codec_clk_direction = SND_SOC_CLOCK_IN;  		mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;  	} else { @@ -451,9 +322,9 @@ static int p1022_ds_probe(struct platform_device *pdev)  	/* Find the playback DMA channel to use. */  	mdata->dai[0].platform_name = mdata->platform_name[0]; -	ret = get_dma_channel(np, "fsl,playback-dma", &mdata->dai[0], -			      &mdata->dma_channel_id[0], -			      &mdata->dma_id[0]); +	ret = fsl_asoc_get_dma_channel(np, "fsl,playback-dma", &mdata->dai[0], +				       &mdata->dma_channel_id[0], +				       &mdata->dma_id[0]);  	if (ret) {  		dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n");  		goto error; @@ -461,9 +332,9 @@ static int p1022_ds_probe(struct platform_device *pdev)  	/* Find the capture DMA channel to use. */  	mdata->dai[1].platform_name = mdata->platform_name[1]; -	ret = get_dma_channel(np, "fsl,capture-dma", &mdata->dai[1], -			      &mdata->dma_channel_id[1], -			      &mdata->dma_id[1]); +	ret = fsl_asoc_get_dma_channel(np, "fsl,capture-dma", &mdata->dai[1], +				       &mdata->dma_channel_id[1], +				       &mdata->dma_id[1]);  	if (ret) {  		dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n");  		goto error; @@ -478,24 +349,15 @@ static int p1022_ds_probe(struct platform_device *pdev)  	mdata->card.probe = p1022_ds_machine_probe;  	mdata->card.remove = p1022_ds_machine_remove;  	mdata->card.name = pdev->name; /* The platform driver name */ +	mdata->card.owner = THIS_MODULE; +	mdata->card.dev = &pdev->dev;  	mdata->card.num_links = 2;  	mdata->card.dai_link = mdata->dai; -	/* Allocate a new audio platform device structure */ -	sound_device = platform_device_alloc("soc-audio", -1); -	if (!sound_device) { -		dev_err(&pdev->dev, "platform device alloc failed\n"); -		ret = -ENOMEM; -		goto error; -	} - -	/* Associate the card data with the sound device */ -	platform_set_drvdata(sound_device, &mdata->card); -  	/* Register with ASoC */ -	ret = platform_device_add(sound_device); +	ret = snd_soc_register_card(&mdata->card);  	if (ret) { -		dev_err(&pdev->dev, "platform device add failed\n"); +		dev_err(&pdev->dev, "could not register card\n");  		goto error;  	} @@ -504,9 +366,6 @@ static int p1022_ds_probe(struct platform_device *pdev)  	return 0;  error: -	if (sound_device) -		platform_device_unregister(sound_device); -  	kfree(mdata);  error_put:  	of_node_put(codec_np); @@ -518,33 +377,27 @@ error_put:   *   * This function is called when the platform device is removed.   */ -static int __devexit p1022_ds_remove(struct platform_device *pdev) +static int p1022_ds_remove(struct platform_device *pdev)  { -	struct platform_device *sound_device = dev_get_drvdata(&pdev->dev); -	struct snd_soc_card *card = platform_get_drvdata(sound_device); +	struct snd_soc_card *card = platform_get_drvdata(pdev);  	struct machine_data *mdata =  		container_of(card, struct machine_data, card); -	platform_device_unregister(sound_device); - +	snd_soc_unregister_card(card);  	kfree(mdata); -	sound_device->dev.platform_data = NULL; - -	dev_set_drvdata(&pdev->dev, NULL);  	return 0;  }  static struct platform_driver p1022_ds_driver = {  	.probe = p1022_ds_probe, -	.remove = __devexit_p(p1022_ds_remove), +	.remove = p1022_ds_remove,  	.driver = { -		/* The name must match the 'model' property in the device tree, -		 * in lowercase letters, but only the part after that last -		 * comma.  This is because some model properties have a "fsl," -		 * prefix. +		/* +		 * The name must match 'compatible' property in the device tree, +		 * in lowercase letters.  		 */ -		.name = "snd-soc-p1022", +		.name = "snd-soc-p1022ds",  		.owner = THIS_MODULE,  	},  }; @@ -559,12 +412,11 @@ static int __init p1022_ds_init(void)  	struct device_node *guts_np;  	struct resource res; -	pr_info("Freescale P1022 DS ALSA SoC machine driver\n"); -  	/* Get the physical address of the global utilities registers */  	guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");  	if (of_address_to_resource(guts_np, 0, &res)) { -		pr_err("p1022-ds: missing/invalid global utilities node\n"); +		pr_err("snd-soc-p1022ds: missing/invalid global utils node\n"); +		of_node_put(guts_np);  		return -EINVAL;  	}  	guts_phys = res.start;  | 
