Blame view

drivers/acpi/acpi_lpss.c 35.3 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
2
3
4
  /*
   * ACPI support for Intel Lynxpoint LPSS.
   *
3df2da968   Rafael J. Wysocki   Revert "ACPI / LP...
5
   * Copyright (C) 2013, Intel Corporation
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
6
7
   * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
   *          Rafael J. Wysocki <rafael.j.wysocki@intel.com>
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
8
9
10
   */
  
  #include <linux/acpi.h>
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
11
12
  #include <linux/clkdev.h>
  #include <linux/clk-provider.h>
6025e2fae   Hans de Goede   ACPI: LPSS: Add d...
13
  #include <linux/dmi.h>
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
14
15
  #include <linux/err.h>
  #include <linux/io.h>
eebb3e8d8   Andy Shevchenko   ACPI / LPSS: over...
16
  #include <linux/mutex.h>
1e30124ac   Hans de Goede   ACPI / LPSS: Make...
17
  #include <linux/pci.h>
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
18
  #include <linux/platform_device.h>
a9443a632   Andy Shevchenko   clk: x86: Move cl...
19
  #include <linux/platform_data/x86/clk-lpss.h>
80a7581f3   Irina Tirdea   arch/x86/platform...
20
  #include <linux/platform_data/x86/pmc_atom.h>
989561de9   Tomeu Vizoso   PM / Domains: add...
21
  #include <linux/pm_domain.h>
2e0f8822d   Rafael J. Wysocki   ACPI / LPSS: Add ...
22
  #include <linux/pm_runtime.h>
bf7696a12   Hans de Goede   acpi: lpss: call ...
23
  #include <linux/pwm.h>
a09c59130   Rafael J. Wysocki   ACPI / LPSS: Avoi...
24
  #include <linux/suspend.h>
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
25
  #include <linux/delay.h>
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
26
27
  
  #include "internal.h"
d6ddaaac8   Rafael J. Wysocki   ACPI / scan: alwa...
28
  #ifdef CONFIG_X86_INTEL_LPSS
eebb3e8d8   Andy Shevchenko   ACPI / LPSS: over...
29
  #include <asm/cpu_device_id.h>
4626d840a   Dave Hansen   x86/acpi/lss: Use...
30
  #include <asm/intel-family.h>
eebb3e8d8   Andy Shevchenko   ACPI / LPSS: over...
31
  #include <asm/iosf_mbi.h>
eebb3e8d8   Andy Shevchenko   ACPI / LPSS: over...
32

d6ddaaac8   Rafael J. Wysocki   ACPI / scan: alwa...
33
  #define LPSS_ADDR(desc) ((unsigned long)&desc)
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
34
  #define LPSS_CLK_SIZE	0x04
2e0f8822d   Rafael J. Wysocki   ACPI / LPSS: Add ...
35
36
37
  #define LPSS_LTR_SIZE	0x18
  
  /* Offsets relative to LPSS_PRIVATE_OFFSET */
ed3a872e2   Heikki Krogerus   ACPI / LPSS: supp...
38
  #define LPSS_CLK_DIVIDER_DEF_MASK	(BIT(1) | BIT(16))
765bdd4e5   Mika Westerberg   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   Rafael J. Wysocki   ACPI / LPSS: Add ...
42
43
  #define LPSS_GENERAL			0x08
  #define LPSS_GENERAL_LTR_MODE_SW	BIT(2)
088f1fd26   Heikki Krogerus   ACPI / LPSS: fix ...
44
  #define LPSS_GENERAL_UART_RTS_OVRD	BIT(3)
2e0f8822d   Rafael J. Wysocki   ACPI / LPSS: Add ...
45
46
  #define LPSS_SW_LTR			0x10
  #define LPSS_AUTO_LTR			0x14
1a8f83515   Rafael J. Wysocki   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   Heikki Krogerus   ACPI / LPSS: mask...
54
55
  #define LPSS_TX_INT			0x20
  #define LPSS_TX_INT_MASK		BIT(1)
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
56

c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
57
  #define LPSS_PRV_REG_COUNT		9
ff8c1af5e   Heikki Krogerus   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   Hans de Goede   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   Mika Westerberg   ACPI / LPSS: add ...
73

06d864150   Heikki Krogerus   ACPI / LPSS: mask...
74
  struct lpss_private_data;
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
75
76
  
  struct lpss_device_desc {
ff8c1af5e   Heikki Krogerus   ACPI / LPSS: intr...
77
  	unsigned int flags;
fcf0789a9   Heikki Krogerus   ACPI / LPSS: prov...
78
  	const char *clk_con_id;
2e0f8822d   Rafael J. Wysocki   ACPI / LPSS: Add ...
79
  	unsigned int prv_offset;
958c4eb2a   Mika Westerberg   ACPI / LPSS: over...
80
  	size_t prv_size_override;
a5565cf23   Heikki Krogerus   ACPI / LPSS: Prov...
81
  	struct property_entry *properties;
06d864150   Heikki Krogerus   ACPI / LPSS: mask...
82
  	void (*setup)(struct lpss_private_data *pdata);
48402cee6   Hans de Goede   ACPI / LPSS: Resu...
83
  	bool resume_from_noirq;
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
84
  };
eebb3e8d8   Andy Shevchenko   ACPI / LPSS: over...
85
  static const struct lpss_device_desc lpss_dma_desc = {
3df2da968   Rafael J. Wysocki   Revert "ACPI / LP...
86
  	.flags = LPSS_CLK,
b59cc200a   Rafael J. Wysocki   ACPI / LPSS: regi...
87
  };
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
88
  struct lpss_private_data {
dd242a080   Hans de Goede   ACPI / LPSS: Only...
89
  	struct acpi_device *adev;
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
90
91
  	void __iomem *mmio_base;
  	resource_size_t mmio_size;
03f09f73b   Heikki Krogerus   ACPI / LPSS: supp...
92
  	unsigned int fixed_clk_rate;
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
93
94
  	struct clk *clk;
  	const struct lpss_device_desc *dev_desc;
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
95
  	u32 prv_reg_ctx[LPSS_PRV_REG_COUNT];
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
96
  };
86b62e5cd   Hans de Goede   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   Andy Shevchenko   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   Andy Shevchenko   ACPI / LPSS: chan...
105
   * The LPSS DMA controller has neither _PS0 nor _PS3 method. Moreover
