Statistics
| Branch: | Revision:

root / hw / max7310.c @ aa941b94

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 "vl.h"
11

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
123
    return 0;
124
}
125

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

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

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

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

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

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

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

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

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

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

    
179
static int max7310_iid = 0;
180

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

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

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

    
205
    max7310_reset(&s->i2c);
206

    
207
    register_savevm("max7310", max7310_iid ++, 0,
208
                    max7310_save, max7310_load, s);
209

    
210
    return &s->i2c;
211
}
212

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

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

    
225
    s->handler[line] = handler;
226
}