2 * BCM2835 dummy thermal sensor
4 * Copyright (C) 2019 Philippe Mathieu-Daudé <f4bug@amsat.org>
6 * SPDX-License-Identifier: GPL-2.0-or-later
9 #include "qemu/osdep.h"
11 #include "qapi/error.h"
12 #include "hw/misc/bcm2835_thermal.h"
13 #include "hw/registerfields.h"
14 #include "migration/vmstate.h"
17 FIELD(CTL
, POWER_DOWN
, 0, 1)
18 FIELD(CTL
, RESET
, 1, 1)
19 FIELD(CTL
, BANDGAP_CTRL
, 2, 3)
20 FIELD(CTL
, INTERRUPT_ENABLE
, 5, 1)
21 FIELD(CTL
, DIRECT
, 6, 1)
22 FIELD(CTL
, INTERRUPT_CLEAR
, 7, 1)
23 FIELD(CTL
, HOLD
, 8, 10)
24 FIELD(CTL
, RESET_DELAY
, 18, 8)
25 FIELD(CTL
, REGULATOR_ENABLE
, 26, 1)
28 FIELD(STAT
, DATA
, 0, 10)
29 FIELD(STAT
, VALID
, 10, 1)
30 FIELD(STAT
, INTERRUPT
, 11, 1)
32 #define THERMAL_OFFSET_C 412
33 #define THERMAL_COEFF (-0.538f)
35 static uint16_t bcm2835_thermal_temp2adc(int temp_C
)
37 return (temp_C
- THERMAL_OFFSET_C
) / THERMAL_COEFF
;
40 static uint64_t bcm2835_thermal_read(void *opaque
, hwaddr addr
, unsigned size
)
42 Bcm2835ThermalState
*s
= BCM2835_THERMAL(opaque
);
50 /* Temperature is constantly 25°C. */
51 val
= FIELD_DP32(bcm2835_thermal_temp2adc(25), STAT
, VALID
, true);
54 /* MemoryRegionOps are aligned, so this can not happen. */
55 g_assert_not_reached();
60 static void bcm2835_thermal_write(void *opaque
, hwaddr addr
,
61 uint64_t value
, unsigned size
)
63 Bcm2835ThermalState
*s
= BCM2835_THERMAL(opaque
);
70 qemu_log_mask(LOG_GUEST_ERROR
, "%s: write 0x%" PRIx64
71 " to 0x%" HWADDR_PRIx
"\n",
72 __func__
, value
, addr
);
75 /* MemoryRegionOps are aligned, so this can not happen. */
76 g_assert_not_reached();
80 static const MemoryRegionOps bcm2835_thermal_ops
= {
81 .read
= bcm2835_thermal_read
,
82 .write
= bcm2835_thermal_write
,
83 .impl
.max_access_size
= 4,
84 .valid
.min_access_size
= 4,
85 .endianness
= DEVICE_NATIVE_ENDIAN
,
88 static void bcm2835_thermal_reset(DeviceState
*dev
)
90 Bcm2835ThermalState
*s
= BCM2835_THERMAL(dev
);
95 static void bcm2835_thermal_realize(DeviceState
*dev
, Error
**errp
)
97 Bcm2835ThermalState
*s
= BCM2835_THERMAL(dev
);
99 memory_region_init_io(&s
->iomem
, OBJECT(s
), &bcm2835_thermal_ops
,
100 s
, TYPE_BCM2835_THERMAL
, 8);
101 sysbus_init_mmio(SYS_BUS_DEVICE(s
), &s
->iomem
);
104 static const VMStateDescription bcm2835_thermal_vmstate
= {
105 .name
= "bcm2835_thermal",
107 .minimum_version_id
= 1,
108 .fields
= (VMStateField
[]) {
109 VMSTATE_UINT32(ctl
, Bcm2835ThermalState
),
110 VMSTATE_END_OF_LIST()
114 static void bcm2835_thermal_class_init(ObjectClass
*klass
, void *data
)
116 DeviceClass
*dc
= DEVICE_CLASS(klass
);
118 dc
->realize
= bcm2835_thermal_realize
;
119 dc
->reset
= bcm2835_thermal_reset
;
120 dc
->vmsd
= &bcm2835_thermal_vmstate
;
123 static const TypeInfo bcm2835_thermal_info
= {
124 .name
= TYPE_BCM2835_THERMAL
,
125 .parent
= TYPE_SYS_BUS_DEVICE
,
126 .instance_size
= sizeof(Bcm2835ThermalState
),
127 .class_init
= bcm2835_thermal_class_init
,
130 static void bcm2835_thermal_register_types(void)
132 type_register_static(&bcm2835_thermal_info
);
135 type_init(bcm2835_thermal_register_types
)