aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEd Blake <ed.blake@sondrel.com>2017-10-06 10:52:28 -0400
committerMark Brown <broonie@kernel.org>2017-10-09 04:43:41 -0400
commita38ced17328bae30dabc15dbc2563860e3921c9c (patch)
tree1e9c03729005e97c956abb97203573faac12e1f9
parent9b4acd33dd64e84be6db9552b6d43979c05135b1 (diff)
ASoC: img-i2s-out: Add control of sys clock to runtime PM
Disable sys clock as well as ref clock when runtime suspended. Signed-off-by: Ed Blake <ed.blake@sondrel.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/img/img-i2s-out.c60
1 files changed, 31 insertions, 29 deletions
diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c
index 1d831c625fe2..30a95bcef2db 100644
--- a/sound/soc/img/img-i2s-out.c
+++ b/sound/soc/img/img-i2s-out.c
@@ -71,8 +71,8 @@ static int img_i2s_out_runtime_suspend(struct device *dev)
71{ 71{
72 struct img_i2s_out *i2s = dev_get_drvdata(dev); 72 struct img_i2s_out *i2s = dev_get_drvdata(dev);
73 73
74 if (!i2s->force_clk_active) 74 clk_disable_unprepare(i2s->clk_ref);
75 clk_disable_unprepare(i2s->clk_ref); 75 clk_disable_unprepare(i2s->clk_sys);
76 76
77 return 0; 77 return 0;
78} 78}
@@ -82,12 +82,17 @@ static int img_i2s_out_runtime_resume(struct device *dev)
82 struct img_i2s_out *i2s = dev_get_drvdata(dev); 82 struct img_i2s_out *i2s = dev_get_drvdata(dev);
83 int ret; 83 int ret;
84 84
85 if (!i2s->force_clk_active) { 85 ret = clk_prepare_enable(i2s->clk_sys);
86 ret = clk_prepare_enable(i2s->clk_ref); 86 if (ret) {
87 if (ret) { 87 dev_err(dev, "clk_enable failed: %d\n", ret);
88 dev_err(dev, "clk_enable failed: %d\n", ret); 88 return ret;
89 return ret; 89 }
90 } 90
91 ret = clk_prepare_enable(i2s->clk_ref);
92 if (ret) {
93 dev_err(dev, "clk_enable failed: %d\n", ret);
94 clk_disable_unprepare(i2s->clk_sys);
95 return ret;
91 } 96 }
92 97
93 return 0; 98 return 0;
@@ -289,7 +294,7 @@ static int img_i2s_out_hw_params(struct snd_pcm_substream *substream,
289static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 294static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
290{ 295{
291 struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); 296 struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai);
292 int i; 297 int i, ret;
293 bool force_clk_active; 298 bool force_clk_active;
294 u32 chan_control_mask, control_mask, chan_control_set = 0; 299 u32 chan_control_mask, control_mask, chan_control_set = 0;
295 u32 reg, control_set = 0; 300 u32 reg, control_set = 0;
@@ -344,6 +349,10 @@ static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
344 349
345 chan_control_mask = IMG_I2S_OUT_CHAN_CTL_CLKT_MASK; 350 chan_control_mask = IMG_I2S_OUT_CHAN_CTL_CLKT_MASK;
346 351
352 ret = pm_runtime_get_sync(i2s->dev);
353 if (ret < 0)
354 return ret;
355
347 img_i2s_out_disable(i2s); 356 img_i2s_out_disable(i2s);
348 357
349 reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); 358 reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL);
@@ -363,6 +372,7 @@ static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
363 img_i2s_out_ch_enable(i2s, i); 372 img_i2s_out_ch_enable(i2s, i);
364 373
365 img_i2s_out_enable(i2s); 374 img_i2s_out_enable(i2s);
375 pm_runtime_put(i2s->dev);
366 376
367 i2s->force_clk_active = force_clk_active; 377 i2s->force_clk_active = force_clk_active;
368 378
@@ -469,16 +479,20 @@ static int img_i2s_out_probe(struct platform_device *pdev)
469 return PTR_ERR(i2s->clk_ref); 479 return PTR_ERR(i2s->clk_ref);
470 } 480 }
471 481
472 ret = clk_prepare_enable(i2s->clk_sys);
473 if (ret)
474 return ret;
475
476 i2s->suspend_ch_ctl = devm_kzalloc(dev, 482 i2s->suspend_ch_ctl = devm_kzalloc(dev,
477 sizeof(*i2s->suspend_ch_ctl) * i2s->max_i2s_chan, GFP_KERNEL); 483 sizeof(*i2s->suspend_ch_ctl) * i2s->max_i2s_chan, GFP_KERNEL);
478 if (!i2s->suspend_ch_ctl) { 484 if (!i2s->suspend_ch_ctl)
479 ret = -ENOMEM; 485 return -ENOMEM;
480 goto err_clk_disable; 486
487 pm_runtime_enable(&pdev->dev);
488 if (!pm_runtime_enabled(&pdev->dev)) {
489 ret = img_i2s_out_runtime_resume(&pdev->dev);
490 if (ret)
491 goto err_pm_disable;
481 } 492 }
493 ret = pm_runtime_get_sync(&pdev->dev);
494 if (ret < 0)
495 goto err_suspend;
482 496
483 reg = IMG_I2S_OUT_CTL_FRM_SIZE_MASK; 497 reg = IMG_I2S_OUT_CTL_FRM_SIZE_MASK;
484 img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); 498 img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL);
@@ -492,13 +506,7 @@ static int img_i2s_out_probe(struct platform_device *pdev)
492 img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL); 506 img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL);
493 507
494 img_i2s_out_reset(i2s); 508 img_i2s_out_reset(i2s);
495 509 pm_runtime_put(&pdev->dev);
496 pm_runtime_enable(&pdev->dev);
497 if (!pm_runtime_enabled(&pdev->dev)) {
498 ret = img_i2s_out_runtime_resume(&pdev->dev);
499 if (ret)
500 goto err_pm_disable;
501 }
502 510
503 i2s->active_channels = 1; 511 i2s->active_channels = 1;
504 i2s->dma_data.addr = res->start + IMG_I2S_OUT_TX_FIFO; 512 i2s->dma_data.addr = res->start + IMG_I2S_OUT_TX_FIFO;
@@ -529,22 +537,16 @@ err_suspend:
529 img_i2s_out_runtime_suspend(&pdev->dev); 537 img_i2s_out_runtime_suspend(&pdev->dev);
530err_pm_disable: 538err_pm_disable:
531 pm_runtime_disable(&pdev->dev); 539 pm_runtime_disable(&pdev->dev);
532err_clk_disable:
533 clk_disable_unprepare(i2s->clk_sys);
534 540
535 return ret; 541 return ret;
536} 542}
537 543
538static int img_i2s_out_dev_remove(struct platform_device *pdev) 544static int img_i2s_out_dev_remove(struct platform_device *pdev)
539{ 545{
540 struct img_i2s_out *i2s = platform_get_drvdata(pdev);
541
542 pm_runtime_disable(&pdev->dev); 546 pm_runtime_disable(&pdev->dev);
543 if (!pm_runtime_status_suspended(&pdev->dev)) 547 if (!pm_runtime_status_suspended(&pdev->dev))
544 img_i2s_out_runtime_suspend(&pdev->dev); 548 img_i2s_out_runtime_suspend(&pdev->dev);
545 549
546 clk_disable_unprepare(i2s->clk_sys);
547
548 return 0; 550 return 0;
549} 551}
550 552