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