blob: 0e9c0d38b85c77eef348b7ff6b1738f5f10a4621 [file] [log] [blame]
Rafael J. Wysockif58b0822013-03-06 23:46:20 +01001/*
2 * ACPI support for Intel Lynxpoint LPSS.
3 *
4 * Copyright (C) 2013, Intel Corporation
5 * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
6 * Rafael J. Wysocki <rafael.j.wysocki@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/acpi.h>
14#include <linux/clk.h>
15#include <linux/clkdev.h>
16#include <linux/clk-provider.h>
17#include <linux/err.h>
18#include <linux/io.h>
19#include <linux/platform_device.h>
20#include <linux/platform_data/clk-lpss.h>
Rafael J. Wysocki2e0f8822013-03-06 23:46:28 +010021#include <linux/pm_runtime.h>
Rafael J. Wysockif58b0822013-03-06 23:46:20 +010022
23#include "internal.h"
24
25ACPI_MODULE_NAME("acpi_lpss");
26
Rafael J. Wysockif58b0822013-03-06 23:46:20 +010027#define LPSS_CLK_SIZE 0x04
Rafael J. Wysocki2e0f8822013-03-06 23:46:28 +010028#define LPSS_LTR_SIZE 0x18
29
30/* Offsets relative to LPSS_PRIVATE_OFFSET */
31#define LPSS_GENERAL 0x08
32#define LPSS_GENERAL_LTR_MODE_SW BIT(2)
Heikki Krogerus088f1fd2013-10-09 09:49:20 +030033#define LPSS_GENERAL_UART_RTS_OVRD BIT(3)
Rafael J. Wysocki2e0f8822013-03-06 23:46:28 +010034#define LPSS_SW_LTR 0x10
35#define LPSS_AUTO_LTR 0x14
Rafael J. Wysocki1a8f8352014-02-11 00:35:53 +010036#define LPSS_LTR_SNOOP_REQ BIT(15)
37#define LPSS_LTR_SNOOP_MASK 0x0000FFFF
38#define LPSS_LTR_SNOOP_LAT_1US 0x800
39#define LPSS_LTR_SNOOP_LAT_32US 0xC00
40#define LPSS_LTR_SNOOP_LAT_SHIFT 5
41#define LPSS_LTR_SNOOP_LAT_CUTOFF 3000
42#define LPSS_LTR_MAX_VAL 0x3FF
Heikki Krogerus06d86412013-06-17 13:25:46 +030043#define LPSS_TX_INT 0x20
44#define LPSS_TX_INT_MASK BIT(1)
Rafael J. Wysockif58b0822013-03-06 23:46:20 +010045
Mika Westerbergf6272172013-05-13 12:42:44 +000046struct lpss_shared_clock {
47 const char *name;
48 unsigned long rate;
49 struct clk *clk;
50};
51
Heikki Krogerus06d86412013-06-17 13:25:46 +030052struct lpss_private_data;
Rafael J. Wysockif58b0822013-03-06 23:46:20 +010053
54struct lpss_device_desc {
55 bool clk_required;
Rafael J. Wysockib59cc202013-05-08 11:55:49 +030056 const char *clkdev_name;
Rafael J. Wysocki2e0f8822013-03-06 23:46:28 +010057 bool ltr_required;
58 unsigned int prv_offset;
Mika Westerberg958c4eb2013-06-18 16:51:35 +030059 size_t prv_size_override;
Mika Westerbergf6272172013-05-13 12:42:44 +000060 bool clk_gate;
61 struct lpss_shared_clock *shared_clock;
Heikki Krogerus06d86412013-06-17 13:25:46 +030062 void (*setup)(struct lpss_private_data *pdata);
Rafael J. Wysockif58b0822013-03-06 23:46:20 +010063};
64
Rafael J. Wysockib59cc202013-05-08 11:55:49 +030065static struct lpss_device_desc lpss_dma_desc = {
66 .clk_required = true,
67 .clkdev_name = "hclk",
68};
69
Rafael J. Wysockif58b0822013-03-06 23:46:20 +010070struct lpss_private_data {
71 void __iomem *mmio_base;
72 resource_size_t mmio_size;
73 struct clk *clk;
74 const struct lpss_device_desc *dev_desc;
75};
76
Heikki Krogerus06d86412013-06-17 13:25:46 +030077static void lpss_uart_setup(struct lpss_private_data *pdata)
78{
Heikki Krogerus088f1fd2013-10-09 09:49:20 +030079 unsigned int offset;
Heikki Krogerus06d86412013-06-17 13:25:46 +030080 u32 reg;
81
Heikki Krogerus088f1fd2013-10-09 09:49:20 +030082 offset = pdata->dev_desc->prv_offset + LPSS_TX_INT;
83 reg = readl(pdata->mmio_base + offset);
84 writel(reg | LPSS_TX_INT_MASK, pdata->mmio_base + offset);
85
86 offset = pdata->dev_desc->prv_offset + LPSS_GENERAL;
87 reg = readl(pdata->mmio_base + offset);
88 writel(reg | LPSS_GENERAL_UART_RTS_OVRD, pdata->mmio_base + offset);
Heikki Krogerus06d86412013-06-17 13:25:46 +030089}
90
Rafael J. Wysockif58b0822013-03-06 23:46:20 +010091static struct lpss_device_desc lpt_dev_desc = {
92 .clk_required = true,
Rafael J. Wysocki2e0f8822013-03-06 23:46:28 +010093 .prv_offset = 0x800,
94 .ltr_required = true,
Mika Westerbergf6272172013-05-13 12:42:44 +000095 .clk_gate = true,
Rafael J. Wysocki2e0f8822013-03-06 23:46:28 +010096};
97
Heikki Krogerus06d86412013-06-17 13:25:46 +030098static struct lpss_device_desc lpt_uart_dev_desc = {
99 .clk_required = true,
100 .prv_offset = 0x800,
101 .ltr_required = true,
102 .clk_gate = true,
103 .setup = lpss_uart_setup,
Rafael J. Wysocki2e0f8822013-03-06 23:46:28 +0100104};
105
106static struct lpss_device_desc lpt_sdio_dev_desc = {
107 .prv_offset = 0x1000,
Mika Westerberg958c4eb2013-06-18 16:51:35 +0300108 .prv_size_override = 0x1018,
Rafael J. Wysocki2e0f8822013-03-06 23:46:28 +0100109 .ltr_required = true,
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100110};
111
Chew, Chiau Eee1c74812014-02-19 02:24:29 +0800112static struct lpss_shared_clock pwm_clock = {
113 .name = "pwm_clk",
114 .rate = 25000000,
115};
116
117static struct lpss_device_desc byt_pwm_dev_desc = {
118 .clk_required = true,
119 .shared_clock = &pwm_clock,
120};
121
Mika Westerbergf6272172013-05-13 12:42:44 +0000122static struct lpss_shared_clock uart_clock = {
123 .name = "uart_clk",
124 .rate = 44236800,
125};
126
127static struct lpss_device_desc byt_uart_dev_desc = {
128 .clk_required = true,
129 .prv_offset = 0x800,
130 .clk_gate = true,
131 .shared_clock = &uart_clock,
Heikki Krogerus06d86412013-06-17 13:25:46 +0300132 .setup = lpss_uart_setup,
Mika Westerbergf6272172013-05-13 12:42:44 +0000133};
134
135static struct lpss_shared_clock spi_clock = {
136 .name = "spi_clk",
137 .rate = 50000000,
138};
139
140static struct lpss_device_desc byt_spi_dev_desc = {
141 .clk_required = true,
142 .prv_offset = 0x400,
143 .clk_gate = true,
144 .shared_clock = &spi_clock,
145};
146
147static struct lpss_device_desc byt_sdio_dev_desc = {
148 .clk_required = true,
149};
150
151static struct lpss_shared_clock i2c_clock = {
152 .name = "i2c_clk",
153 .rate = 100000000,
154};
155
156static struct lpss_device_desc byt_i2c_dev_desc = {
157 .clk_required = true,
158 .prv_offset = 0x800,
159 .shared_clock = &i2c_clock,
160};
161
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100162static const struct acpi_device_id acpi_lpss_device_ids[] = {
Rafael J. Wysockib59cc202013-05-08 11:55:49 +0300163 /* Generic LPSS devices */
164 { "INTL9C60", (unsigned long)&lpss_dma_desc },
165
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100166 /* Lynxpoint LPSS devices */
167 { "INT33C0", (unsigned long)&lpt_dev_desc },
168 { "INT33C1", (unsigned long)&lpt_dev_desc },
169 { "INT33C2", (unsigned long)&lpt_dev_desc },
170 { "INT33C3", (unsigned long)&lpt_dev_desc },
Heikki Krogerus06d86412013-06-17 13:25:46 +0300171 { "INT33C4", (unsigned long)&lpt_uart_dev_desc },
172 { "INT33C5", (unsigned long)&lpt_uart_dev_desc },
Rafael J. Wysocki2e0f8822013-03-06 23:46:28 +0100173 { "INT33C6", (unsigned long)&lpt_sdio_dev_desc },
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100174 { "INT33C7", },
175
Mika Westerbergf6272172013-05-13 12:42:44 +0000176 /* BayTrail LPSS devices */
Chew, Chiau Eee1c74812014-02-19 02:24:29 +0800177 { "80860F09", (unsigned long)&byt_pwm_dev_desc },
Mika Westerbergf6272172013-05-13 12:42:44 +0000178 { "80860F0A", (unsigned long)&byt_uart_dev_desc },
179 { "80860F0E", (unsigned long)&byt_spi_dev_desc },
180 { "80860F14", (unsigned long)&byt_sdio_dev_desc },
181 { "80860F41", (unsigned long)&byt_i2c_dev_desc },
182 { "INT33B2", },
183
Mika Westerberga4d97532013-11-12 11:48:19 +0200184 { "INT3430", (unsigned long)&lpt_dev_desc },
185 { "INT3431", (unsigned long)&lpt_dev_desc },
186 { "INT3432", (unsigned long)&lpt_dev_desc },
187 { "INT3433", (unsigned long)&lpt_dev_desc },
188 { "INT3434", (unsigned long)&lpt_uart_dev_desc },
189 { "INT3435", (unsigned long)&lpt_uart_dev_desc },
190 { "INT3436", (unsigned long)&lpt_sdio_dev_desc },
191 { "INT3437", },
192
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100193 { }
194};
195
196static int is_memory(struct acpi_resource *res, void *not_used)
197{
198 struct resource r;
199 return !acpi_dev_resource_memory(res, &r);
200}
201
202/* LPSS main clock device. */
203static struct platform_device *lpss_clk_dev;
204
205static inline void lpt_register_clock_device(void)
206{
207 lpss_clk_dev = platform_device_register_simple("clk-lpt", -1, NULL, 0);
208}
209
210static int register_device_clock(struct acpi_device *adev,
211 struct lpss_private_data *pdata)
212{
213 const struct lpss_device_desc *dev_desc = pdata->dev_desc;
Mika Westerbergf6272172013-05-13 12:42:44 +0000214 struct lpss_shared_clock *shared_clock = dev_desc->shared_clock;
215 struct clk *clk = ERR_PTR(-ENODEV);
Rafael J. Wysockib59cc202013-05-08 11:55:49 +0300216 struct lpss_clk_data *clk_data;
Mika Westerbergf6272172013-05-13 12:42:44 +0000217 const char *parent;
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100218
219 if (!lpss_clk_dev)
220 lpt_register_clock_device();
221
Rafael J. Wysockib59cc202013-05-08 11:55:49 +0300222 clk_data = platform_get_drvdata(lpss_clk_dev);
223 if (!clk_data)
224 return -ENODEV;
225
226 if (dev_desc->clkdev_name) {
227 clk_register_clkdev(clk_data->clk, dev_desc->clkdev_name,
228 dev_name(&adev->dev));
229 return 0;
230 }
231
232 if (!pdata->mmio_base
Rafael J. Wysocki2e0f8822013-03-06 23:46:28 +0100233 || pdata->mmio_size < dev_desc->prv_offset + LPSS_CLK_SIZE)
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100234 return -ENODATA;
235
Mika Westerbergf6272172013-05-13 12:42:44 +0000236 parent = clk_data->name;
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100237
Mika Westerbergf6272172013-05-13 12:42:44 +0000238 if (shared_clock) {
239 clk = shared_clock->clk;
240 if (!clk) {
241 clk = clk_register_fixed_rate(NULL, shared_clock->name,
242 "lpss_clk", 0,
243 shared_clock->rate);
244 shared_clock->clk = clk;
245 }
246 parent = shared_clock->name;
247 }
248
249 if (dev_desc->clk_gate) {
250 clk = clk_register_gate(NULL, dev_name(&adev->dev), parent, 0,
251 pdata->mmio_base + dev_desc->prv_offset,
252 0, 0, NULL);
253 pdata->clk = clk;
254 }
255
256 if (IS_ERR(clk))
257 return PTR_ERR(clk);
258
259 clk_register_clkdev(clk, NULL, dev_name(&adev->dev));
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100260 return 0;
261}
262
263static int acpi_lpss_create_device(struct acpi_device *adev,
264 const struct acpi_device_id *id)
265{
266 struct lpss_device_desc *dev_desc;
267 struct lpss_private_data *pdata;
268 struct resource_list_entry *rentry;
269 struct list_head resource_list;
Rafael J. Wysocki8ce62f82014-05-25 14:38:52 +0200270 struct platform_device *pdev;
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100271 int ret;
272
273 dev_desc = (struct lpss_device_desc *)id->driver_data;
Rafael J. Wysocki8ce62f82014-05-25 14:38:52 +0200274 if (!dev_desc) {
275 pdev = acpi_create_platform_device(adev);
276 return IS_ERR_OR_NULL(pdev) ? PTR_ERR(pdev) : 1;
277 }
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100278 pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
279 if (!pdata)
280 return -ENOMEM;
281
282 INIT_LIST_HEAD(&resource_list);
283 ret = acpi_dev_get_resources(adev, &resource_list, is_memory, NULL);
284 if (ret < 0)
285 goto err_out;
286
287 list_for_each_entry(rentry, &resource_list, node)
288 if (resource_type(&rentry->res) == IORESOURCE_MEM) {
Mika Westerberg958c4eb2013-06-18 16:51:35 +0300289 if (dev_desc->prv_size_override)
290 pdata->mmio_size = dev_desc->prv_size_override;
291 else
292 pdata->mmio_size = resource_size(&rentry->res);
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100293 pdata->mmio_base = ioremap(rentry->res.start,
294 pdata->mmio_size);
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100295 break;
296 }
297
298 acpi_dev_free_resource_list(&resource_list);
299
Mika Westerbergaf65cfe2013-09-02 13:30:25 +0300300 pdata->dev_desc = dev_desc;
301
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100302 if (dev_desc->clk_required) {
303 ret = register_device_clock(adev, pdata);
304 if (ret) {
Rafael J. Wysockib9e95fc2013-06-19 00:45:34 +0200305 /* Skip the device, but continue the namespace scan. */
306 ret = 0;
307 goto err_out;
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100308 }
309 }
310
Rafael J. Wysockib9e95fc2013-06-19 00:45:34 +0200311 /*
312 * This works around a known issue in ACPI tables where LPSS devices
313 * have _PS0 and _PS3 without _PSC (and no power resources), so
314 * acpi_bus_init_power() will assume that the BIOS has put them into D0.
315 */
316 ret = acpi_device_fix_up_power(adev);
317 if (ret) {
318 /* Skip the device, but continue the namespace scan. */
319 ret = 0;
320 goto err_out;
321 }
322
Heikki Krogerus06d86412013-06-17 13:25:46 +0300323 if (dev_desc->setup)
324 dev_desc->setup(pdata);
325
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100326 adev->driver_data = pdata;
Rafael J. Wysocki8ce62f82014-05-25 14:38:52 +0200327 pdev = acpi_create_platform_device(adev);
328 if (!IS_ERR_OR_NULL(pdev)) {
329 device_enable_async_suspend(&pdev->dev);
330 return 1;
331 }
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100332
Rafael J. Wysocki8ce62f82014-05-25 14:38:52 +0200333 ret = PTR_ERR(pdev);
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100334 adev->driver_data = NULL;
335
336 err_out:
337 kfree(pdata);
338 return ret;
339}
340
Rafael J. Wysocki1a8f8352014-02-11 00:35:53 +0100341static u32 __lpss_reg_read(struct lpss_private_data *pdata, unsigned int reg)
342{
343 return readl(pdata->mmio_base + pdata->dev_desc->prv_offset + reg);
344}
345
346static void __lpss_reg_write(u32 val, struct lpss_private_data *pdata,
347 unsigned int reg)
348{
349 writel(val, pdata->mmio_base + pdata->dev_desc->prv_offset + reg);
350}
351
Rafael J. Wysocki2e0f8822013-03-06 23:46:28 +0100352static int lpss_reg_read(struct device *dev, unsigned int reg, u32 *val)
353{
354 struct acpi_device *adev;
355 struct lpss_private_data *pdata;
356 unsigned long flags;
357 int ret;
358
359 ret = acpi_bus_get_device(ACPI_HANDLE(dev), &adev);
360 if (WARN_ON(ret))
361 return ret;
362
363 spin_lock_irqsave(&dev->power.lock, flags);
364 if (pm_runtime_suspended(dev)) {
365 ret = -EAGAIN;
366 goto out;
367 }
368 pdata = acpi_driver_data(adev);
369 if (WARN_ON(!pdata || !pdata->mmio_base)) {
370 ret = -ENODEV;
371 goto out;
372 }
Rafael J. Wysocki1a8f8352014-02-11 00:35:53 +0100373 *val = __lpss_reg_read(pdata, reg);
Rafael J. Wysocki2e0f8822013-03-06 23:46:28 +0100374
375 out:
376 spin_unlock_irqrestore(&dev->power.lock, flags);
377 return ret;
378}
379
380static ssize_t lpss_ltr_show(struct device *dev, struct device_attribute *attr,
381 char *buf)
382{
383 u32 ltr_value = 0;
384 unsigned int reg;
385 int ret;
386
387 reg = strcmp(attr->attr.name, "auto_ltr") ? LPSS_SW_LTR : LPSS_AUTO_LTR;
388 ret = lpss_reg_read(dev, reg, &ltr_value);
389 if (ret)
390 return ret;
391
392 return snprintf(buf, PAGE_SIZE, "%08x\n", ltr_value);
393}
394
395static ssize_t lpss_ltr_mode_show(struct device *dev,
396 struct device_attribute *attr, char *buf)
397{
398 u32 ltr_mode = 0;
399 char *outstr;
400 int ret;
401
402 ret = lpss_reg_read(dev, LPSS_GENERAL, &ltr_mode);
403 if (ret)
404 return ret;
405
406 outstr = (ltr_mode & LPSS_GENERAL_LTR_MODE_SW) ? "sw" : "auto";
407 return sprintf(buf, "%s\n", outstr);
408}
409
410static DEVICE_ATTR(auto_ltr, S_IRUSR, lpss_ltr_show, NULL);
411static DEVICE_ATTR(sw_ltr, S_IRUSR, lpss_ltr_show, NULL);
412static DEVICE_ATTR(ltr_mode, S_IRUSR, lpss_ltr_mode_show, NULL);
413
414static struct attribute *lpss_attrs[] = {
415 &dev_attr_auto_ltr.attr,
416 &dev_attr_sw_ltr.attr,
417 &dev_attr_ltr_mode.attr,
418 NULL,
419};
420
421static struct attribute_group lpss_attr_group = {
422 .attrs = lpss_attrs,
423 .name = "lpss_ltr",
424};
425
Rafael J. Wysocki1a8f8352014-02-11 00:35:53 +0100426static void acpi_lpss_set_ltr(struct device *dev, s32 val)
427{
428 struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
429 u32 ltr_mode, ltr_val;
430
431 ltr_mode = __lpss_reg_read(pdata, LPSS_GENERAL);
432 if (val < 0) {
433 if (ltr_mode & LPSS_GENERAL_LTR_MODE_SW) {
434 ltr_mode &= ~LPSS_GENERAL_LTR_MODE_SW;
435 __lpss_reg_write(ltr_mode, pdata, LPSS_GENERAL);
436 }
437 return;
438 }
439 ltr_val = __lpss_reg_read(pdata, LPSS_SW_LTR) & ~LPSS_LTR_SNOOP_MASK;
440 if (val >= LPSS_LTR_SNOOP_LAT_CUTOFF) {
441 ltr_val |= LPSS_LTR_SNOOP_LAT_32US;
442 val = LPSS_LTR_MAX_VAL;
443 } else if (val > LPSS_LTR_MAX_VAL) {
444 ltr_val |= LPSS_LTR_SNOOP_LAT_32US | LPSS_LTR_SNOOP_REQ;
445 val >>= LPSS_LTR_SNOOP_LAT_SHIFT;
446 } else {
447 ltr_val |= LPSS_LTR_SNOOP_LAT_1US | LPSS_LTR_SNOOP_REQ;
448 }
449 ltr_val |= val;
450 __lpss_reg_write(ltr_val, pdata, LPSS_SW_LTR);
451 if (!(ltr_mode & LPSS_GENERAL_LTR_MODE_SW)) {
452 ltr_mode |= LPSS_GENERAL_LTR_MODE_SW;
453 __lpss_reg_write(ltr_mode, pdata, LPSS_GENERAL);
454 }
455}
456
Rafael J. Wysocki2e0f8822013-03-06 23:46:28 +0100457static int acpi_lpss_platform_notify(struct notifier_block *nb,
458 unsigned long action, void *data)
459{
460 struct platform_device *pdev = to_platform_device(data);
461 struct lpss_private_data *pdata;
462 struct acpi_device *adev;
463 const struct acpi_device_id *id;
464 int ret = 0;
465
466 id = acpi_match_device(acpi_lpss_device_ids, &pdev->dev);
467 if (!id || !id->driver_data)
468 return 0;
469
470 if (acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev))
471 return 0;
472
473 pdata = acpi_driver_data(adev);
474 if (!pdata || !pdata->mmio_base || !pdata->dev_desc->ltr_required)
475 return 0;
476
477 if (pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) {
478 dev_err(&pdev->dev, "MMIO size insufficient to access LTR\n");
479 return 0;
480 }
481
482 if (action == BUS_NOTIFY_ADD_DEVICE)
483 ret = sysfs_create_group(&pdev->dev.kobj, &lpss_attr_group);
484 else if (action == BUS_NOTIFY_DEL_DEVICE)
485 sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group);
486
487 return ret;
488}
489
490static struct notifier_block acpi_lpss_nb = {
491 .notifier_call = acpi_lpss_platform_notify,
492};
493
Rafael J. Wysocki1a8f8352014-02-11 00:35:53 +0100494static void acpi_lpss_bind(struct device *dev)
495{
496 struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
497
498 if (!pdata || !pdata->mmio_base || !pdata->dev_desc->ltr_required)
499 return;
500
501 if (pdata->mmio_size >= pdata->dev_desc->prv_offset + LPSS_LTR_SIZE)
502 dev->power.set_latency_tolerance = acpi_lpss_set_ltr;
503 else
504 dev_err(dev, "MMIO size insufficient to access LTR\n");
505}
506
507static void acpi_lpss_unbind(struct device *dev)
508{
509 dev->power.set_latency_tolerance = NULL;
510}
511
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100512static struct acpi_scan_handler lpss_handler = {
513 .ids = acpi_lpss_device_ids,
514 .attach = acpi_lpss_create_device,
Rafael J. Wysocki1a8f8352014-02-11 00:35:53 +0100515 .bind = acpi_lpss_bind,
516 .unbind = acpi_lpss_unbind,
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100517};
518
519void __init acpi_lpss_init(void)
520{
Rafael J. Wysocki2e0f8822013-03-06 23:46:28 +0100521 if (!lpt_clk_init()) {
522 bus_register_notifier(&platform_bus_type, &acpi_lpss_nb);
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100523 acpi_scan_add_handler(&lpss_handler);
Rafael J. Wysocki2e0f8822013-03-06 23:46:28 +0100524 }
Rafael J. Wysockif58b0822013-03-06 23:46:20 +0100525}