aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/tegra/tegra20_spdif.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/tegra/tegra20_spdif.c')
-rw-r--r--sound/soc/tegra/tegra20_spdif.c50
1 files changed, 47 insertions, 3 deletions
diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c
index ef5d49ed5658..9efd71e13a0a 100644
--- a/sound/soc/tegra/tegra20_spdif.c
+++ b/sound/soc/tegra/tegra20_spdif.c
@@ -26,6 +26,7 @@
26#include <linux/io.h> 26#include <linux/io.h>
27#include <linux/module.h> 27#include <linux/module.h>
28#include <linux/platform_device.h> 28#include <linux/platform_device.h>
29#include <linux/pm_runtime.h>
29#include <linux/seq_file.h> 30#include <linux/seq_file.h>
30#include <linux/slab.h> 31#include <linux/slab.h>
31#include <sound/core.h> 32#include <sound/core.h>
@@ -48,6 +49,29 @@ static inline u32 tegra20_spdif_read(struct tegra20_spdif *spdif, u32 reg)
48 return __raw_readl(spdif->regs + reg); 49 return __raw_readl(spdif->regs + reg);
49} 50}
50 51
52static int tegra20_spdif_runtime_suspend(struct device *dev)
53{
54 struct tegra20_spdif *spdif = dev_get_drvdata(dev);
55
56 clk_disable(spdif->clk_spdif_out);
57
58 return 0;
59}
60
61static int tegra20_spdif_runtime_resume(struct device *dev)
62{
63 struct tegra20_spdif *spdif = dev_get_drvdata(dev);
64 int ret;
65
66 ret = clk_enable(spdif->clk_spdif_out);
67 if (ret) {
68 dev_err(dev, "clk_enable failed: %d\n", ret);
69 return ret;
70 }
71
72 return 0;
73}
74
51#ifdef CONFIG_DEBUG_FS 75#ifdef CONFIG_DEBUG_FS
52static int tegra20_spdif_show(struct seq_file *s, void *unused) 76static int tegra20_spdif_show(struct seq_file *s, void *unused)
53{ 77{
@@ -195,14 +219,12 @@ static int tegra20_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
195 case SNDRV_PCM_TRIGGER_START: 219 case SNDRV_PCM_TRIGGER_START:
196 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 220 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
197 case SNDRV_PCM_TRIGGER_RESUME: 221 case SNDRV_PCM_TRIGGER_RESUME:
198 clk_enable(spdif->clk_spdif_out);
199 tegra20_spdif_start_playback(spdif); 222 tegra20_spdif_start_playback(spdif);
200 break; 223 break;
201 case SNDRV_PCM_TRIGGER_STOP: 224 case SNDRV_PCM_TRIGGER_STOP:
202 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 225 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
203 case SNDRV_PCM_TRIGGER_SUSPEND: 226 case SNDRV_PCM_TRIGGER_SUSPEND:
204 tegra20_spdif_stop_playback(spdif); 227 tegra20_spdif_stop_playback(spdif);
205 clk_disable(spdif->clk_spdif_out);
206 break; 228 break;
207 default: 229 default:
208 return -EINVAL; 230 return -EINVAL;
@@ -295,11 +317,18 @@ static __devinit int tegra20_spdif_platform_probe(struct platform_device *pdev)
295 spdif->playback_dma_data.width = 32; 317 spdif->playback_dma_data.width = 32;
296 spdif->playback_dma_data.req_sel = dmareq->start; 318 spdif->playback_dma_data.req_sel = dmareq->start;
297 319
320 pm_runtime_enable(&pdev->dev);
321 if (!pm_runtime_enabled(&pdev->dev)) {
322 ret = tegra20_spdif_runtime_resume(&pdev->dev);
323 if (ret)
324 goto err_pm_disable;
325 }
326
298 ret = snd_soc_register_dai(&pdev->dev, &tegra20_spdif_dai); 327 ret = snd_soc_register_dai(&pdev->dev, &tegra20_spdif_dai);
299 if (ret) { 328 if (ret) {
300 dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); 329 dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
301 ret = -ENOMEM; 330 ret = -ENOMEM;
302 goto err_clk_put; 331 goto err_suspend;
303 } 332 }
304 333
305 ret = tegra_pcm_platform_register(&pdev->dev); 334 ret = tegra_pcm_platform_register(&pdev->dev);
@@ -314,6 +343,11 @@ static __devinit int tegra20_spdif_platform_probe(struct platform_device *pdev)
314 343
315err_unregister_dai: 344err_unregister_dai:
316 snd_soc_unregister_dai(&pdev->dev); 345 snd_soc_unregister_dai(&pdev->dev);
346err_suspend:
347 if (!pm_runtime_status_suspended(&pdev->dev))
348 tegra20_spdif_runtime_suspend(&pdev->dev);
349err_pm_disable:
350 pm_runtime_disable(&pdev->dev);
317err_clk_put: 351err_clk_put:
318 clk_put(spdif->clk_spdif_out); 352 clk_put(spdif->clk_spdif_out);
319err: 353err:
@@ -324,6 +358,10 @@ static int __devexit tegra20_spdif_platform_remove(struct platform_device *pdev)
324{ 358{
325 struct tegra20_spdif *spdif = dev_get_drvdata(&pdev->dev); 359 struct tegra20_spdif *spdif = dev_get_drvdata(&pdev->dev);
326 360
361 pm_runtime_disable(&pdev->dev);
362 if (!pm_runtime_status_suspended(&pdev->dev))
363 tegra20_spdif_runtime_suspend(&pdev->dev);
364
327 tegra_pcm_platform_unregister(&pdev->dev); 365 tegra_pcm_platform_unregister(&pdev->dev);
328 snd_soc_unregister_dai(&pdev->dev); 366 snd_soc_unregister_dai(&pdev->dev);
329 367
@@ -334,10 +372,16 @@ static int __devexit tegra20_spdif_platform_remove(struct platform_device *pdev)
334 return 0; 372 return 0;
335} 373}
336 374
375static const struct dev_pm_ops tegra20_spdif_pm_ops __devinitconst = {
376 SET_RUNTIME_PM_OPS(tegra20_spdif_runtime_suspend,
377 tegra20_spdif_runtime_resume, NULL)
378};
379
337static struct platform_driver tegra20_spdif_driver = { 380static struct platform_driver tegra20_spdif_driver = {
338 .driver = { 381 .driver = {
339 .name = DRV_NAME, 382 .name = DRV_NAME,
340 .owner = THIS_MODULE, 383 .owner = THIS_MODULE,
384 .pm = &tegra20_spdif_pm_ops,
341 }, 385 },
342 .probe = tegra20_spdif_platform_probe, 386 .probe = tegra20_spdif_platform_probe,
343 .remove = __devexit_p(tegra20_spdif_platform_remove), 387 .remove = __devexit_p(tegra20_spdif_platform_remove),