1de04c31dSPhilippe Mathieu-Daudé /* 2de04c31dSPhilippe Mathieu-Daudé * M41T80 serial rtc emulation 3de04c31dSPhilippe Mathieu-Daudé * 4de04c31dSPhilippe Mathieu-Daudé * Copyright (c) 2018 BALATON Zoltan 5de04c31dSPhilippe Mathieu-Daudé * 6de04c31dSPhilippe Mathieu-Daudé * This work is licensed under the GNU GPL license version 2 or later. 7de04c31dSPhilippe Mathieu-Daudé * 8de04c31dSPhilippe Mathieu-Daudé */ 9de04c31dSPhilippe Mathieu-Daudé 10de04c31dSPhilippe Mathieu-Daudé #include "qemu/osdep.h" 11de04c31dSPhilippe Mathieu-Daudé #include "qemu-common.h" 12de04c31dSPhilippe Mathieu-Daudé #include "qemu/log.h" 13de04c31dSPhilippe Mathieu-Daudé #include "qemu/module.h" 14de04c31dSPhilippe Mathieu-Daudé #include "qemu/timer.h" 15de04c31dSPhilippe Mathieu-Daudé #include "qemu/bcd.h" 16de04c31dSPhilippe Mathieu-Daudé #include "hw/i2c/i2c.h" 17*db1015e9SEduardo Habkost #include "qom/object.h" 18de04c31dSPhilippe Mathieu-Daudé 19de04c31dSPhilippe Mathieu-Daudé #define TYPE_M41T80 "m41t80" 20*db1015e9SEduardo Habkost typedef struct M41t80State M41t80State; 21de04c31dSPhilippe Mathieu-Daudé #define M41T80(obj) OBJECT_CHECK(M41t80State, (obj), TYPE_M41T80) 22de04c31dSPhilippe Mathieu-Daudé 23*db1015e9SEduardo Habkost struct M41t80State { 24de04c31dSPhilippe Mathieu-Daudé I2CSlave parent_obj; 25de04c31dSPhilippe Mathieu-Daudé int8_t addr; 26*db1015e9SEduardo Habkost }; 27de04c31dSPhilippe Mathieu-Daudé 28de04c31dSPhilippe Mathieu-Daudé static void m41t80_realize(DeviceState *dev, Error **errp) 29de04c31dSPhilippe Mathieu-Daudé { 30de04c31dSPhilippe Mathieu-Daudé M41t80State *s = M41T80(dev); 31de04c31dSPhilippe Mathieu-Daudé 32de04c31dSPhilippe Mathieu-Daudé s->addr = -1; 33de04c31dSPhilippe Mathieu-Daudé } 34de04c31dSPhilippe Mathieu-Daudé 35de04c31dSPhilippe Mathieu-Daudé static int m41t80_send(I2CSlave *i2c, uint8_t data) 36de04c31dSPhilippe Mathieu-Daudé { 37de04c31dSPhilippe Mathieu-Daudé M41t80State *s = M41T80(i2c); 38de04c31dSPhilippe Mathieu-Daudé 39de04c31dSPhilippe Mathieu-Daudé if (s->addr < 0) { 40de04c31dSPhilippe Mathieu-Daudé s->addr = data; 41de04c31dSPhilippe Mathieu-Daudé } else { 42de04c31dSPhilippe Mathieu-Daudé s->addr++; 43de04c31dSPhilippe Mathieu-Daudé } 44de04c31dSPhilippe Mathieu-Daudé return 0; 45de04c31dSPhilippe Mathieu-Daudé } 46de04c31dSPhilippe Mathieu-Daudé 47de04c31dSPhilippe Mathieu-Daudé static uint8_t m41t80_recv(I2CSlave *i2c) 48de04c31dSPhilippe Mathieu-Daudé { 49de04c31dSPhilippe Mathieu-Daudé M41t80State *s = M41T80(i2c); 50de04c31dSPhilippe Mathieu-Daudé struct tm now; 51de04c31dSPhilippe Mathieu-Daudé qemu_timeval tv; 52de04c31dSPhilippe Mathieu-Daudé 53de04c31dSPhilippe Mathieu-Daudé if (s->addr < 0) { 54de04c31dSPhilippe Mathieu-Daudé s->addr = 0; 55de04c31dSPhilippe Mathieu-Daudé } 56de04c31dSPhilippe Mathieu-Daudé if (s->addr >= 1 && s->addr <= 7) { 57de04c31dSPhilippe Mathieu-Daudé qemu_get_timedate(&now, -1); 58de04c31dSPhilippe Mathieu-Daudé } 59de04c31dSPhilippe Mathieu-Daudé switch (s->addr++) { 60de04c31dSPhilippe Mathieu-Daudé case 0: 61de04c31dSPhilippe Mathieu-Daudé qemu_gettimeofday(&tv); 62de04c31dSPhilippe Mathieu-Daudé return to_bcd(tv.tv_usec / 10000); 63de04c31dSPhilippe Mathieu-Daudé case 1: 64de04c31dSPhilippe Mathieu-Daudé return to_bcd(now.tm_sec); 65de04c31dSPhilippe Mathieu-Daudé case 2: 66de04c31dSPhilippe Mathieu-Daudé return to_bcd(now.tm_min); 67de04c31dSPhilippe Mathieu-Daudé case 3: 68de04c31dSPhilippe Mathieu-Daudé return to_bcd(now.tm_hour); 69de04c31dSPhilippe Mathieu-Daudé case 4: 70de04c31dSPhilippe Mathieu-Daudé return to_bcd(now.tm_wday); 71de04c31dSPhilippe Mathieu-Daudé case 5: 72de04c31dSPhilippe Mathieu-Daudé return to_bcd(now.tm_mday); 73de04c31dSPhilippe Mathieu-Daudé case 6: 74de04c31dSPhilippe Mathieu-Daudé return to_bcd(now.tm_mon + 1); 75de04c31dSPhilippe Mathieu-Daudé case 7: 76de04c31dSPhilippe Mathieu-Daudé return to_bcd(now.tm_year % 100); 77de04c31dSPhilippe Mathieu-Daudé case 8 ... 19: 78de04c31dSPhilippe Mathieu-Daudé qemu_log_mask(LOG_UNIMP, "%s: unimplemented register: %d\n", 79de04c31dSPhilippe Mathieu-Daudé __func__, s->addr - 1); 80de04c31dSPhilippe Mathieu-Daudé return 0; 81de04c31dSPhilippe Mathieu-Daudé default: 82de04c31dSPhilippe Mathieu-Daudé qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid register: %d\n", 83de04c31dSPhilippe Mathieu-Daudé __func__, s->addr - 1); 84de04c31dSPhilippe Mathieu-Daudé return 0; 85de04c31dSPhilippe Mathieu-Daudé } 86de04c31dSPhilippe Mathieu-Daudé } 87de04c31dSPhilippe Mathieu-Daudé 88de04c31dSPhilippe Mathieu-Daudé static int m41t80_event(I2CSlave *i2c, enum i2c_event event) 89de04c31dSPhilippe Mathieu-Daudé { 90de04c31dSPhilippe Mathieu-Daudé M41t80State *s = M41T80(i2c); 91de04c31dSPhilippe Mathieu-Daudé 92de04c31dSPhilippe Mathieu-Daudé if (event == I2C_START_SEND) { 93de04c31dSPhilippe Mathieu-Daudé s->addr = -1; 94de04c31dSPhilippe Mathieu-Daudé } 95de04c31dSPhilippe Mathieu-Daudé return 0; 96de04c31dSPhilippe Mathieu-Daudé } 97de04c31dSPhilippe Mathieu-Daudé 98de04c31dSPhilippe Mathieu-Daudé static void m41t80_class_init(ObjectClass *klass, void *data) 99de04c31dSPhilippe Mathieu-Daudé { 100de04c31dSPhilippe Mathieu-Daudé DeviceClass *dc = DEVICE_CLASS(klass); 101de04c31dSPhilippe Mathieu-Daudé I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); 102de04c31dSPhilippe Mathieu-Daudé 103de04c31dSPhilippe Mathieu-Daudé dc->realize = m41t80_realize; 104de04c31dSPhilippe Mathieu-Daudé sc->send = m41t80_send; 105de04c31dSPhilippe Mathieu-Daudé sc->recv = m41t80_recv; 106de04c31dSPhilippe Mathieu-Daudé sc->event = m41t80_event; 107de04c31dSPhilippe Mathieu-Daudé } 108de04c31dSPhilippe Mathieu-Daudé 109de04c31dSPhilippe Mathieu-Daudé static const TypeInfo m41t80_info = { 110de04c31dSPhilippe Mathieu-Daudé .name = TYPE_M41T80, 111de04c31dSPhilippe Mathieu-Daudé .parent = TYPE_I2C_SLAVE, 112de04c31dSPhilippe Mathieu-Daudé .instance_size = sizeof(M41t80State), 113de04c31dSPhilippe Mathieu-Daudé .class_init = m41t80_class_init, 114de04c31dSPhilippe Mathieu-Daudé }; 115de04c31dSPhilippe Mathieu-Daudé 116de04c31dSPhilippe Mathieu-Daudé static void m41t80_register_types(void) 117de04c31dSPhilippe Mathieu-Daudé { 118de04c31dSPhilippe Mathieu-Daudé type_register_static(&m41t80_info); 119de04c31dSPhilippe Mathieu-Daudé } 120de04c31dSPhilippe Mathieu-Daudé 121de04c31dSPhilippe Mathieu-Daudé type_init(m41t80_register_types) 122