eebb3e8d8   Andy Shevchenko   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   Heikki Krogerus   ACPI / LPSS: not ...
115
116
117
  /* UART Component Parameter Register */
  #define LPSS_UART_CPR			0xF4
  #define LPSS_UART_CPR_AFCE		BIT(4)
06d864150   Heikki Krogerus   ACPI / LPSS: mask...
118
119
  static void lpss_uart_setup(struct lpss_private_data *pdata)
  {
088f1fd26   Heikki Krogerus   ACPI / LPSS: fix ...
120
  	unsigned int offset;
1f47a77c4   Heikki Krogerus   ACPI / LPSS: not ...
121
  	u32 val;
06d864150   Heikki Krogerus   ACPI / LPSS: mask...
122

088f1fd26   Heikki Krogerus   ACPI / LPSS: fix ...
123
  	offset = pdata->dev_desc->prv_offset + LPSS_TX_INT;
1f47a77c4   Heikki Krogerus   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   Heikki Krogerus   ACPI / LPSS: mask...
134
  }
3095794ae   Mika Westerberg   ACPI / LPSS: Deas...
135
  static void lpss_deassert_reset(struct lpss_private_data *pdata)
765bdd4e5   Mika Westerberg   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   Mika Westerberg   ACPI / LPSS: Deas...
144
  }
04434ab51   Hans de Goede   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   Hans de Goede   ACPI / LPSS: Rena...
151
  			       "pwm_soc_backlight", 0, PWM_POLARITY_NORMAL,
04434ab51   Hans de Goede   ACPI / LPSS: Call...
152
153
154
155
156
  			       "pwm-lpss-platform"),
  };
  
  static void byt_pwm_setup(struct lpss_private_data *pdata)
  {
dd242a080   Hans de Goede   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   Hans de Goede   ACPI / LPSS: Rena...
162
  	pwm_add_table(byt_pwm_lookup, ARRAY_SIZE(byt_pwm_lookup));
04434ab51   Hans de Goede   ACPI / LPSS: Call...
163
  }
3095794ae   Mika Westerberg   ACPI / LPSS: Deas...
164
165
166
167
  #define LPSS_I2C_ENABLE			0x6c
  
  static void byt_i2c_setup(struct lpss_private_data *pdata)
  {
86b62e5cd   Hans de Goede   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   Mika Westerberg   ACPI / LPSS: Deas...
182
  	lpss_deassert_reset(pdata);
765bdd4e5   Mika Westerberg   ACPI / LPSS: Take...
183

03f09f73b   Heikki Krogerus   ACPI / LPSS: supp...
184
185
  	if (readl(pdata->mmio_base + pdata->dev_desc->prv_offset))
  		pdata->fixed_clk_rate = 133000000;
3293c7b8e   Mika Westerberg   ACPI / LPSS: Alwa...
186
187
  
  	writel(0, pdata->mmio_base + LPSS_I2C_ENABLE);
765bdd4e5   Mika Westerberg   ACPI / LPSS: Take...
188
  }
43218a1b3   Jie Yang   ACPI / LPSS: add ...
189

bf7696a12   Hans de Goede   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   Hans de Goede   ACPI / LPSS: Rena...
193
  			       "pwm_soc_backlight", 0, PWM_POLARITY_NORMAL,
bf7696a12   Hans de Goede   acpi: lpss: call ...
194
195
196
197
198
  			       "pwm-lpss-platform"),
  };
  
  static void bsw_pwm_setup(struct lpss_private_data *pdata)
  {
dd242a080   Hans de Goede   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   Hans de Goede   acpi: lpss: call ...
204
205
  	pwm_add_table(bsw_pwm_lookup, ARRAY_SIZE(bsw_pwm_lookup));
  }
b2687cd7d   Mathias Krause   ACPI / LPSS: cons...
206
  static const struct lpss_device_desc lpt_dev_desc = {
57b300649   Jarkko Nikula   ACPI / LPSS: Save...
207
208
  	.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_LTR
  			| LPSS_SAVE_CTX,
2e0f8822d   Rafael J. Wysocki   ACPI / LPSS: Add ...
209
  	.prv_offset = 0x800,
ed3a872e2   Heikki Krogerus   ACPI / LPSS: supp...
210
  };
b2687cd7d   Mathias Krause   ACPI / LPSS: cons...
211
  static const struct lpss_device_desc lpt_i2c_dev_desc = {
57b300649   Jarkko Nikula   ACPI / LPSS: Save...
212
  	.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_LTR | LPSS_SAVE_CTX,
ed3a872e2   Heikki Krogerus   ACPI / LPSS: supp...
213
  	.prv_offset = 0x800,
2e0f8822d   Rafael J. Wysocki   ACPI / LPSS: Add ...
214
  };
a5565cf23   Heikki Krogerus   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   Mathias Krause   ACPI / LPSS: cons...
221
  static const struct lpss_device_desc lpt_uart_dev_desc = {
57b300649   Jarkko Nikula   ACPI / LPSS: Save...
222
223
  	.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_LTR
  			| LPSS_SAVE_CTX,
fcf0789a9   Heikki Krogerus   ACPI / LPSS: prov...
224
  	.clk_con_id = "baudclk",
06d864150   Heikki Krogerus   ACPI / LPSS: mask...
225
  	.prv_offset = 0x800,
06d864150   Heikki Krogerus   ACPI / LPSS: mask...
226
  	.setup = lpss_uart_setup,
a5565cf23   Heikki Krogerus   ACPI / LPSS: Prov...
227
  	.properties = uart_properties,
2e0f8822d   Rafael J. Wysocki   ACPI / LPSS: Add ...
228
  };
b2687cd7d   Mathias Krause   ACPI / LPSS: cons...
229
  static const struct lpss_device_desc lpt_sdio_dev_desc = {
ff8c1af5e   Heikki Krogerus   ACPI / LPSS: intr...
230
  	.flags = LPSS_LTR,
2e0f8822d   Rafael J. Wysocki   ACPI / LPSS: Add ...
231
  	.prv_offset = 0x1000,
958c4eb2a   Mika Westerberg   ACPI / LPSS: over...
232
  	.prv_size_override = 0x1018,
e1c748179   Chew, Chiau Ee   ACPI / LPSS: Add ...
233
  };
