diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-12-03 18:50:06 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-12-03 18:50:06 -0500 |
commit | 4bea2b4cd93600e4c3aed6059a095209d3fc91b9 (patch) | |
tree | 503b65495edcd26d2e4a17aca8f6503bd0a51f8e /drivers/acpi | |
parent | d30d819dc83107812d9b2876e5e7194e511ed6af (diff) | |
parent | bb32baf76e56cdb348633f4d789a93e81b975c47 (diff) |
Merge branch 'acpi-lpss' into pm-runtime
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/acpi_lpss.c | 94 |
1 files changed, 65 insertions, 29 deletions
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 93d160661f4c..d1dd0ada14b7 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * ACPI support for Intel Lynxpoint LPSS. | 2 | * ACPI support for Intel Lynxpoint LPSS. |
3 | * | 3 | * |
4 | * Copyright (C) 2013, Intel Corporation | 4 | * Copyright (C) 2013, 2014, Intel Corporation |
5 | * Authors: Mika Westerberg <mika.westerberg@linux.intel.com> | 5 | * Authors: Mika Westerberg <mika.westerberg@linux.intel.com> |
6 | * Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 6 | * Rafael J. Wysocki <rafael.j.wysocki@intel.com> |
7 | * | 7 | * |
@@ -60,6 +60,8 @@ ACPI_MODULE_NAME("acpi_lpss"); | |||
60 | #define LPSS_CLK_DIVIDER BIT(2) | 60 | #define LPSS_CLK_DIVIDER BIT(2) |
61 | #define LPSS_LTR BIT(3) | 61 | #define LPSS_LTR BIT(3) |
62 | #define LPSS_SAVE_CTX BIT(4) | 62 | #define LPSS_SAVE_CTX BIT(4) |
63 | #define LPSS_DEV_PROXY BIT(5) | ||
64 | #define LPSS_PROXY_REQ BIT(6) | ||
63 | 65 | ||
64 | struct lpss_private_data; | 66 | struct lpss_private_data; |
65 | 67 | ||
@@ -70,8 +72,10 @@ struct lpss_device_desc { | |||
70 | void (*setup)(struct lpss_private_data *pdata); | 72 | void (*setup)(struct lpss_private_data *pdata); |
71 | }; | 73 | }; |
72 | 74 | ||
75 | static struct device *proxy_device; | ||
76 | |||
73 | static struct lpss_device_desc lpss_dma_desc = { | 77 | static struct lpss_device_desc lpss_dma_desc = { |
74 | .flags = LPSS_CLK, | 78 | .flags = LPSS_CLK | LPSS_PROXY_REQ, |
75 | }; | 79 | }; |
76 | 80 | ||
77 | struct lpss_private_data { | 81 | struct lpss_private_data { |
@@ -146,22 +150,24 @@ static struct lpss_device_desc byt_pwm_dev_desc = { | |||
146 | }; | 150 | }; |
147 | 151 | ||
148 | static struct lpss_device_desc byt_uart_dev_desc = { | 152 | static struct lpss_device_desc byt_uart_dev_desc = { |
149 | .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX, | 153 | .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX | |
154 | LPSS_DEV_PROXY, | ||
150 | .prv_offset = 0x800, | 155 | .prv_offset = 0x800, |
151 | .setup = lpss_uart_setup, | 156 | .setup = lpss_uart_setup, |
152 | }; | 157 | }; |
153 | 158 | ||
154 | static struct lpss_device_desc byt_spi_dev_desc = { | 159 | static struct lpss_device_desc byt_spi_dev_desc = { |
155 | .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX, | 160 | .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX | |
161 | LPSS_DEV_PROXY, | ||
156 | .prv_offset = 0x400, | 162 | .prv_offset = 0x400, |
157 | }; | 163 | }; |
158 | 164 | ||
159 | static struct lpss_device_desc byt_sdio_dev_desc = { | 165 | static struct lpss_device_desc byt_sdio_dev_desc = { |
160 | .flags = LPSS_CLK, | 166 | .flags = LPSS_CLK | LPSS_DEV_PROXY, |
161 | }; | 167 | }; |
162 | 168 | ||
163 | static struct lpss_device_desc byt_i2c_dev_desc = { | 169 | static struct lpss_device_desc byt_i2c_dev_desc = { |
164 | .flags = LPSS_CLK | LPSS_SAVE_CTX, | 170 | .flags = LPSS_CLK | LPSS_SAVE_CTX | LPSS_DEV_PROXY, |
165 | .prv_offset = 0x800, | 171 | .prv_offset = 0x800, |
166 | .setup = byt_i2c_setup, | 172 | .setup = byt_i2c_setup, |
167 | }; | 173 | }; |
@@ -368,6 +374,8 @@ static int acpi_lpss_create_device(struct acpi_device *adev, | |||
368 | adev->driver_data = pdata; | 374 | adev->driver_data = pdata; |
369 | pdev = acpi_create_platform_device(adev); | 375 | pdev = acpi_create_platform_device(adev); |
370 | if (!IS_ERR_OR_NULL(pdev)) { | 376 | if (!IS_ERR_OR_NULL(pdev)) { |
377 | if (!proxy_device && dev_desc->flags & LPSS_DEV_PROXY) | ||
378 | proxy_device = &pdev->dev; | ||
371 | return 1; | 379 | return 1; |
372 | } | 380 | } |
373 | 381 | ||
@@ -499,14 +507,15 @@ static void acpi_lpss_set_ltr(struct device *dev, s32 val) | |||
499 | /** | 507 | /** |
500 | * acpi_lpss_save_ctx() - Save the private registers of LPSS device | 508 | * acpi_lpss_save_ctx() - Save the private registers of LPSS device |
501 | * @dev: LPSS device | 509 | * @dev: LPSS device |
510 | * @pdata: pointer to the private data of the LPSS device | ||
502 | * | 511 | * |
503 | * Most LPSS devices have private registers which may loose their context when | 512 | * Most LPSS devices have private registers which may loose their context when |
504 | * the device is powered down. acpi_lpss_save_ctx() saves those registers into | 513 | * the device is powered down. acpi_lpss_save_ctx() saves those registers into |
505 | * prv_reg_ctx array. | 514 | * prv_reg_ctx array. |
506 | */ | 515 | */ |
507 | static void acpi_lpss_save_ctx(struct device *dev) | 516 | static void acpi_lpss_save_ctx(struct device *dev, |
517 | struct lpss_private_data *pdata) | ||
508 | { | 518 | { |
509 | struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); | ||
510 | unsigned int i; | 519 | unsigned int i; |
511 | 520 | ||
512 | for (i = 0; i < LPSS_PRV_REG_COUNT; i++) { | 521 | for (i = 0; i < LPSS_PRV_REG_COUNT; i++) { |
@@ -521,12 +530,13 @@ static void acpi_lpss_save_ctx(struct device *dev) | |||
521 | /** | 530 | /** |
522 | * acpi_lpss_restore_ctx() - Restore the private registers of LPSS device | 531 | * acpi_lpss_restore_ctx() - Restore the private registers of LPSS device |
523 | * @dev: LPSS device | 532 | * @dev: LPSS device |
533 | * @pdata: pointer to the private data of the LPSS device | ||
524 | * | 534 | * |
525 | * Restores the registers that were previously stored with acpi_lpss_save_ctx(). | 535 | * Restores the registers that were previously stored with acpi_lpss_save_ctx(). |
526 | */ | 536 | */ |
527 | static void acpi_lpss_restore_ctx(struct device *dev) | 537 | static void acpi_lpss_restore_ctx(struct device *dev, |
538 | struct lpss_private_data *pdata) | ||
528 | { | 539 | { |
529 | struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); | ||
530 | unsigned int i; | 540 | unsigned int i; |
531 | 541 | ||
532 | /* | 542 | /* |
@@ -549,23 +559,31 @@ static void acpi_lpss_restore_ctx(struct device *dev) | |||
549 | #ifdef CONFIG_PM_SLEEP | 559 | #ifdef CONFIG_PM_SLEEP |
550 | static int acpi_lpss_suspend_late(struct device *dev) | 560 | static int acpi_lpss_suspend_late(struct device *dev) |
551 | { | 561 | { |
552 | int ret = pm_generic_suspend_late(dev); | 562 | struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); |
563 | int ret; | ||
553 | 564 | ||
565 | ret = pm_generic_suspend_late(dev); | ||
554 | if (ret) | 566 | if (ret) |
555 | return ret; | 567 | return ret; |
556 | 568 | ||
557 | acpi_lpss_save_ctx(dev); | 569 | if (pdata->dev_desc->flags & LPSS_SAVE_CTX) |
570 | acpi_lpss_save_ctx(dev, pdata); | ||
571 | |||
558 | return acpi_dev_suspend_late(dev); | 572 | return acpi_dev_suspend_late(dev); |
559 | } | 573 | } |
560 | 574 | ||
561 | static int acpi_lpss_resume_early(struct device *dev) | 575 | static int acpi_lpss_resume_early(struct device *dev) |
562 | { | 576 | { |
563 | int ret = acpi_dev_resume_early(dev); | 577 | struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); |
578 | int ret; | ||
564 | 579 | ||
580 | ret = acpi_dev_resume_early(dev); | ||
565 | if (ret) | 581 | if (ret) |
566 | return ret; | 582 | return ret; |
567 | 583 | ||
568 | acpi_lpss_restore_ctx(dev); | 584 | if (pdata->dev_desc->flags & LPSS_SAVE_CTX) |
585 | acpi_lpss_restore_ctx(dev, pdata); | ||
586 | |||
569 | return pm_generic_resume_early(dev); | 587 | return pm_generic_resume_early(dev); |
570 | } | 588 | } |
571 | #endif /* CONFIG_PM_SLEEP */ | 589 | #endif /* CONFIG_PM_SLEEP */ |
@@ -573,23 +591,44 @@ static int acpi_lpss_resume_early(struct device *dev) | |||
573 | #ifdef CONFIG_PM_RUNTIME | 591 | #ifdef CONFIG_PM_RUNTIME |
574 | static int acpi_lpss_runtime_suspend(struct device *dev) | 592 | static int acpi_lpss_runtime_suspend(struct device *dev) |
575 | { | 593 | { |
576 | int ret = pm_generic_runtime_suspend(dev); | 594 | struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); |
595 | int ret; | ||
577 | 596 | ||
597 | ret = pm_generic_runtime_suspend(dev); | ||
578 | if (ret) | 598 | if (ret) |
579 | return ret; | 599 | return ret; |
580 | 600 | ||
581 | acpi_lpss_save_ctx(dev); | 601 | if (pdata->dev_desc->flags & LPSS_SAVE_CTX) |
582 | return acpi_dev_runtime_suspend(dev); | 602 | acpi_lpss_save_ctx(dev, pdata); |
603 | |||
604 | ret = acpi_dev_runtime_suspend(dev); | ||
605 | if (ret) | ||
606 | return ret; | ||
607 | |||
608 | if (pdata->dev_desc->flags & LPSS_PROXY_REQ && proxy_device) | ||
609 | return pm_runtime_put_sync_suspend(proxy_device); | ||
610 | |||
611 | return 0; | ||
583 | } | 612 | } |
584 | 613 | ||
585 | static int acpi_lpss_runtime_resume(struct device *dev) | 614 | static int acpi_lpss_runtime_resume(struct device *dev) |
586 | { | 615 | { |
587 | int ret = acpi_dev_runtime_resume(dev); | 616 | struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); |
617 | int ret; | ||
618 | |||
619 | if (pdata->dev_desc->flags & LPSS_PROXY_REQ && proxy_device) { | ||
620 | ret = pm_runtime_get_sync(proxy_device); | ||
621 | if (ret) | ||
622 | return ret; | ||
623 | } | ||
588 | 624 | ||
625 | ret = acpi_dev_runtime_resume(dev); | ||
589 | if (ret) | 626 | if (ret) |
590 | return ret; | 627 | return ret; |
591 | 628 | ||
592 | acpi_lpss_restore_ctx(dev); | 629 | if (pdata->dev_desc->flags & LPSS_SAVE_CTX) |
630 | acpi_lpss_restore_ctx(dev, pdata); | ||
631 | |||
593 | return pm_generic_runtime_resume(dev); | 632 | return pm_generic_runtime_resume(dev); |
594 | } | 633 | } |
595 | #endif /* CONFIG_PM_RUNTIME */ | 634 | #endif /* CONFIG_PM_RUNTIME */ |
@@ -631,30 +670,27 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb, | |||
631 | return 0; | 670 | return 0; |
632 | 671 | ||
633 | pdata = acpi_driver_data(adev); | 672 | pdata = acpi_driver_data(adev); |
634 | if (!pdata || !pdata->mmio_base) | 673 | if (!pdata) |
635 | return 0; | 674 | return 0; |
636 | 675 | ||
637 | if (pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) { | 676 | if (pdata->mmio_base && |
677 | pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) { | ||
638 | dev_err(&pdev->dev, "MMIO size insufficient to access LTR\n"); | 678 | dev_err(&pdev->dev, "MMIO size insufficient to access LTR\n"); |
639 | return 0; | 679 | return 0; |
640 | } | 680 | } |
641 | 681 | ||
642 | switch (action) { | 682 | switch (action) { |
643 | case BUS_NOTIFY_BOUND_DRIVER: | ||
644 | if (pdata->dev_desc->flags & LPSS_SAVE_CTX) | ||
645 | pdev->dev.pm_domain = &acpi_lpss_pm_domain; | ||
646 | break; | ||
647 | case BUS_NOTIFY_UNBOUND_DRIVER: | ||
648 | if (pdata->dev_desc->flags & LPSS_SAVE_CTX) | ||
649 | pdev->dev.pm_domain = NULL; | ||
650 | break; | ||
651 | case BUS_NOTIFY_ADD_DEVICE: | 683 | case BUS_NOTIFY_ADD_DEVICE: |
684 | pdev->dev.pm_domain = &acpi_lpss_pm_domain; | ||
652 | if (pdata->dev_desc->flags & LPSS_LTR) | 685 | if (pdata->dev_desc->flags & LPSS_LTR) |
653 | return sysfs_create_group(&pdev->dev.kobj, | 686 | return sysfs_create_group(&pdev->dev.kobj, |
654 | &lpss_attr_group); | 687 | &lpss_attr_group); |
688 | break; | ||
655 | case BUS_NOTIFY_DEL_DEVICE: | 689 | case BUS_NOTIFY_DEL_DEVICE: |
656 | if (pdata->dev_desc->flags & LPSS_LTR) | 690 | if (pdata->dev_desc->flags & LPSS_LTR) |
657 | sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group); | 691 | sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group); |
692 | pdev->dev.pm_domain = NULL; | ||
693 | break; | ||
658 | default: | 694 | default: |
659 | break; | 695 | break; |
660 | } | 696 | } |