aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/tegra/tegra20_i2s.c
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2012-04-09 11:52:22 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-04-09 12:42:48 -0400
commit82ef0ae46b8614f052cc3ee856c5624eff614063 (patch)
tree6501a803485bd0be0926717373c0555bfbee4b23 /sound/soc/tegra/tegra20_i2s.c
parent1eecb8280b038019f2f914abc01b28caf5d0a168 (diff)
ASoC: tegra: add runtime PM support
To the Tegra I2S and SPDIF drivers Signed-off-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/tegra/tegra20_i2s.c')
-rw-r--r--sound/soc/tegra/tegra20_i2s.c54
1 files changed, 47 insertions, 7 deletions
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index 9427f36e6a25..b598ebdefdee 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -35,6 +35,7 @@
35#include <linux/module.h> 35#include <linux/module.h>
36#include <linux/of.h> 36#include <linux/of.h>
37#include <linux/platform_device.h> 37#include <linux/platform_device.h>
38#include <linux/pm_runtime.h>
38#include <linux/seq_file.h> 39#include <linux/seq_file.h>
39#include <linux/slab.h> 40#include <linux/slab.h>
40#include <sound/core.h> 41#include <sound/core.h>
@@ -56,6 +57,29 @@ static inline u32 tegra20_i2s_read(struct tegra20_i2s *i2s, u32 reg)
56 return __raw_readl(i2s->regs + reg); 57 return __raw_readl(i2s->regs + reg);
57} 58}
58 59
60static int tegra20_i2s_runtime_suspend(struct device *dev)
61{
62 struct tegra20_i2s *i2s = dev_get_drvdata(dev);
63
64 clk_disable(i2s->clk_i2s);
65
66 return 0;
67}
68
69static int tegra20_i2s_runtime_resume(struct device *dev)
70{
71 struct tegra20_i2s *i2s = dev_get_drvdata(dev);
72 int ret;
73
74 ret = clk_enable(i2s->clk_i2s);
75 if (ret) {
76 dev_err(dev, "clk_enable failed: %d\n", ret);
77 return ret;
78 }
79
80 return 0;
81}
82
59#ifdef CONFIG_DEBUG_FS 83#ifdef CONFIG_DEBUG_FS
60static int tegra20_i2s_show(struct seq_file *s, void *unused) 84static int tegra20_i2s_show(struct seq_file *s, void *unused)
61{ 85{
@@ -219,16 +243,12 @@ static int tegra20_i2s_hw_params(struct snd_pcm_substream *substream,
219 if (i2sclock % (2 * srate)) 243 if (i2sclock % (2 * srate))
220 reg |= TEGRA20_I2S_TIMING_NON_SYM_ENABLE; 244 reg |= TEGRA20_I2S_TIMING_NON_SYM_ENABLE;
221 245
222 clk_enable(i2s->clk_i2s);
223
224 tegra20_i2s_write(i2s, TEGRA20_I2S_TIMING, reg); 246 tegra20_i2s_write(i2s, TEGRA20_I2S_TIMING, reg);
225 247
226 tegra20_i2s_write(i2s, TEGRA20_I2S_FIFO_SCR, 248 tegra20_i2s_write(i2s, TEGRA20_I2S_FIFO_SCR,
227 TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS | 249 TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS |
228 TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS); 250 TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS);
229 251
230 clk_disable(i2s->clk_i2s);
231
232 return 0; 252 return 0;
233} 253}
234 254
@@ -265,7 +285,6 @@ static int tegra20_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
265 case SNDRV_PCM_TRIGGER_START: 285 case SNDRV_PCM_TRIGGER_START:
266 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 286 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
267 case SNDRV_PCM_TRIGGER_RESUME: 287 case SNDRV_PCM_TRIGGER_RESUME:
268 clk_enable(i2s->clk_i2s);
269 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 288 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
270 tegra20_i2s_start_playback(i2s); 289 tegra20_i2s_start_playback(i2s);
271 else 290 else
@@ -278,7 +297,6 @@ static int tegra20_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
278 tegra20_i2s_stop_playback(i2s); 297 tegra20_i2s_stop_playback(i2s);
279 else 298 else
280 tegra20_i2s_stop_capture(i2s); 299 tegra20_i2s_stop_capture(i2s);
281 clk_disable(i2s->clk_i2s);
282 break; 300 break;
283 default: 301 default:
284 return -EINVAL; 302 return -EINVAL;
@@ -395,11 +413,18 @@ static __devinit int tegra20_i2s_platform_probe(struct platform_device *pdev)
395 413
396 i2s->reg_ctrl = TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED; 414 i2s->reg_ctrl = TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED;
397 415
416 pm_runtime_enable(&pdev->dev);
417 if (!pm_runtime_enabled(&pdev->dev)) {
418 ret = tegra20_i2s_runtime_resume(&pdev->dev);
419 if (ret)
420 goto err_pm_disable;
421 }
422
398 ret = snd_soc_register_dai(&pdev->dev, &i2s->dai); 423 ret = snd_soc_register_dai(&pdev->dev, &i2s->dai);
399 if (ret) { 424 if (ret) {
400 dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); 425 dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
401 ret = -ENOMEM; 426 ret = -ENOMEM;
402 goto err_clk_put; 427 goto err_suspend;
403 } 428 }
404 429
405 ret = tegra_pcm_platform_register(&pdev->dev); 430 ret = tegra_pcm_platform_register(&pdev->dev);
@@ -414,6 +439,11 @@ static __devinit int tegra20_i2s_platform_probe(struct platform_device *pdev)
414 439
415err_unregister_dai: 440err_unregister_dai:
416 snd_soc_unregister_dai(&pdev->dev); 441 snd_soc_unregister_dai(&pdev->dev);
442err_suspend:
443 if (!pm_runtime_status_suspended(&pdev->dev))
444 tegra20_i2s_runtime_suspend(&pdev->dev);
445err_pm_disable:
446 pm_runtime_disable(&pdev->dev);
417err_clk_put: 447err_clk_put:
418 clk_put(i2s->clk_i2s); 448 clk_put(i2s->clk_i2s);
419err: 449err:
@@ -424,6 +454,10 @@ static int __devexit tegra20_i2s_platform_remove(struct platform_device *pdev)
424{ 454{
425 struct tegra20_i2s *i2s = dev_get_drvdata(&pdev->dev); 455 struct tegra20_i2s *i2s = dev_get_drvdata(&pdev->dev);
426 456
457 pm_runtime_disable(&pdev->dev);
458 if (!pm_runtime_status_suspended(&pdev->dev))
459 tegra20_i2s_runtime_suspend(&pdev->dev);
460
427 tegra_pcm_platform_unregister(&pdev->dev); 461 tegra_pcm_platform_unregister(&pdev->dev);
428 snd_soc_unregister_dai(&pdev->dev); 462 snd_soc_unregister_dai(&pdev->dev);
429 463
@@ -439,11 +473,17 @@ static const struct of_device_id tegra20_i2s_of_match[] __devinitconst = {
439 {}, 473 {},
440}; 474};
441 475
476static const struct dev_pm_ops tegra20_i2s_pm_ops __devinitconst = {
477 SET_RUNTIME_PM_OPS(tegra20_i2s_runtime_suspend,
478 tegra20_i2s_runtime_resume, NULL)
479};
480
442static struct platform_driver tegra20_i2s_driver = { 481static struct platform_driver tegra20_i2s_driver = {
443 .driver = { 482 .driver = {
444 .name = DRV_NAME, 483 .name = DRV_NAME,
445 .owner = THIS_MODULE, 484 .owner = THIS_MODULE,
446 .of_match_table = tegra20_i2s_of_match, 485 .of_match_table = tegra20_i2s_of_match,
486 .pm = &tegra20_i2s_pm_ops,
447 }, 487 },
448 .probe = tegra20_i2s_platform_probe, 488 .probe = tegra20_i2s_platform_probe,
449 .remove = __devexit_p(tegra20_i2s_platform_remove), 489 .remove = __devexit_p(tegra20_i2s_platform_remove),