b2687cd7d   Mathias Krause   ACPI / LPSS: cons...
234
  static const struct lpss_device_desc byt_pwm_dev_desc = {
3f56bf3e9   Heikki Krogerus   ACPI / LPSS: remo...
235
  	.flags = LPSS_SAVE_CTX,
fdcb613d4   Hans de Goede   ACPI / LPSS: Add ...
236
  	.prv_offset = 0x800,
04434ab51   Hans de Goede   ACPI / LPSS: Call...
237
  	.setup = byt_pwm_setup,
e1c748179   Chew, Chiau Ee   ACPI / LPSS: Add ...
238
  };
b00855aec   Srinidhi Kasagar   ACPI / LPSS: Igno...
239
  static const struct lpss_device_desc bsw_pwm_dev_desc = {
15aa5e4c4   Hans de Goede   ACPI / LPSS: Save...
240
  	.flags = LPSS_SAVE_CTX_ONCE | LPSS_NO_D3_DELAY,
fdcb613d4   Hans de Goede   ACPI / LPSS: Add ...
241
  	.prv_offset = 0x800,
bf7696a12   Hans de Goede   acpi: lpss: call ...
242
  	.setup = bsw_pwm_setup,
5e31ee84c   Hans de Goede   ACPI / LPSS: Resu...
243
  	.resume_from_noirq = true,
b00855aec   Srinidhi Kasagar   ACPI / LPSS: Igno...
244
  };
b2687cd7d   Mathias Krause   ACPI / LPSS: cons...
245
  static const struct lpss_device_desc byt_uart_dev_desc = {
3df2da968   Rafael J. Wysocki   Revert "ACPI / LP...
246
  	.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
fcf0789a9   Heikki Krogerus   ACPI / LPSS: prov...
247
  	.clk_con_id = "baudclk",
f62721706   Mika Westerberg   ACPI / LPSS: add ...
248
  	.prv_offset = 0x800,
06d864150   Heikki Krogerus   ACPI / LPSS: mask...
249
  	.setup = lpss_uart_setup,
a5565cf23   Heikki Krogerus   ACPI / LPSS: Prov...
250
  	.properties = uart_properties,
f62721706   Mika Westerberg   ACPI / LPSS: add ...
251
  };
b00855aec   Srinidhi Kasagar   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   Heikki Krogerus   ACPI / LPSS: Prov...
258
  	.properties = uart_properties,
b00855aec   Srinidhi Kasagar   ACPI / LPSS: Igno...
259
  };
b2687cd7d   Mathias Krause   ACPI / LPSS: cons...
260
  static const struct lpss_device_desc byt_spi_dev_desc = {
3df2da968   Rafael J. Wysocki   Revert "ACPI / LP...
261
  	.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
f62721706   Mika Westerberg   ACPI / LPSS: add ...
262
  	.prv_offset = 0x400,
f62721706   Mika Westerberg   ACPI / LPSS: add ...
263
  };
b2687cd7d   Mathias Krause   ACPI / LPSS: cons...
264
  static const struct lpss_device_desc byt_sdio_dev_desc = {
3df2da968   Rafael J. Wysocki   Revert "ACPI / LP...
265
  	.flags = LPSS_CLK,
f62721706   Mika Westerberg   ACPI / LPSS: add ...
266
  };
b2687cd7d   Mathias Krause   ACPI / LPSS: cons...
267
  static const struct lpss_device_desc byt_i2c_dev_desc = {
3df2da968   Rafael J. Wysocki   Revert "ACPI / LP...
268
  	.flags = LPSS_CLK | LPSS_SAVE_CTX,
f62721706   Mika Westerberg   ACPI / LPSS: add ...
269
  	.prv_offset = 0x800,
03f09f73b   Heikki Krogerus   ACPI / LPSS: supp...
270
  	.setup = byt_i2c_setup,
48402cee6   Hans de Goede   ACPI / LPSS: Resu...
271
  	.resume_from_noirq = true,
1bfbd8eb8   Alan Cox   ACPI / LPSS: Add ...
272
  };
b00855aec   Srinidhi Kasagar   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   Hans de Goede   ACPI / LPSS: Resu...
277
  	.resume_from_noirq = true,
b00855aec   Srinidhi Kasagar   ACPI / LPSS: Igno...
278
  };
eebb3e8d8   Andy Shevchenko   ACPI / LPSS: over...
279
  static const struct lpss_device_desc bsw_spi_dev_desc = {
b00855aec   Srinidhi Kasagar   ACPI / LPSS: Igno...
280
281
  	.flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX
  			| LPSS_NO_D3_DELAY,
3095794ae   Mika Westerberg   ACPI / LPSS: Deas...
282
283
284
  	.prv_offset = 0x400,
  	.setup = lpss_deassert_reset,
  };
eebb3e8d8   Andy Shevchenko   ACPI / LPSS: over...
285
  static const struct x86_cpu_id lpss_cpu_ids[] = {
e36cf2f76   Thomas Gleixner   ACPI: Convert to ...
286
287
  	X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT,	NULL),
  	X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT,	NULL),
eebb3e8d8   Andy Shevchenko   ACPI / LPSS: over...
288
289
  	{}
  };
