bcm2835_thermal.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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.max_access_size = 4,
  74. .valid.min_access_size = 4,
  75. .endianness = DEVICE_NATIVE_ENDIAN,
  76. };
  77. static void bcm2835_thermal_reset(DeviceState *dev)
  78. {
  79. Bcm2835ThermalState *s = BCM2835_THERMAL(dev);
  80. s->ctl = 0;
  81. }
  82. static void bcm2835_thermal_realize(DeviceState *dev, Error **errp)
  83. {
  84. Bcm2835ThermalState *s = BCM2835_THERMAL(dev);
  85. memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_thermal_ops,
  86. s, TYPE_BCM2835_THERMAL, 8);
  87. sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
  88. }
  89. static const VMStateDescription bcm2835_thermal_vmstate = {
  90. .name = "bcm2835_thermal",
  91. .version_id = 1,
  92. .minimum_version_id = 1,
  93. .fields = (VMStateField[]) {
  94. VMSTATE_UINT32(ctl, Bcm2835ThermalState),
  95. VMSTATE_END_OF_LIST()
  96. }
  97. };
  98. static void bcm2835_thermal_class_init(ObjectClass *klass, void *data)
  99. {
  100. DeviceClass *dc = DEVICE_CLASS(klass);
  101. dc->realize = bcm2835_thermal_realize;
  102. dc->reset = bcm2835_thermal_reset;
  103. dc->vmsd = &bcm2835_thermal_vmstate;
  104. }
  105. static const TypeInfo bcm2835_thermal_info = {
  106. .name = TYPE_BCM2835_THERMAL,
  107. .parent = TYPE_SYS_BUS_DEVICE,
  108. .instance_size = sizeof(Bcm2835ThermalState),
  109. .class_init = bcm2835_thermal_class_init,
  110. };
  111. static void bcm2835_thermal_register_types(void)
  112. {
  113. type_register_static(&bcm2835_thermal_info);
  114. }
  115. type_init(bcm2835_thermal_register_types)