mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 16:54:21 +00:00 
			
		
		
		
	ACPI: Add CMOS RTC Operation Region handler support
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> Cc: 3.9+ <stable@vger.kernel.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
		
							parent
							
								
									358b4b35c8
								
							
						
					
					
						commit
						2fa97feb44
					
				
					 4 changed files with 99 additions and 0 deletions
				
			
		|  | @ -43,6 +43,7 @@ acpi-y				+= acpi_platform.o | ||||||
| acpi-y				+= power.o | acpi-y				+= power.o | ||||||
| acpi-y				+= event.o | acpi-y				+= event.o | ||||||
| acpi-y				+= sysfs.o | acpi-y				+= sysfs.o | ||||||
|  | acpi-$(CONFIG_X86)		+= acpi_cmos_rtc.o | ||||||
| acpi-$(CONFIG_DEBUG_FS)		+= debugfs.o | acpi-$(CONFIG_DEBUG_FS)		+= debugfs.o | ||||||
| acpi-$(CONFIG_ACPI_NUMA)	+= numa.o | acpi-$(CONFIG_ACPI_NUMA)	+= numa.o | ||||||
| acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o | acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o | ||||||
|  |  | ||||||
							
								
								
									
										92
									
								
								drivers/acpi/acpi_cmos_rtc.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								drivers/acpi/acpi_cmos_rtc.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,92 @@ | ||||||
|  | /*
 | ||||||
|  |  * ACPI support for CMOS RTC Address Space access | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2013, Intel Corporation | ||||||
|  |  * Authors: Lan Tianyu <tianyu.lan@intel.com> | ||||||
|  |  * | ||||||
|  |  * This program is free software; you can redistribute it and/or modify | ||||||
|  |  * it under the terms of the GNU General Public License version 2 as | ||||||
|  |  * published by the Free Software Foundation. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <linux/acpi.h> | ||||||
|  | #include <linux/device.h> | ||||||
|  | #include <linux/err.h> | ||||||
|  | #include <linux/kernel.h> | ||||||
|  | #include <linux/module.h> | ||||||
|  | #include <asm-generic/rtc.h> | ||||||
|  | 
 | ||||||
|  | #include "internal.h" | ||||||
|  | 
 | ||||||
|  | #define PREFIX "ACPI: " | ||||||
|  | 
 | ||||||
|  | ACPI_MODULE_NAME("cmos rtc"); | ||||||
|  | 
 | ||||||
|  | static const struct acpi_device_id acpi_cmos_rtc_ids[] = { | ||||||
|  | 	{ "PNP0B00" }, | ||||||
|  | 	{ "PNP0B01" }, | ||||||
|  | 	{ "PNP0B02" }, | ||||||
|  | 	{} | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static acpi_status | ||||||
|  | acpi_cmos_rtc_space_handler(u32 function, acpi_physical_address address, | ||||||
|  | 		      u32 bits, u64 *value64, | ||||||
|  | 		      void *handler_context, void *region_context) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  | 	u8 *value = (u8 *)&value64; | ||||||
|  | 
 | ||||||
|  | 	if (address > 0xff || !value64) | ||||||
|  | 		return AE_BAD_PARAMETER; | ||||||
|  | 
 | ||||||
|  | 	if (function != ACPI_WRITE && function != ACPI_READ) | ||||||
|  | 		return AE_BAD_PARAMETER; | ||||||
|  | 
 | ||||||
|  | 	spin_lock_irq(&rtc_lock); | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < DIV_ROUND_UP(bits, 8); ++i, ++address, ++value) | ||||||
|  | 		if (function == ACPI_READ) | ||||||
|  | 			*value = CMOS_READ(address); | ||||||
|  | 		else | ||||||
|  | 			CMOS_WRITE(*value, address); | ||||||
|  | 
 | ||||||
|  | 	spin_unlock_irq(&rtc_lock); | ||||||
|  | 
 | ||||||
|  | 	return AE_OK; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int acpi_install_cmos_rtc_space_handler(struct acpi_device *adev, | ||||||
|  | 		const struct acpi_device_id *id) | ||||||
|  | { | ||||||
|  | 	acpi_status status; | ||||||
|  | 
 | ||||||
|  | 	status = acpi_install_address_space_handler(adev->handle, | ||||||
|  | 			ACPI_ADR_SPACE_CMOS, | ||||||
|  | 			&acpi_cmos_rtc_space_handler, | ||||||
|  | 			NULL, NULL); | ||||||
|  | 	if (ACPI_FAILURE(status)) { | ||||||
|  | 		pr_err(PREFIX "Error installing CMOS-RTC region handler\n"); | ||||||
|  | 		return -ENODEV; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void acpi_remove_cmos_rtc_space_handler(struct acpi_device *adev) | ||||||
|  | { | ||||||
|  | 	if (ACPI_FAILURE(acpi_remove_address_space_handler(adev->handle, | ||||||
|  | 			ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler))) | ||||||
|  | 		pr_err(PREFIX "Error removing CMOS-RTC region handler\n"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static struct acpi_scan_handler cmos_rtc_handler = { | ||||||
|  | 	.ids = acpi_cmos_rtc_ids, | ||||||
|  | 	.attach = acpi_install_cmos_rtc_space_handler, | ||||||
|  | 	.detach = acpi_remove_cmos_rtc_space_handler, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void __init acpi_cmos_rtc_init(void) | ||||||
|  | { | ||||||
|  | 	acpi_scan_add_handler(&cmos_rtc_handler); | ||||||
|  | } | ||||||
|  | @ -45,6 +45,11 @@ void acpi_memory_hotplug_init(void); | ||||||
| #else | #else | ||||||
| static inline void acpi_memory_hotplug_init(void) {} | static inline void acpi_memory_hotplug_init(void) {} | ||||||
| #endif | #endif | ||||||
|  | #ifdef CONFIG_X86 | ||||||
|  | void acpi_cmos_rtc_init(void); | ||||||
|  | #else | ||||||
|  | static inline void acpi_cmos_rtc_init(void) {} | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug, | void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug, | ||||||
| 				    const char *name); | 				    const char *name); | ||||||
|  |  | ||||||
|  | @ -2040,6 +2040,7 @@ int __init acpi_scan_init(void) | ||||||
| 	acpi_pci_link_init(); | 	acpi_pci_link_init(); | ||||||
| 	acpi_platform_init(); | 	acpi_platform_init(); | ||||||
| 	acpi_lpss_init(); | 	acpi_lpss_init(); | ||||||
|  | 	acpi_cmos_rtc_init(); | ||||||
| 	acpi_container_init(); | 	acpi_container_init(); | ||||||
| 	acpi_memory_hotplug_init(); | 	acpi_memory_hotplug_init(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Lan Tianyu
						Lan Tianyu