acpi_cmos_rtc.c 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  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 <[email protected]>
  7. */
  8. #define pr_fmt(fmt) "ACPI: " fmt
  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. #include "internal.h"
  16. static const struct acpi_device_id acpi_cmos_rtc_ids[] = {
  17. { "PNP0B00" },
  18. { "PNP0B01" },
  19. { "PNP0B02" },
  20. {}
  21. };
  22. static acpi_status
  23. acpi_cmos_rtc_space_handler(u32 function, acpi_physical_address address,
  24. u32 bits, u64 *value64,
  25. void *handler_context, void *region_context)
  26. {
  27. int i;
  28. u8 *value = (u8 *)value64;
  29. if (address > 0xff || !value64)
  30. return AE_BAD_PARAMETER;
  31. if (function != ACPI_WRITE && function != ACPI_READ)
  32. return AE_BAD_PARAMETER;
  33. spin_lock_irq(&rtc_lock);
  34. for (i = 0; i < DIV_ROUND_UP(bits, 8); ++i, ++address, ++value)
  35. if (function == ACPI_READ)
  36. *value = CMOS_READ(address);
  37. else
  38. CMOS_WRITE(*value, address);
  39. spin_unlock_irq(&rtc_lock);
  40. return AE_OK;
  41. }
  42. static int acpi_install_cmos_rtc_space_handler(struct acpi_device *adev,
  43. const struct acpi_device_id *id)
  44. {
  45. acpi_status status;
  46. status = acpi_install_address_space_handler(adev->handle,
  47. ACPI_ADR_SPACE_CMOS,
  48. &acpi_cmos_rtc_space_handler,
  49. NULL, NULL);
  50. if (ACPI_FAILURE(status)) {
  51. pr_err("Error installing CMOS-RTC region handler\n");
  52. return -ENODEV;
  53. }
  54. return 1;
  55. }
  56. static void acpi_remove_cmos_rtc_space_handler(struct acpi_device *adev)
  57. {
  58. if (ACPI_FAILURE(acpi_remove_address_space_handler(adev->handle,
  59. ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler)))
  60. pr_err("Error removing CMOS-RTC region handler\n");
  61. }
  62. static struct acpi_scan_handler cmos_rtc_handler = {
  63. .ids = acpi_cmos_rtc_ids,
  64. .attach = acpi_install_cmos_rtc_space_handler,
  65. .detach = acpi_remove_cmos_rtc_space_handler,
  66. };
  67. void __init acpi_cmos_rtc_init(void)
  68. {
  69. acpi_scan_add_handler(&cmos_rtc_handler);
  70. }