Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * ACPI support for CMOS RTC Address Space access
0004  *
0005  * Copyright (C) 2013, Intel Corporation
0006  * Authors: Lan Tianyu <tianyu.lan@intel.com>
0007  */
0008 
0009 #define pr_fmt(fmt) "ACPI: " fmt
0010 
0011 #include <linux/acpi.h>
0012 #include <linux/device.h>
0013 #include <linux/err.h>
0014 #include <linux/kernel.h>
0015 #include <linux/module.h>
0016 #include <linux/mc146818rtc.h>
0017 
0018 #include "internal.h"
0019 
0020 static const struct acpi_device_id acpi_cmos_rtc_ids[] = {
0021     { "PNP0B00" },
0022     { "PNP0B01" },
0023     { "PNP0B02" },
0024     {}
0025 };
0026 
0027 static acpi_status
0028 acpi_cmos_rtc_space_handler(u32 function, acpi_physical_address address,
0029               u32 bits, u64 *value64,
0030               void *handler_context, void *region_context)
0031 {
0032     int i;
0033     u8 *value = (u8 *)value64;
0034 
0035     if (address > 0xff || !value64)
0036         return AE_BAD_PARAMETER;
0037 
0038     if (function != ACPI_WRITE && function != ACPI_READ)
0039         return AE_BAD_PARAMETER;
0040 
0041     spin_lock_irq(&rtc_lock);
0042 
0043     for (i = 0; i < DIV_ROUND_UP(bits, 8); ++i, ++address, ++value)
0044         if (function == ACPI_READ)
0045             *value = CMOS_READ(address);
0046         else
0047             CMOS_WRITE(*value, address);
0048 
0049     spin_unlock_irq(&rtc_lock);
0050 
0051     return AE_OK;
0052 }
0053 
0054 static int acpi_install_cmos_rtc_space_handler(struct acpi_device *adev,
0055         const struct acpi_device_id *id)
0056 {
0057     acpi_status status;
0058 
0059     status = acpi_install_address_space_handler(adev->handle,
0060             ACPI_ADR_SPACE_CMOS,
0061             &acpi_cmos_rtc_space_handler,
0062             NULL, NULL);
0063     if (ACPI_FAILURE(status)) {
0064         pr_err("Error installing CMOS-RTC region handler\n");
0065         return -ENODEV;
0066     }
0067 
0068     return 1;
0069 }
0070 
0071 static void acpi_remove_cmos_rtc_space_handler(struct acpi_device *adev)
0072 {
0073     if (ACPI_FAILURE(acpi_remove_address_space_handler(adev->handle,
0074             ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler)))
0075         pr_err("Error removing CMOS-RTC region handler\n");
0076 }
0077 
0078 static struct acpi_scan_handler cmos_rtc_handler = {
0079     .ids = acpi_cmos_rtc_ids,
0080     .attach = acpi_install_cmos_rtc_space_handler,
0081     .detach = acpi_remove_cmos_rtc_space_handler,
0082 };
0083 
0084 void __init acpi_cmos_rtc_init(void)
0085 {
0086     acpi_scan_add_handler(&cmos_rtc_handler);
0087 }