root / hw / ds1338.c @ b4b784fe
History | View | Annotate | Download (3.2 kB)
1 | 1dfe3943 | Paul Brook | /*
|
---|---|---|---|
2 | 1dfe3943 | Paul Brook | * MAXIM DS1338 I2C RTC+NVRAM
|
3 | 1dfe3943 | Paul Brook | *
|
4 | 1dfe3943 | Paul Brook | * Copyright (c) 2009 CodeSourcery.
|
5 | 1dfe3943 | Paul Brook | * Written by Paul Brook
|
6 | 1dfe3943 | Paul Brook | *
|
7 | 1dfe3943 | Paul Brook | * This code is licenced under the GNU GPL v2.
|
8 | 1dfe3943 | Paul Brook | */
|
9 | 1dfe3943 | Paul Brook | |
10 | 1dfe3943 | Paul Brook | #include "i2c.h" |
11 | 1dfe3943 | Paul Brook | |
12 | 1dfe3943 | Paul Brook | typedef struct { |
13 | 1dfe3943 | Paul Brook | i2c_slave i2c; |
14 | 1dfe3943 | Paul Brook | time_t offset; |
15 | 1dfe3943 | Paul Brook | struct tm now;
|
16 | 1dfe3943 | Paul Brook | uint8_t nvram[56];
|
17 | 1dfe3943 | Paul Brook | int ptr;
|
18 | 1dfe3943 | Paul Brook | int addr_byte;
|
19 | 1dfe3943 | Paul Brook | } DS1338State; |
20 | 1dfe3943 | Paul Brook | |
21 | 1dfe3943 | Paul Brook | static void ds1338_event(i2c_slave *i2c, enum i2c_event event) |
22 | 1dfe3943 | Paul Brook | { |
23 | 1dfe3943 | Paul Brook | DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c); |
24 | 1dfe3943 | Paul Brook | |
25 | 1dfe3943 | Paul Brook | switch (event) {
|
26 | 1dfe3943 | Paul Brook | case I2C_START_RECV:
|
27 | 1dfe3943 | Paul Brook | qemu_get_timedate(&s->now, s->offset); |
28 | 1dfe3943 | Paul Brook | s->nvram[0] = to_bcd(s->now.tm_sec);
|
29 | 1dfe3943 | Paul Brook | s->nvram[1] = to_bcd(s->now.tm_min);
|
30 | 1dfe3943 | Paul Brook | if (s->nvram[2] & 0x40) { |
31 | 1dfe3943 | Paul Brook | s->nvram[2] = (to_bcd((s->now.tm_hour % 12)) + 1) | 0x40; |
32 | 1dfe3943 | Paul Brook | if (s->now.tm_hour >= 12) { |
33 | 1dfe3943 | Paul Brook | s->nvram[2] |= 0x20; |
34 | 1dfe3943 | Paul Brook | } |
35 | 1dfe3943 | Paul Brook | } else {
|
36 | 1dfe3943 | Paul Brook | s->nvram[2] = to_bcd(s->now.tm_hour);
|
37 | 1dfe3943 | Paul Brook | } |
38 | 1dfe3943 | Paul Brook | s->nvram[3] = to_bcd(s->now.tm_wday) + 1; |
39 | 1dfe3943 | Paul Brook | s->nvram[4] = to_bcd(s->now.tm_mday);
|
40 | 1dfe3943 | Paul Brook | s->nvram[5] = to_bcd(s->now.tm_mon) + 1; |
41 | 1dfe3943 | Paul Brook | s->nvram[6] = to_bcd(s->now.tm_year - 100); |
42 | 1dfe3943 | Paul Brook | break;
|
43 | 1dfe3943 | Paul Brook | case I2C_START_SEND:
|
44 | 1dfe3943 | Paul Brook | s->addr_byte = 1;
|
45 | 1dfe3943 | Paul Brook | break;
|
46 | 1dfe3943 | Paul Brook | default:
|
47 | 1dfe3943 | Paul Brook | break;
|
48 | 1dfe3943 | Paul Brook | } |
49 | 1dfe3943 | Paul Brook | } |
50 | 1dfe3943 | Paul Brook | |
51 | 1dfe3943 | Paul Brook | static int ds1338_recv(i2c_slave *i2c) |
52 | 1dfe3943 | Paul Brook | { |
53 | 1dfe3943 | Paul Brook | DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c); |
54 | 1dfe3943 | Paul Brook | uint8_t res; |
55 | 1dfe3943 | Paul Brook | |
56 | 1dfe3943 | Paul Brook | res = s->nvram[s->ptr]; |
57 | 1dfe3943 | Paul Brook | s->ptr = (s->ptr + 1) & 0xff; |
58 | 1dfe3943 | Paul Brook | return res;
|
59 | 1dfe3943 | Paul Brook | } |
60 | 1dfe3943 | Paul Brook | |
61 | 1dfe3943 | Paul Brook | static int ds1338_send(i2c_slave *i2c, uint8_t data) |
62 | 1dfe3943 | Paul Brook | { |
63 | 1dfe3943 | Paul Brook | DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c); |
64 | 1dfe3943 | Paul Brook | if (s->addr_byte) {
|
65 | 1dfe3943 | Paul Brook | s->ptr = data; |
66 | 1dfe3943 | Paul Brook | s->addr_byte = 0;
|
67 | 1dfe3943 | Paul Brook | return 0; |
68 | 1dfe3943 | Paul Brook | } |
69 | 1dfe3943 | Paul Brook | s->nvram[s->ptr - 8] = data;
|
70 | 1dfe3943 | Paul Brook | if (data < 8) { |
71 | 1dfe3943 | Paul Brook | qemu_get_timedate(&s->now, s->offset); |
72 | 1dfe3943 | Paul Brook | switch(data) {
|
73 | 1dfe3943 | Paul Brook | case 0: |
74 | 1dfe3943 | Paul Brook | /* TODO: Implement CH (stop) bit. */
|
75 | 1dfe3943 | Paul Brook | s->now.tm_sec = from_bcd(data & 0x7f);
|
76 | 1dfe3943 | Paul Brook | break;
|
77 | 1dfe3943 | Paul Brook | case 1: |
78 | 1dfe3943 | Paul Brook | s->now.tm_min = from_bcd(data & 0x7f);
|
79 | 1dfe3943 | Paul Brook | break;
|
80 | 1dfe3943 | Paul Brook | case 2: |
81 | 1dfe3943 | Paul Brook | if (data & 0x40) { |
82 | 1dfe3943 | Paul Brook | if (data & 0x20) { |
83 | 1dfe3943 | Paul Brook | data = from_bcd(data & 0x4f) + 11; |
84 | 1dfe3943 | Paul Brook | } else {
|
85 | 1dfe3943 | Paul Brook | data = from_bcd(data & 0x1f) - 1; |
86 | 1dfe3943 | Paul Brook | } |
87 | 1dfe3943 | Paul Brook | } else {
|
88 | 1dfe3943 | Paul Brook | data = from_bcd(data); |
89 | 1dfe3943 | Paul Brook | } |
90 | 1dfe3943 | Paul Brook | s->now.tm_hour = data; |
91 | 1dfe3943 | Paul Brook | break;
|
92 | 1dfe3943 | Paul Brook | case 3: |
93 | 1dfe3943 | Paul Brook | s->now.tm_wday = from_bcd(data & 7) - 1; |
94 | 1dfe3943 | Paul Brook | break;
|
95 | 1dfe3943 | Paul Brook | case 4: |
96 | 1dfe3943 | Paul Brook | s->now.tm_mday = from_bcd(data & 0x3f);
|
97 | 1dfe3943 | Paul Brook | break;
|
98 | 1dfe3943 | Paul Brook | case 5: |
99 | 1dfe3943 | Paul Brook | s->now.tm_mon = from_bcd(data & 0x1f) - 1; |
100 | 1dfe3943 | Paul Brook | case 6: |
101 | 1dfe3943 | Paul Brook | s->now.tm_year = from_bcd(data) + 100;
|
102 | 1dfe3943 | Paul Brook | break;
|
103 | 1dfe3943 | Paul Brook | case 7: |
104 | 1dfe3943 | Paul Brook | /* Control register. Currently ignored. */
|
105 | 1dfe3943 | Paul Brook | break;
|
106 | 1dfe3943 | Paul Brook | } |
107 | 1dfe3943 | Paul Brook | s->offset = qemu_timedate_diff(&s->now); |
108 | 1dfe3943 | Paul Brook | } |
109 | 1dfe3943 | Paul Brook | s->ptr = (s->ptr + 1) & 0xff; |
110 | 1dfe3943 | Paul Brook | return 0; |
111 | 1dfe3943 | Paul Brook | } |
112 | 1dfe3943 | Paul Brook | |
113 | 1dfe3943 | Paul Brook | static int ds1338_init(i2c_slave *i2c) |
114 | 1dfe3943 | Paul Brook | { |
115 | 1dfe3943 | Paul Brook | return 0; |
116 | 1dfe3943 | Paul Brook | } |
117 | 1dfe3943 | Paul Brook | |
118 | 1dfe3943 | Paul Brook | static I2CSlaveInfo ds1338_info = {
|
119 | 1dfe3943 | Paul Brook | .qdev.name = "ds1338",
|
120 | 1dfe3943 | Paul Brook | .qdev.size = sizeof(DS1338State),
|
121 | 1dfe3943 | Paul Brook | .init = ds1338_init, |
122 | 1dfe3943 | Paul Brook | .event = ds1338_event, |
123 | 1dfe3943 | Paul Brook | .recv = ds1338_recv, |
124 | 1dfe3943 | Paul Brook | .send = ds1338_send, |
125 | 1dfe3943 | Paul Brook | }; |
126 | 1dfe3943 | Paul Brook | |
127 | 1dfe3943 | Paul Brook | static void ds1338_register_devices(void) |
128 | 1dfe3943 | Paul Brook | { |
129 | 1dfe3943 | Paul Brook | i2c_register_slave(&ds1338_info); |
130 | 1dfe3943 | Paul Brook | } |
131 | 1dfe3943 | Paul Brook | |
132 | 1dfe3943 | Paul Brook | device_init(ds1338_register_devices) |