diff options
Diffstat (limited to 'sound/soc/davinci/davinci-mcasp.c')
-rw-r--r-- | sound/soc/davinci/davinci-mcasp.c | 174 |
1 files changed, 152 insertions, 22 deletions
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index ce5e5cd254d..c3eae1d8e07 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> @@ -782,20 +785,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 +865,114 @@ 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, + }, + { /* 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 +981,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 +1010,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 +1033,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 +1072,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 +1107,7 @@ static struct platform_driver davinci_mcasp_driver = { .driver = { .name = "davinci-mcasp", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(mcasp_dt_ids), }, }; |