get roms more room. (Glauber Costa)
[qemu] / hw / max7310.c
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 >= ARRAY_SIZE(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                     ARRAY_SIZE(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 >= ARRAY_SIZE(s->handler) || line  < 0)
221         hw_error("bad GPIO line");
222
223     s->handler[line] = handler;
224 }