bcm2835_thermal.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /*
  2. * BCM2835 dummy thermal sensor
  3. *
  4. * Copyright (C) 2019 Philippe Mathieu-Daudé <f4bug@amsat.org>
  5. *
  6. * SPDX-License-Identifier: GPL-2.0-or-later
  7. */
  8. #include "qemu/osdep.h"
  9. #include "qemu/log.h"
  10. #include "qapi/error.h"
  11. #include "hw/misc/bcm2835_thermal.h"
  12. #include "hw/registerfields.h"
  13. #include "migration/vmstate.h"
  14. REG32(CTL, 0)
  15. FIELD(CTL, POWER_DOWN, 0, 1)
  16. FIELD(CTL, RESET, 1, 1)
  17. FIELD(CTL, BANDGAP_CTRL, 2, 3)
  18. FIELD(CTL, INTERRUPT_ENABLE, 5, 1)
  19. FIELD(CTL, DIRECT, 6, 1)
  20. FIELD(CTL, INTERRUPT_CLEAR, 7, 1)
  21. FIELD(CTL, HOLD, 8, 10)
  22. FIELD(CTL, RESET_DELAY, 18, 8)
  23. FIELD(CTL, REGULATOR_ENABLE, 26, 1)
  24. REG32(STAT, 4)
  25. FIELD(STAT, DATA, 0, 10)
  26. FIELD(STAT, VALID, 10, 1)
  27. FIELD(STAT, INTERRUPT, 11, 1)
  28. #define THERMAL_OFFSET_C 412
  29. #define THERMAL_COEFF (-0.538f)
  30. static uint16_t bcm2835_thermal_temp2adc(int temp_C)
  31. {
  32. return (temp_C - THERMAL_OFFSET_C) / THERMAL_COEFF;
  33. }
  34. static uint64_t bcm2835_thermal_read(void *opaque, hwaddr addr, unsigned size)
  35. {
  36. Bcm2835ThermalState *s = BCM2835_THERMAL(opaque);
  37. uint32_t val = 0;
  38. switch (addr) {
  39. case A_CTL:
  40. val = s->ctl;
  41. break;
  42. case A_STAT:
  43. /* Temperature is constantly 25°C. */
  44. val = FIELD_DP32(bcm2835_thermal_temp2adc(25), STAT, VALID, true);
  45. break;
  46. default:
  47. /* MemoryRegionOps are aligned, so this can not happen. */
  48. g_assert_not_reached();
  49. }
  50. return val;
  51. }
  52. static void bcm2835_thermal_write(void *opaque, hwaddr addr,
  53. uint64_t value, unsigned size)
  54. {
  55. Bcm2835ThermalState *s = BCM2835_THERMAL(opaque);
  56. switch (addr) {
  57. case A_CTL:
  58. s->ctl = value;
  59. break;
  60. case A_STAT:
  61. qemu_log_mask(LOG_GUEST_ERROR, "%s: write 0x%" PRIx64
  62. " to 0x%" HWADDR_PRIx "\n",
  63. __func__, value, addr);
  64. break;
  65. default:
  66. /* MemoryRegionOps are aligned, so this can not happen. */
  67. g_assert_not_reached();
  68. }
  69. }
  70. static const MemoryRegionOps bcm2835_thermal_ops = {
  71. .read = bcm2835_thermal_read,
  72. .write = bcm2835_thermal_write,
  73. .impl.min_access_size = 4,
  74. .impl.max_access_size = 4,
  75. .valid.min_access_size = 4,
  76. .valid.max_access_size = 4,
  77. .endianness = DEVICE_NATIVE_ENDIAN,
  78. };
  79. static void bcm2835_thermal_reset(DeviceState *dev)
  80. {
  81. Bcm2835ThermalState *s = BCM2835_THERMAL(dev);
  82. s->ctl = 0;
  83. }
  84. static void bcm2835_thermal_realize(DeviceState *dev, Error **errp)
  85. {
  86. Bcm2835ThermalState *s = BCM2835_THERMAL(dev);
  87. memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_thermal_ops,
  88. s, TYPE_BCM2835_THERMAL, 8);
  89. sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
  90. }
  91. static const VMStateDescription bcm2835_thermal_vmstate = {
  92. .name = "bcm2835_thermal",
  93. .version_id = 1,
  94. .minimum_version_id = 1,
  95. .fields = (const VMStateField[]) {
  96. VMSTATE_UINT32(ctl, Bcm2835ThermalState),
  97. VMSTATE_END_OF_LIST()
  98. }
  99. };
  100. static void bcm2835_thermal_class_init(ObjectClass *klass, void *data)
  101. {
  102. DeviceClass *dc = DEVICE_CLASS(klass);
  103. dc->realize = bcm2835_thermal_realize;
  104. device_class_set_legacy_reset(dc, bcm2835_thermal_reset);
  105. dc->vmsd = &bcm2835_thermal_vmstate;
  106. }
  107. static const TypeInfo bcm2835_thermal_info = {
  108. .name = TYPE_BCM2835_THERMAL,
  109. .parent = TYPE_SYS_BUS_DEVICE,
  110. .instance_size = sizeof(Bcm2835ThermalState),
  111. .class_init = bcm2835_thermal_class_init,
  112. };
  113. static void bcm2835_thermal_register_types(void)
  114. {
  115. type_register_static(&bcm2835_thermal_info);
  116. }
  117. type_init(bcm2835_thermal_register_types)