Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only 2 : : /* 3 : : * ACPI support for CMOS RTC Address Space access 4 : : * 5 : : * Copyright (C) 2013, Intel Corporation 6 : : * Authors: Lan Tianyu <tianyu.lan@intel.com> 7 : : */ 8 : : 9 : : #include <linux/acpi.h> 10 : : #include <linux/device.h> 11 : : #include <linux/err.h> 12 : : #include <linux/kernel.h> 13 : : #include <linux/module.h> 14 : : #include <linux/mc146818rtc.h> 15 : : 16 : : #include "internal.h" 17 : : 18 : : ACPI_MODULE_NAME("cmos rtc"); 19 : : 20 : : static const struct acpi_device_id acpi_cmos_rtc_ids[] = { 21 : : { "PNP0B00" }, 22 : : { "PNP0B01" }, 23 : : { "PNP0B02" }, 24 : : {} 25 : : }; 26 : : 27 : : static acpi_status 28 : 0 : acpi_cmos_rtc_space_handler(u32 function, acpi_physical_address address, 29 : : u32 bits, u64 *value64, 30 : : void *handler_context, void *region_context) 31 : : { 32 : 0 : int i; 33 : 0 : u8 *value = (u8 *)value64; 34 : : 35 [ # # ]: 0 : if (address > 0xff || !value64) 36 : : return AE_BAD_PARAMETER; 37 : : 38 [ # # ]: 0 : if (function != ACPI_WRITE && function != ACPI_READ) 39 : : return AE_BAD_PARAMETER; 40 : : 41 : 0 : spin_lock_irq(&rtc_lock); 42 : : 43 [ # # ]: 0 : for (i = 0; i < DIV_ROUND_UP(bits, 8); ++i, ++address, ++value) 44 [ # # ]: 0 : if (function == ACPI_READ) 45 : 0 : *value = CMOS_READ(address); 46 : : else 47 : 0 : CMOS_WRITE(*value, address); 48 : : 49 : 0 : spin_unlock_irq(&rtc_lock); 50 : : 51 : 0 : return AE_OK; 52 : : } 53 : : 54 : 30 : static int acpi_install_cmos_rtc_space_handler(struct acpi_device *adev, 55 : : const struct acpi_device_id *id) 56 : : { 57 : 30 : acpi_status status; 58 : : 59 : 30 : status = acpi_install_address_space_handler(adev->handle, 60 : : ACPI_ADR_SPACE_CMOS, 61 : : &acpi_cmos_rtc_space_handler, 62 : : NULL, NULL); 63 [ - + ]: 30 : if (ACPI_FAILURE(status)) { 64 : 0 : pr_err(PREFIX "Error installing CMOS-RTC region handler\n"); 65 : 0 : return -ENODEV; 66 : : } 67 : : 68 : : return 1; 69 : : } 70 : : 71 : 0 : static void acpi_remove_cmos_rtc_space_handler(struct acpi_device *adev) 72 : : { 73 [ # # ]: 0 : if (ACPI_FAILURE(acpi_remove_address_space_handler(adev->handle, 74 : : ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler))) 75 : 0 : pr_err(PREFIX "Error removing CMOS-RTC region handler\n"); 76 : 0 : } 77 : : 78 : : static struct acpi_scan_handler cmos_rtc_handler = { 79 : : .ids = acpi_cmos_rtc_ids, 80 : : .attach = acpi_install_cmos_rtc_space_handler, 81 : : .detach = acpi_remove_cmos_rtc_space_handler, 82 : : }; 83 : : 84 : 30 : void __init acpi_cmos_rtc_init(void) 85 : : { 86 : 30 : acpi_scan_add_handler(&cmos_rtc_handler); 87 : 30 : }