Blame view
drivers/acpi/acpi_lpss.c
35.3 KB
d2912cb15 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
f58b082ae ACPI / scan: Add ... |
2 3 4 |
/* * ACPI support for Intel Lynxpoint LPSS. * |
3df2da968 Revert "ACPI / LP... |
5 |
* Copyright (C) 2013, Intel Corporation |
f58b082ae ACPI / scan: Add ... |
6 7 |
* Authors: Mika Westerberg <mika.westerberg@linux.intel.com> * Rafael J. Wysocki <rafael.j.wysocki@intel.com> |
f58b082ae ACPI / scan: Add ... |
8 9 10 |
*/ #include <linux/acpi.h> |
f58b082ae ACPI / scan: Add ... |
11 12 |
#include <linux/clkdev.h> #include <linux/clk-provider.h> |
6025e2fae ACPI: LPSS: Add d... |
13 |
#include <linux/dmi.h> |
f58b082ae ACPI / scan: Add ... |
14 15 |
#include <linux/err.h> #include <linux/io.h> |
eebb3e8d8 ACPI / LPSS: over... |
16 |
#include <linux/mutex.h> |
1e30124ac ACPI / LPSS: Make... |
17 |
#include <linux/pci.h> |
f58b082ae ACPI / scan: Add ... |
18 |
#include <linux/platform_device.h> |
a9443a632 clk: x86: Move cl... |
19 |
#include <linux/platform_data/x86/clk-lpss.h> |
80a7581f3 arch/x86/platform... |
20 |
#include <linux/platform_data/x86/pmc_atom.h> |
989561de9 PM / Domains: add... |
21 |
#include <linux/pm_domain.h> |
2e0f8822d ACPI / LPSS: Add ... |
22 |
#include <linux/pm_runtime.h> |
bf7696a12 acpi: lpss: call ... |
23 |
#include <linux/pwm.h> |
a09c59130 ACPI / LPSS: Avoi... |
24 |
#include <linux/suspend.h> |
c78b08306 ACPI / LPSS: cust... |
25 |
#include <linux/delay.h> |
f58b082ae ACPI / scan: Add ... |
26 27 |
#include "internal.h" |
d6ddaaac8 ACPI / scan: alwa... |
28 |
#ifdef CONFIG_X86_INTEL_LPSS |
eebb3e8d8 ACPI / LPSS: over... |
29 |
#include <asm/cpu_device_id.h> |
4626d840a x86/acpi/lss: Use... |
30 |
#include <asm/intel-family.h> |
eebb3e8d8 ACPI / LPSS: over... |
31 |
#include <asm/iosf_mbi.h> |
eebb3e8d8 ACPI / LPSS: over... |
32 |
|
d6ddaaac8 ACPI / scan: alwa... |
33 |
#define LPSS_ADDR(desc) ((unsigned long)&desc) |
f58b082ae ACPI / scan: Add ... |
34 |
#define LPSS_CLK_SIZE 0x04 |
2e0f8822d ACPI / LPSS: Add ... |
35 36 37 |
#define LPSS_LTR_SIZE 0x18 /* Offsets relative to LPSS_PRIVATE_OFFSET */ |
ed3a872e2 ACPI / LPSS: supp... |
38 |
#define LPSS_CLK_DIVIDER_DEF_MASK (BIT(1) | BIT(16)) |
765bdd4e5 ACPI / LPSS: Take... |
39 40 41 |
#define LPSS_RESETS 0x04 #define LPSS_RESETS_RESET_FUNC BIT(0) #define LPSS_RESETS_RESET_APB BIT(1) |
2e0f8822d ACPI / LPSS: Add ... |
42 43 |
#define LPSS_GENERAL 0x08 #define LPSS_GENERAL_LTR_MODE_SW BIT(2) |
088f1fd26 ACPI / LPSS: fix ... |
44 |
#define LPSS_GENERAL_UART_RTS_OVRD BIT(3) |
2e0f8822d ACPI / LPSS: Add ... |
45 46 |
#define LPSS_SW_LTR 0x10 #define LPSS_AUTO_LTR 0x14 |
1a8f83515 ACPI / LPSS: Supp... |
47 48 49 50 51 52 53 |
#define LPSS_LTR_SNOOP_REQ BIT(15) #define LPSS_LTR_SNOOP_MASK 0x0000FFFF #define LPSS_LTR_SNOOP_LAT_1US 0x800 #define LPSS_LTR_SNOOP_LAT_32US 0xC00 #define LPSS_LTR_SNOOP_LAT_SHIFT 5 #define LPSS_LTR_SNOOP_LAT_CUTOFF 3000 #define LPSS_LTR_MAX_VAL 0x3FF |
06d864150 ACPI / LPSS: mask... |
54 55 |
#define LPSS_TX_INT 0x20 #define LPSS_TX_INT_MASK BIT(1) |
f58b082ae ACPI / scan: Add ... |
56 |
|
c78b08306 ACPI / LPSS: cust... |
57 |
#define LPSS_PRV_REG_COUNT 9 |
ff8c1af5e ACPI / LPSS: intr... |
58 59 60 61 62 63 |
/* LPSS Flags */ #define LPSS_CLK BIT(0) #define LPSS_CLK_GATE BIT(1) #define LPSS_CLK_DIVIDER BIT(2) #define LPSS_LTR BIT(3) #define LPSS_SAVE_CTX BIT(4) |
15aa5e4c4 ACPI / LPSS: Save... |
64 65 66 67 68 69 70 71 72 |
/* * For some devices the DSDT AML code for another device turns off the device * before our suspend handler runs, causing us to read/save all 1-s (0xffffffff) * as ctx register values. * Luckily these devices always use the same ctx register values, so we can * work around this by saving the ctx registers once on activation. */ #define LPSS_SAVE_CTX_ONCE BIT(5) #define LPSS_NO_D3_DELAY BIT(6) |
f62721706 ACPI / LPSS: add ... |
73 |
|
06d864150 ACPI / LPSS: mask... |
74 |
struct lpss_private_data; |
f58b082ae ACPI / scan: Add ... |
75 76 |
struct lpss_device_desc { |
ff8c1af5e ACPI / LPSS: intr... |
77 |
unsigned int flags; |
fcf0789a9 ACPI / LPSS: prov... |
78 |
const char *clk_con_id; |
2e0f8822d ACPI / LPSS: Add ... |
79 |
unsigned int prv_offset; |
958c4eb2a ACPI / LPSS: over... |
80 |
size_t prv_size_override; |
a5565cf23 ACPI / LPSS: Prov... |
81 |
struct property_entry *properties; |
06d864150 ACPI / LPSS: mask... |
82 |
void (*setup)(struct lpss_private_data *pdata); |
48402cee6 ACPI / LPSS: Resu... |
83 |
bool resume_from_noirq; |
f58b082ae ACPI / scan: Add ... |
84 |
}; |
eebb3e8d8 ACPI / LPSS: over... |
85 |
static const struct lpss_device_desc lpss_dma_desc = { |
3df2da968 Revert "ACPI / LP... |
86 |
.flags = LPSS_CLK, |
b59cc200a ACPI / LPSS: regi... |
87 |
}; |
f58b082ae ACPI / scan: Add ... |
88 |
struct lpss_private_data { |
dd242a080 ACPI / LPSS: Only... |
89 |
struct acpi_device *adev; |
f58b082ae ACPI / scan: Add ... |
90 91 |
void __iomem *mmio_base; resource_size_t mmio_size; |
03f09f73b ACPI / LPSS: supp... |
92 |
unsigned int fixed_clk_rate; |
f58b082ae ACPI / scan: Add ... |
93 94 |
struct clk *clk; const struct lpss_device_desc *dev_desc; |
c78b08306 ACPI / LPSS: cust... |
95 |
u32 prv_reg_ctx[LPSS_PRV_REG_COUNT]; |
f58b082ae ACPI / scan: Add ... |
96 |
}; |
86b62e5cd ACPI / LPSS: Excl... |
97 98 |
/* Devices which need to be in D3 before lpss_iosf_enter_d3_state() proceeds */ static u32 pmc_atom_d3_mask = 0xfe000ffe; |
eebb3e8d8 ACPI / LPSS: over... |
99 100 101 102 103 104 |
/* LPSS run time quirks */ static unsigned int lpss_quirks; /* * LPSS_QUIRK_ALWAYS_POWER_ON: override power state for LPSS DMA device. * |
fa9e93b11 ACPI / LPSS: chan... |
105 |
* The LPSS DMA controller has neither _PS0 nor _PS3 method. Moreover |
eebb3e8d8 ACPI / LPSS: over... |
106 107 108 109 110 111 112 113 114 |
* it can be powered off automatically whenever the last LPSS device goes down. * In case of no power any access to the DMA controller will hang the system. * The behaviour is reproduced on some HP laptops based on Intel BayTrail as * well as on ASuS T100TA transformer. * * This quirk overrides power state of entire LPSS island to keep DMA powered * on whenever we have at least one other device in use. */ #define LPSS_QUIRK_ALWAYS_POWER_ON BIT(0) |
1f47a77c4 ACPI / LPSS: not ... |
115 116 117 |
/* UART Component Parameter Register */ #define LPSS_UART_CPR 0xF4 #define LPSS_UART_CPR_AFCE BIT(4) |
06d864150 ACPI / LPSS: mask... |
118 119 |
static void lpss_uart_setup(struct lpss_private_data *pdata) { |
088f1fd26 ACPI / LPSS: fix ... |
120 |
unsigned int offset; |
1f47a77c4 ACPI / LPSS: not ... |
121 |
u32 val; |
06d864150 ACPI / LPSS: mask... |
122 |
|
088f1fd26 ACPI / LPSS: fix ... |
123 |
offset = pdata->dev_desc->prv_offset + LPSS_TX_INT; |
1f47a77c4 ACPI / LPSS: not ... |
124 125 126 127 128 129 130 131 132 133 |
val = readl(pdata->mmio_base + offset); writel(val | LPSS_TX_INT_MASK, pdata->mmio_base + offset); val = readl(pdata->mmio_base + LPSS_UART_CPR); if (!(val & LPSS_UART_CPR_AFCE)) { offset = pdata->dev_desc->prv_offset + LPSS_GENERAL; val = readl(pdata->mmio_base + offset); val |= LPSS_GENERAL_UART_RTS_OVRD; writel(val, pdata->mmio_base + offset); } |
06d864150 ACPI / LPSS: mask... |
134 |
} |
3095794ae ACPI / LPSS: Deas... |
135 |
static void lpss_deassert_reset(struct lpss_private_data *pdata) |
765bdd4e5 ACPI / LPSS: Take... |
136 137 138 139 140 141 142 143 |
{ unsigned int offset; u32 val; offset = pdata->dev_desc->prv_offset + LPSS_RESETS; val = readl(pdata->mmio_base + offset); val |= LPSS_RESETS_RESET_APB | LPSS_RESETS_RESET_FUNC; writel(val, pdata->mmio_base + offset); |
3095794ae ACPI / LPSS: Deas... |
144 |
} |
04434ab51 ACPI / LPSS: Call... |
145 146 147 148 149 150 |
/* * BYT PWM used for backlight control by the i915 driver on systems without * the Crystal Cove PMIC. */ static struct pwm_lookup byt_pwm_lookup[] = { PWM_LOOKUP_WITH_MODULE("80860F09:00", 0, "0000:00:02.0", |
b2147a3a4 ACPI / LPSS: Rena... |
151 |
"pwm_soc_backlight", 0, PWM_POLARITY_NORMAL, |
04434ab51 ACPI / LPSS: Call... |
152 153 154 155 156 |
"pwm-lpss-platform"), }; static void byt_pwm_setup(struct lpss_private_data *pdata) { |
dd242a080 ACPI / LPSS: Only... |
157 158 159 160 161 |
struct acpi_device *adev = pdata->adev; /* Only call pwm_add_table for the first PWM controller */ if (!adev->pnp.unique_id || strcmp(adev->pnp.unique_id, "1")) return; |
b2147a3a4 ACPI / LPSS: Rena... |
162 |
pwm_add_table(byt_pwm_lookup, ARRAY_SIZE(byt_pwm_lookup)); |
04434ab51 ACPI / LPSS: Call... |
163 |
} |
3095794ae ACPI / LPSS: Deas... |
164 165 166 167 |
#define LPSS_I2C_ENABLE 0x6c static void byt_i2c_setup(struct lpss_private_data *pdata) { |
86b62e5cd ACPI / LPSS: Excl... |
168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
const char *uid_str = acpi_device_uid(pdata->adev); acpi_handle handle = pdata->adev->handle; unsigned long long shared_host = 0; acpi_status status; long uid = 0; /* Expected to always be true, but better safe then sorry */ if (uid_str) uid = simple_strtol(uid_str, NULL, 10); /* Detect I2C bus shared with PUNIT and ignore its d3 status */ status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host); if (ACPI_SUCCESS(status) && shared_host && uid) pmc_atom_d3_mask &= ~(BIT_LPSS2_F1_I2C1 << (uid - 1)); |
3095794ae ACPI / LPSS: Deas... |
182 |
lpss_deassert_reset(pdata); |
765bdd4e5 ACPI / LPSS: Take... |
183 |
|
03f09f73b ACPI / LPSS: supp... |
184 185 |
if (readl(pdata->mmio_base + pdata->dev_desc->prv_offset)) pdata->fixed_clk_rate = 133000000; |
3293c7b8e ACPI / LPSS: Alwa... |
186 187 |
writel(0, pdata->mmio_base + LPSS_I2C_ENABLE); |
765bdd4e5 ACPI / LPSS: Take... |
188 |
} |
43218a1b3 ACPI / LPSS: add ... |
189 |
|
bf7696a12 acpi: lpss: call ... |
190 191 192 |
/* BSW PWM used for backlight control by the i915 driver */ static struct pwm_lookup bsw_pwm_lookup[] = { PWM_LOOKUP_WITH_MODULE("80862288:00", 0, "0000:00:02.0", |
b2147a3a4 ACPI / LPSS: Rena... |
193 |
"pwm_soc_backlight", 0, PWM_POLARITY_NORMAL, |
bf7696a12 acpi: lpss: call ... |
194 195 196 197 198 |
"pwm-lpss-platform"), }; static void bsw_pwm_setup(struct lpss_private_data *pdata) { |
dd242a080 ACPI / LPSS: Only... |
199 200 201 202 203 |
struct acpi_device *adev = pdata->adev; /* Only call pwm_add_table for the first PWM controller */ if (!adev->pnp.unique_id || strcmp(adev->pnp.unique_id, "1")) return; |
bf7696a12 acpi: lpss: call ... |
204 205 |
pwm_add_table(bsw_pwm_lookup, ARRAY_SIZE(bsw_pwm_lookup)); } |
b2687cd7d ACPI / LPSS: cons... |
206 |
static const struct lpss_device_desc lpt_dev_desc = { |
57b300649 ACPI / LPSS: Save... |
207 208 |
.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_LTR | LPSS_SAVE_CTX, |
2e0f8822d ACPI / LPSS: Add ... |
209 |
.prv_offset = 0x800, |
ed3a872e2 ACPI / LPSS: supp... |
210 |
}; |
b2687cd7d ACPI / LPSS: cons... |
211 |
static const struct lpss_device_desc lpt_i2c_dev_desc = { |
57b300649 ACPI / LPSS: Save... |
212 |
.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_LTR | LPSS_SAVE_CTX, |
ed3a872e2 ACPI / LPSS: supp... |
213 |
.prv_offset = 0x800, |
2e0f8822d ACPI / LPSS: Add ... |
214 |
}; |
a5565cf23 ACPI / LPSS: Prov... |
215 216 217 218 219 220 |
static struct property_entry uart_properties[] = { PROPERTY_ENTRY_U32("reg-io-width", 4), PROPERTY_ENTRY_U32("reg-shift", 2), PROPERTY_ENTRY_BOOL("snps,uart-16550-compatible"), { }, }; |
b2687cd7d ACPI / LPSS: cons... |
221 |
static const struct lpss_device_desc lpt_uart_dev_desc = { |
57b300649 ACPI / LPSS: Save... |
222 223 |
.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_LTR | LPSS_SAVE_CTX, |
fcf0789a9 ACPI / LPSS: prov... |
224 |
.clk_con_id = "baudclk", |
06d864150 ACPI / LPSS: mask... |
225 |
.prv_offset = 0x800, |
06d864150 ACPI / LPSS: mask... |
226 |
.setup = lpss_uart_setup, |
a5565cf23 ACPI / LPSS: Prov... |
227 |
.properties = uart_properties, |
2e0f8822d ACPI / LPSS: Add ... |
228 |
}; |
b2687cd7d ACPI / LPSS: cons... |
229 |
static const struct lpss_device_desc lpt_sdio_dev_desc = { |
ff8c1af5e ACPI / LPSS: intr... |
230 |
.flags = LPSS_LTR, |
2e0f8822d ACPI / LPSS: Add ... |
231 |
.prv_offset = 0x1000, |
958c4eb2a ACPI / LPSS: over... |
232 |
.prv_size_override = 0x1018, |
e1c748179 ACPI / LPSS: Add ... |
233 |
}; |
b2687cd7d ACPI / LPSS: cons... |
234 |
static const struct lpss_device_desc byt_pwm_dev_desc = { |
3f56bf3e9 ACPI / LPSS: remo... |
235 |
.flags = LPSS_SAVE_CTX, |
fdcb613d4 ACPI / LPSS: Add ... |
236 |
.prv_offset = 0x800, |
04434ab51 ACPI / LPSS: Call... |
237 |
.setup = byt_pwm_setup, |
e1c748179 ACPI / LPSS: Add ... |
238 |
}; |
b00855aec ACPI / LPSS: Igno... |
239 |
static const struct lpss_device_desc bsw_pwm_dev_desc = { |
15aa5e4c4 ACPI / LPSS: Save... |
240 |
.flags = LPSS_SAVE_CTX_ONCE | LPSS_NO_D3_DELAY, |
fdcb613d4 ACPI / LPSS: Add ... |
241 |
.prv_offset = 0x800, |
bf7696a12 acpi: lpss: call ... |
242 |
.setup = bsw_pwm_setup, |
5e31ee84c ACPI / LPSS: Resu... |
243 |
.resume_from_noirq = true, |
b00855aec ACPI / LPSS: Igno... |
244 |
}; |
b2687cd7d ACPI / LPSS: cons... |
245 |
static const struct lpss_device_desc byt_uart_dev_desc = { |
3df2da968 Revert "ACPI / LP... |
246 |
.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX, |
fcf0789a9 ACPI / LPSS: prov... |
247 |
.clk_con_id = "baudclk", |
f62721706 ACPI / LPSS: add ... |
248 |
.prv_offset = 0x800, |
06d864150 ACPI / LPSS: mask... |
249 |
.setup = lpss_uart_setup, |
a5565cf23 ACPI / LPSS: Prov... |
250 |
.properties = uart_properties, |
f62721706 ACPI / LPSS: add ... |
251 |
}; |
b00855aec ACPI / LPSS: Igno... |
252 253 254 255 256 257 |
static const struct lpss_device_desc bsw_uart_dev_desc = { .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX | LPSS_NO_D3_DELAY, .clk_con_id = "baudclk", .prv_offset = 0x800, .setup = lpss_uart_setup, |
a5565cf23 ACPI / LPSS: Prov... |
258 |
.properties = uart_properties, |
b00855aec ACPI / LPSS: Igno... |
259 |
}; |
b2687cd7d ACPI / LPSS: cons... |
260 |
static const struct lpss_device_desc byt_spi_dev_desc = { |
3df2da968 Revert "ACPI / LP... |
261 |
.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX, |
f62721706 ACPI / LPSS: add ... |
262 |
.prv_offset = 0x400, |
f62721706 ACPI / LPSS: add ... |
263 |
}; |
b2687cd7d ACPI / LPSS: cons... |
264 |
static const struct lpss_device_desc byt_sdio_dev_desc = { |
3df2da968 Revert "ACPI / LP... |
265 |
.flags = LPSS_CLK, |
f62721706 ACPI / LPSS: add ... |
266 |
}; |
b2687cd7d ACPI / LPSS: cons... |
267 |
static const struct lpss_device_desc byt_i2c_dev_desc = { |
3df2da968 Revert "ACPI / LP... |
268 |
.flags = LPSS_CLK | LPSS_SAVE_CTX, |
f62721706 ACPI / LPSS: add ... |
269 |
.prv_offset = 0x800, |
03f09f73b ACPI / LPSS: supp... |
270 |
.setup = byt_i2c_setup, |
48402cee6 ACPI / LPSS: Resu... |
271 |
.resume_from_noirq = true, |
1bfbd8eb8 ACPI / LPSS: Add ... |
272 |
}; |
b00855aec ACPI / LPSS: Igno... |
273 274 275 276 |
static const struct lpss_device_desc bsw_i2c_dev_desc = { .flags = LPSS_CLK | LPSS_SAVE_CTX | LPSS_NO_D3_DELAY, .prv_offset = 0x800, .setup = byt_i2c_setup, |
48402cee6 ACPI / LPSS: Resu... |
277 |
.resume_from_noirq = true, |
b00855aec ACPI / LPSS: Igno... |
278 |
}; |
eebb3e8d8 ACPI / LPSS: over... |
279 |
static const struct lpss_device_desc bsw_spi_dev_desc = { |
b00855aec ACPI / LPSS: Igno... |
280 281 |
.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX | LPSS_NO_D3_DELAY, |
3095794ae ACPI / LPSS: Deas... |
282 283 284 |
.prv_offset = 0x400, .setup = lpss_deassert_reset, }; |
eebb3e8d8 ACPI / LPSS: over... |
285 |
static const struct x86_cpu_id lpss_cpu_ids[] = { |
e36cf2f76 ACPI: Convert to ... |
286 287 |
X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT, NULL), X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT, NULL), |
eebb3e8d8 ACPI / LPSS: over... |
288 289 |
{} }; |
d6ddaaac8 ACPI / scan: alwa... |
290 291 292 293 294 |
#else #define LPSS_ADDR(desc) (0UL) #endif /* CONFIG_X86_INTEL_LPSS */ |
f58b082ae ACPI / scan: Add ... |
295 |
static const struct acpi_device_id acpi_lpss_device_ids[] = { |
b59cc200a ACPI / LPSS: regi... |
296 |
/* Generic LPSS devices */ |
d6ddaaac8 ACPI / scan: alwa... |
297 |
{ "INTL9C60", LPSS_ADDR(lpss_dma_desc) }, |
b59cc200a ACPI / LPSS: regi... |
298 |
|
f58b082ae ACPI / scan: Add ... |
299 |
/* Lynxpoint LPSS devices */ |
d6ddaaac8 ACPI / scan: alwa... |
300 301 302 303 304 305 306 |
{ "INT33C0", LPSS_ADDR(lpt_dev_desc) }, { "INT33C1", LPSS_ADDR(lpt_dev_desc) }, { "INT33C2", LPSS_ADDR(lpt_i2c_dev_desc) }, { "INT33C3", LPSS_ADDR(lpt_i2c_dev_desc) }, { "INT33C4", LPSS_ADDR(lpt_uart_dev_desc) }, { "INT33C5", LPSS_ADDR(lpt_uart_dev_desc) }, { "INT33C6", LPSS_ADDR(lpt_sdio_dev_desc) }, |
f58b082ae ACPI / scan: Add ... |
307 |
{ "INT33C7", }, |
f62721706 ACPI / LPSS: add ... |
308 |
/* BayTrail LPSS devices */ |
d6ddaaac8 ACPI / scan: alwa... |
309 310 311 312 313 |
{ "80860F09", LPSS_ADDR(byt_pwm_dev_desc) }, { "80860F0A", LPSS_ADDR(byt_uart_dev_desc) }, { "80860F0E", LPSS_ADDR(byt_spi_dev_desc) }, { "80860F14", LPSS_ADDR(byt_sdio_dev_desc) }, { "80860F41", LPSS_ADDR(byt_i2c_dev_desc) }, |
f62721706 ACPI / LPSS: add ... |
314 |
{ "INT33B2", }, |
20482d327 pinctrl: baytrail... |
315 |
{ "INT33FC", }, |
f62721706 ACPI / LPSS: add ... |
316 |
|
1bfbd8eb8 ACPI / LPSS: Add ... |
317 |
/* Braswell LPSS devices */ |
240714061 ACPI / LPSS: Add ... |
318 |
{ "80862286", LPSS_ADDR(lpss_dma_desc) }, |
b00855aec ACPI / LPSS: Igno... |
319 320 |
{ "80862288", LPSS_ADDR(bsw_pwm_dev_desc) }, { "8086228A", LPSS_ADDR(bsw_uart_dev_desc) }, |
3095794ae ACPI / LPSS: Deas... |
321 |
{ "8086228E", LPSS_ADDR(bsw_spi_dev_desc) }, |
240714061 ACPI / LPSS: Add ... |
322 |
{ "808622C0", LPSS_ADDR(lpss_dma_desc) }, |
b00855aec ACPI / LPSS: Igno... |
323 |
{ "808622C1", LPSS_ADDR(bsw_i2c_dev_desc) }, |
1bfbd8eb8 ACPI / LPSS: Add ... |
324 |
|
b00855aec ACPI / LPSS: Igno... |
325 |
/* Broadwell LPSS devices */ |
d6ddaaac8 ACPI / scan: alwa... |
326 327 328 329 330 331 332 |
{ "INT3430", LPSS_ADDR(lpt_dev_desc) }, { "INT3431", LPSS_ADDR(lpt_dev_desc) }, { "INT3432", LPSS_ADDR(lpt_i2c_dev_desc) }, { "INT3433", LPSS_ADDR(lpt_i2c_dev_desc) }, { "INT3434", LPSS_ADDR(lpt_uart_dev_desc) }, { "INT3435", LPSS_ADDR(lpt_uart_dev_desc) }, { "INT3436", LPSS_ADDR(lpt_sdio_dev_desc) }, |
a4d97536a ACPI / LPSS: add ... |
333 |
{ "INT3437", }, |
ff8c1af5e ACPI / LPSS: intr... |
334 335 |
/* Wildcat Point LPSS devices */ { "INT3438", LPSS_ADDR(lpt_dev_desc) }, |
43218a1b3 ACPI / LPSS: add ... |
336 |
|
f58b082ae ACPI / scan: Add ... |
337 338 |
{ } }; |
d6ddaaac8 ACPI / scan: alwa... |
339 |
#ifdef CONFIG_X86_INTEL_LPSS |
f58b082ae ACPI / scan: Add ... |
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 |
static int is_memory(struct acpi_resource *res, void *not_used) { struct resource r; return !acpi_dev_resource_memory(res, &r); } /* LPSS main clock device. */ static struct platform_device *lpss_clk_dev; static inline void lpt_register_clock_device(void) { lpss_clk_dev = platform_device_register_simple("clk-lpt", -1, NULL, 0); } static int register_device_clock(struct acpi_device *adev, struct lpss_private_data *pdata) { const struct lpss_device_desc *dev_desc = pdata->dev_desc; |
ed3a872e2 ACPI / LPSS: supp... |
358 |
const char *devname = dev_name(&adev->dev); |
71c50dbe1 ACPI / LPSS: Remo... |
359 |
struct clk *clk; |
b59cc200a ACPI / LPSS: regi... |
360 |
struct lpss_clk_data *clk_data; |
ed3a872e2 ACPI / LPSS: supp... |
361 362 |
const char *parent, *clk_name; void __iomem *prv_base; |
f58b082ae ACPI / scan: Add ... |
363 364 365 |
if (!lpss_clk_dev) lpt_register_clock_device(); |
b59cc200a ACPI / LPSS: regi... |
366 367 368 |
clk_data = platform_get_drvdata(lpss_clk_dev); if (!clk_data) return -ENODEV; |
b0d00f8bd ACPI / LPSS: drop... |
369 |
clk = clk_data->clk; |
b59cc200a ACPI / LPSS: regi... |
370 371 |
if (!pdata->mmio_base |
2e0f8822d ACPI / LPSS: Add ... |
372 |
|| pdata->mmio_size < dev_desc->prv_offset + LPSS_CLK_SIZE) |
f58b082ae ACPI / scan: Add ... |
373 |
return -ENODATA; |
f62721706 ACPI / LPSS: add ... |
374 |
parent = clk_data->name; |
ed3a872e2 ACPI / LPSS: supp... |
375 |
prv_base = pdata->mmio_base + dev_desc->prv_offset; |
f62721706 ACPI / LPSS: add ... |
376 |
|
03f09f73b ACPI / LPSS: supp... |
377 378 379 380 |
if (pdata->fixed_clk_rate) { clk = clk_register_fixed_rate(NULL, devname, parent, 0, pdata->fixed_clk_rate); goto out; |
f62721706 ACPI / LPSS: add ... |
381 |
} |
ff8c1af5e ACPI / LPSS: intr... |
382 |
if (dev_desc->flags & LPSS_CLK_GATE) { |
ed3a872e2 ACPI / LPSS: supp... |
383 384 385 386 |
clk = clk_register_gate(NULL, devname, parent, 0, prv_base, 0, 0, NULL); parent = devname; } |
ff8c1af5e ACPI / LPSS: intr... |
387 |
if (dev_desc->flags & LPSS_CLK_DIVIDER) { |
ed3a872e2 ACPI / LPSS: supp... |
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 |
/* Prevent division by zero */ if (!readl(prv_base)) writel(LPSS_CLK_DIVIDER_DEF_MASK, prv_base); clk_name = kasprintf(GFP_KERNEL, "%s-div", devname); if (!clk_name) return -ENOMEM; clk = clk_register_fractional_divider(NULL, clk_name, parent, 0, prv_base, 1, 15, 16, 15, 0, NULL); parent = clk_name; clk_name = kasprintf(GFP_KERNEL, "%s-update", devname); if (!clk_name) { kfree(parent); return -ENOMEM; } clk = clk_register_gate(NULL, clk_name, parent, CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, prv_base, 31, 0, NULL); kfree(parent); kfree(clk_name); |
f62721706 ACPI / LPSS: add ... |
410 |
} |
03f09f73b ACPI / LPSS: supp... |
411 |
out: |
f62721706 ACPI / LPSS: add ... |
412 413 |
if (IS_ERR(clk)) return PTR_ERR(clk); |
f58b082ae ACPI / scan: Add ... |
414 |
|
ed3a872e2 ACPI / LPSS: supp... |
415 |
pdata->clk = clk; |
fcf0789a9 ACPI / LPSS: prov... |
416 |
clk_register_clkdev(clk, dev_desc->clk_con_id, devname); |
f58b082ae ACPI / scan: Add ... |
417 418 |
return 0; } |
e6ce0ce34 ACPI / LPSS: Add ... |
419 420 421 422 423 424 |
struct lpss_device_links { const char *supplier_hid; const char *supplier_uid; const char *consumer_hid; const char *consumer_uid; u32 flags; |
6025e2fae ACPI: LPSS: Add d... |
425 426 427 428 429 430 431 432 433 434 435 436 |
const struct dmi_system_id *dep_missing_ids; }; /* Please keep this list sorted alphabetically by vendor and model */ static const struct dmi_system_id i2c1_dep_missing_dmi_ids[] = { { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_PRODUCT_NAME, "T200TA"), }, }, {} |
e6ce0ce34 ACPI / LPSS: Add ... |
437 438 439 440 441 442 443 444 445 446 |
}; /* * The _DEP method is used to identify dependencies but instead of creating * device links for every handle in _DEP, only links in the following list are * created. That is necessary because, in the general case, _DEP can refer to * devices that might not have drivers, or that are on different buses, or where * the supplier is not enumerated until after the consumer is probed. */ static const struct lpss_device_links lpss_device_links[] = { |
cc18735f2 ACPI: LPSS: Add L... |
447 |
/* CHT External sdcard slot controller depends on PMIC I2C ctrl */ |
e6ce0ce34 ACPI / LPSS: Add ... |
448 |
{"808622C1", "7", "80860F14", "3", DL_FLAG_PM_RUNTIME}, |
cc18735f2 ACPI: LPSS: Add L... |
449 |
/* CHT iGPU depends on PMIC I2C controller */ |
bd0f4e342 ACPI / LPSS: Add ... |
450 |
{"808622C1", "7", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME}, |
b3b3519c0 ACPI: LPSS: Add L... |
451 |
/* BYT iGPU depends on the Embedded Controller I2C controller (UID 1) */ |
6025e2fae ACPI: LPSS: Add d... |
452 453 |
{"80860F41", "1", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME, i2c1_dep_missing_dmi_ids}, |
cc18735f2 ACPI: LPSS: Add L... |
454 |
/* BYT CR iGPU depends on PMIC I2C controller (UID 5 on CR) */ |
2d71ee0ce ACPI / LPSS: Add ... |
455 |
{"80860F41", "5", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME}, |
cc18735f2 ACPI: LPSS: Add L... |
456 457 |
/* BYT iGPU depends on PMIC I2C controller (UID 7 on non CR) */ {"80860F41", "7", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME}, |
e6ce0ce34 ACPI / LPSS: Add ... |
458 |
}; |
e6ce0ce34 ACPI / LPSS: Add ... |
459 460 461 |
static bool acpi_lpss_is_supplier(struct acpi_device *adev, const struct lpss_device_links *link) { |
7e70c8acf ACPI / LPSS: Swit... |
462 |
return acpi_dev_hid_uid_match(adev, link->supplier_hid, link->supplier_uid); |
e6ce0ce34 ACPI / LPSS: Add ... |
463 464 465 466 467 |
} static bool acpi_lpss_is_consumer(struct acpi_device *adev, const struct lpss_device_links *link) { |
7e70c8acf ACPI / LPSS: Swit... |
468 |
return acpi_dev_hid_uid_match(adev, link->consumer_hid, link->consumer_uid); |
e6ce0ce34 ACPI / LPSS: Add ... |
469 470 471 472 473 474 |
} struct hid_uid { const char *hid; const char *uid; }; |
418e3ea15 bus_find_device: ... |
475 |
static int match_hid_uid(struct device *dev, const void *data) |
e6ce0ce34 ACPI / LPSS: Add ... |
476 477 |
{ struct acpi_device *adev = ACPI_COMPANION(dev); |
418e3ea15 bus_find_device: ... |
478 |
const struct hid_uid *id = data; |
e6ce0ce34 ACPI / LPSS: Add ... |
479 480 481 |
if (!adev) return 0; |
7e70c8acf ACPI / LPSS: Swit... |
482 |
return acpi_dev_hid_uid_match(adev, id->hid, id->uid); |
e6ce0ce34 ACPI / LPSS: Add ... |
483 484 485 486 |
} static struct device *acpi_lpss_find_device(const char *hid, const char *uid) { |
1e30124ac ACPI / LPSS: Make... |
487 |
struct device *dev; |
e6ce0ce34 ACPI / LPSS: Add ... |
488 489 490 491 |
struct hid_uid data = { .hid = hid, .uid = uid, }; |
1e30124ac ACPI / LPSS: Make... |
492 493 494 495 496 |
dev = bus_find_device(&platform_bus_type, NULL, &data, match_hid_uid); if (dev) return dev; return bus_find_device(&pci_bus_type, NULL, &data, match_hid_uid); |
e6ce0ce34 ACPI / LPSS: Add ... |
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 |
} static bool acpi_lpss_dep(struct acpi_device *adev, acpi_handle handle) { struct acpi_handle_list dep_devices; acpi_status status; int i; if (!acpi_has_method(adev->handle, "_DEP")) return false; status = acpi_evaluate_reference(adev->handle, "_DEP", NULL, &dep_devices); if (ACPI_FAILURE(status)) { dev_dbg(&adev->dev, "Failed to evaluate _DEP. "); return false; } for (i = 0; i < dep_devices.count; i++) { if (dep_devices.handles[i] == handle) return true; } return false; } static void acpi_lpss_link_consumer(struct device *dev1, const struct lpss_device_links *link) { struct device *dev2; dev2 = acpi_lpss_find_device(link->consumer_hid, link->consumer_uid); if (!dev2) return; |
6025e2fae ACPI: LPSS: Add d... |
532 533 |
if ((link->dep_missing_ids && dmi_check_system(link->dep_missing_ids)) || acpi_lpss_dep(ACPI_COMPANION(dev2), ACPI_HANDLE(dev1))) |
e6ce0ce34 ACPI / LPSS: Add ... |
534 535 536 537 538 539 540 541 542 543 544 545 546 |
device_link_add(dev2, dev1, link->flags); put_device(dev2); } static void acpi_lpss_link_supplier(struct device *dev1, const struct lpss_device_links *link) { struct device *dev2; dev2 = acpi_lpss_find_device(link->supplier_hid, link->supplier_uid); if (!dev2) return; |
6025e2fae ACPI: LPSS: Add d... |
547 548 |
if ((link->dep_missing_ids && dmi_check_system(link->dep_missing_ids)) || acpi_lpss_dep(ACPI_COMPANION(dev1), ACPI_HANDLE(dev2))) |
e6ce0ce34 ACPI / LPSS: Add ... |
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 |
device_link_add(dev1, dev2, link->flags); put_device(dev2); } static void acpi_lpss_create_device_links(struct acpi_device *adev, struct platform_device *pdev) { int i; for (i = 0; i < ARRAY_SIZE(lpss_device_links); i++) { const struct lpss_device_links *link = &lpss_device_links[i]; if (acpi_lpss_is_supplier(adev, link)) acpi_lpss_link_consumer(&pdev->dev, link); if (acpi_lpss_is_consumer(adev, link)) acpi_lpss_link_supplier(&pdev->dev, link); } } |
f58b082ae ACPI / scan: Add ... |
569 570 571 |
static int acpi_lpss_create_device(struct acpi_device *adev, const struct acpi_device_id *id) { |
b2687cd7d ACPI / LPSS: cons... |
572 |
const struct lpss_device_desc *dev_desc; |
f58b082ae ACPI / scan: Add ... |
573 |
struct lpss_private_data *pdata; |
90e978206 resources: Move s... |
574 |
struct resource_entry *rentry; |
f58b082ae ACPI / scan: Add ... |
575 |
struct list_head resource_list; |
8ce62f85a ACPI / platform /... |
576 |
struct platform_device *pdev; |
f58b082ae ACPI / scan: Add ... |
577 |
int ret; |
b2687cd7d ACPI / LPSS: cons... |
578 |
dev_desc = (const struct lpss_device_desc *)id->driver_data; |
8ce62f85a ACPI / platform /... |
579 |
if (!dev_desc) { |
1571875be ACPI / platform: ... |
580 |
pdev = acpi_create_platform_device(adev, NULL); |
8ce62f85a ACPI / platform /... |
581 582 |
return IS_ERR_OR_NULL(pdev) ? PTR_ERR(pdev) : 1; } |
f58b082ae ACPI / scan: Add ... |
583 584 585 586 587 588 589 590 591 592 |
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, is_memory, NULL); if (ret < 0) goto err_out; list_for_each_entry(rentry, &resource_list, node) |
90e978206 resources: Move s... |
593 |
if (resource_type(rentry->res) == IORESOURCE_MEM) { |
958c4eb2a ACPI / LPSS: over... |
594 595 596 |
if (dev_desc->prv_size_override) pdata->mmio_size = dev_desc->prv_size_override; else |
90e978206 resources: Move s... |
597 598 |
pdata->mmio_size = resource_size(rentry->res); pdata->mmio_base = ioremap(rentry->res->start, |
f58b082ae ACPI / scan: Add ... |
599 |
pdata->mmio_size); |
f58b082ae ACPI / scan: Add ... |
600 601 602 603 |
break; } acpi_dev_free_resource_list(&resource_list); |
d3e13ff3c ACPI / LPSS: Fix ... |
604 |
if (!pdata->mmio_base) { |
e16815993 ACPI / LPSS: Do n... |
605 606 |
/* Avoid acpi_bus_attach() instantiating a pdev for this dev. */ adev->pnp.type.platform_id = 0; |
a4bb2b493 ACPI / LPSS: Don'... |
607 608 |
/* Skip the device, but continue the namespace scan. */ ret = 0; |
d3e13ff3c ACPI / LPSS: Fix ... |
609 610 |
goto err_out; } |
dd242a080 ACPI / LPSS: Only... |
611 |
pdata->adev = adev; |
af65cfe9a ACPI / LPSS: don'... |
612 |
pdata->dev_desc = dev_desc; |
03f09f73b ACPI / LPSS: supp... |
613 614 |
if (dev_desc->setup) dev_desc->setup(pdata); |
ff8c1af5e ACPI / LPSS: intr... |
615 |
if (dev_desc->flags & LPSS_CLK) { |
f58b082ae ACPI / scan: Add ... |
616 617 |
ret = register_device_clock(adev, pdata); if (ret) { |
b9e95fc65 ACPI / LPSS: Powe... |
618 619 620 |
/* Skip the device, but continue the namespace scan. */ ret = 0; goto err_out; |
f58b082ae ACPI / scan: Add ... |
621 622 |
} } |
b9e95fc65 ACPI / LPSS: Powe... |
623 624 625 626 627 |
/* * This works around a known issue in ACPI tables where LPSS devices * have _PS0 and _PS3 without _PSC (and no power resources), so * acpi_bus_init_power() will assume that the BIOS has put them into D0. */ |
1a2fa02f7 ACPI / LPSS: Igno... |
628 |
acpi_device_fix_up_power(adev); |
b9e95fc65 ACPI / LPSS: Powe... |
629 |
|
f58b082ae ACPI / scan: Add ... |
630 |
adev->driver_data = pdata; |
1571875be ACPI / platform: ... |
631 |
pdev = acpi_create_platform_device(adev, dev_desc->properties); |
8ce62f85a ACPI / platform /... |
632 |
if (!IS_ERR_OR_NULL(pdev)) { |
e6ce0ce34 ACPI / LPSS: Add ... |
633 |
acpi_lpss_create_device_links(adev, pdev); |
8ce62f85a ACPI / platform /... |
634 635 |
return 1; } |
f58b082ae ACPI / scan: Add ... |
636 |
|
8ce62f85a ACPI / platform /... |
637 |
ret = PTR_ERR(pdev); |
f58b082ae ACPI / scan: Add ... |
638 639 640 641 642 643 |
adev->driver_data = NULL; err_out: kfree(pdata); return ret; } |
1a8f83515 ACPI / LPSS: Supp... |
644 645 646 647 648 649 650 651 652 653 |
static u32 __lpss_reg_read(struct lpss_private_data *pdata, unsigned int reg) { return readl(pdata->mmio_base + pdata->dev_desc->prv_offset + reg); } static void __lpss_reg_write(u32 val, struct lpss_private_data *pdata, unsigned int reg) { writel(val, pdata->mmio_base + pdata->dev_desc->prv_offset + reg); } |
2e0f8822d ACPI / LPSS: Add ... |
654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 |
static int lpss_reg_read(struct device *dev, unsigned int reg, u32 *val) { struct acpi_device *adev; struct lpss_private_data *pdata; unsigned long flags; int ret; ret = acpi_bus_get_device(ACPI_HANDLE(dev), &adev); if (WARN_ON(ret)) return ret; spin_lock_irqsave(&dev->power.lock, flags); if (pm_runtime_suspended(dev)) { ret = -EAGAIN; goto out; } pdata = acpi_driver_data(adev); if (WARN_ON(!pdata || !pdata->mmio_base)) { ret = -ENODEV; goto out; } |
1a8f83515 ACPI / LPSS: Supp... |
675 |
*val = __lpss_reg_read(pdata, reg); |
2e0f8822d ACPI / LPSS: Add ... |
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 |
out: spin_unlock_irqrestore(&dev->power.lock, flags); return ret; } static ssize_t lpss_ltr_show(struct device *dev, struct device_attribute *attr, char *buf) { u32 ltr_value = 0; unsigned int reg; int ret; reg = strcmp(attr->attr.name, "auto_ltr") ? LPSS_SW_LTR : LPSS_AUTO_LTR; ret = lpss_reg_read(dev, reg, <r_value); if (ret) return ret; return snprintf(buf, PAGE_SIZE, "%08x ", ltr_value); } static ssize_t lpss_ltr_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { u32 ltr_mode = 0; char *outstr; int ret; ret = lpss_reg_read(dev, LPSS_GENERAL, <r_mode); if (ret) return ret; outstr = (ltr_mode & LPSS_GENERAL_LTR_MODE_SW) ? "sw" : "auto"; return sprintf(buf, "%s ", outstr); } static DEVICE_ATTR(auto_ltr, S_IRUSR, lpss_ltr_show, NULL); static DEVICE_ATTR(sw_ltr, S_IRUSR, lpss_ltr_show, NULL); static DEVICE_ATTR(ltr_mode, S_IRUSR, lpss_ltr_mode_show, NULL); static struct attribute *lpss_attrs[] = { &dev_attr_auto_ltr.attr, &dev_attr_sw_ltr.attr, &dev_attr_ltr_mode.attr, NULL, }; |
31945d0eb ACPI / LPSS: cons... |
724 |
static const struct attribute_group lpss_attr_group = { |
2e0f8822d ACPI / LPSS: Add ... |
725 726 727 |
.attrs = lpss_attrs, .name = "lpss_ltr", }; |
1a8f83515 ACPI / LPSS: Supp... |
728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 |
static void acpi_lpss_set_ltr(struct device *dev, s32 val) { struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); u32 ltr_mode, ltr_val; ltr_mode = __lpss_reg_read(pdata, LPSS_GENERAL); if (val < 0) { if (ltr_mode & LPSS_GENERAL_LTR_MODE_SW) { ltr_mode &= ~LPSS_GENERAL_LTR_MODE_SW; __lpss_reg_write(ltr_mode, pdata, LPSS_GENERAL); } return; } ltr_val = __lpss_reg_read(pdata, LPSS_SW_LTR) & ~LPSS_LTR_SNOOP_MASK; if (val >= LPSS_LTR_SNOOP_LAT_CUTOFF) { ltr_val |= LPSS_LTR_SNOOP_LAT_32US; val = LPSS_LTR_MAX_VAL; } else if (val > LPSS_LTR_MAX_VAL) { ltr_val |= LPSS_LTR_SNOOP_LAT_32US | LPSS_LTR_SNOOP_REQ; val >>= LPSS_LTR_SNOOP_LAT_SHIFT; } else { ltr_val |= LPSS_LTR_SNOOP_LAT_1US | LPSS_LTR_SNOOP_REQ; } ltr_val |= val; __lpss_reg_write(ltr_val, pdata, LPSS_SW_LTR); if (!(ltr_mode & LPSS_GENERAL_LTR_MODE_SW)) { ltr_mode |= LPSS_GENERAL_LTR_MODE_SW; __lpss_reg_write(ltr_mode, pdata, LPSS_GENERAL); } } |
c78b08306 ACPI / LPSS: cust... |
758 759 760 761 |
#ifdef CONFIG_PM /** * acpi_lpss_save_ctx() - Save the private registers of LPSS device * @dev: LPSS device |
cb39dcdd4 ACPI / LPSS: add ... |
762 |
* @pdata: pointer to the private data of the LPSS device |
c78b08306 ACPI / LPSS: cust... |
763 764 765 766 767 |
* * Most LPSS devices have private registers which may loose their context when * the device is powered down. acpi_lpss_save_ctx() saves those registers into * prv_reg_ctx array. */ |
cb39dcdd4 ACPI / LPSS: add ... |
768 769 |
static void acpi_lpss_save_ctx(struct device *dev, struct lpss_private_data *pdata) |
c78b08306 ACPI / LPSS: cust... |
770 |
{ |
c78b08306 ACPI / LPSS: cust... |
771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 |
unsigned int i; for (i = 0; i < LPSS_PRV_REG_COUNT; i++) { unsigned long offset = i * sizeof(u32); pdata->prv_reg_ctx[i] = __lpss_reg_read(pdata, offset); dev_dbg(dev, "saving 0x%08x from LPSS reg at offset 0x%02lx ", pdata->prv_reg_ctx[i], offset); } } /** * acpi_lpss_restore_ctx() - Restore the private registers of LPSS device * @dev: LPSS device |
cb39dcdd4 ACPI / LPSS: add ... |
786 |
* @pdata: pointer to the private data of the LPSS device |
c78b08306 ACPI / LPSS: cust... |
787 788 789 |
* * Restores the registers that were previously stored with acpi_lpss_save_ctx(). */ |
cb39dcdd4 ACPI / LPSS: add ... |
790 791 |
static void acpi_lpss_restore_ctx(struct device *dev, struct lpss_private_data *pdata) |
c78b08306 ACPI / LPSS: cust... |
792 |
{ |
c78b08306 ACPI / LPSS: cust... |
793 |
unsigned int i; |
02b985404 ACPI / LPSS: do d... |
794 795 796 797 798 799 800 801 802 803 804 805 |
for (i = 0; i < LPSS_PRV_REG_COUNT; i++) { unsigned long offset = i * sizeof(u32); __lpss_reg_write(pdata->prv_reg_ctx[i], pdata, offset); dev_dbg(dev, "restoring 0x%08x to LPSS reg at offset 0x%02lx ", pdata->prv_reg_ctx[i], offset); } } static void acpi_lpss_d3_to_d0_delay(struct lpss_private_data *pdata) { |
c78b08306 ACPI / LPSS: cust... |
806 807 808 809 |
/* * The following delay is needed or the subsequent write operations may * fail. The LPSS devices are actually PCI devices and the PCI spec * expects 10ms delay before the device can be accessed after D3 to D0 |
b00855aec ACPI / LPSS: Igno... |
810 |
* transition. However some platforms like BSW does not need this delay. |
c78b08306 ACPI / LPSS: cust... |
811 |
*/ |
b00855aec ACPI / LPSS: Igno... |
812 813 814 815 816 817 |
unsigned int delay = 10; /* default 10ms delay */ if (pdata->dev_desc->flags & LPSS_NO_D3_DELAY) delay = 0; msleep(delay); |
c78b08306 ACPI / LPSS: cust... |
818 |
} |
c3a49cf35 ACPI / LPSS: powe... |
819 820 821 822 |
static int acpi_lpss_activate(struct device *dev) { struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); int ret; |
63705c406 ACPI / PM: Combin... |
823 |
ret = acpi_dev_resume(dev); |
c3a49cf35 ACPI / LPSS: powe... |
824 825 826 827 828 829 830 831 832 833 834 |
if (ret) return ret; acpi_lpss_d3_to_d0_delay(pdata); /* * This is called only on ->probe() stage where a device is either in * known state defined by BIOS or most likely powered off. Due to this * we have to deassert reset line to be sure that ->probe() will * recognize the device. */ |
15aa5e4c4 ACPI / LPSS: Save... |
835 |
if (pdata->dev_desc->flags & (LPSS_SAVE_CTX | LPSS_SAVE_CTX_ONCE)) |
c3a49cf35 ACPI / LPSS: powe... |
836 |
lpss_deassert_reset(pdata); |
15aa5e4c4 ACPI / LPSS: Save... |
837 838 839 840 |
#ifdef CONFIG_PM if (pdata->dev_desc->flags & LPSS_SAVE_CTX_ONCE) acpi_lpss_save_ctx(dev, pdata); #endif |
c3a49cf35 ACPI / LPSS: powe... |
841 842 843 844 845 |
return 0; } static void acpi_lpss_dismiss(struct device *dev) { |
cbe25ce37 ACPI / PM: Combin... |
846 |
acpi_dev_suspend(dev, false); |
c3a49cf35 ACPI / LPSS: powe... |
847 |
} |
eebb3e8d8 ACPI / LPSS: over... |
848 849 850 851 852 853 854 855 856 857 858 859 860 861 |
/* IOSF SB for LPSS island */ #define LPSS_IOSF_UNIT_LPIOEP 0xA0 #define LPSS_IOSF_UNIT_LPIO1 0xAB #define LPSS_IOSF_UNIT_LPIO2 0xAC #define LPSS_IOSF_PMCSR 0x84 #define LPSS_PMCSR_D0 0 #define LPSS_PMCSR_D3hot 3 #define LPSS_PMCSR_Dx_MASK GENMASK(1, 0) #define LPSS_IOSF_GPIODEF0 0x154 #define LPSS_GPIODEF0_DMA1_D3 BIT(2) #define LPSS_GPIODEF0_DMA2_D3 BIT(3) #define LPSS_GPIODEF0_DMA_D3_MASK GENMASK(3, 2) |
d132d6d53 ACPI / LPSS: enab... |
862 |
#define LPSS_GPIODEF0_DMA_LLP BIT(13) |
eebb3e8d8 ACPI / LPSS: over... |
863 864 |
static DEFINE_MUTEX(lpss_iosf_mutex); |
f11fc4bc6 ACPI / LPSS: Forc... |
865 |
static bool lpss_iosf_d3_entered = true; |
eebb3e8d8 ACPI / LPSS: over... |
866 867 868 869 |
static void lpss_iosf_enter_d3_state(void) { u32 value1 = 0; |
d132d6d53 ACPI / LPSS: enab... |
870 |
u32 mask1 = LPSS_GPIODEF0_DMA_D3_MASK | LPSS_GPIODEF0_DMA_LLP; |
eebb3e8d8 ACPI / LPSS: over... |
871 872 873 874 875 876 877 |
u32 value2 = LPSS_PMCSR_D3hot; u32 mask2 = LPSS_PMCSR_Dx_MASK; /* * PMC provides an information about actual status of the LPSS devices. * Here we read the values related to LPSS power island, i.e. LPSS * devices, excluding both LPSS DMA controllers, along with SCC domain. */ |
86b62e5cd ACPI / LPSS: Excl... |
878 |
u32 func_dis, d3_sts_0, pmc_status; |
eebb3e8d8 ACPI / LPSS: over... |
879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 |
int ret; ret = pmc_atom_read(PMC_FUNC_DIS, &func_dis); if (ret) return; mutex_lock(&lpss_iosf_mutex); ret = pmc_atom_read(PMC_D3_STS_0, &d3_sts_0); if (ret) goto exit; /* * Get the status of entire LPSS power island per device basis. * Shutdown both LPSS DMA controllers if and only if all other devices * are already in D3hot. */ |
86b62e5cd ACPI / LPSS: Excl... |
896 |
pmc_status = (~(d3_sts_0 | func_dis)) & pmc_atom_d3_mask; |
eebb3e8d8 ACPI / LPSS: over... |
897 898 899 900 901 902 903 904 905 906 907 |
if (pmc_status) goto exit; iosf_mbi_modify(LPSS_IOSF_UNIT_LPIO1, MBI_CFG_WRITE, LPSS_IOSF_PMCSR, value2, mask2); iosf_mbi_modify(LPSS_IOSF_UNIT_LPIO2, MBI_CFG_WRITE, LPSS_IOSF_PMCSR, value2, mask2); iosf_mbi_modify(LPSS_IOSF_UNIT_LPIOEP, MBI_CR_WRITE, LPSS_IOSF_GPIODEF0, value1, mask1); |
12864ff85 ACPI / LPSS: Avoi... |
908 909 |
lpss_iosf_d3_entered = true; |
eebb3e8d8 ACPI / LPSS: over... |
910 911 912 913 914 915 |
exit: mutex_unlock(&lpss_iosf_mutex); } static void lpss_iosf_exit_d3_state(void) { |
d132d6d53 ACPI / LPSS: enab... |
916 917 918 |
u32 value1 = LPSS_GPIODEF0_DMA1_D3 | LPSS_GPIODEF0_DMA2_D3 | LPSS_GPIODEF0_DMA_LLP; u32 mask1 = LPSS_GPIODEF0_DMA_D3_MASK | LPSS_GPIODEF0_DMA_LLP; |
eebb3e8d8 ACPI / LPSS: over... |
919 920 921 922 |
u32 value2 = LPSS_PMCSR_D0; u32 mask2 = LPSS_PMCSR_Dx_MASK; mutex_lock(&lpss_iosf_mutex); |
12864ff85 ACPI / LPSS: Avoi... |
923 924 925 926 |
if (!lpss_iosf_d3_entered) goto exit; lpss_iosf_d3_entered = false; |
eebb3e8d8 ACPI / LPSS: over... |
927 928 929 930 931 932 933 934 |
iosf_mbi_modify(LPSS_IOSF_UNIT_LPIOEP, MBI_CR_WRITE, LPSS_IOSF_GPIODEF0, value1, mask1); iosf_mbi_modify(LPSS_IOSF_UNIT_LPIO2, MBI_CFG_WRITE, LPSS_IOSF_PMCSR, value2, mask2); iosf_mbi_modify(LPSS_IOSF_UNIT_LPIO1, MBI_CFG_WRITE, LPSS_IOSF_PMCSR, value2, mask2); |
12864ff85 ACPI / LPSS: Avoi... |
935 |
exit: |
eebb3e8d8 ACPI / LPSS: over... |
936 937 |
mutex_unlock(&lpss_iosf_mutex); } |
12864ff85 ACPI / LPSS: Avoi... |
938 |
static int acpi_lpss_suspend(struct device *dev, bool wakeup) |
c78b08306 ACPI / LPSS: cust... |
939 |
{ |
cb39dcdd4 ACPI / LPSS: add ... |
940 941 |
struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); int ret; |
c78b08306 ACPI / LPSS: cust... |
942 |
|
cb39dcdd4 ACPI / LPSS: add ... |
943 944 |
if (pdata->dev_desc->flags & LPSS_SAVE_CTX) acpi_lpss_save_ctx(dev, pdata); |
a192aa923 ACPI / LPSS: Cons... |
945 |
ret = acpi_dev_suspend(dev, wakeup); |
eebb3e8d8 ACPI / LPSS: over... |
946 947 948 949 950 951 |
/* * This call must be last in the sequence, otherwise PMC will return * wrong status for devices being about to be powered off. See * lpss_iosf_enter_d3_state() for further information. */ |
12864ff85 ACPI / LPSS: Avoi... |
952 |
if (acpi_target_system_state() == ACPI_STATE_S0 && |
a09c59130 ACPI / LPSS: Avoi... |
953 |
lpss_quirks & LPSS_QUIRK_ALWAYS_POWER_ON && iosf_mbi_available()) |
eebb3e8d8 ACPI / LPSS: over... |
954 955 956 |
lpss_iosf_enter_d3_state(); return ret; |
c78b08306 ACPI / LPSS: cust... |
957 |
} |
12864ff85 ACPI / LPSS: Avoi... |
958 |
static int acpi_lpss_resume(struct device *dev) |
c78b08306 ACPI / LPSS: cust... |
959 |
{ |
cb39dcdd4 ACPI / LPSS: add ... |
960 961 |
struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); int ret; |
c78b08306 ACPI / LPSS: cust... |
962 |
|
eebb3e8d8 ACPI / LPSS: over... |
963 964 965 966 |
/* * This call is kept first to be in symmetry with * acpi_lpss_runtime_suspend() one. */ |
12864ff85 ACPI / LPSS: Avoi... |
967 |
if (lpss_quirks & LPSS_QUIRK_ALWAYS_POWER_ON && iosf_mbi_available()) |
eebb3e8d8 ACPI / LPSS: over... |
968 |
lpss_iosf_exit_d3_state(); |
63705c406 ACPI / PM: Combin... |
969 |
ret = acpi_dev_resume(dev); |
c78b08306 ACPI / LPSS: cust... |
970 971 |
if (ret) return ret; |
02b985404 ACPI / LPSS: do d... |
972 |
acpi_lpss_d3_to_d0_delay(pdata); |
15aa5e4c4 ACPI / LPSS: Save... |
973 |
if (pdata->dev_desc->flags & (LPSS_SAVE_CTX | LPSS_SAVE_CTX_ONCE)) |
cb39dcdd4 ACPI / LPSS: add ... |
974 |
acpi_lpss_restore_ctx(dev, pdata); |
a192aa923 ACPI / LPSS: Cons... |
975 976 977 978 |
return 0; } #ifdef CONFIG_PM_SLEEP |
48402cee6 ACPI / LPSS: Resu... |
979 |
static int acpi_lpss_do_suspend_late(struct device *dev) |
a192aa923 ACPI / LPSS: Cons... |
980 |
{ |
05087360f ACPI / PM: Take S... |
981 |
int ret; |
fa2bfead9 PM: sleep: core: ... |
982 |
if (dev_pm_skip_suspend(dev)) |
05087360f ACPI / PM: Take S... |
983 |
return 0; |
a192aa923 ACPI / LPSS: Cons... |
984 |
|
05087360f ACPI / PM: Take S... |
985 |
ret = pm_generic_suspend_late(dev); |
12864ff85 ACPI / LPSS: Avoi... |
986 |
return ret ? ret : acpi_lpss_suspend(dev, device_may_wakeup(dev)); |
a192aa923 ACPI / LPSS: Cons... |
987 |
} |
48402cee6 ACPI / LPSS: Resu... |
988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 |
static int acpi_lpss_suspend_late(struct device *dev) { struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); if (pdata->dev_desc->resume_from_noirq) return 0; return acpi_lpss_do_suspend_late(dev); } static int acpi_lpss_suspend_noirq(struct device *dev) { struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); int ret; if (pdata->dev_desc->resume_from_noirq) { |
c95b7595f ACPI: PM: Introdu... |
1004 1005 1006 1007 1008 1009 1010 |
/* * The driver's ->suspend_late callback will be invoked by * acpi_lpss_do_suspend_late(), with the assumption that the * driver really wanted to run that code in ->suspend_noirq, but * it could not run after acpi_dev_suspend() and the driver * expected the latter to be called in the "late" phase. */ |
48402cee6 ACPI / LPSS: Resu... |
1011 1012 1013 1014 1015 1016 1017 1018 1019 |
ret = acpi_lpss_do_suspend_late(dev); if (ret) return ret; } return acpi_subsys_suspend_noirq(dev); } static int acpi_lpss_do_resume_early(struct device *dev) |
a192aa923 ACPI / LPSS: Cons... |
1020 |
{ |
12864ff85 ACPI / LPSS: Avoi... |
1021 |
int ret = acpi_lpss_resume(dev); |
a192aa923 ACPI / LPSS: Cons... |
1022 1023 1024 |
return ret ? ret : pm_generic_resume_early(dev); } |
48402cee6 ACPI / LPSS: Resu... |
1025 1026 1027 1028 1029 1030 1031 |
static int acpi_lpss_resume_early(struct device *dev) { struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); if (pdata->dev_desc->resume_from_noirq) return 0; |
76c70cb58 PM: sleep: core: ... |
1032 |
if (dev_pm_skip_resume(dev)) |
6e176bf8d PM: sleep: core: ... |
1033 |
return 0; |
48402cee6 ACPI / LPSS: Resu... |
1034 1035 1036 1037 1038 1039 1040 |
return acpi_lpss_do_resume_early(dev); } static int acpi_lpss_resume_noirq(struct device *dev) { struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); int ret; |
3cd7957e8 ACPI: PM: Simplif... |
1041 |
/* Follow acpi_subsys_resume_noirq(). */ |
76c70cb58 PM: sleep: core: ... |
1042 |
if (dev_pm_skip_resume(dev)) |
3cd7957e8 ACPI: PM: Simplif... |
1043 |
return 0; |
3cd7957e8 ACPI: PM: Simplif... |
1044 |
ret = pm_generic_resume_noirq(dev); |
48402cee6 ACPI / LPSS: Resu... |
1045 1046 |
if (ret) return ret; |
3cd7957e8 ACPI: PM: Simplif... |
1047 1048 |
if (!pdata->dev_desc->resume_from_noirq) return 0; |
48402cee6 ACPI / LPSS: Resu... |
1049 |
|
3cd7957e8 ACPI: PM: Simplif... |
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 |
/* * The driver's ->resume_early callback will be invoked by * acpi_lpss_do_resume_early(), with the assumption that the driver * really wanted to run that code in ->resume_noirq, but it could not * run before acpi_dev_resume() and the driver expected the latter to be * called in the "early" phase. */ return acpi_lpss_do_resume_early(dev); } static int acpi_lpss_do_restore_early(struct device *dev) { int ret = acpi_lpss_resume(dev); return ret ? ret : pm_generic_restore_early(dev); |
48402cee6 ACPI / LPSS: Resu... |
1065 |
} |
3cd7957e8 ACPI: PM: Simplif... |
1066 1067 1068 1069 1070 1071 1072 1073 |
static int acpi_lpss_restore_early(struct device *dev) { struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); if (pdata->dev_desc->resume_from_noirq) return 0; return acpi_lpss_do_restore_early(dev); |
48402cee6 ACPI / LPSS: Resu... |
1074 |
} |
3cd7957e8 ACPI: PM: Simplif... |
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 |
static int acpi_lpss_restore_noirq(struct device *dev) { struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); int ret; ret = pm_generic_restore_noirq(dev); if (ret) return ret; if (!pdata->dev_desc->resume_from_noirq) return 0; /* This is analogous to what happens in acpi_lpss_resume_noirq(). */ return acpi_lpss_do_restore_early(dev); } |
c95b7595f ACPI: PM: Introdu... |
1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 |
static int acpi_lpss_do_poweroff_late(struct device *dev) { int ret = pm_generic_poweroff_late(dev); return ret ? ret : acpi_lpss_suspend(dev, device_may_wakeup(dev)); } static int acpi_lpss_poweroff_late(struct device *dev) { struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); |
fa2bfead9 PM: sleep: core: ... |
1101 |
if (dev_pm_skip_suspend(dev)) |
c95b7595f ACPI: PM: Introdu... |
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 |
return 0; if (pdata->dev_desc->resume_from_noirq) return 0; return acpi_lpss_do_poweroff_late(dev); } static int acpi_lpss_poweroff_noirq(struct device *dev) { struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); |
fa2bfead9 PM: sleep: core: ... |
1113 |
if (dev_pm_skip_suspend(dev)) |
c95b7595f ACPI: PM: Introdu... |
1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 |
return 0; if (pdata->dev_desc->resume_from_noirq) { /* This is analogous to the acpi_lpss_suspend_noirq() case. */ int ret = acpi_lpss_do_poweroff_late(dev); if (ret) return ret; } return pm_generic_poweroff_noirq(dev); } |
a192aa923 ACPI / LPSS: Cons... |
1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 |
#endif /* CONFIG_PM_SLEEP */ static int acpi_lpss_runtime_suspend(struct device *dev) { int ret = pm_generic_runtime_suspend(dev); return ret ? ret : acpi_lpss_suspend(dev, true); } static int acpi_lpss_runtime_resume(struct device *dev) { |
12864ff85 ACPI / LPSS: Avoi... |
1136 |
int ret = acpi_lpss_resume(dev); |
a192aa923 ACPI / LPSS: Cons... |
1137 1138 |
return ret ? ret : pm_generic_runtime_resume(dev); |
c78b08306 ACPI / LPSS: cust... |
1139 |
} |
c78b08306 ACPI / LPSS: cust... |
1140 1141 1142 |
#endif /* CONFIG_PM */ static struct dev_pm_domain acpi_lpss_pm_domain = { |
c3a49cf35 ACPI / LPSS: powe... |
1143 1144 1145 1146 |
#ifdef CONFIG_PM .activate = acpi_lpss_activate, .dismiss = acpi_lpss_dismiss, #endif |
c78b08306 ACPI / LPSS: cust... |
1147 |
.ops = { |
5de21bb99 ACPI / PM: Drop C... |
1148 |
#ifdef CONFIG_PM |
c78b08306 ACPI / LPSS: cust... |
1149 |
#ifdef CONFIG_PM_SLEEP |
c78b08306 ACPI / LPSS: cust... |
1150 |
.prepare = acpi_subsys_prepare, |
e4da817d2 ACPI / PM: Restor... |
1151 |
.complete = acpi_subsys_complete, |
c78b08306 ACPI / LPSS: cust... |
1152 |
.suspend = acpi_subsys_suspend, |
f4168b617 ACPI / LPSS: comp... |
1153 |
.suspend_late = acpi_lpss_suspend_late, |
48402cee6 ACPI / LPSS: Resu... |
1154 1155 |
.suspend_noirq = acpi_lpss_suspend_noirq, .resume_noirq = acpi_lpss_resume_noirq, |
f4168b617 ACPI / LPSS: comp... |
1156 |
.resume_early = acpi_lpss_resume_early, |
c78b08306 ACPI / LPSS: cust... |
1157 |
.freeze = acpi_subsys_freeze, |
c95b7595f ACPI: PM: Introdu... |
1158 1159 1160 |
.poweroff = acpi_subsys_poweroff, .poweroff_late = acpi_lpss_poweroff_late, .poweroff_noirq = acpi_lpss_poweroff_noirq, |
3cd7957e8 ACPI: PM: Simplif... |
1161 1162 |
.restore_noirq = acpi_lpss_restore_noirq, .restore_early = acpi_lpss_restore_early, |
c78b08306 ACPI / LPSS: cust... |
1163 |
#endif |
c78b08306 ACPI / LPSS: cust... |
1164 1165 1166 1167 1168 |
.runtime_suspend = acpi_lpss_runtime_suspend, .runtime_resume = acpi_lpss_runtime_resume, #endif }, }; |
2e0f8822d ACPI / LPSS: Add ... |
1169 1170 1171 1172 1173 1174 1175 |
static int acpi_lpss_platform_notify(struct notifier_block *nb, unsigned long action, void *data) { struct platform_device *pdev = to_platform_device(data); struct lpss_private_data *pdata; struct acpi_device *adev; const struct acpi_device_id *id; |
2e0f8822d ACPI / LPSS: Add ... |
1176 1177 1178 1179 1180 1181 1182 1183 1184 |
id = acpi_match_device(acpi_lpss_device_ids, &pdev->dev); if (!id || !id->driver_data) return 0; if (acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev)) return 0; pdata = acpi_driver_data(adev); |
cb39dcdd4 ACPI / LPSS: add ... |
1185 |
if (!pdata) |
2e0f8822d ACPI / LPSS: Add ... |
1186 |
return 0; |
cb39dcdd4 ACPI / LPSS: add ... |
1187 1188 |
if (pdata->mmio_base && pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) { |
2e0f8822d ACPI / LPSS: Add ... |
1189 1190 1191 1192 |
dev_err(&pdev->dev, "MMIO size insufficient to access LTR "); return 0; } |
c78b08306 ACPI / LPSS: cust... |
1193 |
switch (action) { |
de16d5520 ACPI / LPSS: allo... |
1194 |
case BUS_NOTIFY_BIND_DRIVER: |
989561de9 PM / Domains: add... |
1195 |
dev_pm_domain_set(&pdev->dev, &acpi_lpss_pm_domain); |
b5f88dd1d Revert "ACPI / LP... |
1196 |
break; |
de16d5520 ACPI / LPSS: allo... |
1197 |
case BUS_NOTIFY_DRIVER_NOT_BOUND: |
b5f88dd1d Revert "ACPI / LP... |
1198 |
case BUS_NOTIFY_UNBOUND_DRIVER: |
5be6ada39 ACPI / LPSS: set ... |
1199 |
dev_pm_domain_set(&pdev->dev, NULL); |
b5f88dd1d Revert "ACPI / LP... |
1200 1201 |
break; case BUS_NOTIFY_ADD_DEVICE: |
989561de9 PM / Domains: add... |
1202 |
dev_pm_domain_set(&pdev->dev, &acpi_lpss_pm_domain); |
ff8c1af5e ACPI / LPSS: intr... |
1203 |
if (pdata->dev_desc->flags & LPSS_LTR) |
c78b08306 ACPI / LPSS: cust... |
1204 1205 |
return sysfs_create_group(&pdev->dev.kobj, &lpss_attr_group); |
01ac170ba ACPI / LPSS: allo... |
1206 |
break; |
c78b08306 ACPI / LPSS: cust... |
1207 |
case BUS_NOTIFY_DEL_DEVICE: |
ff8c1af5e ACPI / LPSS: intr... |
1208 |
if (pdata->dev_desc->flags & LPSS_LTR) |
c78b08306 ACPI / LPSS: cust... |
1209 |
sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group); |
989561de9 PM / Domains: add... |
1210 |
dev_pm_domain_set(&pdev->dev, NULL); |
01ac170ba ACPI / LPSS: allo... |
1211 |
break; |
c78b08306 ACPI / LPSS: cust... |
1212 1213 1214 |
default: break; } |
2e0f8822d ACPI / LPSS: Add ... |
1215 |
|
c78b08306 ACPI / LPSS: cust... |
1216 |
return 0; |
2e0f8822d ACPI / LPSS: Add ... |
1217 1218 1219 1220 1221 |
} static struct notifier_block acpi_lpss_nb = { .notifier_call = acpi_lpss_platform_notify, }; |
1a8f83515 ACPI / LPSS: Supp... |
1222 1223 1224 |
static void acpi_lpss_bind(struct device *dev) { struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); |
ff8c1af5e ACPI / LPSS: intr... |
1225 |
if (!pdata || !pdata->mmio_base || !(pdata->dev_desc->flags & LPSS_LTR)) |
1a8f83515 ACPI / LPSS: Supp... |
1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 |
return; if (pdata->mmio_size >= pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) dev->power.set_latency_tolerance = acpi_lpss_set_ltr; else dev_err(dev, "MMIO size insufficient to access LTR "); } static void acpi_lpss_unbind(struct device *dev) { dev->power.set_latency_tolerance = NULL; } |
f58b082ae ACPI / scan: Add ... |
1239 1240 1241 |
static struct acpi_scan_handler lpss_handler = { .ids = acpi_lpss_device_ids, .attach = acpi_lpss_create_device, |
1a8f83515 ACPI / LPSS: Supp... |
1242 1243 |
.bind = acpi_lpss_bind, .unbind = acpi_lpss_unbind, |
f58b082ae ACPI / scan: Add ... |
1244 1245 1246 1247 |
}; void __init acpi_lpss_init(void) { |
eebb3e8d8 ACPI / LPSS: over... |
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 |
const struct x86_cpu_id *id; int ret; ret = lpt_clk_init(); if (ret) return; id = x86_match_cpu(lpss_cpu_ids); if (id) lpss_quirks |= LPSS_QUIRK_ALWAYS_POWER_ON; bus_register_notifier(&platform_bus_type, &acpi_lpss_nb); acpi_scan_add_handler(&lpss_handler); |
f58b082ae ACPI / scan: Add ... |
1261 |
} |
d6ddaaac8 ACPI / scan: alwa... |
1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 |
#else static struct acpi_scan_handler lpss_handler = { .ids = acpi_lpss_device_ids, }; void __init acpi_lpss_init(void) { acpi_scan_add_handler(&lpss_handler); } #endif /* CONFIG_X86_INTEL_LPSS */ |