aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeikki Krogerus <heikki.krogerus@linux.intel.com>2014-05-23 09:15:09 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-05-25 08:40:28 -0400
commitc78b0830667a7e7c1f0ca65b76b33166a84806b3 (patch)
treee49dbc23ff2132c95842342a3010c464300b70a9
parent4cf563c5d97c83d4b2fb3a778dd7d5e362cc3e34 (diff)
ACPI / LPSS: custom power domain for LPSS
A power domain where we save the context of the additional LPSS registers. We need to do this or all LPSS devices are left in reset state when resuming from D3 on some Baytrails. The devices with the fractional clock divider also have zeros for N and M values after resuming unless they are reset. Li Aubrey found the root cause for the issue. The idea of using power domain for LPSS came from Mika Westerberg. Reported-by: Jin Yao <yao.jin@linux.intel.com> Suggested-by: Li Aubrey <aubrey.li@linux.intel.com> Suggested-by: Mika Westerberg <mika.westerberg@linux.intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com> Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> [rjw: Added the .complete() callback to the PM domain, fixed build warning on 32-bit.] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/acpi/acpi_lpss.c157
1 files changed, 150 insertions, 7 deletions
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index 69e29f409d4c..a01d4d1343dd 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -19,6 +19,7 @@
19#include <linux/platform_device.h> 19#include <linux/platform_device.h>
20#include <linux/platform_data/clk-lpss.h> 20#include <linux/platform_data/clk-lpss.h>
21#include <linux/pm_runtime.h> 21#include <linux/pm_runtime.h>
22#include <linux/delay.h>
22 23
23#include "internal.h" 24#include "internal.h"
24 25
@@ -43,6 +44,8 @@ ACPI_MODULE_NAME("acpi_lpss");
43#define LPSS_TX_INT 0x20 44#define LPSS_TX_INT 0x20
44#define LPSS_TX_INT_MASK BIT(1) 45#define LPSS_TX_INT_MASK BIT(1)
45 46
47#define LPSS_PRV_REG_COUNT 9
48
46struct lpss_shared_clock { 49struct lpss_shared_clock {
47 const char *name; 50 const char *name;
48 unsigned long rate; 51 unsigned long rate;
@@ -58,6 +61,7 @@ struct lpss_device_desc {
58 unsigned int prv_offset; 61 unsigned int prv_offset;
59 size_t prv_size_override; 62 size_t prv_size_override;
60 bool clk_gate; 63 bool clk_gate;
64 bool save_ctx;
61 struct lpss_shared_clock *shared_clock; 65 struct lpss_shared_clock *shared_clock;
62 void (*setup)(struct lpss_private_data *pdata); 66 void (*setup)(struct lpss_private_data *pdata);
63}; 67};
@@ -72,6 +76,7 @@ struct lpss_private_data {
72 resource_size_t mmio_size; 76 resource_size_t mmio_size;
73 struct clk *clk; 77 struct clk *clk;
74 const struct lpss_device_desc *dev_desc; 78 const struct lpss_device_desc *dev_desc;
79 u32 prv_reg_ctx[LPSS_PRV_REG_COUNT];
75}; 80};
76 81
77static void lpss_uart_setup(struct lpss_private_data *pdata) 82static void lpss_uart_setup(struct lpss_private_data *pdata)
@@ -116,6 +121,7 @@ static struct lpss_shared_clock pwm_clock = {
116 121
117static struct lpss_device_desc byt_pwm_dev_desc = { 122static struct lpss_device_desc byt_pwm_dev_desc = {
118 .clk_required = true, 123 .clk_required = true,
124 .save_ctx = true,
119 .shared_clock = &pwm_clock, 125 .shared_clock = &pwm_clock,
120}; 126};
121 127
@@ -128,6 +134,7 @@ static struct lpss_device_desc byt_uart_dev_desc = {
128 .clk_required = true, 134 .clk_required = true,
129 .prv_offset = 0x800, 135 .prv_offset = 0x800,
130 .clk_gate = true, 136 .clk_gate = true,
137 .save_ctx = true,
131 .shared_clock = &uart_clock, 138 .shared_clock = &uart_clock,
132 .setup = lpss_uart_setup, 139 .setup = lpss_uart_setup,
133}; 140};
@@ -141,6 +148,7 @@ static struct lpss_device_desc byt_spi_dev_desc = {
141 .clk_required = true, 148 .clk_required = true,
142 .prv_offset = 0x400, 149 .prv_offset = 0x400,
143 .clk_gate = true, 150 .clk_gate = true,
151 .save_ctx = true,
144 .shared_clock = &spi_clock, 152 .shared_clock = &spi_clock,
145}; 153};
146 154
@@ -156,6 +164,7 @@ static struct lpss_shared_clock i2c_clock = {
156static struct lpss_device_desc byt_i2c_dev_desc = { 164static struct lpss_device_desc byt_i2c_dev_desc = {
157 .clk_required = true, 165 .clk_required = true,
158 .prv_offset = 0x800, 166 .prv_offset = 0x800,
167 .save_ctx = true,
159 .shared_clock = &i2c_clock, 168 .shared_clock = &i2c_clock,
160}; 169};
161 170
@@ -449,6 +458,126 @@ static void acpi_lpss_set_ltr(struct device *dev, s32 val)
449 } 458 }
450} 459}
451 460
461#ifdef CONFIG_PM
462/**
463 * acpi_lpss_save_ctx() - Save the private registers of LPSS device
464 * @dev: LPSS device
465 *
466 * Most LPSS devices have private registers which may loose their context when
467 * the device is powered down. acpi_lpss_save_ctx() saves those registers into
468 * prv_reg_ctx array.
469 */
470static void acpi_lpss_save_ctx(struct device *dev)
471{
472 struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
473 unsigned int i;
474
475 for (i = 0; i < LPSS_PRV_REG_COUNT; i++) {
476 unsigned long offset = i * sizeof(u32);
477
478 pdata->prv_reg_ctx[i] = __lpss_reg_read(pdata, offset);
479 dev_dbg(dev, "saving 0x%08x from LPSS reg at offset 0x%02lx\n",
480 pdata->prv_reg_ctx[i], offset);
481 }
482}
483
484/**
485 * acpi_lpss_restore_ctx() - Restore the private registers of LPSS device
486 * @dev: LPSS device
487 *
488 * Restores the registers that were previously stored with acpi_lpss_save_ctx().
489 */
490static void acpi_lpss_restore_ctx(struct device *dev)
491{
492 struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
493 unsigned int i;
494
495 /*
496 * The following delay is needed or the subsequent write operations may
497 * fail. The LPSS devices are actually PCI devices and the PCI spec
498 * expects 10ms delay before the device can be accessed after D3 to D0
499 * transition.
500 */
501 msleep(10);
502
503 for (i = 0; i < LPSS_PRV_REG_COUNT; i++) {
504 unsigned long offset = i * sizeof(u32);
505
506 __lpss_reg_write(pdata->prv_reg_ctx[i], pdata, offset);
507 dev_dbg(dev, "restoring 0x%08x to LPSS reg at offset 0x%02lx\n",
508 pdata->prv_reg_ctx[i], offset);
509 }
510}
511
512#ifdef CONFIG_PM_SLEEP
513static int acpi_lpss_suspend_late(struct device *dev)
514{
515 int ret = pm_generic_suspend_late(dev);
516
517 if (ret)
518 return ret;
519
520 acpi_lpss_save_ctx(dev);
521 return acpi_dev_suspend_late(dev);
522}
523
524static int acpi_lpss_restore_early(struct device *dev)
525{
526 int ret = acpi_dev_resume_early(dev);
527
528 if (ret)
529 return ret;
530
531 acpi_lpss_restore_ctx(dev);
532 return pm_generic_resume_early(dev);
533}
534#endif /* CONFIG_PM_SLEEP */
535
536#ifdef CONFIG_PM_RUNTIME
537static int acpi_lpss_runtime_suspend(struct device *dev)
538{
539 int ret = pm_generic_runtime_suspend(dev);
540
541 if (ret)
542 return ret;
543
544 acpi_lpss_save_ctx(dev);
545 return acpi_dev_runtime_suspend(dev);
546}
547
548static int acpi_lpss_runtime_resume(struct device *dev)
549{
550 int ret = acpi_dev_runtime_resume(dev);
551
552 if (ret)
553 return ret;
554
555 acpi_lpss_restore_ctx(dev);
556 return pm_generic_runtime_resume(dev);
557}
558#endif /* CONFIG_PM_RUNTIME */
559#endif /* CONFIG_PM */
560
561static struct dev_pm_domain acpi_lpss_pm_domain = {
562 .ops = {
563#ifdef CONFIG_PM_SLEEP
564 .suspend_late = acpi_lpss_suspend_late,
565 .restore_early = acpi_lpss_restore_early,
566 .prepare = acpi_subsys_prepare,
567 .complete = acpi_subsys_complete,
568 .suspend = acpi_subsys_suspend,
569 .resume_early = acpi_subsys_resume_early,
570 .freeze = acpi_subsys_freeze,
571 .poweroff = acpi_subsys_suspend,
572 .poweroff_late = acpi_subsys_suspend_late,
573#endif
574#ifdef CONFIG_PM_RUNTIME
575 .runtime_suspend = acpi_lpss_runtime_suspend,
576 .runtime_resume = acpi_lpss_runtime_resume,
577#endif
578 },
579};
580
452static int acpi_lpss_platform_notify(struct notifier_block *nb, 581static int acpi_lpss_platform_notify(struct notifier_block *nb,
453 unsigned long action, void *data) 582 unsigned long action, void *data)
454{ 583{
@@ -456,7 +585,6 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb,
456 struct lpss_private_data *pdata; 585 struct lpss_private_data *pdata;
457 struct acpi_device *adev; 586 struct acpi_device *adev;
458 const struct acpi_device_id *id; 587 const struct acpi_device_id *id;
459 int ret = 0;
460 588
461 id = acpi_match_device(acpi_lpss_device_ids, &pdev->dev); 589 id = acpi_match_device(acpi_lpss_device_ids, &pdev->dev);
462 if (!id || !id->driver_data) 590 if (!id || !id->driver_data)
@@ -466,7 +594,7 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb,
466 return 0; 594 return 0;
467 595
468 pdata = acpi_driver_data(adev); 596 pdata = acpi_driver_data(adev);
469 if (!pdata || !pdata->mmio_base || !pdata->dev_desc->ltr_required) 597 if (!pdata || !pdata->mmio_base)
470 return 0; 598 return 0;
471 599
472 if (pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) { 600 if (pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) {
@@ -474,12 +602,27 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb,
474 return 0; 602 return 0;
475 } 603 }
476 604
477 if (action == BUS_NOTIFY_ADD_DEVICE) 605 switch (action) {
478 ret = sysfs_create_group(&pdev->dev.kobj, &lpss_attr_group); 606 case BUS_NOTIFY_BOUND_DRIVER:
479 else if (action == BUS_NOTIFY_DEL_DEVICE) 607 if (pdata->dev_desc->save_ctx)
480 sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group); 608 pdev->dev.pm_domain = &acpi_lpss_pm_domain;
609 break;
610 case BUS_NOTIFY_UNBOUND_DRIVER:
611 if (pdata->dev_desc->save_ctx)
612 pdev->dev.pm_domain = NULL;
613 break;
614 case BUS_NOTIFY_ADD_DEVICE:
615 if (pdata->dev_desc->ltr_required)
616 return sysfs_create_group(&pdev->dev.kobj,
617 &lpss_attr_group);
618 case BUS_NOTIFY_DEL_DEVICE:
619 if (pdata->dev_desc->ltr_required)
620 sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group);
621 default:
622 break;
623 }
481 624
482 return ret; 625 return 0;
483} 626}
484 627
485static struct notifier_block acpi_lpss_nb = { 628static struct notifier_block acpi_lpss_nb = {