d6ddaaac8   Rafael J. Wysocki   ACPI / scan: alwa...
290
291
292
293
294
  #else
  
  #define LPSS_ADDR(desc) (0UL)
  
  #endif /* CONFIG_X86_INTEL_LPSS */
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
295
  static const struct acpi_device_id acpi_lpss_device_ids[] = {
b59cc200a   Rafael J. Wysocki   ACPI / LPSS: regi...
296
  	/* Generic LPSS devices */
d6ddaaac8   Rafael J. Wysocki   ACPI / scan: alwa...
297
  	{ "INTL9C60", LPSS_ADDR(lpss_dma_desc) },
b59cc200a   Rafael J. Wysocki   ACPI / LPSS: regi...
298

f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
299
  	/* Lynxpoint LPSS devices */
d6ddaaac8   Rafael J. Wysocki   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   Rafael J. Wysocki   ACPI / scan: Add ...
307
  	{ "INT33C7", },
f62721706   Mika Westerberg   ACPI / LPSS: add ...
308
  	/* BayTrail LPSS devices */
d6ddaaac8   Rafael J. Wysocki   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   Mika Westerberg   ACPI / LPSS: add ...
314
  	{ "INT33B2", },
20482d327   Jin Yao   pinctrl: baytrail...
315
  	{ "INT33FC", },
f62721706   Mika Westerberg   ACPI / LPSS: add ...
316

1bfbd8eb8   Alan Cox   ACPI / LPSS: Add ...
317
  	/* Braswell LPSS devices */
240714061   Hans de Goede   ACPI / LPSS: Add ...
318
  	{ "80862286", LPSS_ADDR(lpss_dma_desc) },
b00855aec   Srinidhi Kasagar   ACPI / LPSS: Igno...
319
320
  	{ "80862288", LPSS_ADDR(bsw_pwm_dev_desc) },
  	{ "8086228A", LPSS_ADDR(bsw_uart_dev_desc) },
3095794ae   Mika Westerberg   ACPI / LPSS: Deas...
321
  	{ "8086228E", LPSS_ADDR(bsw_spi_dev_desc) },
240714061   Hans de Goede   ACPI / LPSS: Add ...
322
  	{ "808622C0", LPSS_ADDR(lpss_dma_desc) },
b00855aec   Srinidhi Kasagar   ACPI / LPSS: Igno...
323
  	{ "808622C1", LPSS_ADDR(bsw_i2c_dev_desc) },
1bfbd8eb8   Alan Cox   ACPI / LPSS: Add ...
324

b00855aec   Srinidhi Kasagar   ACPI / LPSS: Igno...
325
  	/* Broadwell LPSS devices */
d6ddaaac8   Rafael J. Wysocki   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   Mika Westerberg   ACPI / LPSS: add ...
333
  	{ "INT3437", },
ff8c1af5e   Heikki Krogerus   ACPI / LPSS: intr...
334
335
  	/* Wildcat Point LPSS devices */
  	{ "INT3438", LPSS_ADDR(lpt_dev_desc) },
43218a1b3   Jie Yang   ACPI / LPSS: add ...
336

f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
337
338
  	{ }
  };
d6ddaaac8   Rafael J. Wysocki   ACPI / scan: alwa...
339
  #ifdef CONFIG_X86_INTEL_LPSS
f58b082ae   Rafael J. Wysocki   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   Heikki Krogerus   ACPI / LPSS: supp...
358
  	const char *devname = dev_name(&adev->dev);
71c50dbe1   Colin Ian King   ACPI / LPSS: Remo...
359
  	struct clk *clk;
b59cc200a   Rafael J. Wysocki   ACPI / LPSS: regi...
360
  	struct lpss_clk_data *clk_data;
ed3a872e2   Heikki Krogerus   ACPI / LPSS: supp...
361
362
  	const char *parent, *clk_name;
  	void __iomem *prv_base;
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
363
364
365
  
  	if (!lpss_clk_dev)
  		lpt_register_clock_device();
b59cc200a   Rafael J. Wysocki   ACPI / LPSS: regi...
366
367
368
  	clk_data = platform_get_drvdata(lpss_clk_dev);
  	if (!clk_data)
  		return -ENODEV;
b0d00f8bd   Heikki Krogerus   ACPI / LPSS: drop...
369
  	clk = clk_data->clk;
b59cc200a   Rafael J. Wysocki   ACPI / LPSS: regi...
370
371
  
  	if (!pdata->mmio_base
2e0f8822d   Rafael J. Wysocki   ACPI / LPSS: Add ...
372
  	    || pdata->mmio_size < dev_desc->prv_offset + LPSS_CLK_SIZE)
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
373
  		return -ENODATA;
f62721706   Mika Westerberg   ACPI / LPSS: add ...
374
  	parent = clk_data->name;
ed3a872e2   Heikki Krogerus   ACPI / LPSS: supp...
375
  	prv_base = pdata->mmio_base + dev_desc->prv_offset;
f62721706   Mika Westerberg   ACPI / LPSS: add ...
376

03f09f73b   Heikki Krogerus   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   Mika Westerberg   ACPI / LPSS: add ...
381
  	}
ff8c1af5e   Heikki Krogerus   ACPI / LPSS: intr...
382
  	if (dev_desc->flags & LPSS_CLK_GATE) {
ed3a872e2   Heikki Krogerus   ACPI / LPSS: supp...
383
384
385
386
  		clk = clk_register_gate(NULL, devname, parent, 0,
  					prv_base, 0, 0, NULL);
  		parent = devname;
  	}
ff8c1af5e   Heikki Krogerus   ACPI / LPSS: intr...
387
  	if (dev_desc->flags & LPSS_CLK_DIVIDER) {
ed3a872e2   Heikki Krogerus   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   Mika Westerberg   ACPI / LPSS: add ...
410
  	}
03f09f73b   Heikki Krogerus   ACPI / LPSS: supp...
411
  out:
f62721706   Mika Westerberg   ACPI / LPSS: add ...
412
413
  	if (IS_ERR(clk))
  		return PTR_ERR(clk);
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
414

ed3a872e2   Heikki Krogerus   ACPI / LPSS: supp...
415
  	pdata->clk = clk;
fcf0789a9   Heikki Krogerus   ACPI / LPSS: prov...
416
  	clk_register_clkdev(clk, dev_desc->clk_con_id, devname);
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
417
418
  	return 0;
  }
e6ce0ce34   Adrian Hunter   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   Hans de Goede   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   Adrian Hunter   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   Hans de Goede   ACPI: LPSS: Add L...
447
  	/* CHT External sdcard slot controller depends on PMIC I2C ctrl */
e6ce0ce34   Adrian Hunter   ACPI / LPSS: Add ...
448
  	{"808622C1", "7", "80860F14", "3", DL_FLAG_PM_RUNTIME},
cc18735f2   Hans de Goede   ACPI: LPSS: Add L...
449
  	/* CHT iGPU depends on PMIC I2C controller */
bd0f4e342   Hans de Goede   ACPI / LPSS: Add ...
450
  	{"808622C1", "7", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME},
b3b3519c0   Hans de Goede   ACPI: LPSS: Add L...
451
  	/* BYT iGPU depends on the Embedded Controller I2C controller (UID 1) */
6025e2fae   Hans de Goede   ACPI: LPSS: Add d...
452
453
  	{"80860F41", "1", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME,
  	 i2c1_dep_missing_dmi_ids},
cc18735f2   Hans de Goede   ACPI: LPSS: Add L...
454
  	/* BYT CR iGPU depends on PMIC I2C controller (UID 5 on CR) */
2d71ee0ce   Hans de Goede   ACPI / LPSS: Add ...
455
  	{"80860F41", "5", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME},
cc18735f2   Hans de Goede   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   Adrian Hunter   ACPI / LPSS: Add ...
458
  };
