Statistics
| Branch: | Revision:

root / hw / max7310.c @ 18be5187

History | View | Annotate | Download (5.2 kB)

1
/*
2
 * MAX7310 8-port GPIO expansion chip.
3
 *
4
 * Copyright (c) 2006 Openedhand Ltd.
5
 * Written by Andrzej Zaborowski <balrog@zabor.org>
6
 *
7
 * This file is licensed under GNU GPL.
8
 */
9

    
10
#include "hw.h"
11
#include "i2c.h"
12

    
13
struct max7310_s {
14
    i2c_slave i2c;
15
    int i2c_command_byte;
16
    int len;
17

    
18
    uint8_t level;
19
    uint8_t direction;
20
    uint8_t polarity;
21
    uint8_t status;
22
    uint8_t command;
23
    qemu_irq handler[8];
24
    qemu_irq *gpio_in;
25
};
26

    
27
void max7310_reset(i2c_slave *i2c)
28
{
29
    struct max7310_s *s = (struct max7310_s *) i2c;
30
    s->level &= s->direction;
31
    s->direction = 0xff;
32
    s->polarity = 0xf0;
33
    s->status = 0x01;
34
    s->command = 0x00;
35
}
36

    
37
static int max7310_rx(i2c_slave *i2c)
38
{
39
    struct max7310_s *s = (struct max7310_s *) i2c;
40

    
41
    switch (s->command) {
42
    case 0x00:        /* Input port */
43
        return s->level ^ s->polarity;
44
        break;
45

    
46
    case 0x01:        /* Output port */
47
        return s->level & ~s->direction;
48
        break;
49

    
50
    case 0x02:        /* Polarity inversion */
51
        return s->polarity;
52

    
53
    case 0x03:        /* Configuration */
54
        return s->direction;
55

    
56
    case 0x04:        /* Timeout */
57
        return s->status;
58
        break;
59

    
60
    case 0xff:        /* Reserved */
61
        return 0xff;
62

    
63
    default:
64
#ifdef VERBOSE
65
        printf("%s: unknown register %02x\n", __FUNCTION__, s->command);
66
#endif
67
        break;
68
    }
69
    return 0xff;
70
}
71

    
72
static int max7310_tx(i2c_slave *i2c, uint8_t data)
73
{
74
    struct max7310_s *s = (struct max7310_s *) i2c;
75
    uint8_t diff;
76
    int line;
77

    
78
    if (s->len ++ > 1) {
79
#ifdef VERBOSE
80
        printf("%s: message too long (%i bytes)\n", __FUNCTION__, s->len);
81
#endif
82
        return 1;
83
    }
84

    
85
    if (s->i2c_command_byte) {
86
        s->command = data;
87
        s->i2c_command_byte = 0;
88
        return 0;
89
    }
90

    
91
    switch (s->command) {
92
    case 0x01:        /* Output port */
93
        for (diff = (data ^ s->level) & ~s->direction; diff;
94
                        diff &= ~(1 << line)) {
95
            line = ffs(diff) - 1;
96
            if (s->handler[line])
97
                qemu_set_irq(s->handler[line], (data >> line) & 1);
98
        }
99
        s->level = (s->level & s->direction) | (data & ~s->direction);
100
        break;
101

    
102
    case 0x02:        /* Polarity inversion */
103
        s->polarity = data;
104
        break;
105

    
106
    case 0x03:        /* Configuration */
107
        s->level &= ~(s->direction ^ data);
108
        s->direction = data;
109
        break;
110

    
111
    case 0x04:        /* Timeout */
112
        s->status = data;
113
        break;
114

    
115
    case 0x00:        /* Input port - ignore writes */
116
        break;
117
    default:
118
#ifdef VERBOSE
119
        printf("%s: unknown register %02x\n", __FUNCTION__, s->command);
120
#endif
121
        return 1;
122
    }
123

    
124
    return 0;
125
}
126

    
127
static void max7310_event(i2c_slave *i2c, enum i2c_event event)
128
{
129
    struct max7310_s *s = (struct max7310_s *) i2c;
130
    s->len = 0;
131

    
132
    switch (event) {
133
    case I2C_START_SEND:
134
        s->i2c_command_byte = 1;
135
        break;
136
    case I2C_FINISH:
137
#ifdef VERBOSE
138
        if (s->len == 1)
139
            printf("%s: message too short (%i bytes)\n", __FUNCTION__, s->len);
140
#endif
141
        break;
142
    default:
143
        break;
144
    }
145
}
146

    
147
static void max7310_save(QEMUFile *f, void *opaque)
148
{
149
    struct max7310_s *s = (struct max7310_s *) opaque;
150

    
151
    qemu_put_be32(f, s->i2c_command_byte);
152
    qemu_put_be32(f, s->len);
153

    
154
    qemu_put_8s(f, &s->level);
155
    qemu_put_8s(f, &s->direction);
156
    qemu_put_8s(f, &s->polarity);
157
    qemu_put_8s(f, &s->status);
158
    qemu_put_8s(f, &s->command);
159

    
160
    i2c_slave_save(f, &s->i2c);
161
}
162

    
163
static int max7310_load(QEMUFile *f, void *opaque, int version_id)
164
{
165
    struct max7310_s *s = (struct max7310_s *) opaque;
166

    
167
    s->i2c_command_byte = qemu_get_be32(f);
168
    s->len = qemu_get_be32(f);
169

    
170
    qemu_get_8s(f, &s->level);
171
    qemu_get_8s(f, &s->direction);
172
    qemu_get_8s(f, &s->polarity);
173
    qemu_get_8s(f, &s->status);
174
    qemu_get_8s(f, &s->command);
175

    
176
    i2c_slave_load(f, &s->i2c);
177
    return 0;
178
}
179

    
180
static void max7310_gpio_set(void *opaque, int line, int level)
181
{
182
    struct max7310_s *s = (struct max7310_s *) opaque;
183
    if (line >= sizeof(s->handler) / sizeof(*s->handler) || line  < 0)
184
        hw_error("bad GPIO line");
185

    
186
    if (level)
187
        s->level |= s->direction & (1 << line);
188
    else
189
        s->level &= ~(s->direction & (1 << line));
190
}
191

    
192
/* MAX7310 is SMBus-compatible (can be used with only SMBus protocols),
193
 * but also accepts sequences that are not SMBus so return an I2C device.  */
194
struct i2c_slave *max7310_init(i2c_bus *bus)
195
{
196
    struct max7310_s *s = (struct max7310_s *)
197
            i2c_slave_init(bus, 0, sizeof(struct max7310_s));
198
    s->i2c.event = max7310_event;
199
    s->i2c.recv = max7310_rx;
200
    s->i2c.send = max7310_tx;
201
    s->gpio_in = qemu_allocate_irqs(max7310_gpio_set, s,
202
                    sizeof(s->handler) / sizeof(*s->handler));
203

    
204
    max7310_reset(&s->i2c);
205

    
206
    register_savevm("max7310", -1, 0, max7310_save, max7310_load, s);
207

    
208
    return &s->i2c;
209
}
210

    
211
qemu_irq *max7310_gpio_in_get(i2c_slave *i2c)
212
{
213
    struct max7310_s *s = (struct max7310_s *) i2c;
214
    return s->gpio_in;
215
}
216

    
217
void max7310_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler)
218
{
219
    struct max7310_s *s = (struct max7310_s *) i2c;
220
    if (line >= sizeof(s->handler) / sizeof(*s->handler) || line  < 0)
221
        hw_error("bad GPIO line");
222

    
223
    s->handler[line] = handler;
224
}