12fa97febSLan Tianyu /* 22fa97febSLan Tianyu * ACPI support for CMOS RTC Address Space access 32fa97febSLan Tianyu * 42fa97febSLan Tianyu * Copyright (C) 2013, Intel Corporation 52fa97febSLan Tianyu * Authors: Lan Tianyu <tianyu.lan@intel.com> 62fa97febSLan Tianyu * 72fa97febSLan Tianyu * This program is free software; you can redistribute it and/or modify 82fa97febSLan Tianyu * it under the terms of the GNU General Public License version 2 as 92fa97febSLan Tianyu * published by the Free Software Foundation. 102fa97febSLan Tianyu */ 112fa97febSLan Tianyu 122fa97febSLan Tianyu #include <linux/acpi.h> 132fa97febSLan Tianyu #include <linux/device.h> 142fa97febSLan Tianyu #include <linux/err.h> 152fa97febSLan Tianyu #include <linux/kernel.h> 162fa97febSLan Tianyu #include <linux/module.h> 172fa97febSLan Tianyu #include <asm-generic/rtc.h> 182fa97febSLan Tianyu 192fa97febSLan Tianyu #include "internal.h" 202fa97febSLan Tianyu 212fa97febSLan Tianyu #define PREFIX "ACPI: " 222fa97febSLan Tianyu 232fa97febSLan Tianyu ACPI_MODULE_NAME("cmos rtc"); 242fa97febSLan Tianyu 252fa97febSLan Tianyu static const struct acpi_device_id acpi_cmos_rtc_ids[] = { 262fa97febSLan Tianyu { "PNP0B00" }, 272fa97febSLan Tianyu { "PNP0B01" }, 282fa97febSLan Tianyu { "PNP0B02" }, 292fa97febSLan Tianyu {} 302fa97febSLan Tianyu }; 312fa97febSLan Tianyu 322fa97febSLan Tianyu static acpi_status 332fa97febSLan Tianyu acpi_cmos_rtc_space_handler(u32 function, acpi_physical_address address, 342fa97febSLan Tianyu u32 bits, u64 *value64, 352fa97febSLan Tianyu void *handler_context, void *region_context) 362fa97febSLan Tianyu { 372fa97febSLan Tianyu int i; 382fa97febSLan Tianyu u8 *value = (u8 *)&value64; 392fa97febSLan Tianyu 402fa97febSLan Tianyu if (address > 0xff || !value64) 412fa97febSLan Tianyu return AE_BAD_PARAMETER; 422fa97febSLan Tianyu 432fa97febSLan Tianyu if (function != ACPI_WRITE && function != ACPI_READ) 442fa97febSLan Tianyu return AE_BAD_PARAMETER; 452fa97febSLan Tianyu 462fa97febSLan Tianyu spin_lock_irq(&rtc_lock); 472fa97febSLan Tianyu 482fa97febSLan Tianyu for (i = 0; i < DIV_ROUND_UP(bits, 8); ++i, ++address, ++value) 492fa97febSLan Tianyu if (function == ACPI_READ) 502fa97febSLan Tianyu *value = CMOS_READ(address); 512fa97febSLan Tianyu else 522fa97febSLan Tianyu CMOS_WRITE(*value, address); 532fa97febSLan Tianyu 542fa97febSLan Tianyu spin_unlock_irq(&rtc_lock); 552fa97febSLan Tianyu 562fa97febSLan Tianyu return AE_OK; 572fa97febSLan Tianyu } 582fa97febSLan Tianyu 592fa97febSLan Tianyu static int acpi_install_cmos_rtc_space_handler(struct acpi_device *adev, 602fa97febSLan Tianyu const struct acpi_device_id *id) 612fa97febSLan Tianyu { 622fa97febSLan Tianyu acpi_status status; 632fa97febSLan Tianyu 642fa97febSLan Tianyu status = acpi_install_address_space_handler(adev->handle, 652fa97febSLan Tianyu ACPI_ADR_SPACE_CMOS, 662fa97febSLan Tianyu &acpi_cmos_rtc_space_handler, 672fa97febSLan Tianyu NULL, NULL); 682fa97febSLan Tianyu if (ACPI_FAILURE(status)) { 692fa97febSLan Tianyu pr_err(PREFIX "Error installing CMOS-RTC region handler\n"); 702fa97febSLan Tianyu return -ENODEV; 712fa97febSLan Tianyu } 722fa97febSLan Tianyu 732fa97febSLan Tianyu return 0; 742fa97febSLan Tianyu } 752fa97febSLan Tianyu 762fa97febSLan Tianyu static void acpi_remove_cmos_rtc_space_handler(struct acpi_device *adev) 772fa97febSLan Tianyu { 782fa97febSLan Tianyu if (ACPI_FAILURE(acpi_remove_address_space_handler(adev->handle, 792fa97febSLan Tianyu ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler))) 802fa97febSLan Tianyu pr_err(PREFIX "Error removing CMOS-RTC region handler\n"); 812fa97febSLan Tianyu } 822fa97febSLan Tianyu 832fa97febSLan Tianyu static struct acpi_scan_handler cmos_rtc_handler = { 842fa97febSLan Tianyu .ids = acpi_cmos_rtc_ids, 852fa97febSLan Tianyu .attach = acpi_install_cmos_rtc_space_handler, 862fa97febSLan Tianyu .detach = acpi_remove_cmos_rtc_space_handler, 872fa97febSLan Tianyu }; 882fa97febSLan Tianyu 892fa97febSLan Tianyu void __init acpi_cmos_rtc_init(void) 902fa97febSLan Tianyu { 912fa97febSLan Tianyu acpi_scan_add_handler(&cmos_rtc_handler); 922fa97febSLan Tianyu } 93