diff options
| author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-06-03 17:12:09 -0400 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-06-03 17:12:09 -0400 |
| commit | 864e055f44a5701cb033bf3afa2b6cc37ddba678 (patch) | |
| tree | 9843c97302482f2a5da16c3c89bdeceec280e8fb | |
| parent | 6ad29246e3053085fdf28b5aa2a248ec787b3446 (diff) | |
| parent | 3022f4de491c096650d55ae9d562a9c811830724 (diff) | |
Merge branch 'acpi-lpss'
* acpi-lpss:
ACPI / LPSS: support for fractional divider clock
ACPI / LPSS: custom power domain for LPSS
| -rw-r--r-- | drivers/acpi/acpi_lpss.c | 232 |
1 files changed, 202 insertions, 30 deletions
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 0e9c0d38b85c..db362a96c38e 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 | ||
| @@ -28,6 +29,7 @@ ACPI_MODULE_NAME("acpi_lpss"); | |||
| 28 | #define LPSS_LTR_SIZE 0x18 | 29 | #define LPSS_LTR_SIZE 0x18 |
| 29 | 30 | ||
| 30 | /* Offsets relative to LPSS_PRIVATE_OFFSET */ | 31 | /* Offsets relative to LPSS_PRIVATE_OFFSET */ |
| 32 | #define LPSS_CLK_DIVIDER_DEF_MASK (BIT(1) | BIT(16)) | ||
| 31 | #define LPSS_GENERAL 0x08 | 33 | #define LPSS_GENERAL 0x08 |
| 32 | #define LPSS_GENERAL_LTR_MODE_SW BIT(2) | 34 | #define LPSS_GENERAL_LTR_MODE_SW BIT(2) |
| 33 | #define LPSS_GENERAL_UART_RTS_OVRD BIT(3) | 35 | #define LPSS_GENERAL_UART_RTS_OVRD BIT(3) |
| @@ -43,6 +45,8 @@ ACPI_MODULE_NAME("acpi_lpss"); | |||
| 43 | #define LPSS_TX_INT 0x20 | 45 | #define LPSS_TX_INT 0x20 |
| 44 | #define LPSS_TX_INT_MASK BIT(1) | 46 | #define LPSS_TX_INT_MASK BIT(1) |
| 45 | 47 | ||
| 48 | #define LPSS_PRV_REG_COUNT 9 | ||
| 49 | |||
| 46 | struct lpss_shared_clock { | 50 | struct lpss_shared_clock { |
| 47 | const char *name; | 51 | const char *name; |
| 48 | unsigned long rate; | 52 | unsigned long rate; |
| @@ -57,7 +61,9 @@ struct lpss_device_desc { | |||
| 57 | bool ltr_required; | 61 | bool ltr_required; |
| 58 | unsigned int prv_offset; | 62 | unsigned int prv_offset; |
| 59 | size_t prv_size_override; | 63 | size_t prv_size_override; |
| 64 | bool clk_divider; | ||
| 60 | bool clk_gate; | 65 | bool clk_gate; |
| 66 | bool save_ctx; | ||
| 61 | struct lpss_shared_clock *shared_clock; | 67 | struct lpss_shared_clock *shared_clock; |
| 62 | void (*setup)(struct lpss_private_data *pdata); | 68 | void (*setup)(struct lpss_private_data *pdata); |
| 63 | }; | 69 | }; |
| @@ -72,6 +78,7 @@ struct lpss_private_data { | |||
| 72 | resource_size_t mmio_size; | 78 | resource_size_t mmio_size; |
| 73 | struct clk *clk; | 79 | struct clk *clk; |
| 74 | const struct lpss_device_desc *dev_desc; | 80 | const struct lpss_device_desc *dev_desc; |
| 81 | u32 prv_reg_ctx[LPSS_PRV_REG_COUNT]; | ||
| 75 | }; | 82 | }; |
| 76 | 83 | ||
| 77 | static void lpss_uart_setup(struct lpss_private_data *pdata) | 84 | static void lpss_uart_setup(struct lpss_private_data *pdata) |
| @@ -92,6 +99,14 @@ static struct lpss_device_desc lpt_dev_desc = { | |||
| 92 | .clk_required = true, | 99 | .clk_required = true, |
| 93 | .prv_offset = 0x800, | 100 | .prv_offset = 0x800, |
| 94 | .ltr_required = true, | 101 | .ltr_required = true, |
| 102 | .clk_divider = true, | ||
| 103 | .clk_gate = true, | ||
| 104 | }; | ||
| 105 | |||
| 106 | static struct lpss_device_desc lpt_i2c_dev_desc = { | ||
| 107 | .clk_required = true, | ||
| 108 | .prv_offset = 0x800, | ||
| 109 | .ltr_required = true, | ||
| 95 | .clk_gate = true, | 110 | .clk_gate = true, |
| 96 | }; | 111 | }; |
| 97 | 112 | ||
| @@ -99,6 +114,7 @@ static struct lpss_device_desc lpt_uart_dev_desc = { | |||
| 99 | .clk_required = true, | 114 | .clk_required = true, |
| 100 | .prv_offset = 0x800, | 115 | .prv_offset = 0x800, |
| 101 | .ltr_required = true, | 116 | .ltr_required = true, |
| 117 | .clk_divider = true, | ||
| 102 | .clk_gate = true, | 118 | .clk_gate = true, |
| 103 | .setup = lpss_uart_setup, | 119 | .setup = lpss_uart_setup, |
| 104 | }; | 120 | }; |
| @@ -116,32 +132,25 @@ static struct lpss_shared_clock pwm_clock = { | |||
| 116 | 132 | ||
| 117 | static struct lpss_device_desc byt_pwm_dev_desc = { | 133 | static struct lpss_device_desc byt_pwm_dev_desc = { |
| 118 | .clk_required = true, | 134 | .clk_required = true, |
| 135 | .save_ctx = true, | ||
| 119 | .shared_clock = &pwm_clock, | 136 | .shared_clock = &pwm_clock, |
| 120 | }; | 137 | }; |
| 121 | 138 | ||
| 122 | static struct lpss_shared_clock uart_clock = { | ||
| 123 | .name = "uart_clk", | ||
| 124 | .rate = 44236800, | ||
| 125 | }; | ||
| 126 | |||
| 127 | static struct lpss_device_desc byt_uart_dev_desc = { | 139 | static struct lpss_device_desc byt_uart_dev_desc = { |
| 128 | .clk_required = true, | 140 | .clk_required = true, |
| 129 | .prv_offset = 0x800, | 141 | .prv_offset = 0x800, |
| 142 | .clk_divider = true, | ||
| 130 | .clk_gate = true, | 143 | .clk_gate = true, |
| 131 | .shared_clock = &uart_clock, | 144 | .save_ctx = true, |
| 132 | .setup = lpss_uart_setup, | 145 | .setup = lpss_uart_setup, |
| 133 | }; | 146 | }; |
| 134 | 147 | ||
| 135 | static struct lpss_shared_clock spi_clock = { | ||
| 136 | .name = "spi_clk", | ||
| 137 | .rate = 50000000, | ||
| 138 | }; | ||
| 139 | |||
| 140 | static struct lpss_device_desc byt_spi_dev_desc = { | 148 | static struct lpss_device_desc byt_spi_dev_desc = { |
| 141 | .clk_required = true, | 149 | .clk_required = true, |
| 142 | .prv_offset = 0x400, | 150 | .prv_offset = 0x400, |
| 151 | .clk_divider = true, | ||
| 143 | .clk_gate = true, | 152 | .clk_gate = true, |
| 144 | .shared_clock = &spi_clock, | 153 | .save_ctx = true, |
| 145 | }; | 154 | }; |
| 146 | 155 | ||
| 147 | static struct lpss_device_desc byt_sdio_dev_desc = { | 156 | static struct lpss_device_desc byt_sdio_dev_desc = { |
| @@ -156,6 +165,7 @@ static struct lpss_shared_clock i2c_clock = { | |||
| 156 | static struct lpss_device_desc byt_i2c_dev_desc = { | 165 | static struct lpss_device_desc byt_i2c_dev_desc = { |
| 157 | .clk_required = true, | 166 | .clk_required = true, |
| 158 | .prv_offset = 0x800, | 167 | .prv_offset = 0x800, |
| 168 | .save_ctx = true, | ||
| 159 | .shared_clock = &i2c_clock, | 169 | .shared_clock = &i2c_clock, |
| 160 | }; | 170 | }; |
| 161 | 171 | ||
| @@ -166,8 +176,8 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = { | |||
| 166 | /* Lynxpoint LPSS devices */ | 176 | /* Lynxpoint LPSS devices */ |
| 167 | { "INT33C0", (unsigned long)&lpt_dev_desc }, | 177 | { "INT33C0", (unsigned long)&lpt_dev_desc }, |
| 168 | { "INT33C1", (unsigned long)&lpt_dev_desc }, | 178 | { "INT33C1", (unsigned long)&lpt_dev_desc }, |
| 169 | { "INT33C2", (unsigned long)&lpt_dev_desc }, | 179 | { "INT33C2", (unsigned long)&lpt_i2c_dev_desc }, |
| 170 | { "INT33C3", (unsigned long)&lpt_dev_desc }, | 180 | { "INT33C3", (unsigned long)&lpt_i2c_dev_desc }, |
| 171 | { "INT33C4", (unsigned long)&lpt_uart_dev_desc }, | 181 | { "INT33C4", (unsigned long)&lpt_uart_dev_desc }, |
| 172 | { "INT33C5", (unsigned long)&lpt_uart_dev_desc }, | 182 | { "INT33C5", (unsigned long)&lpt_uart_dev_desc }, |
| 173 | { "INT33C6", (unsigned long)&lpt_sdio_dev_desc }, | 183 | { "INT33C6", (unsigned long)&lpt_sdio_dev_desc }, |
| @@ -183,8 +193,8 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = { | |||
| 183 | 193 | ||
| 184 | { "INT3430", (unsigned long)&lpt_dev_desc }, | 194 | { "INT3430", (unsigned long)&lpt_dev_desc }, |
| 185 | { "INT3431", (unsigned long)&lpt_dev_desc }, | 195 | { "INT3431", (unsigned long)&lpt_dev_desc }, |
| 186 | { "INT3432", (unsigned long)&lpt_dev_desc }, | 196 | { "INT3432", (unsigned long)&lpt_i2c_dev_desc }, |
| 187 | { "INT3433", (unsigned long)&lpt_dev_desc }, | 197 | { "INT3433", (unsigned long)&lpt_i2c_dev_desc }, |
| 188 | { "INT3434", (unsigned long)&lpt_uart_dev_desc }, | 198 | { "INT3434", (unsigned long)&lpt_uart_dev_desc }, |
| 189 | { "INT3435", (unsigned long)&lpt_uart_dev_desc }, | 199 | { "INT3435", (unsigned long)&lpt_uart_dev_desc }, |
| 190 | { "INT3436", (unsigned long)&lpt_sdio_dev_desc }, | 200 | { "INT3436", (unsigned long)&lpt_sdio_dev_desc }, |
| @@ -212,9 +222,11 @@ static int register_device_clock(struct acpi_device *adev, | |||
| 212 | { | 222 | { |
| 213 | const struct lpss_device_desc *dev_desc = pdata->dev_desc; | 223 | const struct lpss_device_desc *dev_desc = pdata->dev_desc; |
| 214 | struct lpss_shared_clock *shared_clock = dev_desc->shared_clock; | 224 | struct lpss_shared_clock *shared_clock = dev_desc->shared_clock; |
| 225 | const char *devname = dev_name(&adev->dev); | ||
| 215 | struct clk *clk = ERR_PTR(-ENODEV); | 226 | struct clk *clk = ERR_PTR(-ENODEV); |
| 216 | struct lpss_clk_data *clk_data; | 227 | struct lpss_clk_data *clk_data; |
| 217 | const char *parent; | 228 | const char *parent, *clk_name; |
| 229 | void __iomem *prv_base; | ||
| 218 | 230 | ||
| 219 | if (!lpss_clk_dev) | 231 | if (!lpss_clk_dev) |
| 220 | lpt_register_clock_device(); | 232 | lpt_register_clock_device(); |
| @@ -225,7 +237,7 @@ static int register_device_clock(struct acpi_device *adev, | |||
| 225 | 237 | ||
| 226 | if (dev_desc->clkdev_name) { | 238 | if (dev_desc->clkdev_name) { |
| 227 | clk_register_clkdev(clk_data->clk, dev_desc->clkdev_name, | 239 | clk_register_clkdev(clk_data->clk, dev_desc->clkdev_name, |
| 228 | dev_name(&adev->dev)); | 240 | devname); |
| 229 | return 0; | 241 | return 0; |
| 230 | } | 242 | } |
| 231 | 243 | ||
| @@ -234,6 +246,7 @@ static int register_device_clock(struct acpi_device *adev, | |||
| 234 | return -ENODATA; | 246 | return -ENODATA; |
| 235 | 247 | ||
| 236 | parent = clk_data->name; | 248 | parent = clk_data->name; |
| 249 | prv_base = pdata->mmio_base + dev_desc->prv_offset; | ||
| 237 | 250 | ||
| 238 | if (shared_clock) { | 251 | if (shared_clock) { |
| 239 | clk = shared_clock->clk; | 252 | clk = shared_clock->clk; |
| @@ -247,16 +260,41 @@ static int register_device_clock(struct acpi_device *adev, | |||
| 247 | } | 260 | } |
| 248 | 261 | ||
| 249 | if (dev_desc->clk_gate) { | 262 | if (dev_desc->clk_gate) { |
| 250 | clk = clk_register_gate(NULL, dev_name(&adev->dev), parent, 0, | 263 | clk = clk_register_gate(NULL, devname, parent, 0, |
| 251 | pdata->mmio_base + dev_desc->prv_offset, | 264 | prv_base, 0, 0, NULL); |
| 252 | 0, 0, NULL); | 265 | parent = devname; |
| 253 | pdata->clk = clk; | 266 | } |
| 267 | |||
| 268 | if (dev_desc->clk_divider) { | ||
| 269 | /* Prevent division by zero */ | ||
| 270 | if (!readl(prv_base)) | ||
| 271 | writel(LPSS_CLK_DIVIDER_DEF_MASK, prv_base); | ||
| 272 | |||
| 273 | clk_name = kasprintf(GFP_KERNEL, "%s-div", devname); | ||
| 274 | if (!clk_name) | ||
| 275 | return -ENOMEM; | ||
| 276 | clk = clk_register_fractional_divider(NULL, clk_name, parent, | ||
| 277 | 0, prv_base, | ||
| 278 | 1, 15, 16, 15, 0, NULL); | ||
| 279 | parent = clk_name; | ||
| 280 | |||
| 281 | clk_name = kasprintf(GFP_KERNEL, "%s-update", devname); | ||
| 282 | if (!clk_name) { | ||
| 283 | kfree(parent); | ||
| 284 | return -ENOMEM; | ||
| 285 | } | ||
| 286 | clk = clk_register_gate(NULL, clk_name, parent, | ||
| 287 | CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, | ||
| 288 | prv_base, 31, 0, NULL); | ||
| 289 | kfree(parent); | ||
| 290 | kfree(clk_name); | ||
| 254 | } | 291 | } |
| 255 | 292 | ||
| 256 | if (IS_ERR(clk)) | 293 | if (IS_ERR(clk)) |
| 257 | return PTR_ERR(clk); | 294 | return PTR_ERR(clk); |
| 258 | 295 | ||
| 259 | clk_register_clkdev(clk, NULL, dev_name(&adev->dev)); | 296 | pdata->clk = clk; |
| 297 | clk_register_clkdev(clk, NULL, devname); | ||
| 260 | return 0; | 298 | return 0; |
| 261 | } | 299 | } |
| 262 | 300 | ||
| @@ -454,6 +492,126 @@ static void acpi_lpss_set_ltr(struct device *dev, s32 val) | |||
| 454 | } | 492 | } |
| 455 | } | 493 | } |
| 456 | 494 | ||
| 495 | #ifdef CONFIG_PM | ||
| 496 | /** | ||
| 497 | * acpi_lpss_save_ctx() - Save the private registers of LPSS device | ||
| 498 | * @dev: LPSS device | ||
| 499 | * | ||
| 500 | * Most LPSS devices have private registers which may loose their context when | ||
| 501 | * the device is powered down. acpi_lpss_save_ctx() saves those registers into | ||
| 502 | * prv_reg_ctx array. | ||
| 503 | */ | ||
| 504 | static void acpi_lpss_save_ctx(struct device *dev) | ||
| 505 | { | ||
| 506 | struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); | ||
| 507 | unsigned int i; | ||
| 508 | |||
| 509 | for (i = 0; i < LPSS_PRV_REG_COUNT; i++) { | ||
| 510 | unsigned long offset = i * sizeof(u32); | ||
| 511 | |||
| 512 | pdata->prv_reg_ctx[i] = __lpss_reg_read(pdata, offset); | ||
| 513 | dev_dbg(dev, "saving 0x%08x from LPSS reg at offset 0x%02lx\n", | ||
| 514 | pdata->prv_reg_ctx[i], offset); | ||
| 515 | } | ||
| 516 | } | ||
| 517 | |||
| 518 | /** | ||
| 519 | * acpi_lpss_restore_ctx() - Restore the private registers of LPSS device | ||
| 520 | * @dev: LPSS device | ||
| 521 | * | ||
| 522 | * Restores the registers that were previously stored with acpi_lpss_save_ctx(). | ||
| 523 | */ | ||
| 524 | static void acpi_lpss_restore_ctx(struct device *dev) | ||
| 525 | { | ||
| 526 | struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); | ||
| 527 | unsigned int i; | ||
| 528 | |||
| 529 | /* | ||
| 530 | * The following delay is needed or the subsequent write operations may | ||
| 531 | * fail. The LPSS devices are actually PCI devices and the PCI spec | ||
| 532 | * expects 10ms delay before the device can be accessed after D3 to D0 | ||
| 533 | * transition. | ||
| 534 | */ | ||
| 535 | msleep(10); | ||
| 536 | |||
| 537 | for (i = 0; i < LPSS_PRV_REG_COUNT; i++) { | ||
| 538 | unsigned long offset = i * sizeof(u32); | ||
| 539 | |||
| 540 | __lpss_reg_write(pdata->prv_reg_ctx[i], pdata, offset); | ||
| 541 | dev_dbg(dev, "restoring 0x%08x to LPSS reg at offset 0x%02lx\n", | ||
| 542 | pdata->prv_reg_ctx[i], offset); | ||
| 543 | } | ||
| 544 | } | ||
| 545 | |||
| 546 | #ifdef CONFIG_PM_SLEEP | ||
| 547 | static int acpi_lpss_suspend_late(struct device *dev) | ||
| 548 | { | ||
| 549 | int ret = pm_generic_suspend_late(dev); | ||
| 550 | |||
| 551 | if (ret) | ||
| 552 | return ret; | ||
| 553 | |||
| 554 | acpi_lpss_save_ctx(dev); | ||
| 555 | return acpi_dev_suspend_late(dev); | ||
| 556 | } | ||
| 557 | |||
| 558 | static int acpi_lpss_restore_early(struct device *dev) | ||
| 559 | { | ||
| 560 | int ret = acpi_dev_resume_early(dev); | ||
| 561 | |||
| 562 | if (ret) | ||
| 563 | return ret; | ||
| 564 | |||
| 565 | acpi_lpss_restore_ctx(dev); | ||
| 566 | return pm_generic_resume_early(dev); | ||
| 567 | } | ||
| 568 | #endif /* CONFIG_PM_SLEEP */ | ||
| 569 | |||
| 570 | #ifdef CONFIG_PM_RUNTIME | ||
| 571 | static int acpi_lpss_runtime_suspend(struct device *dev) | ||
| 572 | { | ||
| 573 | int ret = pm_generic_runtime_suspend(dev); | ||
| 574 | |||
| 575 | if (ret) | ||
| 576 | return ret; | ||
| 577 | |||
| 578 | acpi_lpss_save_ctx(dev); | ||
| 579 | return acpi_dev_runtime_suspend(dev); | ||
| 580 | } | ||
| 581 | |||
| 582 | static int acpi_lpss_runtime_resume(struct device *dev) | ||
| 583 | { | ||
| 584 | int ret = acpi_dev_runtime_resume(dev); | ||
| 585 | |||
| 586 | if (ret) | ||
| 587 | return ret; | ||
| 588 | |||
| 589 | acpi_lpss_restore_ctx(dev); | ||
| 590 | return pm_generic_runtime_resume(dev); | ||
| 591 | } | ||
| 592 | #endif /* CONFIG_PM_RUNTIME */ | ||
| 593 | #endif /* CONFIG_PM */ | ||
| 594 | |||
| 595 | static struct dev_pm_domain acpi_lpss_pm_domain = { | ||
| 596 | .ops = { | ||
| 597 | #ifdef CONFIG_PM_SLEEP | ||
| 598 | .suspend_late = acpi_lpss_suspend_late, | ||
| 599 | .restore_early = acpi_lpss_restore_early, | ||
| 600 | .prepare = acpi_subsys_prepare, | ||
| 601 | .complete = acpi_subsys_complete, | ||
| 602 | .suspend = acpi_subsys_suspend, | ||
| 603 | .resume_early = acpi_subsys_resume_early, | ||
| 604 | .freeze = acpi_subsys_freeze, | ||
| 605 | .poweroff = acpi_subsys_suspend, | ||
| 606 | .poweroff_late = acpi_subsys_suspend_late, | ||
| 607 | #endif | ||
| 608 | #ifdef CONFIG_PM_RUNTIME | ||
| 609 | .runtime_suspend = acpi_lpss_runtime_suspend, | ||
| 610 | .runtime_resume = acpi_lpss_runtime_resume, | ||
| 611 | #endif | ||
| 612 | }, | ||
| 613 | }; | ||
| 614 | |||
| 457 | static int acpi_lpss_platform_notify(struct notifier_block *nb, | 615 | static int acpi_lpss_platform_notify(struct notifier_block *nb, |
| 458 | unsigned long action, void *data) | 616 | unsigned long action, void *data) |
| 459 | { | 617 | { |
| @@ -461,7 +619,6 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb, | |||
| 461 | struct lpss_private_data *pdata; | 619 | struct lpss_private_data *pdata; |
| 462 | struct acpi_device *adev; | 620 | struct acpi_device *adev; |
| 463 | const struct acpi_device_id *id; | 621 | const struct acpi_device_id *id; |
| 464 | int ret = 0; | ||
| 465 | 622 | ||
| 466 | id = acpi_match_device(acpi_lpss_device_ids, &pdev->dev); | 623 | id = acpi_match_device(acpi_lpss_device_ids, &pdev->dev); |
| 467 | if (!id || !id->driver_data) | 624 | if (!id || !id->driver_data) |
| @@ -471,7 +628,7 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb, | |||
| 471 | return 0; | 628 | return 0; |
| 472 | 629 | ||
| 473 | pdata = acpi_driver_data(adev); | 630 | pdata = acpi_driver_data(adev); |
| 474 | if (!pdata || !pdata->mmio_base || !pdata->dev_desc->ltr_required) | 631 | if (!pdata || !pdata->mmio_base) |
| 475 | return 0; | 632 | return 0; |
| 476 | 633 | ||
| 477 | if (pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) { | 634 | if (pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) { |
| @@ -479,12 +636,27 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb, | |||
| 479 | return 0; | 636 | return 0; |
| 480 | } | 637 | } |
| 481 | 638 | ||
| 482 | if (action == BUS_NOTIFY_ADD_DEVICE) | 639 | switch (action) { |
| 483 | ret = sysfs_create_group(&pdev->dev.kobj, &lpss_attr_group); | 640 | case BUS_NOTIFY_BOUND_DRIVER: |
| 484 | else if (action == BUS_NOTIFY_DEL_DEVICE) | 641 | if (pdata->dev_desc->save_ctx) |
| 485 | sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group); | 642 | pdev->dev.pm_domain = &acpi_lpss_pm_domain; |
| 643 | break; | ||
| 644 | case BUS_NOTIFY_UNBOUND_DRIVER: | ||
| 645 | if (pdata->dev_desc->save_ctx) | ||
| 646 | pdev->dev.pm_domain = NULL; | ||
| 647 | break; | ||
| 648 | case BUS_NOTIFY_ADD_DEVICE: | ||
| 649 | if (pdata->dev_desc->ltr_required) | ||
| 650 | return sysfs_create_group(&pdev->dev.kobj, | ||
| 651 | &lpss_attr_group); | ||
| 652 | case BUS_NOTIFY_DEL_DEVICE: | ||
| 653 | if (pdata->dev_desc->ltr_required) | ||
| 654 | sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group); | ||
| 655 | default: | ||
| 656 | break; | ||
| 657 | } | ||
| 486 | 658 | ||
| 487 | return ret; | 659 | return 0; |
| 488 | } | 660 | } |
| 489 | 661 | ||
| 490 | static struct notifier_block acpi_lpss_nb = { | 662 | static struct notifier_block acpi_lpss_nb = { |
