summaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorRavindra Lokhande <rlokhande@nvidia.com>2015-08-19 08:22:56 -0400
committerSameer Pujar <spujar@nvidia.com>2017-08-07 05:26:21 -0400
commitf967a99dc42cbd40024830913b1e84e6c9ac2682 (patch)
tree63755e165652e79f5c8e49a629396cd265fc0284 /sound/pci/hda
parent3de71a6bfe89a217a78d2e04e447b5d4208e0a87 (diff)
ALSA: hda - Add power management support
Add pm runtime suspend/resume function to tegra hda driver. Bug 200127452 Change-Id: I6146cbcbd2b2f71a0f17f6678f4113147ad9b480 Signed-off-by: Ravindra Lokhande <rlokhande@nvidia.com> Reviewed-on: http://git-master/r/785946 Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com> Reviewed-by: Sumit Bhattacharya <sumitb@nvidia.com>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/hda_tegra.c88
1 files changed, 84 insertions, 4 deletions
diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c
index e9bd8a4f6..7483705df 100644
--- a/sound/pci/hda/hda_tegra.c
+++ b/sound/pci/hda/hda_tegra.c
@@ -31,6 +31,7 @@
31#include <linux/of_device.h> 31#include <linux/of_device.h>
32#include <linux/slab.h> 32#include <linux/slab.h>
33#include <linux/time.h> 33#include <linux/time.h>
34#include <linux/pm_runtime.h>
34#include <linux/tegra-powergate.h> 35#include <linux/tegra-powergate.h>
35#include <linux/tegra_pm_domains.h> 36#include <linux/tegra_pm_domains.h>
36 37
@@ -40,6 +41,14 @@
40#include "hda_codec.h" 41#include "hda_codec.h"
41#include "hda_controller.h" 42#include "hda_controller.h"
42 43
44
45static struct of_device_id tegra_disb_pd[] = {
46 { .compatible = "nvidia,tegra210-disb-pd", },
47 { .compatible = "nvidia,tegra132-disb-pd", },
48 { .compatible = "nvidia,tegra124-disb-pd", },
49 {},
50};
51
43/* Defines for Nvidia Tegra HDA support */ 52/* Defines for Nvidia Tegra HDA support */
44#define HDA_BAR0 0x8000 53#define HDA_BAR0 0x8000
45 54
@@ -74,6 +83,7 @@ struct hda_tegra {
74 struct clk *hda_clk; 83 struct clk *hda_clk;
75 struct clk *hda2codec_2x_clk; 84 struct clk *hda2codec_2x_clk;
76 struct clk *hda2hdmi_clk; 85 struct clk *hda2hdmi_clk;
86 int partition_id;
77 void __iomem *regs; 87 void __iomem *regs;
78 struct work_struct probe_work; 88 struct work_struct probe_work;
79}; 89};
@@ -216,7 +226,7 @@ static int hda_tegra_enable_clocks(struct hda_tegra *data)
216{ 226{
217 int rc; 227 int rc;
218 228
219 tegra_unpowergate_partition(TEGRA_POWERGATE_DISB); 229 tegra_unpowergate_partition(data->partition_id);
220 230
221 rc = clk_prepare_enable(data->hda_clk); 231 rc = clk_prepare_enable(data->hda_clk);
222 if (rc) 232 if (rc)
@@ -234,7 +244,7 @@ disable_codec_2x:
234 clk_disable_unprepare(data->hda2codec_2x_clk); 244 clk_disable_unprepare(data->hda2codec_2x_clk);
235disable_hda: 245disable_hda:
236 clk_disable_unprepare(data->hda_clk); 246 clk_disable_unprepare(data->hda_clk);
237 tegra_powergate_partition(TEGRA_POWERGATE_DISB); 247 tegra_powergate_partition(data->partition_id);
238 return rc; 248 return rc;
239} 249}
240 250
@@ -245,7 +255,7 @@ static void hda_tegra_disable_clocks(struct hda_tegra *data)
245 clk_disable_unprepare(data->hda2codec_2x_clk); 255 clk_disable_unprepare(data->hda2codec_2x_clk);
246 clk_disable_unprepare(data->hda_clk); 256 clk_disable_unprepare(data->hda_clk);
247 257
248 tegra_powergate_partition(TEGRA_POWERGATE_DISB); 258 tegra_powergate_partition(data->partition_id);
249} 259}
250 260
251/* 261/*
@@ -257,6 +267,8 @@ static int hda_tegra_suspend(struct device *dev)
257 struct azx *chip = card->private_data; 267 struct azx *chip = card->private_data;
258 struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip); 268 struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
259 269
270 hda_tegra_enable_clocks(hda);
271
260 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); 272 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
261 273
262 azx_stop_chip(chip); 274 azx_stop_chip(chip);
@@ -274,18 +286,63 @@ static int hda_tegra_resume(struct device *dev)
274 286
275 hda_tegra_enable_clocks(hda); 287 hda_tegra_enable_clocks(hda);
276 288
289 if (hda->dev) {
290 pm_runtime_disable(hda->dev);
291 pm_runtime_set_active(hda->dev);
292 pm_runtime_get_noresume(hda->dev);
293 pm_runtime_enable(hda->dev);
294 }
277 hda_tegra_init(hda); 295 hda_tegra_init(hda);
278 296
279 azx_init_chip(chip, 1); 297 azx_init_chip(chip, 1);
280 298
281 snd_power_change_state(card, SNDRV_CTL_POWER_D0); 299 snd_power_change_state(card, SNDRV_CTL_POWER_D0);
282 300
301 pm_runtime_put(hda->dev);
302
283 return 0; 303 return 0;
284} 304}
285#endif /* CONFIG_PM_SLEEP */ 305#endif /* CONFIG_PM_SLEEP */
286 306
307#ifdef CONFIG_PM_RUNTIME
308static int hda_tegra_runtime_suspend(struct device *dev)
309{
310 struct snd_card *card = dev_get_drvdata(dev);
311 struct azx *chip = card->private_data;
312 struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
313
314 if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
315 return 0;
316
317 azx_stop_chip(chip);
318 hda_tegra_disable_clocks(hda);
319
320 return 0;
321}
322
323static int hda_tegra_runtime_resume(struct device *dev)
324{
325 struct snd_card *card = dev_get_drvdata(dev);
326 struct azx *chip = card->private_data;
327 struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
328
329 if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
330 return 0;
331
332 hda_tegra_enable_clocks(hda);
333
334 hda_tegra_init(hda);
335
336 azx_init_chip(chip, 1);
337
338 return 0;
339}
340#endif /* CONFIG_PM_RUNTIME */
341
287static const struct dev_pm_ops hda_tegra_pm = { 342static const struct dev_pm_ops hda_tegra_pm = {
288 SET_SYSTEM_SLEEP_PM_OPS(hda_tegra_suspend, hda_tegra_resume) 343 SET_SYSTEM_SLEEP_PM_OPS(hda_tegra_suspend, hda_tegra_resume)
344 SET_RUNTIME_PM_OPS(hda_tegra_runtime_suspend,
345 hda_tegra_runtime_resume, NULL)
289}; 346};
290 347
291static int hda_tegra_dev_disconnect(struct snd_device *device) 348static int hda_tegra_dev_disconnect(struct snd_device *device)
@@ -313,6 +370,8 @@ static int hda_tegra_dev_free(struct snd_device *device)
313 azx_free_stream_pages(chip); 370 azx_free_stream_pages(chip);
314 azx_free_streams(chip); 371 azx_free_streams(chip);
315 snd_hdac_bus_exit(azx_bus(chip)); 372 snd_hdac_bus_exit(azx_bus(chip));
373 hda_tegra_disable_clocks(hda);
374 pm_runtime_put(hda->dev);
316 375
317 return 0; 376 return 0;
318} 377}
@@ -450,6 +509,14 @@ static int hda_tegra_create(struct snd_card *card,
450 struct azx *chip; 509 struct azx *chip;
451 int err; 510 int err;
452 511
512 if (hda->dev) {
513 err = pm_runtime_set_active(hda->dev);
514 if (err < 0)
515 return err;
516 pm_runtime_get_noresume(hda->dev);
517 pm_runtime_enable(hda->dev);
518 }
519
453 chip = &hda->chip; 520 chip = &hda->chip;
454 521
455 mutex_init(&chip->open_mutex); 522 mutex_init(&chip->open_mutex);
@@ -488,11 +555,13 @@ MODULE_DEVICE_TABLE(of, hda_tegra_match);
488 555
489static int hda_tegra_probe(struct platform_device *pdev) 556static int hda_tegra_probe(struct platform_device *pdev)
490{ 557{
491 const unsigned int driver_flags = AZX_DCAPS_CORBRP_SELF_CLEAR; 558 const unsigned int driver_flags = AZX_DCAPS_CORBRP_SELF_CLEAR |
559 AZX_DCAPS_PM_RUNTIME;
492 struct snd_card *card; 560 struct snd_card *card;
493 struct azx *chip; 561 struct azx *chip;
494 struct hda_tegra *hda; 562 struct hda_tegra *hda;
495 int err; 563 int err;
564 const unsigned int driver_flags = 0;
496 565
497 hda = devm_kzalloc(&pdev->dev, sizeof(*hda), GFP_KERNEL); 566 hda = devm_kzalloc(&pdev->dev, sizeof(*hda), GFP_KERNEL);
498 if (!hda) 567 if (!hda)
@@ -500,6 +569,12 @@ static int hda_tegra_probe(struct platform_device *pdev)
500 hda->dev = &pdev->dev; 569 hda->dev = &pdev->dev;
501 chip = &hda->chip; 570 chip = &hda->chip;
502 571
572 hda->partition_id = tegra_pd_get_powergate_id(tegra_disb_pd);
573 if (hda->partition_id < 0) {
574 dev_err(&pdev->dev, "Failed to get hda power domain id\n");
575 return -EINVAL;
576 }
577
503 err = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, 578 err = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
504 THIS_MODULE, 0, &card); 579 THIS_MODULE, 0, &card);
505 if (err < 0) { 580 if (err < 0) {
@@ -533,6 +608,8 @@ static void hda_tegra_probe_work(struct work_struct *work)
533 if (err < 0) 608 if (err < 0)
534 goto out_free; 609 goto out_free;
535 610
611 tegra_pd_add_device(hda->dev);
612
536 /* create codec instances */ 613 /* create codec instances */
537 err = azx_probe_codecs(chip, 0); 614 err = azx_probe_codecs(chip, 0);
538 if (err < 0) 615 if (err < 0)
@@ -549,12 +626,15 @@ static void hda_tegra_probe_work(struct work_struct *work)
549 chip->running = 1; 626 chip->running = 1;
550 snd_hda_set_power_save(&chip->bus, power_save * 1000); 627 snd_hda_set_power_save(&chip->bus, power_save * 1000);
551 628
629 pm_runtime_put(hda->dev);
630
552 out_free: 631 out_free:
553 return; /* no error return from async probe */ 632 return; /* no error return from async probe */
554} 633}
555 634
556static int hda_tegra_remove(struct platform_device *pdev) 635static int hda_tegra_remove(struct platform_device *pdev)
557{ 636{
637 pm_runtime_get_noresume(&pdev->dev);
558 return snd_card_free(dev_get_drvdata(&pdev->dev)); 638 return snd_card_free(dev_get_drvdata(&pdev->dev));
559} 639}
560 640