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