~ubuntu-branches/ubuntu/wily/qemu-kvm-spice/wily

« back to all changes in this revision

Viewing changes to hw/ds1338.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-10-19 10:44:56 UTC
  • Revision ID: james.westby@ubuntu.com-20111019104456-xgvskumk3sxi97f4
Tags: upstream-0.15.0+noroms
ImportĀ upstreamĀ versionĀ 0.15.0+noroms

Show diffs side-by-side

added added

removed removed

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