cmos_rtc.c 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  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. #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. int acpi_install_cmos_rtc_space_handler(acpi_handle handle)
  43. {
  44. acpi_status status;
  45. status = acpi_install_address_space_handler(handle,
  46. ACPI_ADR_SPACE_CMOS,
  47. &acpi_cmos_rtc_space_handler,
  48. NULL, NULL);
  49. if (ACPI_FAILURE(status)) {
  50. pr_err("Error installing CMOS-RTC region handler\n");
  51. return -ENODEV;
  52. }
  53. return 1;
  54. }
  55. EXPORT_SYMBOL_GPL(acpi_install_cmos_rtc_space_handler);
  56. void acpi_remove_cmos_rtc_space_handler(acpi_handle handle)
  57. {
  58. if (ACPI_FAILURE(acpi_remove_address_space_handler(handle,
  59. ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler)))
  60. pr_err("Error removing CMOS-RTC region handler\n");
  61. }
  62. EXPORT_SYMBOL_GPL(acpi_remove_cmos_rtc_space_handler);
  63. static int acpi_cmos_rtc_attach_handler(struct acpi_device *adev, const struct acpi_device_id *id)
  64. {
  65. return acpi_install_cmos_rtc_space_handler(adev->handle);
  66. }
  67. static void acpi_cmos_rtc_detach_handler(struct acpi_device *adev)
  68. {
  69. acpi_remove_cmos_rtc_space_handler(adev->handle);
  70. }
  71. static struct acpi_scan_handler cmos_rtc_handler = {
  72. .ids = acpi_cmos_rtc_ids,
  73. .attach = acpi_cmos_rtc_attach_handler,
  74. .detach = acpi_cmos_rtc_detach_handler,
  75. };
  76. void __init acpi_cmos_rtc_init(void)
  77. {
  78. acpi_scan_add_handler(&cmos_rtc_handler);
  79. }