e6ce0ce34   Adrian Hunter   ACPI / LPSS: Add ...
459
460
461
  static bool acpi_lpss_is_supplier(struct acpi_device *adev,
  				  const struct lpss_device_links *link)
  {
7e70c8acf   Andy Shevchenko   ACPI / LPSS: Swit...
462
  	return acpi_dev_hid_uid_match(adev, link->supplier_hid, link->supplier_uid);
e6ce0ce34   Adrian Hunter   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   Andy Shevchenko   ACPI / LPSS: Swit...
468
  	return acpi_dev_hid_uid_match(adev, link->consumer_hid, link->consumer_uid);
e6ce0ce34   Adrian Hunter   ACPI / LPSS: Add ...
469
470
471
472
473
474
  }
  
  struct hid_uid {
  	const char *hid;
  	const char *uid;
  };
418e3ea15   Suzuki K Poulose   bus_find_device: ...
475
  static int match_hid_uid(struct device *dev, const void *data)
e6ce0ce34   Adrian Hunter   ACPI / LPSS: Add ...
476
477
  {
  	struct acpi_device *adev = ACPI_COMPANION(dev);
418e3ea15   Suzuki K Poulose   bus_find_device: ...
478
  	const struct hid_uid *id = data;
e6ce0ce34   Adrian Hunter   ACPI / LPSS: Add ...
479
480
481
  
  	if (!adev)
  		return 0;
7e70c8acf   Andy Shevchenko   ACPI / LPSS: Swit...
482
  	return acpi_dev_hid_uid_match(adev, id->hid, id->uid);
e6ce0ce34   Adrian Hunter   ACPI / LPSS: Add ...
483
484
485
486
  }
  
  static struct device *acpi_lpss_find_device(const char *hid, const char *uid)
  {
1e30124ac   Hans de Goede   ACPI / LPSS: Make...
487
  	struct device *dev;
e6ce0ce34   Adrian Hunter   ACPI / LPSS: Add ...
488
489
490
491
  	struct hid_uid data = {
  		.hid = hid,
  		.uid = uid,
  	};
1e30124ac   Hans de Goede   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   Adrian Hunter   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   Hans de Goede   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   Adrian Hunter   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   Hans de Goede   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   Adrian Hunter   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   Rafael J. Wysocki   ACPI / scan: Add ...
569
570
571
  static int acpi_lpss_create_device(struct acpi_device *adev,
  				   const struct acpi_device_id *id)
  {
b2687cd7d   Mathias Krause   ACPI / LPSS: cons...
572
  	const struct lpss_device_desc *dev_desc;
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
573
  	struct lpss_private_data *pdata;
90e978206   Jiang Liu   resources: Move s...
574
  	struct resource_entry *rentry;
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
575
  	struct list_head resource_list;
8ce62f85a   Rafael J. Wysocki   ACPI / platform /...
576
  	struct platform_device *pdev;
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
577
  	int ret;
b2687cd7d   Mathias Krause   ACPI / LPSS: cons...
578
  	dev_desc = (const struct lpss_device_desc *)id->driver_data;
8ce62f85a   Rafael J. Wysocki   ACPI / platform /...
579
  	if (!dev_desc) {
1571875be   Heikki Krogerus   ACPI / platform: ...
580
  		pdev = acpi_create_platform_device(adev, NULL);
8ce62f85a   Rafael J. Wysocki   ACPI / platform /...
581
582
  		return IS_ERR_OR_NULL(pdev) ? PTR_ERR(pdev) : 1;
  	}
f58b082ae   Rafael J. Wysocki   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   Jiang Liu   resources: Move s...
593
  		if (resource_type(rentry->res) == IORESOURCE_MEM) {
958c4eb2a   Mika Westerberg   ACPI / LPSS: over...
594
595
596
  			if (dev_desc->prv_size_override)
  				pdata->mmio_size = dev_desc->prv_size_override;
  			else
90e978206   Jiang Liu   resources: Move s...
597
598
  				pdata->mmio_size = resource_size(rentry->res);
  			pdata->mmio_base = ioremap(rentry->res->start,
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
599
  						   pdata->mmio_size);
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
600
601
602
603
  			break;
  		}
  
  	acpi_dev_free_resource_list(&resource_list);
d3e13ff3c   Rafael J. Wysocki   ACPI / LPSS: Fix ...
604
  	if (!pdata->mmio_base) {
e16815993   Hans de Goede   ACPI / LPSS: Do n...
605
606
  		/* Avoid acpi_bus_attach() instantiating a pdev for this dev. */
  		adev->pnp.type.platform_id = 0;
a4bb2b493   Ronald Tschalär   ACPI / LPSS: Don'...
607
608
  		/* Skip the device, but continue the namespace scan. */
  		ret = 0;
d3e13ff3c   Rafael J. Wysocki   ACPI / LPSS: Fix ...
609
610
  		goto err_out;
  	}
dd242a080   Hans de Goede   ACPI / LPSS: Only...
611
  	pdata->adev = adev;
af65cfe9a   Mika Westerberg   ACPI / LPSS: don'...
612
  	pdata->dev_desc = dev_desc;
03f09f73b   Heikki Krogerus   ACPI / LPSS: supp...
613
614
  	if (dev_desc->setup)
  		dev_desc->setup(pdata);
ff8c1af5e   Heikki Krogerus   ACPI / LPSS: intr...
615
  	if (dev_desc->flags & LPSS_CLK) {
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
616
617
  		ret = register_device_clock(adev, pdata);
  		if (ret) {
b9e95fc65   Rafael J. Wysocki   ACPI / LPSS: Powe...
618
619
620
  			/* Skip the device, but continue the namespace scan. */
  			ret = 0;
  			goto err_out;
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
621
622
  		}
  	}
b9e95fc65   Rafael J. Wysocki   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   Hans de Goede   ACPI / LPSS: Igno...
628
  	acpi_device_fix_up_power(adev);
b9e95fc65   Rafael J. Wysocki   ACPI / LPSS: Powe...
629

f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
630
  	adev->driver_data = pdata;
1571875be   Heikki Krogerus   ACPI / platform: ...
631
  	pdev = acpi_create_platform_device(adev, dev_desc->properties);
8ce62f85a   Rafael J. Wysocki   ACPI / platform /...
632
  	if (!IS_ERR_OR_NULL(pdev)) {
e6ce0ce34   Adrian Hunter   ACPI / LPSS: Add ...
633
  		acpi_lpss_create_device_links(adev, pdev);
8ce62f85a   Rafael J. Wysocki   ACPI / platform /...
634
635
  		return 1;
  	}
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
636

8ce62f85a   Rafael J. Wysocki   ACPI / platform /...
637
  	ret = PTR_ERR(pdev);
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
638
639
640
641
642
643
  	adev->driver_data = NULL;
  
   err_out:
  	kfree(pdata);
  	return ret;
  }
1a8f83515   Rafael J. Wysocki   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   Rafael J. Wysocki   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   Rafael J. Wysocki   ACPI / LPSS: Supp...
675
  	*val = __lpss_reg_read(pdata, reg);
2e0f8822d   Rafael J. Wysocki   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, &ltr_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, &ltr_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   Arvind Yadav   ACPI / LPSS: cons...
724
  static const struct attribute_group lpss_attr_group = {
2e0f8822d   Rafael J. Wysocki   ACPI / LPSS: Add ...
725
726
727
  	.attrs = lpss_attrs,
  	.name = "lpss_ltr",
  };
1a8f83515   Rafael J. Wysocki   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   Heikki Krogerus   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   Andy Shevchenko   ACPI / LPSS: add ...
762
   * @pdata: pointer to the private data of the LPSS device
c78b08306   Heikki Krogerus   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   Andy Shevchenko   ACPI / LPSS: add ...
768
769
  static void acpi_lpss_save_ctx(struct device *dev,
  			       struct lpss_private_data *pdata)
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
770
  {
c78b08306   Heikki Krogerus   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   Andy Shevchenko   ACPI / LPSS: add ...
786
   * @pdata: pointer to the private data of the LPSS device
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
787
788
789
   *
   * Restores the registers that were previously stored with acpi_lpss_save_ctx().
   */
cb39dcdd4   Andy Shevchenko   ACPI / LPSS: add ...
790
791
  static void acpi_lpss_restore_ctx(struct device *dev,
  				  struct lpss_private_data *pdata)
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
792
  {
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
793
  	unsigned int i;
02b985404   Andy Shevchenko   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   Heikki Krogerus   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   Srinidhi Kasagar   ACPI / LPSS: Igno...
810
  	 * transition. However some platforms like BSW does not need this delay.
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
811
  	 */
b00855aec   Srinidhi Kasagar   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   Heikki Krogerus   ACPI / LPSS: cust...
818
  }
c3a49cf35   Andy Shevchenko   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   Rafael J. Wysocki   ACPI / PM: Combin...
823
  	ret = acpi_dev_resume(dev);
c3a49cf35   Andy Shevchenko   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   Hans de Goede   ACPI / LPSS: Save...
835
  	if (pdata->dev_desc->flags & (LPSS_SAVE_CTX | LPSS_SAVE_CTX_ONCE))
c3a49cf35   Andy Shevchenko   ACPI / LPSS: powe...
836
  		lpss_deassert_reset(pdata);
15aa5e4c4   Hans de Goede   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   Andy Shevchenko   ACPI / LPSS: powe...
841
842
843
844
845
  	return 0;
  }
  
  static void acpi_lpss_dismiss(struct device *dev)
  {
cbe25ce37   Rafael J. Wysocki   ACPI / PM: Combin...
846
  	acpi_dev_suspend(dev, false);
c3a49cf35   Andy Shevchenko   ACPI / LPSS: powe...
847
  }
eebb3e8d8   Andy Shevchenko   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   Andy Shevchenko   ACPI / LPSS: enab...
862
  #define LPSS_GPIODEF0_DMA_LLP		BIT(13)
eebb3e8d8   Andy Shevchenko   ACPI / LPSS: over...
863
864
  
  static DEFINE_MUTEX(lpss_iosf_mutex);
f11fc4bc6   Zhang Rui   ACPI / LPSS: Forc...
865
  static bool lpss_iosf_d3_entered = true;
eebb3e8d8   Andy Shevchenko   ACPI / LPSS: over...
866
867
868
869
  
  static void lpss_iosf_enter_d3_state(void)
  {
  	u32 value1 = 0;
d132d6d53   Andy Shevchenko   ACPI / LPSS: enab...
870
  	u32 mask1 = LPSS_GPIODEF0_DMA_D3_MASK | LPSS_GPIODEF0_DMA_LLP;
eebb3e8d8   Andy Shevchenko   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   Hans de Goede   ACPI / LPSS: Excl...
878
  	u32 func_dis, d3_sts_0, pmc_status;
eebb3e8d8   Andy Shevchenko   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   Hans de Goede   ACPI / LPSS: Excl...
896
  	pmc_status = (~(d3_sts_0 | func_dis)) & pmc_atom_d3_mask;
eebb3e8d8   Andy Shevchenko   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   Rafael J. Wysocki   ACPI / LPSS: Avoi...
908
909
  
  	lpss_iosf_d3_entered = true;
eebb3e8d8   Andy Shevchenko   ACPI / LPSS: over...
910
911
912
913
914
915
  exit:
  	mutex_unlock(&lpss_iosf_mutex);
  }
  
  static void lpss_iosf_exit_d3_state(void)
  {
d132d6d53   Andy Shevchenko   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   Andy Shevchenko   ACPI / LPSS: over...
919
920
921
922
  	u32 value2 = LPSS_PMCSR_D0;
  	u32 mask2 = LPSS_PMCSR_Dx_MASK;
  
  	mutex_lock(&lpss_iosf_mutex);
12864ff85   Rafael J. Wysocki   ACPI / LPSS: Avoi...
923
924
925
926
  	if (!lpss_iosf_d3_entered)
  		goto exit;
  
  	lpss_iosf_d3_entered = false;
eebb3e8d8   Andy Shevchenko   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   Rafael J. Wysocki   ACPI / LPSS: Avoi...
935
  exit:
eebb3e8d8   Andy Shevchenko   ACPI / LPSS: over...
936
937
  	mutex_unlock(&lpss_iosf_mutex);
  }
12864ff85   Rafael J. Wysocki   ACPI / LPSS: Avoi...
938
  static int acpi_lpss_suspend(struct device *dev, bool wakeup)
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
939
  {
cb39dcdd4   Andy Shevchenko   ACPI / LPSS: add ...
940
941
  	struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
  	int ret;
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
942

cb39dcdd4   Andy Shevchenko   ACPI / LPSS: add ...
943
944
  	if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
  		acpi_lpss_save_ctx(dev, pdata);
a192aa923   Rafael J. Wysocki   ACPI / LPSS: Cons...
945
  	ret = acpi_dev_suspend(dev, wakeup);
eebb3e8d8   Andy Shevchenko   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   Rafael J. Wysocki   ACPI / LPSS: Avoi...
952
  	if (acpi_target_system_state() == ACPI_STATE_S0 &&
a09c59130   Rafael J. Wysocki   ACPI / LPSS: Avoi...
953
  	    lpss_quirks & LPSS_QUIRK_ALWAYS_POWER_ON && iosf_mbi_available())
eebb3e8d8   Andy Shevchenko   ACPI / LPSS: over...
954
955
956
  		lpss_iosf_enter_d3_state();
  
  	return ret;
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
957
  }
12864ff85   Rafael J. Wysocki   ACPI / LPSS: Avoi...
958
  static int acpi_lpss_resume(struct device *dev)
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
959
  {
cb39dcdd4   Andy Shevchenko   ACPI / LPSS: add ...
960
961
  	struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
  	int ret;
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
962

eebb3e8d8   Andy Shevchenko   ACPI / LPSS: over...
963
964
965
966
  	/*
  	 * This call is kept first to be in symmetry with
  	 * acpi_lpss_runtime_suspend() one.
  	 */
12864ff85   Rafael J. Wysocki   ACPI / LPSS: Avoi...
967
  	if (lpss_quirks & LPSS_QUIRK_ALWAYS_POWER_ON && iosf_mbi_available())
eebb3e8d8   Andy Shevchenko   ACPI / LPSS: over...
968
  		lpss_iosf_exit_d3_state();
63705c406   Rafael J. Wysocki   ACPI / PM: Combin...
969
  	ret = acpi_dev_resume(dev);
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
970
971
  	if (ret)
  		return ret;
02b985404   Andy Shevchenko   ACPI / LPSS: do d...
972
  	acpi_lpss_d3_to_d0_delay(pdata);
15aa5e4c4   Hans de Goede   ACPI / LPSS: Save...
973
  	if (pdata->dev_desc->flags & (LPSS_SAVE_CTX | LPSS_SAVE_CTX_ONCE))
cb39dcdd4   Andy Shevchenko   ACPI / LPSS: add ...
974
  		acpi_lpss_restore_ctx(dev, pdata);
a192aa923   Rafael J. Wysocki   ACPI / LPSS: Cons...
975
976
977
978
  	return 0;
  }
  
  #ifdef CONFIG_PM_SLEEP
48402cee6   Hans de Goede   ACPI / LPSS: Resu...
979
  static int acpi_lpss_do_suspend_late(struct device *dev)
a192aa923   Rafael J. Wysocki   ACPI / LPSS: Cons...
980
  {
05087360f   Rafael J. Wysocki   ACPI / PM: Take S...
981
  	int ret;
fa2bfead9   Rafael J. Wysocki   PM: sleep: core: ...
982
  	if (dev_pm_skip_suspend(dev))
05087360f   Rafael J. Wysocki   ACPI / PM: Take S...
983
  		return 0;
a192aa923   Rafael J. Wysocki   ACPI / LPSS: Cons...
984

05087360f   Rafael J. Wysocki   ACPI / PM: Take S...
985
  	ret = pm_generic_suspend_late(dev);
12864ff85   Rafael J. Wysocki   ACPI / LPSS: Avoi...
986
  	return ret ? ret : acpi_lpss_suspend(dev, device_may_wakeup(dev));
a192aa923   Rafael J. Wysocki   ACPI / LPSS: Cons...
987
  }
48402cee6   Hans de Goede   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   Rafael J. Wysocki   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   Hans de Goede   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   Rafael J. Wysocki   ACPI / LPSS: Cons...
1020
  {
12864ff85   Rafael J. Wysocki   ACPI / LPSS: Avoi...
1021
  	int ret = acpi_lpss_resume(dev);
a192aa923   Rafael J. Wysocki   ACPI / LPSS: Cons...
1022
1023
1024
  
  	return ret ? ret : pm_generic_resume_early(dev);
  }
48402cee6   Hans de Goede   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   Rafael J. Wysocki   PM: sleep: core: ...
1032
  	if (dev_pm_skip_resume(dev))
6e176bf8d   Rafael J. Wysocki   PM: sleep: core: ...
1033
  		return 0;
48402cee6   Hans de Goede   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   Rafael J. Wysocki   ACPI: PM: Simplif...
1041
  	/* Follow acpi_subsys_resume_noirq(). */
76c70cb58   Rafael J. Wysocki   PM: sleep: core: ...
1042
  	if (dev_pm_skip_resume(dev))
3cd7957e8   Rafael J. Wysocki   ACPI: PM: Simplif...
1043
  		return 0;
3cd7957e8   Rafael J. Wysocki   ACPI: PM: Simplif...
1044
  	ret = pm_generic_resume_noirq(dev);
48402cee6   Hans de Goede   ACPI / LPSS: Resu...
1045
1046
  	if (ret)
  		return ret;
3cd7957e8   Rafael J. Wysocki   ACPI: PM: Simplif...
1047
1048
  	if (!pdata->dev_desc->resume_from_noirq)
  		return 0;
48402cee6   Hans de Goede   ACPI / LPSS: Resu...
1049

3cd7957e8   Rafael J. Wysocki   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   Hans de Goede   ACPI / LPSS: Resu...
1065
  }
