diff options
Diffstat (limited to 'sound/soc/davinci/davinci-mcasp.c')
| -rw-r--r-- | sound/soc/davinci/davinci-mcasp.c | 260 | 
1 files changed, 225 insertions, 35 deletions
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index ce5e5cd254d..714e51e5be5 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -21,7 +21,10 @@  #include <linux/slab.h>  #include <linux/delay.h>  #include <linux/io.h> -#include <linux/clk.h> +#include <linux/pm_runtime.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/of_device.h>  #include <sound/core.h>  #include <sound/pcm.h> @@ -108,6 +111,10 @@  #define DAVINCI_MCASP_WFIFOSTS		(0x1014)  #define DAVINCI_MCASP_RFIFOCTL		(0x1018)  #define DAVINCI_MCASP_RFIFOSTS		(0x101C) +#define MCASP_VER3_WFIFOCTL		(0x1000) +#define MCASP_VER3_WFIFOSTS		(0x1004) +#define MCASP_VER3_RFIFOCTL		(0x1008) +#define MCASP_VER3_RFIFOSTS		(0x100C)  /*   * DAVINCI_MCASP_PWREMUMGT_REG - Power Down and Emulation Management @@ -381,18 +388,36 @@ static void davinci_mcasp_start(struct davinci_audio_dev *dev, int stream)  {  	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {  		if (dev->txnumevt) {	/* enable FIFO */ -			mcasp_clr_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, +			switch (dev->version) { +			case MCASP_VERSION_3: +				mcasp_clr_bits(dev->base + MCASP_VER3_WFIFOCTL,  								FIFO_ENABLE); -			mcasp_set_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, +				mcasp_set_bits(dev->base + MCASP_VER3_WFIFOCTL,  								FIFO_ENABLE); +				break; +			default: +				mcasp_clr_bits(dev->base + +					DAVINCI_MCASP_WFIFOCTL,	FIFO_ENABLE); +				mcasp_set_bits(dev->base + +					DAVINCI_MCASP_WFIFOCTL,	FIFO_ENABLE); +			}  		}  		mcasp_start_tx(dev);  	} else {  		if (dev->rxnumevt) {	/* enable FIFO */ -			mcasp_clr_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, +			switch (dev->version) { +			case MCASP_VERSION_3: +				mcasp_clr_bits(dev->base + MCASP_VER3_RFIFOCTL,  								FIFO_ENABLE); -			mcasp_set_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, +				mcasp_set_bits(dev->base + MCASP_VER3_RFIFOCTL,  								FIFO_ENABLE); +				break; +			default: +				mcasp_clr_bits(dev->base + +					DAVINCI_MCASP_RFIFOCTL,	FIFO_ENABLE); +				mcasp_set_bits(dev->base + +					DAVINCI_MCASP_RFIFOCTL,	FIFO_ENABLE); +			}  		}  		mcasp_start_rx(dev);  	} @@ -413,14 +438,31 @@ static void mcasp_stop_tx(struct davinci_audio_dev *dev)  static void davinci_mcasp_stop(struct davinci_audio_dev *dev, int stream)  {  	if (stream == SNDRV_PCM_STREAM_PLAYBACK) { -		if (dev->txnumevt)	/* disable FIFO */ -			mcasp_clr_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, +		if (dev->txnumevt) {	/* disable FIFO */ +			switch (dev->version) { +			case MCASP_VERSION_3: +				mcasp_clr_bits(dev->base + MCASP_VER3_WFIFOCTL,  								FIFO_ENABLE); +				break; +			default: +				mcasp_clr_bits(dev->base + +					DAVINCI_MCASP_WFIFOCTL,	FIFO_ENABLE); +			} +		}  		mcasp_stop_tx(dev);  	} else { -		if (dev->rxnumevt)	/* disable FIFO */ -			mcasp_clr_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, +		if (dev->rxnumevt) {	/* disable FIFO */ +			switch (dev->version) { +			case MCASP_VERSION_3: +				mcasp_clr_bits(dev->base + MCASP_VER3_RFIFOCTL,  								FIFO_ENABLE); +			break; + +			default: +				mcasp_clr_bits(dev->base + +					DAVINCI_MCASP_RFIFOCTL,	FIFO_ENABLE); +			} +		}  		mcasp_stop_rx(dev);  	}  } @@ -619,20 +661,37 @@ static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream)  		if (dev->txnumevt * tx_ser > 64)  			dev->txnumevt = 1; -		mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, tx_ser, +		switch (dev->version) { +		case MCASP_VERSION_3: +			mcasp_mod_bits(dev->base + MCASP_VER3_WFIFOCTL, tx_ser,  								NUMDMA_MASK); -		mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, +			mcasp_mod_bits(dev->base + MCASP_VER3_WFIFOCTL,  				((dev->txnumevt * tx_ser) << 8), NUMEVT_MASK); +			break; +		default: +			mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, +							tx_ser,	NUMDMA_MASK); +			mcasp_mod_bits(dev->base + DAVINCI_MCASP_WFIFOCTL, +				((dev->txnumevt * tx_ser) << 8), NUMEVT_MASK); +		}  	}  	if (dev->rxnumevt && stream == SNDRV_PCM_STREAM_CAPTURE) {  		if (dev->rxnumevt * rx_ser > 64)  			dev->rxnumevt = 1; - -		mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, rx_ser, +		switch (dev->version) { +		case MCASP_VERSION_3: +			mcasp_mod_bits(dev->base + MCASP_VER3_RFIFOCTL, rx_ser,  								NUMDMA_MASK); -		mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, +			mcasp_mod_bits(dev->base + MCASP_VER3_RFIFOCTL,  				((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK); +			break; +		default: +			mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, +							rx_ser,	NUMDMA_MASK); +			mcasp_mod_bits(dev->base + DAVINCI_MCASP_RFIFOCTL, +				((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK); +		}  	}  } @@ -782,20 +841,17 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,  	case SNDRV_PCM_TRIGGER_RESUME:  	case SNDRV_PCM_TRIGGER_START:  	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -		if (!dev->clk_active) { -			clk_enable(dev->clk); -			dev->clk_active = 1; -		} +		ret = pm_runtime_get_sync(dev->dev); +		if (IS_ERR_VALUE(ret)) +			dev_err(dev->dev, "pm_runtime_get_sync() failed\n");  		davinci_mcasp_start(dev, substream->stream);  		break;  	case SNDRV_PCM_TRIGGER_SUSPEND:  		davinci_mcasp_stop(dev, substream->stream); -		if (dev->clk_active) { -			clk_disable(dev->clk); -			dev->clk_active = 0; -		} - +		ret = pm_runtime_put_sync(dev->dev); +		if (IS_ERR_VALUE(ret)) +			dev_err(dev->dev, "pm_runtime_put_sync() failed\n");  		break;  	case SNDRV_PCM_TRIGGER_STOP: @@ -865,6 +921,118 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {  }; +static const struct of_device_id mcasp_dt_ids[] = { +	{ +		.compatible = "ti,dm646x-mcasp-audio", +		.data = (void *)MCASP_VERSION_1, +	}, +	{ +		.compatible = "ti,da830-mcasp-audio", +		.data = (void *)MCASP_VERSION_2, +	}, +	{ +		.compatible = "ti,omap2-mcasp-audio", +		.data = (void *)MCASP_VERSION_3, +	}, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mcasp_dt_ids); + +static struct snd_platform_data *davinci_mcasp_set_pdata_from_of( +						struct platform_device *pdev) +{ +	struct device_node *np = pdev->dev.of_node; +	struct snd_platform_data *pdata = NULL; +	const struct of_device_id *match = +			of_match_device(of_match_ptr(mcasp_dt_ids), &pdev->dev); + +	const u32 *of_serial_dir32; +	u8 *of_serial_dir; +	u32 val; +	int i, ret = 0; + +	if (pdev->dev.platform_data) { +		pdata = pdev->dev.platform_data; +		return pdata; +	} else if (match) { +		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); +		if (!pdata) { +			ret = -ENOMEM; +			goto nodata; +		} +	} else { +		/* control shouldn't reach here. something is wrong */ +		ret = -EINVAL; +		goto nodata; +	} + +	if (match->data) +		pdata->version = (u8)((int)match->data); + +	ret = of_property_read_u32(np, "op-mode", &val); +	if (ret >= 0) +		pdata->op_mode = val; + +	ret = of_property_read_u32(np, "tdm-slots", &val); +	if (ret >= 0) +		pdata->tdm_slots = val; + +	ret = of_property_read_u32(np, "num-serializer", &val); +	if (ret >= 0) +		pdata->num_serializer = val; + +	of_serial_dir32 = of_get_property(np, "serial-dir", &val); +	val /= sizeof(u32); +	if (val != pdata->num_serializer) { +		dev_err(&pdev->dev, +				"num-serializer(%d) != serial-dir size(%d)\n", +				pdata->num_serializer, val); +		ret = -EINVAL; +		goto nodata; +	} + +	if (of_serial_dir32) { +		of_serial_dir = devm_kzalloc(&pdev->dev, +						(sizeof(*of_serial_dir) * val), +						GFP_KERNEL); +		if (!of_serial_dir) { +			ret = -ENOMEM; +			goto nodata; +		} + +		for (i = 0; i < pdata->num_serializer; i++) +			of_serial_dir[i] = be32_to_cpup(&of_serial_dir32[i]); + +		pdata->serial_dir = of_serial_dir; +	} + +	ret = of_property_read_u32(np, "tx-num-evt", &val); +	if (ret >= 0) +		pdata->txnumevt = val; + +	ret = of_property_read_u32(np, "rx-num-evt", &val); +	if (ret >= 0) +		pdata->rxnumevt = val; + +	ret = of_property_read_u32(np, "sram-size-playback", &val); +	if (ret >= 0) +		pdata->sram_size_playback = val; + +	ret = of_property_read_u32(np, "sram-size-capture", &val); +	if (ret >= 0) +		pdata->sram_size_capture = val; + +	return  pdata; + +nodata: +	if (ret < 0) { +		dev_err(&pdev->dev, "Error populating platform data, err %d\n", +			ret); +		pdata = NULL; +	} +	return  pdata; +} +  static int davinci_mcasp_probe(struct platform_device *pdev)  {  	struct davinci_pcm_dma_params *dma_data; @@ -873,11 +1041,22 @@ static int davinci_mcasp_probe(struct platform_device *pdev)  	struct davinci_audio_dev *dev;  	int ret; +	if (!pdev->dev.platform_data && !pdev->dev.of_node) { +		dev_err(&pdev->dev, "No platform data supplied\n"); +		return -EINVAL; +	} +  	dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_audio_dev),  			   GFP_KERNEL);  	if (!dev)  		return	-ENOMEM; +	pdata = davinci_mcasp_set_pdata_from_of(pdev); +	if (!pdata) { +		dev_err(&pdev->dev, "no platform data\n"); +		return -EINVAL; +	} +  	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (!mem) {  		dev_err(&pdev->dev, "no mem resource?\n"); @@ -891,13 +1070,13 @@ static int davinci_mcasp_probe(struct platform_device *pdev)  		return -EBUSY;  	} -	pdata = pdev->dev.platform_data; -	dev->clk = clk_get(&pdev->dev, NULL); -	if (IS_ERR(dev->clk)) -		return -ENODEV; +	pm_runtime_enable(&pdev->dev); -	clk_enable(dev->clk); -	dev->clk_active = 1; +	ret = pm_runtime_get_sync(&pdev->dev); +	if (IS_ERR_VALUE(ret)) { +		dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); +		return ret; +	}  	dev->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));  	if (!dev->base) { @@ -914,6 +1093,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)  	dev->version = pdata->version;  	dev->txnumevt = pdata->txnumevt;  	dev->rxnumevt = pdata->rxnumevt; +	dev->dev = &pdev->dev;  	dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK];  	dma_data->asp_chan_q = pdata->asp_chan_q; @@ -952,22 +1132,31 @@ static int davinci_mcasp_probe(struct platform_device *pdev)  	if (ret != 0)  		goto err_release_clk; + +	ret = davinci_soc_platform_register(&pdev->dev); +	if (ret) { +		dev_err(&pdev->dev, "register PCM failed: %d\n", ret); +		goto err_unregister_dai; +	} +  	return 0; +err_unregister_dai: +	snd_soc_unregister_dai(&pdev->dev);  err_release_clk: -	clk_disable(dev->clk); -	clk_put(dev->clk); +	pm_runtime_put_sync(&pdev->dev); +	pm_runtime_disable(&pdev->dev);  	return ret;  }  static int davinci_mcasp_remove(struct platform_device *pdev)  { -	struct davinci_audio_dev *dev = dev_get_drvdata(&pdev->dev);  	snd_soc_unregister_dai(&pdev->dev); -	clk_disable(dev->clk); -	clk_put(dev->clk); -	dev->clk = NULL; +	davinci_soc_platform_unregister(&pdev->dev); + +	pm_runtime_put_sync(&pdev->dev); +	pm_runtime_disable(&pdev->dev);  	return 0;  } @@ -978,6 +1167,7 @@ static struct platform_driver davinci_mcasp_driver = {  	.driver		= {  		.name	= "davinci-mcasp",  		.owner	= THIS_MODULE, +		.of_match_table = of_match_ptr(mcasp_dt_ids),  	},  };  |