123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- /*
- * Microbit stub for Nordic Semiconductor nRF51 SoC Two-Wire Interface
- * http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.1.pdf
- *
- * This is a microbit-specific stub for the TWI controller on the nRF51 SoC.
- * We don't emulate I2C devices but the firmware probes the
- * accelerometer/magnetometer on startup and panics if they are not found.
- * Therefore we stub out the probing.
- *
- * In the future this file could evolve into a full nRF51 TWI controller
- * device.
- *
- * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
- * Copyright 2019 Red Hat, Inc.
- *
- * This code is licensed under the GPL version 2 or later. See
- * the COPYING file in the top-level directory.
- */
- #include "qemu/osdep.h"
- #include "qemu/log.h"
- #include "qemu/module.h"
- #include "hw/i2c/microbit_i2c.h"
- #include "migration/vmstate.h"
- static const uint32_t twi_read_sequence[] = {0x5A, 0x5A, 0x40};
- static uint64_t microbit_i2c_read(void *opaque, hwaddr addr, unsigned int size)
- {
- MicrobitI2CState *s = opaque;
- uint64_t data = 0x00;
- switch (addr) {
- case NRF51_TWI_EVENT_STOPPED:
- data = 0x01;
- break;
- case NRF51_TWI_EVENT_RXDREADY:
- data = 0x01;
- break;
- case NRF51_TWI_EVENT_TXDSENT:
- data = 0x01;
- break;
- case NRF51_TWI_REG_RXD:
- data = twi_read_sequence[s->read_idx];
- if (s->read_idx < G_N_ELEMENTS(twi_read_sequence)) {
- s->read_idx++;
- }
- break;
- default:
- data = s->regs[addr / sizeof(s->regs[0])];
- break;
- }
- qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " [%u] = %" PRIx32 "\n",
- __func__, addr, size, (uint32_t)data);
- return data;
- }
- static void microbit_i2c_write(void *opaque, hwaddr addr, uint64_t data,
- unsigned int size)
- {
- MicrobitI2CState *s = opaque;
- qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " <- 0x%" PRIx64 " [%u]\n",
- __func__, addr, data, size);
- s->regs[addr / sizeof(s->regs[0])] = data;
- }
- static const MemoryRegionOps microbit_i2c_ops = {
- .read = microbit_i2c_read,
- .write = microbit_i2c_write,
- .endianness = DEVICE_LITTLE_ENDIAN,
- .impl.min_access_size = 4,
- .impl.max_access_size = 4,
- };
- static const VMStateDescription microbit_i2c_vmstate = {
- .name = TYPE_MICROBIT_I2C,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, MicrobitI2CState, MICROBIT_I2C_NREGS),
- VMSTATE_UINT32(read_idx, MicrobitI2CState),
- VMSTATE_END_OF_LIST()
- },
- };
- static void microbit_i2c_reset(DeviceState *dev)
- {
- MicrobitI2CState *s = MICROBIT_I2C(dev);
- memset(s->regs, 0, sizeof(s->regs));
- s->read_idx = 0;
- }
- static void microbit_i2c_realize(DeviceState *dev, Error **errp)
- {
- SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- MicrobitI2CState *s = MICROBIT_I2C(dev);
- memory_region_init_io(&s->iomem, OBJECT(s), µbit_i2c_ops, s,
- "microbit.twi", NRF51_PERIPHERAL_SIZE);
- sysbus_init_mmio(sbd, &s->iomem);
- }
- static void microbit_i2c_class_init(ObjectClass *klass, void *data)
- {
- DeviceClass *dc = DEVICE_CLASS(klass);
- dc->vmsd = µbit_i2c_vmstate;
- dc->reset = microbit_i2c_reset;
- dc->realize = microbit_i2c_realize;
- dc->desc = "Microbit I2C controller";
- }
- static const TypeInfo microbit_i2c_info = {
- .name = TYPE_MICROBIT_I2C,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(MicrobitI2CState),
- .class_init = microbit_i2c_class_init,
- };
- static void microbit_i2c_register_types(void)
- {
- type_register_static(µbit_i2c_info);
- }
- type_init(microbit_i2c_register_types)
|