3cd7957e8   Rafael J. Wysocki   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   Hans de Goede   ACPI / LPSS: Resu...
1074
  }
3cd7957e8   Rafael J. Wysocki   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   Rafael J. Wysocki   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   Rafael J. Wysocki   PM: sleep: core: ...
1101
  	if (dev_pm_skip_suspend(dev))
c95b7595f   Rafael J. Wysocki   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   Rafael J. Wysocki   PM: sleep: core: ...
1113
  	if (dev_pm_skip_suspend(dev))
c95b7595f   Rafael J. Wysocki   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   Rafael J. Wysocki   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   Rafael J. Wysocki   ACPI / LPSS: Avoi...
1136
  	int ret = acpi_lpss_resume(dev);
a192aa923   Rafael J. Wysocki   ACPI / LPSS: Cons...
1137
1138
  
  	return ret ? ret : pm_generic_runtime_resume(dev);
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
1139
  }
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
1140
1141
1142
  #endif /* CONFIG_PM */
  
  static struct dev_pm_domain acpi_lpss_pm_domain = {
c3a49cf35   Andy Shevchenko   ACPI / LPSS: powe...
1143
1144
1145
1146
  #ifdef CONFIG_PM
  	.activate = acpi_lpss_activate,
  	.dismiss = acpi_lpss_dismiss,
  #endif
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
1147
  	.ops = {
5de21bb99   Rafael J. Wysocki   ACPI / PM: Drop C...
1148
  #ifdef CONFIG_PM
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
1149
  #ifdef CONFIG_PM_SLEEP
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
1150
  		.prepare = acpi_subsys_prepare,
e4da817d2   Ulf Hansson   ACPI / PM: Restor...
1151
  		.complete = acpi_subsys_complete,
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
1152
  		.suspend = acpi_subsys_suspend,
f4168b617   Fu Zhonghui   ACPI / LPSS: comp...
1153
  		.suspend_late = acpi_lpss_suspend_late,
48402cee6   Hans de Goede   ACPI / LPSS: Resu...
1154
1155
  		.suspend_noirq = acpi_lpss_suspend_noirq,
  		.resume_noirq = acpi_lpss_resume_noirq,
f4168b617   Fu Zhonghui   ACPI / LPSS: comp...
1156
  		.resume_early = acpi_lpss_resume_early,
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
1157
  		.freeze = acpi_subsys_freeze,
c95b7595f   Rafael J. Wysocki   ACPI: PM: Introdu...
1158
1159
1160
  		.poweroff = acpi_subsys_poweroff,
  		.poweroff_late = acpi_lpss_poweroff_late,
  		.poweroff_noirq = acpi_lpss_poweroff_noirq,
3cd7957e8   Rafael J. Wysocki   ACPI: PM: Simplif...
1161
1162
  		.restore_noirq = acpi_lpss_restore_noirq,
  		.restore_early = acpi_lpss_restore_early,
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
1163
  #endif
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
1164
1165
1166
1167
1168
  		.runtime_suspend = acpi_lpss_runtime_suspend,
  		.runtime_resume = acpi_lpss_runtime_resume,
  #endif
  	},
  };
