xref: /openbmc/qemu/hw/rtc/m41t80.c (revision db1015e92e04835c9eb50c29625fe566d1202dbd)
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