diff options
author | Ed Blake <ed.blake@sondrel.com> | 2017-10-06 10:52:28 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2017-10-09 04:43:41 -0400 |
commit | a38ced17328bae30dabc15dbc2563860e3921c9c (patch) | |
tree | 1e9c03729005e97c956abb97203573faac12e1f9 | |
parent | 9b4acd33dd64e84be6db9552b6d43979c05135b1 (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.c | 60 |
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, | |||
289 | static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | 294 | static 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); |
530 | err_pm_disable: | 538 | err_pm_disable: |
531 | pm_runtime_disable(&pdev->dev); | 539 | pm_runtime_disable(&pdev->dev); |
532 | err_clk_disable: | ||
533 | clk_disable_unprepare(i2s->clk_sys); | ||
534 | 540 | ||
535 | return ret; | 541 | return ret; |
536 | } | 542 | } |
537 | 543 | ||
538 | static int img_i2s_out_dev_remove(struct platform_device *pdev) | 544 | static 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 | ||