xref: /linux/drivers/acpi/x86/cmos_rtc.c (revision 53597deca0e38c30e6cd4ba2114fa42d2bcd85bb)
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 #define pr_fmt(fmt) "ACPI: " fmt
10 
11 #include <linux/acpi.h>
12 #include <linux/device.h>
13 #include <linux/err.h>
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/mc146818rtc.h>
17 
18 #include "../internal.h"
19 
20 static const struct acpi_device_id acpi_cmos_rtc_ids[] = {
21 	{ "ACPI000E", 1 }, /* ACPI Time and Alarm Device (TAD) */
22 	ACPI_CMOS_RTC_IDS
23 };
24 
25 bool cmos_rtc_platform_device_present;
26 
27 static acpi_status acpi_cmos_rtc_space_handler(u32 function,
28 					       acpi_physical_address address,
29 					       u32 bits, u64 *value64,
30 					       void *handler_context,
31 					       void *region_context)
32 {
33 	unsigned int i, bytes = DIV_ROUND_UP(bits, 8);
34 	u8 *value = (u8 *)value64;
35 
36 	if (address > 0xff || !value64)
37 		return AE_BAD_PARAMETER;
38 
39 	guard(spinlock_irq)(&rtc_lock);
40 
41 	if (function == ACPI_WRITE) {
42 		for (i = 0; i < bytes; i++, address++, value++)
43 			CMOS_WRITE(*value, address);
44 
45 		return AE_OK;
46 	}
47 
48 	if (function == ACPI_READ) {
49 		for (i = 0; i < bytes; i++, address++, value++)
50 			*value = CMOS_READ(address);
51 
52 		return AE_OK;
53 	}
54 
55 	return AE_BAD_PARAMETER;
56 }
57 
58 static int acpi_install_cmos_rtc_space_handler(acpi_handle handle)
59 {
60 	static bool cmos_rtc_space_handler_present __read_mostly;
61 	acpi_status status;
62 
63 	if (cmos_rtc_space_handler_present)
64 		return 0;
65 
66 	status = acpi_install_address_space_handler(handle,
67 						    ACPI_ADR_SPACE_CMOS,
68 						    acpi_cmos_rtc_space_handler,
69 						    NULL, NULL);
70 	if (ACPI_FAILURE(status)) {
71 		pr_err("Failed to install CMOS-RTC address space handler\n");
72 		return -ENODEV;
73 	}
74 
75 	cmos_rtc_space_handler_present = true;
76 
77 	return 1;
78 }
79 
80 static int acpi_cmos_rtc_attach(struct acpi_device *adev,
81 				const struct acpi_device_id *id)
82 {
83 	int ret;
84 
85 	ret = acpi_install_cmos_rtc_space_handler(adev->handle);
86 	if (ret < 0)
87 		return ret;
88 
89 	if (IS_ERR_OR_NULL(acpi_create_platform_device(adev, NULL))) {
90 		pr_err("Failed to create a platform device for %s\n", (char *)id->id);
91 		return 0;
92 	} else if (!id->driver_data) {
93 		cmos_rtc_platform_device_present = true;
94 	}
95 	return 1;
96 }
97 
98 static struct acpi_scan_handler cmos_rtc_handler = {
99 	.ids = acpi_cmos_rtc_ids,
100 	.attach = acpi_cmos_rtc_attach,
101 };
102 
103 void __init acpi_cmos_rtc_init(void)
104 {
105 	acpi_scan_add_handler(&cmos_rtc_handler);
106 }
107