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