aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/acpi_lpss.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-06-04 11:57:16 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-06-04 11:57:16 -0400
commit4dc4226f994db264c844a5fcf556935c66f963a5 (patch)
tree981bf2cb0005c3de8383d749942640d88cb852f2 /drivers/acpi/acpi_lpss.c
parentd6b92c2c373e0beefa8048c1448992cd5cda6e07 (diff)
parent2e30baad228624e3868714af6ecab967c4445d4a (diff)
Merge tag 'pm+acpi-3.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm into next
Pull ACPI and power management updates from Rafael Wysocki: "ACPICA is the leader this time (63 commits), followed by cpufreq (28 commits), devfreq (15 commits), system suspend/hibernation (12 commits), ACPI video and ACPI device enumeration (10 commits each). We have no major new features this time, but there are a few significant changes of how things work. The most visible one will probably be that we are now going to create platform devices rather than PNP devices by default for ACPI device objects with _HID. That was long overdue and will be really necessary to be able to use the same drivers for the same hardware blocks on ACPI and DT-based systems going forward. We're not expecting fallout from this one (as usual), but it's something to watch nevertheless. The second change having a chance to be visible is that ACPI video will now default to using native backlight rather than the ACPI backlight interface which should generally help systems with broken Win8 BIOSes. We're hoping that all problems with the native backlight handling that we had previously have been addressed and we are in a good enough shape to flip the default, but this change should be easy enough to revert if need be. In addition to that, the system suspend core has a new mechanism to allow runtime-suspended devices to stay suspended throughout system suspend/resume transitions if some extra conditions are met (generally, they are related to coordination within device hierarchy). However, enabling this feature requires cooperation from the bus type layer and for now it has only been implemented for the ACPI PM domain (used by ACPI-enumerated platform devices mostly today). Also, the acpidump utility that was previously shipped as a separate tool will now be provided by the upstream ACPICA along with the rest of ACPICA code, which will allow it to be more up to date and better supported, and we have one new cpuidle driver (ARM clps711x). The rest is improvements related to certain specific use cases, cleanups and fixes all over the place. Specifics: - ACPICA update to upstream version 20140424. That includes a number of fixes and improvements related to things like GPE handling, table loading, headers, memory mapping and unmapping, DSDT/SSDT overriding, and the Unload() operator. The acpidump utility from upstream ACPICA is included too. From Bob Moore, Lv Zheng, David Box, David Binderman, and Colin Ian King. - Fixes and cleanups related to ACPI video and backlight interfaces from Hans de Goede. That includes blacklist entries for some new machines and using native backlight by default. - ACPI device enumeration changes to create platform devices rather than PNP devices for ACPI device objects with _HID by default. PNP devices will still be created for the ACPI device object with device IDs corresponding to real PNP devices, so that change should not break things left and right, and we're expecting to see more and more ACPI-enumerated platform devices in the future. From Zhang Rui and Rafael J Wysocki. - Updates for the ACPI LPSS (Low-Power Subsystem) driver allowing it to handle system suspend/resume on Asus T100 correctly. From Heikki Krogerus and Rafael J Wysocki. - PM core update introducing a mechanism to allow runtime-suspended devices to stay suspended over system suspend/resume transitions if certain additional conditions related to coordination within device hierarchy are met. Related PM documentation update and ACPI PM domain support for the new feature. From Rafael J Wysocki. - Fixes and improvements related to the "freeze" sleep state. They affect several places including cpuidle, PM core, ACPI core, and the ACPI battery driver. From Rafael J Wysocki and Zhang Rui. - Miscellaneous fixes and updates of the ACPI core from Aaron Lu, Bjørn Mork, Hanjun Guo, Lan Tianyu, and Rafael J Wysocki. - Fixes and cleanups for the ACPI processor and ACPI PAD (Processor Aggregator Device) drivers from Baoquan He, Manuel Schölling, Tony Camuso, and Toshi Kani. - System suspend/resume optimization in the ACPI battery driver from Lan Tianyu. - OPP (Operating Performance Points) subsystem updates from Chander Kashyap, Mark Brown, and Nishanth Menon. - cpufreq core fixes, updates and cleanups from Srivatsa S Bhat, Stratos Karafotis, and Viresh Kumar. - Updates, fixes and cleanups for the Tegra, powernow-k8, imx6q, s5pv210, nforce2, and powernv cpufreq drivers from Brian Norris, Jingoo Han, Paul Bolle, Philipp Zabel, Stratos Karafotis, and Viresh Kumar. - intel_pstate driver fixes and cleanups from Dirk Brandewie, Doug Smythies, and Stratos Karafotis. - Enabling the big.LITTLE cpufreq driver on arm64 from Mark Brown. - Fix for the cpuidle menu governor from Chander Kashyap. - New ARM clps711x cpuidle driver from Alexander Shiyan. - Hibernate core fixes and cleanups from Chen Gang, Dan Carpenter, Fabian Frederick, Pali Rohár, and Sebastian Capella. - Intel RAPL (Running Average Power Limit) driver updates from Jacob Pan. - PNP subsystem updates from Bjorn Helgaas and Fabian Frederick. - devfreq core updates from Chanwoo Choi and Paul Bolle. - devfreq updates for exynos4 and exynos5 from Chanwoo Choi and Bartlomiej Zolnierkiewicz. - turbostat tool fix from Jean Delvare. - cpupower tool updates from Prarit Bhargava, Ramkumar Ramachandra and Thomas Renninger. - New ACPI ec_access.c tool for poking at the EC in a safe way from Thomas Renninger" * tag 'pm+acpi-3.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (187 commits) ACPICA: Namespace: Remove _PRP method support. intel_pstate: Improve initial busy calculation intel_pstate: add sample time scaling intel_pstate: Correct rounding in busy calculation intel_pstate: Remove C0 tracking PM / hibernate: fixed typo in comment ACPI: Fix x86 regression related to early mapping size limitation ACPICA: Tables: Add mechanism to control early table checksum verification. ACPI / scan: use platform bus type by default for _HID enumeration ACPI / scan: always register ACPI LPSS scan handler ACPI / scan: always register memory hotplug scan handler ACPI / scan: always register container scan handler ACPI / scan: Change the meaning of missing .attach() in scan handlers ACPI / scan: introduce platform_id device PNP type flag ACPI / scan: drop unsupported serial IDs from PNP ACPI scan handler ID list ACPI / scan: drop IDs that do not comply with the ACPI PNP ID rule ACPI / PNP: use device ID list for PNPACPI device enumeration ACPI / scan: .match() callback for ACPI scan handlers ACPI / battery: wakeup the system only when necessary power_supply: allow power supply devices registered w/o wakeup source ...
Diffstat (limited to 'drivers/acpi/acpi_lpss.c')
-rw-r--r--drivers/acpi/acpi_lpss.c306
1 files changed, 254 insertions, 52 deletions
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index d79c6d7f598e..63407d264885 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -19,15 +19,21 @@
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
25ACPI_MODULE_NAME("acpi_lpss"); 26ACPI_MODULE_NAME("acpi_lpss");
26 27
28#ifdef CONFIG_X86_INTEL_LPSS
29
30#define LPSS_ADDR(desc) ((unsigned long)&desc)
31
27#define LPSS_CLK_SIZE 0x04 32#define LPSS_CLK_SIZE 0x04
28#define LPSS_LTR_SIZE 0x18 33#define LPSS_LTR_SIZE 0x18
29 34
30/* Offsets relative to LPSS_PRIVATE_OFFSET */ 35/* Offsets relative to LPSS_PRIVATE_OFFSET */
36#define LPSS_CLK_DIVIDER_DEF_MASK (BIT(1) | BIT(16))
31#define LPSS_GENERAL 0x08 37#define LPSS_GENERAL 0x08
32#define LPSS_GENERAL_LTR_MODE_SW BIT(2) 38#define LPSS_GENERAL_LTR_MODE_SW BIT(2)
33#define LPSS_GENERAL_UART_RTS_OVRD BIT(3) 39#define LPSS_GENERAL_UART_RTS_OVRD BIT(3)
@@ -43,6 +49,8 @@ ACPI_MODULE_NAME("acpi_lpss");
43#define LPSS_TX_INT 0x20 49#define LPSS_TX_INT 0x20
44#define LPSS_TX_INT_MASK BIT(1) 50#define LPSS_TX_INT_MASK BIT(1)
45 51
52#define LPSS_PRV_REG_COUNT 9
53
46struct lpss_shared_clock { 54struct lpss_shared_clock {
47 const char *name; 55 const char *name;
48 unsigned long rate; 56 unsigned long rate;
@@ -57,7 +65,9 @@ struct lpss_device_desc {
57 bool ltr_required; 65 bool ltr_required;
58 unsigned int prv_offset; 66 unsigned int prv_offset;
59 size_t prv_size_override; 67 size_t prv_size_override;
68 bool clk_divider;
60 bool clk_gate; 69 bool clk_gate;
70 bool save_ctx;
61 struct lpss_shared_clock *shared_clock; 71 struct lpss_shared_clock *shared_clock;
62 void (*setup)(struct lpss_private_data *pdata); 72 void (*setup)(struct lpss_private_data *pdata);
63}; 73};
@@ -72,6 +82,7 @@ struct lpss_private_data {
72 resource_size_t mmio_size; 82 resource_size_t mmio_size;
73 struct clk *clk; 83 struct clk *clk;
74 const struct lpss_device_desc *dev_desc; 84 const struct lpss_device_desc *dev_desc;
85 u32 prv_reg_ctx[LPSS_PRV_REG_COUNT];
75}; 86};
76 87
77static void lpss_uart_setup(struct lpss_private_data *pdata) 88static void lpss_uart_setup(struct lpss_private_data *pdata)
@@ -92,6 +103,14 @@ static struct lpss_device_desc lpt_dev_desc = {
92 .clk_required = true, 103 .clk_required = true,
93 .prv_offset = 0x800, 104 .prv_offset = 0x800,
94 .ltr_required = true, 105 .ltr_required = true,
106 .clk_divider = true,
107 .clk_gate = true,
108};
109
110static struct lpss_device_desc lpt_i2c_dev_desc = {
111 .clk_required = true,
112 .prv_offset = 0x800,
113 .ltr_required = true,
95 .clk_gate = true, 114 .clk_gate = true,
96}; 115};
97 116
@@ -99,6 +118,7 @@ static struct lpss_device_desc lpt_uart_dev_desc = {
99 .clk_required = true, 118 .clk_required = true,
100 .prv_offset = 0x800, 119 .prv_offset = 0x800,
101 .ltr_required = true, 120 .ltr_required = true,
121 .clk_divider = true,
102 .clk_gate = true, 122 .clk_gate = true,
103 .setup = lpss_uart_setup, 123 .setup = lpss_uart_setup,
104}; 124};
@@ -116,32 +136,25 @@ static struct lpss_shared_clock pwm_clock = {
116 136
117static struct lpss_device_desc byt_pwm_dev_desc = { 137static struct lpss_device_desc byt_pwm_dev_desc = {
118 .clk_required = true, 138 .clk_required = true,
139 .save_ctx = true,
119 .shared_clock = &pwm_clock, 140 .shared_clock = &pwm_clock,
120}; 141};
121 142
122static struct lpss_shared_clock uart_clock = {
123 .name = "uart_clk",
124 .rate = 44236800,
125};
126
127static struct lpss_device_desc byt_uart_dev_desc = { 143static struct lpss_device_desc byt_uart_dev_desc = {
128 .clk_required = true, 144 .clk_required = true,
129 .prv_offset = 0x800, 145 .prv_offset = 0x800,
146 .clk_divider = true,
130 .clk_gate = true, 147 .clk_gate = true,
131 .shared_clock = &uart_clock, 148 .save_ctx = true,
132 .setup = lpss_uart_setup, 149 .setup = lpss_uart_setup,
133}; 150};
134 151
135static struct lpss_shared_clock spi_clock = {
136 .name = "spi_clk",
137 .rate = 50000000,
138};
139
140static struct lpss_device_desc byt_spi_dev_desc = { 152static struct lpss_device_desc byt_spi_dev_desc = {
141 .clk_required = true, 153 .clk_required = true,
142 .prv_offset = 0x400, 154 .prv_offset = 0x400,
155 .clk_divider = true,
143 .clk_gate = true, 156 .clk_gate = true,
144 .shared_clock = &spi_clock, 157 .save_ctx = true,
145}; 158};
146 159
147static struct lpss_device_desc byt_sdio_dev_desc = { 160static struct lpss_device_desc byt_sdio_dev_desc = {
@@ -156,44 +169,53 @@ static struct lpss_shared_clock i2c_clock = {
156static struct lpss_device_desc byt_i2c_dev_desc = { 169static struct lpss_device_desc byt_i2c_dev_desc = {
157 .clk_required = true, 170 .clk_required = true,
158 .prv_offset = 0x800, 171 .prv_offset = 0x800,
172 .save_ctx = true,
159 .shared_clock = &i2c_clock, 173 .shared_clock = &i2c_clock,
160}; 174};
161 175
176#else
177
178#define LPSS_ADDR(desc) (0UL)
179
180#endif /* CONFIG_X86_INTEL_LPSS */
181
162static const struct acpi_device_id acpi_lpss_device_ids[] = { 182static const struct acpi_device_id acpi_lpss_device_ids[] = {
163 /* Generic LPSS devices */ 183 /* Generic LPSS devices */
164 { "INTL9C60", (unsigned long)&lpss_dma_desc }, 184 { "INTL9C60", LPSS_ADDR(lpss_dma_desc) },
165 185
166 /* Lynxpoint LPSS devices */ 186 /* Lynxpoint LPSS devices */
167 { "INT33C0", (unsigned long)&lpt_dev_desc }, 187 { "INT33C0", LPSS_ADDR(lpt_dev_desc) },
168 { "INT33C1", (unsigned long)&lpt_dev_desc }, 188 { "INT33C1", LPSS_ADDR(lpt_dev_desc) },
169 { "INT33C2", (unsigned long)&lpt_dev_desc }, 189 { "INT33C2", LPSS_ADDR(lpt_i2c_dev_desc) },
170 { "INT33C3", (unsigned long)&lpt_dev_desc }, 190 { "INT33C3", LPSS_ADDR(lpt_i2c_dev_desc) },
171 { "INT33C4", (unsigned long)&lpt_uart_dev_desc }, 191 { "INT33C4", LPSS_ADDR(lpt_uart_dev_desc) },
172 { "INT33C5", (unsigned long)&lpt_uart_dev_desc }, 192 { "INT33C5", LPSS_ADDR(lpt_uart_dev_desc) },
173 { "INT33C6", (unsigned long)&lpt_sdio_dev_desc }, 193 { "INT33C6", LPSS_ADDR(lpt_sdio_dev_desc) },
174 { "INT33C7", }, 194 { "INT33C7", },
175 195
176 /* BayTrail LPSS devices */ 196 /* BayTrail LPSS devices */
177 { "80860F09", (unsigned long)&byt_pwm_dev_desc }, 197 { "80860F09", LPSS_ADDR(byt_pwm_dev_desc) },
178 { "80860F0A", (unsigned long)&byt_uart_dev_desc }, 198 { "80860F0A", LPSS_ADDR(byt_uart_dev_desc) },
179 { "80860F0E", (unsigned long)&byt_spi_dev_desc }, 199 { "80860F0E", LPSS_ADDR(byt_spi_dev_desc) },
180 { "80860F14", (unsigned long)&byt_sdio_dev_desc }, 200 { "80860F14", LPSS_ADDR(byt_sdio_dev_desc) },
181 { "80860F41", (unsigned long)&byt_i2c_dev_desc }, 201 { "80860F41", LPSS_ADDR(byt_i2c_dev_desc) },
182 { "INT33B2", }, 202 { "INT33B2", },
183 { "INT33FC", }, 203 { "INT33FC", },
184 204
185 { "INT3430", (unsigned long)&lpt_dev_desc }, 205 { "INT3430", LPSS_ADDR(lpt_dev_desc) },
186 { "INT3431", (unsigned long)&lpt_dev_desc }, 206 { "INT3431", LPSS_ADDR(lpt_dev_desc) },
187 { "INT3432", (unsigned long)&lpt_dev_desc }, 207 { "INT3432", LPSS_ADDR(lpt_i2c_dev_desc) },
188 { "INT3433", (unsigned long)&lpt_dev_desc }, 208 { "INT3433", LPSS_ADDR(lpt_i2c_dev_desc) },
189 { "INT3434", (unsigned long)&lpt_uart_dev_desc }, 209 { "INT3434", LPSS_ADDR(lpt_uart_dev_desc) },
190 { "INT3435", (unsigned long)&lpt_uart_dev_desc }, 210 { "INT3435", LPSS_ADDR(lpt_uart_dev_desc) },
191 { "INT3436", (unsigned long)&lpt_sdio_dev_desc }, 211 { "INT3436", LPSS_ADDR(lpt_sdio_dev_desc) },
192 { "INT3437", }, 212 { "INT3437", },
193 213
194 { } 214 { }
195}; 215};
196 216
217#ifdef CONFIG_X86_INTEL_LPSS
218
197static int is_memory(struct acpi_resource *res, void *not_used) 219static int is_memory(struct acpi_resource *res, void *not_used)
198{ 220{
199 struct resource r; 221 struct resource r;
@@ -213,9 +235,11 @@ static int register_device_clock(struct acpi_device *adev,
213{ 235{
214 const struct lpss_device_desc *dev_desc = pdata->dev_desc; 236 const struct lpss_device_desc *dev_desc = pdata->dev_desc;
215 struct lpss_shared_clock *shared_clock = dev_desc->shared_clock; 237 struct lpss_shared_clock *shared_clock = dev_desc->shared_clock;
238 const char *devname = dev_name(&adev->dev);
216 struct clk *clk = ERR_PTR(-ENODEV); 239 struct clk *clk = ERR_PTR(-ENODEV);
217 struct lpss_clk_data *clk_data; 240 struct lpss_clk_data *clk_data;
218 const char *parent; 241 const char *parent, *clk_name;
242 void __iomem *prv_base;
219 243
220 if (!lpss_clk_dev) 244 if (!lpss_clk_dev)
221 lpt_register_clock_device(); 245 lpt_register_clock_device();
@@ -226,7 +250,7 @@ static int register_device_clock(struct acpi_device *adev,
226 250
227 if (dev_desc->clkdev_name) { 251 if (dev_desc->clkdev_name) {
228 clk_register_clkdev(clk_data->clk, dev_desc->clkdev_name, 252 clk_register_clkdev(clk_data->clk, dev_desc->clkdev_name,
229 dev_name(&adev->dev)); 253 devname);
230 return 0; 254 return 0;
231 } 255 }
232 256
@@ -235,6 +259,7 @@ static int register_device_clock(struct acpi_device *adev,
235 return -ENODATA; 259 return -ENODATA;
236 260
237 parent = clk_data->name; 261 parent = clk_data->name;
262 prv_base = pdata->mmio_base + dev_desc->prv_offset;
238 263
239 if (shared_clock) { 264 if (shared_clock) {
240 clk = shared_clock->clk; 265 clk = shared_clock->clk;
@@ -248,16 +273,41 @@ static int register_device_clock(struct acpi_device *adev,
248 } 273 }
249 274
250 if (dev_desc->clk_gate) { 275 if (dev_desc->clk_gate) {
251 clk = clk_register_gate(NULL, dev_name(&adev->dev), parent, 0, 276 clk = clk_register_gate(NULL, devname, parent, 0,
252 pdata->mmio_base + dev_desc->prv_offset, 277 prv_base, 0, 0, NULL);
253 0, 0, NULL); 278 parent = devname;
254 pdata->clk = clk; 279 }
280
281 if (dev_desc->clk_divider) {
282 /* Prevent division by zero */
283 if (!readl(prv_base))
284 writel(LPSS_CLK_DIVIDER_DEF_MASK, prv_base);
285
286 clk_name = kasprintf(GFP_KERNEL, "%s-div", devname);
287 if (!clk_name)
288 return -ENOMEM;
289 clk = clk_register_fractional_divider(NULL, clk_name, parent,
290 0, prv_base,
291 1, 15, 16, 15, 0, NULL);
292 parent = clk_name;
293
294 clk_name = kasprintf(GFP_KERNEL, "%s-update", devname);
295 if (!clk_name) {
296 kfree(parent);
297 return -ENOMEM;
298 }
299 clk = clk_register_gate(NULL, clk_name, parent,
300 CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE,
301 prv_base, 31, 0, NULL);
302 kfree(parent);
303 kfree(clk_name);
255 } 304 }
256 305
257 if (IS_ERR(clk)) 306 if (IS_ERR(clk))
258 return PTR_ERR(clk); 307 return PTR_ERR(clk);
259 308
260 clk_register_clkdev(clk, NULL, dev_name(&adev->dev)); 309 pdata->clk = clk;
310 clk_register_clkdev(clk, NULL, devname);
261 return 0; 311 return 0;
262} 312}
263 313
@@ -268,12 +318,14 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
268 struct lpss_private_data *pdata; 318 struct lpss_private_data *pdata;
269 struct resource_list_entry *rentry; 319 struct resource_list_entry *rentry;
270 struct list_head resource_list; 320 struct list_head resource_list;
321 struct platform_device *pdev;
271 int ret; 322 int ret;
272 323
273 dev_desc = (struct lpss_device_desc *)id->driver_data; 324 dev_desc = (struct lpss_device_desc *)id->driver_data;
274 if (!dev_desc) 325 if (!dev_desc) {
275 return acpi_create_platform_device(adev, id); 326 pdev = acpi_create_platform_device(adev);
276 327 return IS_ERR_OR_NULL(pdev) ? PTR_ERR(pdev) : 1;
328 }
277 pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); 329 pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
278 if (!pdata) 330 if (!pdata)
279 return -ENOMEM; 331 return -ENOMEM;
@@ -323,10 +375,13 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
323 dev_desc->setup(pdata); 375 dev_desc->setup(pdata);
324 376
325 adev->driver_data = pdata; 377 adev->driver_data = pdata;
326 ret = acpi_create_platform_device(adev, id); 378 pdev = acpi_create_platform_device(adev);
327 if (ret > 0) 379 if (!IS_ERR_OR_NULL(pdev)) {
328 return ret; 380 device_enable_async_suspend(&pdev->dev);
381 return 1;
382 }
329 383
384 ret = PTR_ERR(pdev);
330 adev->driver_data = NULL; 385 adev->driver_data = NULL;
331 386
332 err_out: 387 err_out:
@@ -450,6 +505,126 @@ static void acpi_lpss_set_ltr(struct device *dev, s32 val)
450 } 505 }
451} 506}
452 507
508#ifdef CONFIG_PM
509/**
510 * acpi_lpss_save_ctx() - Save the private registers of LPSS device
511 * @dev: LPSS device
512 *
513 * Most LPSS devices have private registers which may loose their context when
514 * the device is powered down. acpi_lpss_save_ctx() saves those registers into
515 * prv_reg_ctx array.
516 */
517static void acpi_lpss_save_ctx(struct device *dev)
518{
519 struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
520 unsigned int i;
521
522 for (i = 0; i < LPSS_PRV_REG_COUNT; i++) {
523 unsigned long offset = i * sizeof(u32);
524
525 pdata->prv_reg_ctx[i] = __lpss_reg_read(pdata, offset);
526 dev_dbg(dev, "saving 0x%08x from LPSS reg at offset 0x%02lx\n",
527 pdata->prv_reg_ctx[i], offset);
528 }
529}
530
531/**
532 * acpi_lpss_restore_ctx() - Restore the private registers of LPSS device
533 * @dev: LPSS device
534 *
535 * Restores the registers that were previously stored with acpi_lpss_save_ctx().
536 */
537static void acpi_lpss_restore_ctx(struct device *dev)
538{
539 struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
540 unsigned int i;
541
542 /*
543 * The following delay is needed or the subsequent write operations may
544 * fail. The LPSS devices are actually PCI devices and the PCI spec
545 * expects 10ms delay before the device can be accessed after D3 to D0
546 * transition.
547 */
548 msleep(10);
549
550 for (i = 0; i < LPSS_PRV_REG_COUNT; i++) {
551 unsigned long offset = i * sizeof(u32);
552
553 __lpss_reg_write(pdata->prv_reg_ctx[i], pdata, offset);
554 dev_dbg(dev, "restoring 0x%08x to LPSS reg at offset 0x%02lx\n",
555 pdata->prv_reg_ctx[i], offset);
556 }
557}
558
559#ifdef CONFIG_PM_SLEEP
560static int acpi_lpss_suspend_late(struct device *dev)
561{
562 int ret = pm_generic_suspend_late(dev);
563
564 if (ret)
565 return ret;
566
567 acpi_lpss_save_ctx(dev);
568 return acpi_dev_suspend_late(dev);
569}
570
571static int acpi_lpss_restore_early(struct device *dev)
572{
573 int ret = acpi_dev_resume_early(dev);
574
575 if (ret)
576 return ret;
577
578 acpi_lpss_restore_ctx(dev);
579 return pm_generic_resume_early(dev);
580}
581#endif /* CONFIG_PM_SLEEP */
582
583#ifdef CONFIG_PM_RUNTIME
584static int acpi_lpss_runtime_suspend(struct device *dev)
585{
586 int ret = pm_generic_runtime_suspend(dev);
587
588 if (ret)
589 return ret;
590
591 acpi_lpss_save_ctx(dev);
592 return acpi_dev_runtime_suspend(dev);
593}
594
595static int acpi_lpss_runtime_resume(struct device *dev)
596{
597 int ret = acpi_dev_runtime_resume(dev);
598
599 if (ret)
600 return ret;
601
602 acpi_lpss_restore_ctx(dev);
603 return pm_generic_runtime_resume(dev);
604}
605#endif /* CONFIG_PM_RUNTIME */
606#endif /* CONFIG_PM */
607
608static struct dev_pm_domain acpi_lpss_pm_domain = {
609 .ops = {
610#ifdef CONFIG_PM_SLEEP
611 .suspend_late = acpi_lpss_suspend_late,
612 .restore_early = acpi_lpss_restore_early,
613 .prepare = acpi_subsys_prepare,
614 .complete = acpi_subsys_complete,
615 .suspend = acpi_subsys_suspend,
616 .resume_early = acpi_subsys_resume_early,
617 .freeze = acpi_subsys_freeze,
618 .poweroff = acpi_subsys_suspend,
619 .poweroff_late = acpi_subsys_suspend_late,
620#endif
621#ifdef CONFIG_PM_RUNTIME
622 .runtime_suspend = acpi_lpss_runtime_suspend,
623 .runtime_resume = acpi_lpss_runtime_resume,
624#endif
625 },
626};
627
453static int acpi_lpss_platform_notify(struct notifier_block *nb, 628static int acpi_lpss_platform_notify(struct notifier_block *nb,
454 unsigned long action, void *data) 629 unsigned long action, void *data)
455{ 630{
@@ -457,7 +632,6 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb,
457 struct lpss_private_data *pdata; 632 struct lpss_private_data *pdata;
458 struct acpi_device *adev; 633 struct acpi_device *adev;
459 const struct acpi_device_id *id; 634 const struct acpi_device_id *id;
460 int ret = 0;
461 635
462 id = acpi_match_device(acpi_lpss_device_ids, &pdev->dev); 636 id = acpi_match_device(acpi_lpss_device_ids, &pdev->dev);
463 if (!id || !id->driver_data) 637 if (!id || !id->driver_data)
@@ -467,7 +641,7 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb,
467 return 0; 641 return 0;
468 642
469 pdata = acpi_driver_data(adev); 643 pdata = acpi_driver_data(adev);
470 if (!pdata || !pdata->mmio_base || !pdata->dev_desc->ltr_required) 644 if (!pdata || !pdata->mmio_base)
471 return 0; 645 return 0;
472 646
473 if (pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) { 647 if (pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) {
@@ -475,12 +649,27 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb,
475 return 0; 649 return 0;
476 } 650 }
477 651
478 if (action == BUS_NOTIFY_ADD_DEVICE) 652 switch (action) {
479 ret = sysfs_create_group(&pdev->dev.kobj, &lpss_attr_group); 653 case BUS_NOTIFY_BOUND_DRIVER:
480 else if (action == BUS_NOTIFY_DEL_DEVICE) 654 if (pdata->dev_desc->save_ctx)
481 sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group); 655 pdev->dev.pm_domain = &acpi_lpss_pm_domain;
656 break;
657 case BUS_NOTIFY_UNBOUND_DRIVER:
658 if (pdata->dev_desc->save_ctx)
659 pdev->dev.pm_domain = NULL;
660 break;
661 case BUS_NOTIFY_ADD_DEVICE:
662 if (pdata->dev_desc->ltr_required)
663 return sysfs_create_group(&pdev->dev.kobj,
664 &lpss_attr_group);
665 case BUS_NOTIFY_DEL_DEVICE:
666 if (pdata->dev_desc->ltr_required)
667 sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group);
668 default:
669 break;
670 }
482 671
483 return ret; 672 return 0;
484} 673}
485 674
486static struct notifier_block acpi_lpss_nb = { 675static struct notifier_block acpi_lpss_nb = {
@@ -519,3 +708,16 @@ void __init acpi_lpss_init(void)
519 acpi_scan_add_handler(&lpss_handler); 708 acpi_scan_add_handler(&lpss_handler);
520 } 709 }
521} 710}
711
712#else
713
714static struct acpi_scan_handler lpss_handler = {
715 .ids = acpi_lpss_device_ids,
716};
717
718void __init acpi_lpss_init(void)
719{
720 acpi_scan_add_handler(&lpss_handler);
721}
722
723#endif /* CONFIG_X86_INTEL_LPSS */