xref: /qemu/hw/timer/nrf51_timer.c (revision 64552b6be4758d3a774f7787b294543ccebd5358)
1c5a4829cSSteffen Görtz /*
2c5a4829cSSteffen Görtz  * nRF51 System-on-Chip Timer peripheral
3c5a4829cSSteffen Görtz  *
4c5a4829cSSteffen Görtz  * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
5c5a4829cSSteffen Görtz  * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf
6c5a4829cSSteffen Görtz  *
7c5a4829cSSteffen Görtz  * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
8c5a4829cSSteffen Görtz  * Copyright (c) 2019 Red Hat, Inc.
9c5a4829cSSteffen Görtz  *
10c5a4829cSSteffen Görtz  * This code is licensed under the GPL version 2 or later.  See
11c5a4829cSSteffen Görtz  * the COPYING file in the top-level directory.
12c5a4829cSSteffen Görtz  */
13c5a4829cSSteffen Görtz 
14c5a4829cSSteffen Görtz #include "qemu/osdep.h"
15c5a4829cSSteffen Görtz #include "qemu/log.h"
160b8fa32fSMarkus Armbruster #include "qemu/module.h"
17c5a4829cSSteffen Görtz #include "hw/arm/nrf51.h"
18*64552b6bSMarkus Armbruster #include "hw/irq.h"
19c5a4829cSSteffen Görtz #include "hw/timer/nrf51_timer.h"
20c5a4829cSSteffen Görtz #include "trace.h"
21c5a4829cSSteffen Görtz 
22c5a4829cSSteffen Görtz #define TIMER_CLK_FREQ 16000000UL
23c5a4829cSSteffen Görtz 
24c5a4829cSSteffen Görtz static uint32_t const bitwidths[] = {16, 8, 24, 32};
25c5a4829cSSteffen Görtz 
26c5a4829cSSteffen Görtz static uint32_t ns_to_ticks(NRF51TimerState *s, int64_t ns)
27c5a4829cSSteffen Görtz {
28c5a4829cSSteffen Görtz     uint32_t freq = TIMER_CLK_FREQ >> s->prescaler;
29c5a4829cSSteffen Görtz 
30c5a4829cSSteffen Görtz     return muldiv64(ns, freq, NANOSECONDS_PER_SECOND);
31c5a4829cSSteffen Görtz }
32c5a4829cSSteffen Görtz 
33c5a4829cSSteffen Görtz static int64_t ticks_to_ns(NRF51TimerState *s, uint32_t ticks)
34c5a4829cSSteffen Görtz {
35c5a4829cSSteffen Görtz     uint32_t freq = TIMER_CLK_FREQ >> s->prescaler;
36c5a4829cSSteffen Görtz 
37c5a4829cSSteffen Görtz     return muldiv64(ticks, NANOSECONDS_PER_SECOND, freq);
38c5a4829cSSteffen Görtz }
39c5a4829cSSteffen Görtz 
40c5a4829cSSteffen Görtz /* Returns number of ticks since last call */
41c5a4829cSSteffen Görtz static uint32_t update_counter(NRF51TimerState *s, int64_t now)
42c5a4829cSSteffen Görtz {
43c5a4829cSSteffen Görtz     uint32_t ticks = ns_to_ticks(s, now - s->update_counter_ns);
44c5a4829cSSteffen Görtz 
45c5a4829cSSteffen Görtz     s->counter = (s->counter + ticks) % BIT(bitwidths[s->bitmode]);
46c5a4829cSSteffen Görtz     s->update_counter_ns = now;
47c5a4829cSSteffen Görtz     return ticks;
48c5a4829cSSteffen Görtz }
49c5a4829cSSteffen Görtz 
50c5a4829cSSteffen Görtz /* Assumes s->counter is up-to-date */
51c5a4829cSSteffen Görtz static void rearm_timer(NRF51TimerState *s, int64_t now)
52c5a4829cSSteffen Görtz {
53c5a4829cSSteffen Görtz     int64_t min_ns = INT64_MAX;
54c5a4829cSSteffen Görtz     size_t i;
55c5a4829cSSteffen Görtz 
56c5a4829cSSteffen Görtz     for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
57c5a4829cSSteffen Görtz         int64_t delta_ns;
58c5a4829cSSteffen Görtz 
59c5a4829cSSteffen Görtz         if (s->events_compare[i]) {
60c5a4829cSSteffen Görtz             continue; /* already expired, ignore it for now */
61c5a4829cSSteffen Görtz         }
62c5a4829cSSteffen Görtz 
63c5a4829cSSteffen Görtz         if (s->cc[i] <= s->counter) {
64c5a4829cSSteffen Görtz             delta_ns = ticks_to_ns(s, BIT(bitwidths[s->bitmode]) -
65c5a4829cSSteffen Görtz                                       s->counter + s->cc[i]);
66c5a4829cSSteffen Görtz         } else {
67c5a4829cSSteffen Görtz             delta_ns = ticks_to_ns(s, s->cc[i] - s->counter);
68c5a4829cSSteffen Görtz         }
69c5a4829cSSteffen Görtz 
70c5a4829cSSteffen Görtz         if (delta_ns < min_ns) {
71c5a4829cSSteffen Görtz             min_ns = delta_ns;
72c5a4829cSSteffen Görtz         }
73c5a4829cSSteffen Görtz     }
74c5a4829cSSteffen Görtz 
75c5a4829cSSteffen Görtz     if (min_ns != INT64_MAX) {
76c5a4829cSSteffen Görtz         timer_mod_ns(&s->timer, now + min_ns);
77c5a4829cSSteffen Görtz     }
78c5a4829cSSteffen Görtz }
79c5a4829cSSteffen Görtz 
80c5a4829cSSteffen Görtz static void update_irq(NRF51TimerState *s)
81c5a4829cSSteffen Görtz {
82c5a4829cSSteffen Görtz     bool flag = false;
83c5a4829cSSteffen Görtz     size_t i;
84c5a4829cSSteffen Görtz 
85c5a4829cSSteffen Görtz     for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
86c5a4829cSSteffen Görtz         flag |= s->events_compare[i] && extract32(s->inten, 16 + i, 1);
87c5a4829cSSteffen Görtz     }
88c5a4829cSSteffen Görtz     qemu_set_irq(s->irq, flag);
89c5a4829cSSteffen Görtz }
90c5a4829cSSteffen Görtz 
91c5a4829cSSteffen Görtz static void timer_expire(void *opaque)
92c5a4829cSSteffen Görtz {
93c5a4829cSSteffen Görtz     NRF51TimerState *s = NRF51_TIMER(opaque);
94c5a4829cSSteffen Görtz     int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
95c5a4829cSSteffen Görtz     uint32_t cc_remaining[NRF51_TIMER_REG_COUNT];
96c5a4829cSSteffen Görtz     bool should_stop = false;
97c5a4829cSSteffen Görtz     uint32_t ticks;
98c5a4829cSSteffen Görtz     size_t i;
99c5a4829cSSteffen Görtz 
100c5a4829cSSteffen Görtz     for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
101c5a4829cSSteffen Görtz         if (s->cc[i] > s->counter) {
102c5a4829cSSteffen Görtz             cc_remaining[i] = s->cc[i] - s->counter;
103c5a4829cSSteffen Görtz         } else {
104c5a4829cSSteffen Görtz             cc_remaining[i] = BIT(bitwidths[s->bitmode]) -
105c5a4829cSSteffen Görtz                               s->counter + s->cc[i];
106c5a4829cSSteffen Görtz         }
107c5a4829cSSteffen Görtz     }
108c5a4829cSSteffen Görtz 
109c5a4829cSSteffen Görtz     ticks = update_counter(s, now);
110c5a4829cSSteffen Görtz 
111c5a4829cSSteffen Görtz     for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
112c5a4829cSSteffen Görtz         if (cc_remaining[i] <= ticks) {
113c5a4829cSSteffen Görtz             s->events_compare[i] = 1;
114c5a4829cSSteffen Görtz 
115c5a4829cSSteffen Görtz             if (s->shorts & BIT(i)) {
116c5a4829cSSteffen Görtz                 s->timer_start_ns = now;
117c5a4829cSSteffen Görtz                 s->update_counter_ns = s->timer_start_ns;
118c5a4829cSSteffen Görtz                 s->counter = 0;
119c5a4829cSSteffen Görtz             }
120c5a4829cSSteffen Görtz 
121c5a4829cSSteffen Görtz             should_stop |= s->shorts & BIT(i + 8);
122c5a4829cSSteffen Görtz         }
123c5a4829cSSteffen Görtz     }
124c5a4829cSSteffen Görtz 
125c5a4829cSSteffen Görtz     update_irq(s);
126c5a4829cSSteffen Görtz 
127c5a4829cSSteffen Görtz     if (should_stop) {
128c5a4829cSSteffen Görtz         s->running = false;
129c5a4829cSSteffen Görtz         timer_del(&s->timer);
130c5a4829cSSteffen Görtz     } else {
131c5a4829cSSteffen Görtz         rearm_timer(s, now);
132c5a4829cSSteffen Görtz     }
133c5a4829cSSteffen Görtz }
134c5a4829cSSteffen Görtz 
135c5a4829cSSteffen Görtz static void counter_compare(NRF51TimerState *s)
136c5a4829cSSteffen Görtz {
137c5a4829cSSteffen Görtz     uint32_t counter = s->counter;
138c5a4829cSSteffen Görtz     size_t i;
139c5a4829cSSteffen Görtz 
140c5a4829cSSteffen Görtz     for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
141c5a4829cSSteffen Görtz         if (counter == s->cc[i]) {
142c5a4829cSSteffen Görtz             s->events_compare[i] = 1;
143c5a4829cSSteffen Görtz 
144c5a4829cSSteffen Görtz             if (s->shorts & BIT(i)) {
145c5a4829cSSteffen Görtz                 s->counter = 0;
146c5a4829cSSteffen Görtz             }
147c5a4829cSSteffen Görtz         }
148c5a4829cSSteffen Görtz     }
149c5a4829cSSteffen Görtz }
150c5a4829cSSteffen Görtz 
151c5a4829cSSteffen Görtz static uint64_t nrf51_timer_read(void *opaque, hwaddr offset, unsigned int size)
152c5a4829cSSteffen Görtz {
153c5a4829cSSteffen Görtz     NRF51TimerState *s = NRF51_TIMER(opaque);
154c5a4829cSSteffen Görtz     uint64_t r = 0;
155c5a4829cSSteffen Görtz 
156c5a4829cSSteffen Görtz     switch (offset) {
157c5a4829cSSteffen Görtz     case NRF51_TIMER_EVENT_COMPARE_0 ... NRF51_TIMER_EVENT_COMPARE_3:
158c5a4829cSSteffen Görtz         r = s->events_compare[(offset - NRF51_TIMER_EVENT_COMPARE_0) / 4];
159c5a4829cSSteffen Görtz         break;
160c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_SHORTS:
161c5a4829cSSteffen Görtz         r = s->shorts;
162c5a4829cSSteffen Görtz         break;
163c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_INTENSET:
164c5a4829cSSteffen Görtz         r = s->inten;
165c5a4829cSSteffen Görtz         break;
166c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_INTENCLR:
167c5a4829cSSteffen Görtz         r = s->inten;
168c5a4829cSSteffen Görtz         break;
169c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_MODE:
170c5a4829cSSteffen Görtz         r = s->mode;
171c5a4829cSSteffen Görtz         break;
172c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_BITMODE:
173c5a4829cSSteffen Görtz         r = s->bitmode;
174c5a4829cSSteffen Görtz         break;
175c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_PRESCALER:
176c5a4829cSSteffen Görtz         r = s->prescaler;
177c5a4829cSSteffen Görtz         break;
178c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_CC0 ... NRF51_TIMER_REG_CC3:
179c5a4829cSSteffen Görtz         r = s->cc[(offset - NRF51_TIMER_REG_CC0) / 4];
180c5a4829cSSteffen Görtz         break;
181c5a4829cSSteffen Görtz     default:
182c5a4829cSSteffen Görtz         qemu_log_mask(LOG_GUEST_ERROR,
183c5a4829cSSteffen Görtz                 "%s: bad read offset 0x%" HWADDR_PRIx "\n",
184c5a4829cSSteffen Görtz                       __func__, offset);
185c5a4829cSSteffen Görtz     }
186c5a4829cSSteffen Görtz 
187c5a4829cSSteffen Görtz     trace_nrf51_timer_read(offset, r, size);
188c5a4829cSSteffen Görtz 
189c5a4829cSSteffen Görtz     return r;
190c5a4829cSSteffen Görtz }
191c5a4829cSSteffen Görtz 
192c5a4829cSSteffen Görtz static void nrf51_timer_write(void *opaque, hwaddr offset,
193c5a4829cSSteffen Görtz                        uint64_t value, unsigned int size)
194c5a4829cSSteffen Görtz {
195c5a4829cSSteffen Görtz     NRF51TimerState *s = NRF51_TIMER(opaque);
196c5a4829cSSteffen Görtz     uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
197c5a4829cSSteffen Görtz     size_t idx;
198c5a4829cSSteffen Görtz 
199c5a4829cSSteffen Görtz     trace_nrf51_timer_write(offset, value, size);
200c5a4829cSSteffen Görtz 
201c5a4829cSSteffen Görtz     switch (offset) {
202c5a4829cSSteffen Görtz     case NRF51_TIMER_TASK_START:
203c5a4829cSSteffen Görtz         if (value == NRF51_TRIGGER_TASK && s->mode == NRF51_TIMER_TIMER) {
204c5a4829cSSteffen Görtz             s->running = true;
205c5a4829cSSteffen Görtz             s->timer_start_ns = now - ticks_to_ns(s, s->counter);
206c5a4829cSSteffen Görtz             s->update_counter_ns = s->timer_start_ns;
207c5a4829cSSteffen Görtz             rearm_timer(s, now);
208c5a4829cSSteffen Görtz         }
209c5a4829cSSteffen Görtz         break;
210c5a4829cSSteffen Görtz     case NRF51_TIMER_TASK_STOP:
211c5a4829cSSteffen Görtz     case NRF51_TIMER_TASK_SHUTDOWN:
212c5a4829cSSteffen Görtz         if (value == NRF51_TRIGGER_TASK) {
213c5a4829cSSteffen Görtz             s->running = false;
214c5a4829cSSteffen Görtz             timer_del(&s->timer);
215c5a4829cSSteffen Görtz         }
216c5a4829cSSteffen Görtz         break;
217c5a4829cSSteffen Görtz     case NRF51_TIMER_TASK_COUNT:
218c5a4829cSSteffen Görtz         if (value == NRF51_TRIGGER_TASK && s->mode == NRF51_TIMER_COUNTER) {
219c5a4829cSSteffen Görtz             s->counter = (s->counter + 1) % BIT(bitwidths[s->bitmode]);
220c5a4829cSSteffen Görtz             counter_compare(s);
221c5a4829cSSteffen Görtz         }
222c5a4829cSSteffen Görtz         break;
223c5a4829cSSteffen Görtz     case NRF51_TIMER_TASK_CLEAR:
224c5a4829cSSteffen Görtz         if (value == NRF51_TRIGGER_TASK) {
225c5a4829cSSteffen Görtz             s->timer_start_ns = now;
226c5a4829cSSteffen Görtz             s->update_counter_ns = s->timer_start_ns;
227c5a4829cSSteffen Görtz             s->counter = 0;
228c5a4829cSSteffen Görtz             if (s->running) {
229c5a4829cSSteffen Görtz                 rearm_timer(s, now);
230c5a4829cSSteffen Görtz             }
231c5a4829cSSteffen Görtz         }
232c5a4829cSSteffen Görtz         break;
233c5a4829cSSteffen Görtz     case NRF51_TIMER_TASK_CAPTURE_0 ... NRF51_TIMER_TASK_CAPTURE_3:
234c5a4829cSSteffen Görtz         if (value == NRF51_TRIGGER_TASK) {
235c5a4829cSSteffen Görtz             if (s->running) {
236c5a4829cSSteffen Görtz                 timer_expire(s); /* update counter and all state */
237c5a4829cSSteffen Görtz             }
238c5a4829cSSteffen Görtz 
239c5a4829cSSteffen Görtz             idx = (offset - NRF51_TIMER_TASK_CAPTURE_0) / 4;
240c5a4829cSSteffen Görtz             s->cc[idx] = s->counter;
241c5a4829cSSteffen Görtz         }
242c5a4829cSSteffen Görtz         break;
243c5a4829cSSteffen Görtz     case NRF51_TIMER_EVENT_COMPARE_0 ... NRF51_TIMER_EVENT_COMPARE_3:
244c5a4829cSSteffen Görtz         if (value == NRF51_EVENT_CLEAR) {
245c5a4829cSSteffen Görtz             s->events_compare[(offset - NRF51_TIMER_EVENT_COMPARE_0) / 4] = 0;
246c5a4829cSSteffen Görtz 
247c5a4829cSSteffen Görtz             if (s->running) {
248c5a4829cSSteffen Görtz                 timer_expire(s); /* update counter and all state */
249c5a4829cSSteffen Görtz             }
250c5a4829cSSteffen Görtz         }
251c5a4829cSSteffen Görtz         break;
252c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_SHORTS:
253c5a4829cSSteffen Görtz         s->shorts = value & NRF51_TIMER_REG_SHORTS_MASK;
254c5a4829cSSteffen Görtz         break;
255c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_INTENSET:
256c5a4829cSSteffen Görtz         s->inten |= value & NRF51_TIMER_REG_INTEN_MASK;
257c5a4829cSSteffen Görtz         break;
258c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_INTENCLR:
259c5a4829cSSteffen Görtz         s->inten &= ~(value & NRF51_TIMER_REG_INTEN_MASK);
260c5a4829cSSteffen Görtz         break;
261c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_MODE:
262c5a4829cSSteffen Görtz         s->mode = value;
263c5a4829cSSteffen Görtz         break;
264c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_BITMODE:
265c5a4829cSSteffen Görtz         if (s->mode == NRF51_TIMER_TIMER && s->running) {
266c5a4829cSSteffen Görtz             qemu_log_mask(LOG_GUEST_ERROR,
267c5a4829cSSteffen Görtz                     "%s: erroneous change of BITMODE while timer is running\n",
268c5a4829cSSteffen Görtz                     __func__);
269c5a4829cSSteffen Görtz         }
270c5a4829cSSteffen Görtz         s->bitmode = value & NRF51_TIMER_REG_BITMODE_MASK;
271c5a4829cSSteffen Görtz         break;
272c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_PRESCALER:
273c5a4829cSSteffen Görtz         if (s->mode == NRF51_TIMER_TIMER && s->running) {
274c5a4829cSSteffen Görtz             qemu_log_mask(LOG_GUEST_ERROR,
275c5a4829cSSteffen Görtz                 "%s: erroneous change of PRESCALER while timer is running\n",
276c5a4829cSSteffen Görtz                 __func__);
277c5a4829cSSteffen Görtz         }
278c5a4829cSSteffen Görtz         s->prescaler = value & NRF51_TIMER_REG_PRESCALER_MASK;
279c5a4829cSSteffen Görtz         break;
280c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_CC0 ... NRF51_TIMER_REG_CC3:
281c5a4829cSSteffen Görtz         if (s->running) {
282c5a4829cSSteffen Görtz             timer_expire(s); /* update counter */
283c5a4829cSSteffen Görtz         }
284c5a4829cSSteffen Görtz 
285c5a4829cSSteffen Görtz         idx = (offset - NRF51_TIMER_REG_CC0) / 4;
286c5a4829cSSteffen Görtz         s->cc[idx] = value % BIT(bitwidths[s->bitmode]);
287c5a4829cSSteffen Görtz 
288c5a4829cSSteffen Görtz         if (s->running) {
289c5a4829cSSteffen Görtz             rearm_timer(s, now);
290c5a4829cSSteffen Görtz         }
291c5a4829cSSteffen Görtz         break;
292c5a4829cSSteffen Görtz     default:
293c5a4829cSSteffen Görtz         qemu_log_mask(LOG_GUEST_ERROR,
294c5a4829cSSteffen Görtz                       "%s: bad write offset 0x%" HWADDR_PRIx "\n",
295c5a4829cSSteffen Görtz                       __func__, offset);
296c5a4829cSSteffen Görtz     }
297c5a4829cSSteffen Görtz 
298c5a4829cSSteffen Görtz     update_irq(s);
299c5a4829cSSteffen Görtz }
300c5a4829cSSteffen Görtz 
301c5a4829cSSteffen Görtz static const MemoryRegionOps rng_ops = {
302c5a4829cSSteffen Görtz     .read =  nrf51_timer_read,
303c5a4829cSSteffen Görtz     .write = nrf51_timer_write,
304c5a4829cSSteffen Görtz     .endianness = DEVICE_LITTLE_ENDIAN,
305c5a4829cSSteffen Görtz     .impl.min_access_size = 4,
306c5a4829cSSteffen Görtz     .impl.max_access_size = 4,
307c5a4829cSSteffen Görtz };
308c5a4829cSSteffen Görtz 
309c5a4829cSSteffen Görtz static void nrf51_timer_init(Object *obj)
310c5a4829cSSteffen Görtz {
311c5a4829cSSteffen Görtz     NRF51TimerState *s = NRF51_TIMER(obj);
312c5a4829cSSteffen Görtz     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
313c5a4829cSSteffen Görtz 
314c5a4829cSSteffen Görtz     memory_region_init_io(&s->iomem, obj, &rng_ops, s,
315c5a4829cSSteffen Görtz             TYPE_NRF51_TIMER, NRF51_TIMER_SIZE);
316c5a4829cSSteffen Görtz     sysbus_init_mmio(sbd, &s->iomem);
317c5a4829cSSteffen Görtz     sysbus_init_irq(sbd, &s->irq);
318c5a4829cSSteffen Görtz 
319c5a4829cSSteffen Görtz     timer_init_ns(&s->timer, QEMU_CLOCK_VIRTUAL, timer_expire, s);
320c5a4829cSSteffen Görtz }
321c5a4829cSSteffen Görtz 
322c5a4829cSSteffen Görtz static void nrf51_timer_reset(DeviceState *dev)
323c5a4829cSSteffen Görtz {
324c5a4829cSSteffen Görtz     NRF51TimerState *s = NRF51_TIMER(dev);
325c5a4829cSSteffen Görtz 
326c5a4829cSSteffen Görtz     timer_del(&s->timer);
327c5a4829cSSteffen Görtz     s->timer_start_ns = 0x00;
328c5a4829cSSteffen Görtz     s->update_counter_ns = 0x00;
329c5a4829cSSteffen Görtz     s->counter = 0x00;
330c5a4829cSSteffen Görtz     s->running = false;
331c5a4829cSSteffen Görtz 
332c5a4829cSSteffen Görtz     memset(s->events_compare, 0x00, sizeof(s->events_compare));
333c5a4829cSSteffen Görtz     memset(s->cc, 0x00, sizeof(s->cc));
334c5a4829cSSteffen Görtz 
335c5a4829cSSteffen Görtz     s->shorts = 0x00;
336c5a4829cSSteffen Görtz     s->inten = 0x00;
337c5a4829cSSteffen Görtz     s->mode = 0x00;
338c5a4829cSSteffen Görtz     s->bitmode = 0x00;
339c5a4829cSSteffen Görtz     s->prescaler = 0x00;
340c5a4829cSSteffen Görtz }
341c5a4829cSSteffen Görtz 
342c5a4829cSSteffen Görtz static int nrf51_timer_post_load(void *opaque, int version_id)
343c5a4829cSSteffen Görtz {
344c5a4829cSSteffen Görtz     NRF51TimerState *s = NRF51_TIMER(opaque);
345c5a4829cSSteffen Görtz 
346c5a4829cSSteffen Görtz     if (s->running && s->mode == NRF51_TIMER_TIMER) {
347c5a4829cSSteffen Görtz         timer_expire(s);
348c5a4829cSSteffen Görtz     }
349c5a4829cSSteffen Görtz     return 0;
350c5a4829cSSteffen Görtz }
351c5a4829cSSteffen Görtz 
352c5a4829cSSteffen Görtz static const VMStateDescription vmstate_nrf51_timer = {
353c5a4829cSSteffen Görtz     .name = TYPE_NRF51_TIMER,
354c5a4829cSSteffen Görtz     .version_id = 1,
355c5a4829cSSteffen Görtz     .post_load = nrf51_timer_post_load,
356c5a4829cSSteffen Görtz     .fields = (VMStateField[]) {
357c5a4829cSSteffen Görtz         VMSTATE_TIMER(timer, NRF51TimerState),
358c5a4829cSSteffen Görtz         VMSTATE_INT64(timer_start_ns, NRF51TimerState),
359c5a4829cSSteffen Görtz         VMSTATE_INT64(update_counter_ns, NRF51TimerState),
360c5a4829cSSteffen Görtz         VMSTATE_UINT32(counter, NRF51TimerState),
361c5a4829cSSteffen Görtz         VMSTATE_BOOL(running, NRF51TimerState),
362c5a4829cSSteffen Görtz         VMSTATE_UINT8_ARRAY(events_compare, NRF51TimerState,
363c5a4829cSSteffen Görtz                             NRF51_TIMER_REG_COUNT),
364c5a4829cSSteffen Görtz         VMSTATE_UINT32_ARRAY(cc, NRF51TimerState, NRF51_TIMER_REG_COUNT),
365c5a4829cSSteffen Görtz         VMSTATE_UINT32(shorts, NRF51TimerState),
366c5a4829cSSteffen Görtz         VMSTATE_UINT32(inten, NRF51TimerState),
367c5a4829cSSteffen Görtz         VMSTATE_UINT32(mode, NRF51TimerState),
368c5a4829cSSteffen Görtz         VMSTATE_UINT32(bitmode, NRF51TimerState),
369c5a4829cSSteffen Görtz         VMSTATE_UINT32(prescaler, NRF51TimerState),
370c5a4829cSSteffen Görtz         VMSTATE_END_OF_LIST()
371c5a4829cSSteffen Görtz     }
372c5a4829cSSteffen Görtz };
373c5a4829cSSteffen Görtz 
374c5a4829cSSteffen Görtz static void nrf51_timer_class_init(ObjectClass *klass, void *data)
375c5a4829cSSteffen Görtz {
376c5a4829cSSteffen Görtz     DeviceClass *dc = DEVICE_CLASS(klass);
377c5a4829cSSteffen Görtz 
378c5a4829cSSteffen Görtz     dc->reset = nrf51_timer_reset;
379c5a4829cSSteffen Görtz     dc->vmsd = &vmstate_nrf51_timer;
380c5a4829cSSteffen Görtz }
381c5a4829cSSteffen Görtz 
382c5a4829cSSteffen Görtz static const TypeInfo nrf51_timer_info = {
383c5a4829cSSteffen Görtz     .name = TYPE_NRF51_TIMER,
384c5a4829cSSteffen Görtz     .parent = TYPE_SYS_BUS_DEVICE,
385c5a4829cSSteffen Görtz     .instance_size = sizeof(NRF51TimerState),
386c5a4829cSSteffen Görtz     .instance_init = nrf51_timer_init,
387c5a4829cSSteffen Görtz     .class_init = nrf51_timer_class_init
388c5a4829cSSteffen Görtz };
389c5a4829cSSteffen Görtz 
390c5a4829cSSteffen Görtz static void nrf51_timer_register_types(void)
391c5a4829cSSteffen Görtz {
392c5a4829cSSteffen Görtz     type_register_static(&nrf51_timer_info);
393c5a4829cSSteffen Görtz }
394c5a4829cSSteffen Görtz 
395c5a4829cSSteffen Görtz type_init(nrf51_timer_register_types)
396