diff options
author | Lan Tianyu <tianyu.lan@intel.com> | 2013-06-04 22:27:50 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-07-21 21:21:28 -0400 |
commit | 623c1cba04991c15d594a25fd31d7480d931aa57 (patch) | |
tree | f82e520cd4fa829712db79930782355b0822b5d5 | |
parent | e64c0641beee09a0d9870efc5ea40eb06b6529cb (diff) |
ACPI: Add CMOS RTC Operation Region handler support
commit 2fa97feb4406c546b52e35b6b6c50cb8f63425d2 upstream.
On HP Folio 13-2000, the BIOS defines a CMOS RTC Operation Region and
the EC's _REG methord accesses that region. Thus an appropriate
address space handler must be registered for that region before the
EC driver is loaded.
Introduce a mechanism for adding CMOS RTC address space handlers.
Register an ACPI scan handler for CMOS RTC devices such that, when
a device of that kind is detected during an ACPI namespace scan, a
common CMOS RTC operation region address space handler will be
installed for it.
References: https://bugzilla.kernel.org/show_bug.cgi?id=54621
Reported-and-tested-by: Stefan Nagy <public@stefan-nagy.at>
Signed-off-by: Lan Tianyu <tianyu.lan@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/acpi/Makefile | 1 | ||||
-rw-r--r-- | drivers/acpi/acpi_cmos_rtc.c | 92 | ||||
-rw-r--r-- | drivers/acpi/internal.h | 5 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 1 |
4 files changed, 99 insertions, 0 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 536562c626a2..97c949abfabb 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile | |||
@@ -43,6 +43,7 @@ acpi-y += acpi_platform.o | |||
43 | acpi-y += power.o | 43 | acpi-y += power.o |
44 | acpi-y += event.o | 44 | acpi-y += event.o |
45 | acpi-y += sysfs.o | 45 | acpi-y += sysfs.o |
46 | acpi-$(CONFIG_X86) += acpi_cmos_rtc.o | ||
46 | acpi-$(CONFIG_DEBUG_FS) += debugfs.o | 47 | acpi-$(CONFIG_DEBUG_FS) += debugfs.o |
47 | acpi-$(CONFIG_ACPI_NUMA) += numa.o | 48 | acpi-$(CONFIG_ACPI_NUMA) += numa.o |
48 | acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o | 49 | acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o |
diff --git a/drivers/acpi/acpi_cmos_rtc.c b/drivers/acpi/acpi_cmos_rtc.c new file mode 100644 index 000000000000..84190ed89c04 --- /dev/null +++ b/drivers/acpi/acpi_cmos_rtc.c | |||
@@ -0,0 +1,92 @@ | |||
1 | /* | ||
2 | * ACPI support for CMOS RTC Address Space access | ||
3 | * | ||
4 | * Copyright (C) 2013, Intel Corporation | ||
5 | * Authors: Lan Tianyu <tianyu.lan@intel.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/acpi.h> | ||
13 | #include <linux/device.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <asm-generic/rtc.h> | ||
18 | |||
19 | #include "internal.h" | ||
20 | |||
21 | #define PREFIX "ACPI: " | ||
22 | |||
23 | ACPI_MODULE_NAME("cmos rtc"); | ||
24 | |||
25 | static const struct acpi_device_id acpi_cmos_rtc_ids[] = { | ||
26 | { "PNP0B00" }, | ||
27 | { "PNP0B01" }, | ||
28 | { "PNP0B02" }, | ||
29 | {} | ||
30 | }; | ||
31 | |||
32 | static acpi_status | ||
33 | acpi_cmos_rtc_space_handler(u32 function, acpi_physical_address address, | ||
34 | u32 bits, u64 *value64, | ||
35 | void *handler_context, void *region_context) | ||
36 | { | ||
37 | int i; | ||
38 | u8 *value = (u8 *)&value64; | ||
39 | |||
40 | if (address > 0xff || !value64) | ||
41 | return AE_BAD_PARAMETER; | ||
42 | |||
43 | if (function != ACPI_WRITE && function != ACPI_READ) | ||
44 | return AE_BAD_PARAMETER; | ||
45 | |||
46 | spin_lock_irq(&rtc_lock); | ||
47 | |||
48 | for (i = 0; i < DIV_ROUND_UP(bits, 8); ++i, ++address, ++value) | ||
49 | if (function == ACPI_READ) | ||
50 | *value = CMOS_READ(address); | ||
51 | else | ||
52 | CMOS_WRITE(*value, address); | ||
53 | |||
54 | spin_unlock_irq(&rtc_lock); | ||
55 | |||
56 | return AE_OK; | ||
57 | } | ||
58 | |||
59 | static int acpi_install_cmos_rtc_space_handler(struct acpi_device *adev, | ||
60 | const struct acpi_device_id *id) | ||
61 | { | ||
62 | acpi_status status; | ||
63 | |||
64 | status = acpi_install_address_space_handler(adev->handle, | ||
65 | ACPI_ADR_SPACE_CMOS, | ||
66 | &acpi_cmos_rtc_space_handler, | ||
67 | NULL, NULL); | ||
68 | if (ACPI_FAILURE(status)) { | ||
69 | pr_err(PREFIX "Error installing CMOS-RTC region handler\n"); | ||
70 | return -ENODEV; | ||
71 | } | ||
72 | |||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static void acpi_remove_cmos_rtc_space_handler(struct acpi_device *adev) | ||
77 | { | ||
78 | if (ACPI_FAILURE(acpi_remove_address_space_handler(adev->handle, | ||
79 | ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler))) | ||
80 | pr_err(PREFIX "Error removing CMOS-RTC region handler\n"); | ||
81 | } | ||
82 | |||
83 | static struct acpi_scan_handler cmos_rtc_handler = { | ||
84 | .ids = acpi_cmos_rtc_ids, | ||
85 | .attach = acpi_install_cmos_rtc_space_handler, | ||
86 | .detach = acpi_remove_cmos_rtc_space_handler, | ||
87 | }; | ||
88 | |||
89 | void __init acpi_cmos_rtc_init(void) | ||
90 | { | ||
91 | acpi_scan_add_handler(&cmos_rtc_handler); | ||
92 | } | ||
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index c610a76d92c4..63a08549bfa2 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h | |||
@@ -50,6 +50,11 @@ void acpi_memory_hotplug_init(void); | |||
50 | #else | 50 | #else |
51 | static inline void acpi_memory_hotplug_init(void) {} | 51 | static inline void acpi_memory_hotplug_init(void) {} |
52 | #endif | 52 | #endif |
53 | #ifdef CONFIG_X86 | ||
54 | void acpi_cmos_rtc_init(void); | ||
55 | #else | ||
56 | static inline void acpi_cmos_rtc_init(void) {} | ||
57 | #endif | ||
53 | 58 | ||
54 | void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug, | 59 | void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug, |
55 | const char *name); | 60 | const char *name); |
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 27da63061e11..14807e53ccae 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -2040,6 +2040,7 @@ int __init acpi_scan_init(void) | |||
2040 | acpi_pci_link_init(); | 2040 | acpi_pci_link_init(); |
2041 | acpi_platform_init(); | 2041 | acpi_platform_init(); |
2042 | acpi_lpss_init(); | 2042 | acpi_lpss_init(); |
2043 | acpi_cmos_rtc_init(); | ||
2043 | acpi_container_init(); | 2044 | acpi_container_init(); |
2044 | acpi_memory_hotplug_init(); | 2045 | acpi_memory_hotplug_init(); |
2045 | acpi_dock_init(); | 2046 | acpi_dock_init(); |