2e0f8822d   Rafael J. Wysocki   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   Rafael J. Wysocki   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   Andy Shevchenko   ACPI / LPSS: add ...
1185
  	if (!pdata)
2e0f8822d   Rafael J. Wysocki   ACPI / LPSS: Add ...
1186
  		return 0;
cb39dcdd4   Andy Shevchenko   ACPI / LPSS: add ...
1187
1188
  	if (pdata->mmio_base &&
  	    pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) {
2e0f8822d   Rafael J. Wysocki   ACPI / LPSS: Add ...
1189
1190
1191
1192
  		dev_err(&pdev->dev, "MMIO size insufficient to access LTR
  ");
  		return 0;
  	}
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
1193
  	switch (action) {
de16d5520   Andy Shevchenko   ACPI / LPSS: allo...
1194
  	case BUS_NOTIFY_BIND_DRIVER:
989561de9   Tomeu Vizoso   PM / Domains: add...
1195
  		dev_pm_domain_set(&pdev->dev, &acpi_lpss_pm_domain);
b5f88dd1d   Andy Shevchenko   Revert "ACPI / LP...
1196
  		break;
de16d5520   Andy Shevchenko   ACPI / LPSS: allo...
1197
  	case BUS_NOTIFY_DRIVER_NOT_BOUND:
b5f88dd1d   Andy Shevchenko   Revert "ACPI / LP...
1198
  	case BUS_NOTIFY_UNBOUND_DRIVER:
5be6ada39   Andy Shevchenko   ACPI / LPSS: set ...
1199
  		dev_pm_domain_set(&pdev->dev, NULL);
b5f88dd1d   Andy Shevchenko   Revert "ACPI / LP...
1200
1201
  		break;
  	case BUS_NOTIFY_ADD_DEVICE:
989561de9   Tomeu Vizoso   PM / Domains: add...
1202
  		dev_pm_domain_set(&pdev->dev, &acpi_lpss_pm_domain);
ff8c1af5e   Heikki Krogerus   ACPI / LPSS: intr...
1203
  		if (pdata->dev_desc->flags & LPSS_LTR)
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
1204
1205
  			return sysfs_create_group(&pdev->dev.kobj,
  						  &lpss_attr_group);
01ac170ba   Andy Shevchenko   ACPI / LPSS: allo...
1206
  		break;
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
1207
  	case BUS_NOTIFY_DEL_DEVICE:
ff8c1af5e   Heikki Krogerus   ACPI / LPSS: intr...
1208
  		if (pdata->dev_desc->flags & LPSS_LTR)
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
1209
  			sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group);
989561de9   Tomeu Vizoso   PM / Domains: add...
1210
  		dev_pm_domain_set(&pdev->dev, NULL);
01ac170ba   Andy Shevchenko   ACPI / LPSS: allo...
1211
  		break;
c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
1212
1213
1214
  	default:
  		break;
  	}
