acpi_cmos_rtc.c 2.0 KB

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