|
25 | 25 | #include <linux/of_clk.h> |
26 | 26 | #include <linux/of_platform.h> |
27 | 27 | #include <linux/parser.h> |
| 28 | +#include <linux/pm_domain.h> |
28 | 29 | #include <linux/regulator/consumer.h> |
29 | 30 |
|
30 | 31 | static const struct fb_fix_screeninfo simplefb_fix = { |
@@ -78,6 +79,11 @@ struct simplefb_par { |
78 | 79 | unsigned int clk_count; |
79 | 80 | struct clk **clks; |
80 | 81 | #endif |
| 82 | +#if defined CONFIG_OF && defined CONFIG_PM_GENERIC_DOMAINS |
| 83 | + unsigned int num_genpds; |
| 84 | + struct device **genpds; |
| 85 | + struct device_link **genpd_links; |
| 86 | +#endif |
81 | 87 | #if defined CONFIG_OF && defined CONFIG_REGULATOR |
82 | 88 | bool regulators_enabled; |
83 | 89 | u32 regulator_count; |
@@ -432,6 +438,89 @@ static void simplefb_regulators_enable(struct simplefb_par *par, |
432 | 438 | static void simplefb_regulators_destroy(struct simplefb_par *par) { } |
433 | 439 | #endif |
434 | 440 |
|
| 441 | +#if defined CONFIG_OF && defined CONFIG_PM_GENERIC_DOMAINS |
| 442 | +static void simplefb_detach_genpds(void *res) |
| 443 | +{ |
| 444 | + struct simplefb_par *par = res; |
| 445 | + unsigned int i = par->num_genpds; |
| 446 | + |
| 447 | + if (par->num_genpds <= 1) |
| 448 | + return; |
| 449 | + |
| 450 | + while (i--) { |
| 451 | + if (par->genpd_links[i]) |
| 452 | + device_link_del(par->genpd_links[i]); |
| 453 | + |
| 454 | + if (!IS_ERR_OR_NULL(par->genpds[i])) |
| 455 | + dev_pm_domain_detach(par->genpds[i], true); |
| 456 | + } |
| 457 | +} |
| 458 | + |
| 459 | +static int simplefb_attach_genpds(struct simplefb_par *par, |
| 460 | + struct platform_device *pdev) |
| 461 | +{ |
| 462 | + struct device *dev = &pdev->dev; |
| 463 | + unsigned int i; |
| 464 | + int err; |
| 465 | + |
| 466 | + err = of_count_phandle_with_args(dev->of_node, "power-domains", |
| 467 | + "#power-domain-cells"); |
| 468 | + if (err < 0) { |
| 469 | + dev_info(dev, "failed to parse power-domains: %d\n", err); |
| 470 | + return err; |
| 471 | + } |
| 472 | + |
| 473 | + par->num_genpds = err; |
| 474 | + |
| 475 | + /* |
| 476 | + * Single power-domain devices are handled by the driver core, so |
| 477 | + * nothing to do here. |
| 478 | + */ |
| 479 | + if (par->num_genpds <= 1) |
| 480 | + return 0; |
| 481 | + |
| 482 | + par->genpds = devm_kcalloc(dev, par->num_genpds, sizeof(*par->genpds), |
| 483 | + GFP_KERNEL); |
| 484 | + if (!par->genpds) |
| 485 | + return -ENOMEM; |
| 486 | + |
| 487 | + par->genpd_links = devm_kcalloc(dev, par->num_genpds, |
| 488 | + sizeof(*par->genpd_links), |
| 489 | + GFP_KERNEL); |
| 490 | + if (!par->genpd_links) |
| 491 | + return -ENOMEM; |
| 492 | + |
| 493 | + for (i = 0; i < par->num_genpds; i++) { |
| 494 | + par->genpds[i] = dev_pm_domain_attach_by_id(dev, i); |
| 495 | + if (IS_ERR(par->genpds[i])) { |
| 496 | + err = PTR_ERR(par->genpds[i]); |
| 497 | + if (err == -EPROBE_DEFER) { |
| 498 | + simplefb_detach_genpds(par); |
| 499 | + return err; |
| 500 | + } |
| 501 | + |
| 502 | + dev_warn(dev, "failed to attach domain %u: %d\n", i, err); |
| 503 | + continue; |
| 504 | + } |
| 505 | + |
| 506 | + par->genpd_links[i] = device_link_add(dev, par->genpds[i], |
| 507 | + DL_FLAG_STATELESS | |
| 508 | + DL_FLAG_PM_RUNTIME | |
| 509 | + DL_FLAG_RPM_ACTIVE); |
| 510 | + if (!par->genpd_links[i]) |
| 511 | + dev_warn(dev, "failed to link power-domain %u\n", i); |
| 512 | + } |
| 513 | + |
| 514 | + return devm_add_action_or_reset(dev, simplefb_detach_genpds, par); |
| 515 | +} |
| 516 | +#else |
| 517 | +static int simplefb_attach_genpds(struct simplefb_par *par, |
| 518 | + struct platform_device *pdev) |
| 519 | +{ |
| 520 | + return 0; |
| 521 | +} |
| 522 | +#endif |
| 523 | + |
435 | 524 | static int simplefb_probe(struct platform_device *pdev) |
436 | 525 | { |
437 | 526 | int ret; |
@@ -518,6 +607,10 @@ static int simplefb_probe(struct platform_device *pdev) |
518 | 607 | if (ret < 0) |
519 | 608 | goto error_clocks; |
520 | 609 |
|
| 610 | + ret = simplefb_attach_genpds(par, pdev); |
| 611 | + if (ret < 0) |
| 612 | + goto error_regulators; |
| 613 | + |
521 | 614 | simplefb_clocks_enable(par, pdev); |
522 | 615 | simplefb_regulators_enable(par, pdev); |
523 | 616 |
|
|
0 commit comments