2e0f8822d   Rafael J. Wysocki   ACPI / LPSS: Add ...
1215

c78b08306   Heikki Krogerus   ACPI / LPSS: cust...
1216
  	return 0;
2e0f8822d   Rafael J. Wysocki   ACPI / LPSS: Add ...
1217
1218
1219
1220
1221
  }
  
  static struct notifier_block acpi_lpss_nb = {
  	.notifier_call = acpi_lpss_platform_notify,
  };
1a8f83515   Rafael J. Wysocki   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   Heikki Krogerus   ACPI / LPSS: intr...
1225
  	if (!pdata || !pdata->mmio_base || !(pdata->dev_desc->flags & LPSS_LTR))
1a8f83515   Rafael J. Wysocki   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   Rafael J. Wysocki   ACPI / scan: Add ...
1239
1240
1241
  static struct acpi_scan_handler lpss_handler = {
  	.ids = acpi_lpss_device_ids,
  	.attach = acpi_lpss_create_device,
1a8f83515   Rafael J. Wysocki   ACPI / LPSS: Supp...
1242
1243
  	.bind = acpi_lpss_bind,
  	.unbind = acpi_lpss_unbind,
f58b082ae   Rafael J. Wysocki   ACPI / scan: Add ...
1244
1245
1246
1247
  };
  
  void __init acpi_lpss_init(void)
  {
eebb3e8d8   Andy Shevchenko   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   Rafael J. Wysocki   ACPI / scan: Add ...
1261
  }
d6ddaaac8   Rafael J. Wysocki   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 */