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é
m41t80_realize(DeviceState * dev,Error ** errp)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é
m41t80_send(I2CSlave * i2c,uint8_t data)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é
m41t80_recv(I2CSlave * i2c)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é
m41t80_event(I2CSlave * i2c,enum i2c_event event)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é
m41t80_class_init(ObjectClass * klass,void * data)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é
m41t80_register_types(void)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