root / hw / exynos4210_i2c.c @ fa2ddcb4
History | View | Annotate | Download (10 kB)
1 | ffbbe7d0 | Mitsyanko Igor | /*
|
---|---|---|---|
2 | ffbbe7d0 | Mitsyanko Igor | * Exynos4210 I2C Bus Serial Interface Emulation
|
3 | ffbbe7d0 | Mitsyanko Igor | *
|
4 | ffbbe7d0 | Mitsyanko Igor | * Copyright (C) 2012 Samsung Electronics Co Ltd.
|
5 | ffbbe7d0 | Mitsyanko Igor | * Maksim Kozlov, <m.kozlov@samsung.com>
|
6 | ffbbe7d0 | Mitsyanko Igor | * Igor Mitsyanko, <i.mitsyanko@samsung.com>
|
7 | ffbbe7d0 | Mitsyanko Igor | *
|
8 | ffbbe7d0 | Mitsyanko Igor | * This program is free software; you can redistribute it and/or modify it
|
9 | ffbbe7d0 | Mitsyanko Igor | * under the terms of the GNU General Public License as published by the
|
10 | ffbbe7d0 | Mitsyanko Igor | * Free Software Foundation; either version 2 of the License, or
|
11 | ffbbe7d0 | Mitsyanko Igor | * (at your option) any later version.
|
12 | ffbbe7d0 | Mitsyanko Igor | *
|
13 | ffbbe7d0 | Mitsyanko Igor | * This program is distributed in the hope that it will be useful, but WITHOUT
|
14 | ffbbe7d0 | Mitsyanko Igor | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
15 | ffbbe7d0 | Mitsyanko Igor | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
16 | ffbbe7d0 | Mitsyanko Igor | * for more details.
|
17 | ffbbe7d0 | Mitsyanko Igor | *
|
18 | ffbbe7d0 | Mitsyanko Igor | * You should have received a copy of the GNU General Public License along
|
19 | ffbbe7d0 | Mitsyanko Igor | * with this program; if not, see <http://www.gnu.org/licenses/>.
|
20 | ffbbe7d0 | Mitsyanko Igor | *
|
21 | ffbbe7d0 | Mitsyanko Igor | */
|
22 | ffbbe7d0 | Mitsyanko Igor | |
23 | ffbbe7d0 | Mitsyanko Igor | #include "qemu-timer.h" |
24 | ffbbe7d0 | Mitsyanko Igor | #include "sysbus.h" |
25 | ffbbe7d0 | Mitsyanko Igor | #include "i2c.h" |
26 | ffbbe7d0 | Mitsyanko Igor | |
27 | ffbbe7d0 | Mitsyanko Igor | #ifndef EXYNOS4_I2C_DEBUG
|
28 | ffbbe7d0 | Mitsyanko Igor | #define EXYNOS4_I2C_DEBUG 0 |
29 | ffbbe7d0 | Mitsyanko Igor | #endif
|
30 | ffbbe7d0 | Mitsyanko Igor | |
31 | ffbbe7d0 | Mitsyanko Igor | #define TYPE_EXYNOS4_I2C "exynos4210.i2c" |
32 | ffbbe7d0 | Mitsyanko Igor | #define EXYNOS4_I2C(obj) \
|
33 | ffbbe7d0 | Mitsyanko Igor | OBJECT_CHECK(Exynos4210I2CState, (obj), TYPE_EXYNOS4_I2C) |
34 | ffbbe7d0 | Mitsyanko Igor | |
35 | ffbbe7d0 | Mitsyanko Igor | /* Exynos4210 I2C memory map */
|
36 | ffbbe7d0 | Mitsyanko Igor | #define EXYNOS4_I2C_MEM_SIZE 0x14 |
37 | ffbbe7d0 | Mitsyanko Igor | #define I2CCON_ADDR 0x00 /* control register */ |
38 | ffbbe7d0 | Mitsyanko Igor | #define I2CSTAT_ADDR 0x04 /* control/status register */ |
39 | ffbbe7d0 | Mitsyanko Igor | #define I2CADD_ADDR 0x08 /* address register */ |
40 | ffbbe7d0 | Mitsyanko Igor | #define I2CDS_ADDR 0x0c /* data shift register */ |
41 | ffbbe7d0 | Mitsyanko Igor | #define I2CLC_ADDR 0x10 /* line control register */ |
42 | ffbbe7d0 | Mitsyanko Igor | |
43 | ffbbe7d0 | Mitsyanko Igor | #define I2CCON_ACK_GEN (1 << 7) |
44 | ffbbe7d0 | Mitsyanko Igor | #define I2CCON_INTRS_EN (1 << 5) |
45 | ffbbe7d0 | Mitsyanko Igor | #define I2CCON_INT_PEND (1 << 4) |
46 | ffbbe7d0 | Mitsyanko Igor | |
47 | ffbbe7d0 | Mitsyanko Igor | #define EXYNOS4_I2C_MODE(reg) (((reg) >> 6) & 3) |
48 | ffbbe7d0 | Mitsyanko Igor | #define I2C_IN_MASTER_MODE(reg) (((reg) >> 6) & 2) |
49 | ffbbe7d0 | Mitsyanko Igor | #define I2CMODE_MASTER_Rx 0x2 |
50 | ffbbe7d0 | Mitsyanko Igor | #define I2CMODE_MASTER_Tx 0x3 |
51 | ffbbe7d0 | Mitsyanko Igor | #define I2CSTAT_LAST_BIT (1 << 0) |
52 | ffbbe7d0 | Mitsyanko Igor | #define I2CSTAT_OUTPUT_EN (1 << 4) |
53 | ffbbe7d0 | Mitsyanko Igor | #define I2CSTAT_START_BUSY (1 << 5) |
54 | ffbbe7d0 | Mitsyanko Igor | |
55 | ffbbe7d0 | Mitsyanko Igor | |
56 | ffbbe7d0 | Mitsyanko Igor | #if EXYNOS4_I2C_DEBUG
|
57 | ffbbe7d0 | Mitsyanko Igor | #define DPRINT(fmt, args...) \
|
58 | ffbbe7d0 | Mitsyanko Igor | do { fprintf(stderr, "QEMU I2C: "fmt, ## args); } while (0) |
59 | ffbbe7d0 | Mitsyanko Igor | |
60 | ffbbe7d0 | Mitsyanko Igor | static const char *exynos4_i2c_get_regname(unsigned offset) |
61 | ffbbe7d0 | Mitsyanko Igor | { |
62 | ffbbe7d0 | Mitsyanko Igor | switch (offset) {
|
63 | ffbbe7d0 | Mitsyanko Igor | case I2CCON_ADDR:
|
64 | ffbbe7d0 | Mitsyanko Igor | return "I2CCON"; |
65 | ffbbe7d0 | Mitsyanko Igor | case I2CSTAT_ADDR:
|
66 | ffbbe7d0 | Mitsyanko Igor | return "I2CSTAT"; |
67 | ffbbe7d0 | Mitsyanko Igor | case I2CADD_ADDR:
|
68 | ffbbe7d0 | Mitsyanko Igor | return "I2CADD"; |
69 | ffbbe7d0 | Mitsyanko Igor | case I2CDS_ADDR:
|
70 | ffbbe7d0 | Mitsyanko Igor | return "I2CDS"; |
71 | ffbbe7d0 | Mitsyanko Igor | case I2CLC_ADDR:
|
72 | ffbbe7d0 | Mitsyanko Igor | return "I2CLC"; |
73 | ffbbe7d0 | Mitsyanko Igor | default:
|
74 | ffbbe7d0 | Mitsyanko Igor | return "[?]"; |
75 | ffbbe7d0 | Mitsyanko Igor | } |
76 | ffbbe7d0 | Mitsyanko Igor | } |
77 | ffbbe7d0 | Mitsyanko Igor | |
78 | ffbbe7d0 | Mitsyanko Igor | #else
|
79 | ffbbe7d0 | Mitsyanko Igor | #define DPRINT(fmt, args...) do { } while (0) |
80 | ffbbe7d0 | Mitsyanko Igor | #endif
|
81 | ffbbe7d0 | Mitsyanko Igor | |
82 | ffbbe7d0 | Mitsyanko Igor | typedef struct Exynos4210I2CState { |
83 | ffbbe7d0 | Mitsyanko Igor | SysBusDevice busdev; |
84 | ffbbe7d0 | Mitsyanko Igor | MemoryRegion iomem; |
85 | ffbbe7d0 | Mitsyanko Igor | i2c_bus *bus; |
86 | ffbbe7d0 | Mitsyanko Igor | qemu_irq irq; |
87 | ffbbe7d0 | Mitsyanko Igor | |
88 | ffbbe7d0 | Mitsyanko Igor | uint8_t i2ccon; |
89 | ffbbe7d0 | Mitsyanko Igor | uint8_t i2cstat; |
90 | ffbbe7d0 | Mitsyanko Igor | uint8_t i2cadd; |
91 | ffbbe7d0 | Mitsyanko Igor | uint8_t i2cds; |
92 | ffbbe7d0 | Mitsyanko Igor | uint8_t i2clc; |
93 | ffbbe7d0 | Mitsyanko Igor | bool scl_free;
|
94 | ffbbe7d0 | Mitsyanko Igor | } Exynos4210I2CState; |
95 | ffbbe7d0 | Mitsyanko Igor | |
96 | ffbbe7d0 | Mitsyanko Igor | static inline void exynos4210_i2c_raise_interrupt(Exynos4210I2CState *s) |
97 | ffbbe7d0 | Mitsyanko Igor | { |
98 | ffbbe7d0 | Mitsyanko Igor | if (s->i2ccon & I2CCON_INTRS_EN) {
|
99 | ffbbe7d0 | Mitsyanko Igor | s->i2ccon |= I2CCON_INT_PEND; |
100 | ffbbe7d0 | Mitsyanko Igor | qemu_irq_raise(s->irq); |
101 | ffbbe7d0 | Mitsyanko Igor | } |
102 | ffbbe7d0 | Mitsyanko Igor | } |
103 | ffbbe7d0 | Mitsyanko Igor | |
104 | ffbbe7d0 | Mitsyanko Igor | static void exynos4210_i2c_data_receive(void *opaque) |
105 | ffbbe7d0 | Mitsyanko Igor | { |
106 | ffbbe7d0 | Mitsyanko Igor | Exynos4210I2CState *s = (Exynos4210I2CState *)opaque; |
107 | ffbbe7d0 | Mitsyanko Igor | int ret;
|
108 | ffbbe7d0 | Mitsyanko Igor | |
109 | ffbbe7d0 | Mitsyanko Igor | s->i2cstat &= ~I2CSTAT_LAST_BIT; |
110 | ffbbe7d0 | Mitsyanko Igor | s->scl_free = false;
|
111 | ffbbe7d0 | Mitsyanko Igor | ret = i2c_recv(s->bus); |
112 | ffbbe7d0 | Mitsyanko Igor | if (ret < 0 && (s->i2ccon & I2CCON_ACK_GEN)) { |
113 | ffbbe7d0 | Mitsyanko Igor | s->i2cstat |= I2CSTAT_LAST_BIT; /* Data is not acknowledged */
|
114 | ffbbe7d0 | Mitsyanko Igor | } else {
|
115 | ffbbe7d0 | Mitsyanko Igor | s->i2cds = ret; |
116 | ffbbe7d0 | Mitsyanko Igor | } |
117 | ffbbe7d0 | Mitsyanko Igor | exynos4210_i2c_raise_interrupt(s); |
118 | ffbbe7d0 | Mitsyanko Igor | } |
119 | ffbbe7d0 | Mitsyanko Igor | |
120 | ffbbe7d0 | Mitsyanko Igor | static void exynos4210_i2c_data_send(void *opaque) |
121 | ffbbe7d0 | Mitsyanko Igor | { |
122 | ffbbe7d0 | Mitsyanko Igor | Exynos4210I2CState *s = (Exynos4210I2CState *)opaque; |
123 | ffbbe7d0 | Mitsyanko Igor | |
124 | ffbbe7d0 | Mitsyanko Igor | s->i2cstat &= ~I2CSTAT_LAST_BIT; |
125 | ffbbe7d0 | Mitsyanko Igor | s->scl_free = false;
|
126 | ffbbe7d0 | Mitsyanko Igor | if (i2c_send(s->bus, s->i2cds) < 0 && (s->i2ccon & I2CCON_ACK_GEN)) { |
127 | ffbbe7d0 | Mitsyanko Igor | s->i2cstat |= I2CSTAT_LAST_BIT; |
128 | ffbbe7d0 | Mitsyanko Igor | } |
129 | ffbbe7d0 | Mitsyanko Igor | exynos4210_i2c_raise_interrupt(s); |
130 | ffbbe7d0 | Mitsyanko Igor | } |
131 | ffbbe7d0 | Mitsyanko Igor | |
132 | ffbbe7d0 | Mitsyanko Igor | static uint64_t exynos4210_i2c_read(void *opaque, target_phys_addr_t offset, |
133 | ffbbe7d0 | Mitsyanko Igor | unsigned size)
|
134 | ffbbe7d0 | Mitsyanko Igor | { |
135 | ffbbe7d0 | Mitsyanko Igor | Exynos4210I2CState *s = (Exynos4210I2CState *)opaque; |
136 | ffbbe7d0 | Mitsyanko Igor | uint8_t value; |
137 | ffbbe7d0 | Mitsyanko Igor | |
138 | ffbbe7d0 | Mitsyanko Igor | switch (offset) {
|
139 | ffbbe7d0 | Mitsyanko Igor | case I2CCON_ADDR:
|
140 | ffbbe7d0 | Mitsyanko Igor | value = s->i2ccon; |
141 | ffbbe7d0 | Mitsyanko Igor | break;
|
142 | ffbbe7d0 | Mitsyanko Igor | case I2CSTAT_ADDR:
|
143 | ffbbe7d0 | Mitsyanko Igor | value = s->i2cstat; |
144 | ffbbe7d0 | Mitsyanko Igor | break;
|
145 | ffbbe7d0 | Mitsyanko Igor | case I2CADD_ADDR:
|
146 | ffbbe7d0 | Mitsyanko Igor | value = s->i2cadd; |
147 | ffbbe7d0 | Mitsyanko Igor | break;
|
148 | ffbbe7d0 | Mitsyanko Igor | case I2CDS_ADDR:
|
149 | ffbbe7d0 | Mitsyanko Igor | value = s->i2cds; |
150 | ffbbe7d0 | Mitsyanko Igor | s->scl_free = true;
|
151 | ffbbe7d0 | Mitsyanko Igor | if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Rx &&
|
152 | ffbbe7d0 | Mitsyanko Igor | (s->i2cstat & I2CSTAT_START_BUSY) && |
153 | ffbbe7d0 | Mitsyanko Igor | !(s->i2ccon & I2CCON_INT_PEND)) { |
154 | ffbbe7d0 | Mitsyanko Igor | exynos4210_i2c_data_receive(s); |
155 | ffbbe7d0 | Mitsyanko Igor | } |
156 | ffbbe7d0 | Mitsyanko Igor | break;
|
157 | ffbbe7d0 | Mitsyanko Igor | case I2CLC_ADDR:
|
158 | ffbbe7d0 | Mitsyanko Igor | value = s->i2clc; |
159 | ffbbe7d0 | Mitsyanko Igor | break;
|
160 | ffbbe7d0 | Mitsyanko Igor | default:
|
161 | ffbbe7d0 | Mitsyanko Igor | value = 0;
|
162 | ffbbe7d0 | Mitsyanko Igor | DPRINT("ERROR: Bad read offset 0x%x\n", (unsigned int)offset); |
163 | ffbbe7d0 | Mitsyanko Igor | break;
|
164 | ffbbe7d0 | Mitsyanko Igor | } |
165 | ffbbe7d0 | Mitsyanko Igor | |
166 | ffbbe7d0 | Mitsyanko Igor | DPRINT("read %s [0x%02x] -> 0x%02x\n", exynos4_i2c_get_regname(offset),
|
167 | ffbbe7d0 | Mitsyanko Igor | (unsigned int)offset, value); |
168 | ffbbe7d0 | Mitsyanko Igor | return value;
|
169 | ffbbe7d0 | Mitsyanko Igor | } |
170 | ffbbe7d0 | Mitsyanko Igor | |
171 | ffbbe7d0 | Mitsyanko Igor | static void exynos4210_i2c_write(void *opaque, target_phys_addr_t offset, |
172 | ffbbe7d0 | Mitsyanko Igor | uint64_t value, unsigned size)
|
173 | ffbbe7d0 | Mitsyanko Igor | { |
174 | ffbbe7d0 | Mitsyanko Igor | Exynos4210I2CState *s = (Exynos4210I2CState *)opaque; |
175 | ffbbe7d0 | Mitsyanko Igor | uint8_t v = value & 0xff;
|
176 | ffbbe7d0 | Mitsyanko Igor | |
177 | ffbbe7d0 | Mitsyanko Igor | DPRINT("write %s [0x%02x] <- 0x%02x\n", exynos4_i2c_get_regname(offset),
|
178 | ffbbe7d0 | Mitsyanko Igor | (unsigned int)offset, v); |
179 | ffbbe7d0 | Mitsyanko Igor | |
180 | ffbbe7d0 | Mitsyanko Igor | switch (offset) {
|
181 | ffbbe7d0 | Mitsyanko Igor | case I2CCON_ADDR:
|
182 | ffbbe7d0 | Mitsyanko Igor | s->i2ccon = (v & ~I2CCON_INT_PEND) | (s->i2ccon & I2CCON_INT_PEND); |
183 | ffbbe7d0 | Mitsyanko Igor | if ((s->i2ccon & I2CCON_INT_PEND) && !(v & I2CCON_INT_PEND)) {
|
184 | ffbbe7d0 | Mitsyanko Igor | s->i2ccon &= ~I2CCON_INT_PEND; |
185 | ffbbe7d0 | Mitsyanko Igor | qemu_irq_lower(s->irq); |
186 | ffbbe7d0 | Mitsyanko Igor | if (!(s->i2ccon & I2CCON_INTRS_EN)) {
|
187 | ffbbe7d0 | Mitsyanko Igor | s->i2cstat &= ~I2CSTAT_START_BUSY; |
188 | ffbbe7d0 | Mitsyanko Igor | } |
189 | ffbbe7d0 | Mitsyanko Igor | |
190 | ffbbe7d0 | Mitsyanko Igor | if (s->i2cstat & I2CSTAT_START_BUSY) {
|
191 | ffbbe7d0 | Mitsyanko Igor | if (s->scl_free) {
|
192 | ffbbe7d0 | Mitsyanko Igor | if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Tx) {
|
193 | ffbbe7d0 | Mitsyanko Igor | exynos4210_i2c_data_send(s); |
194 | ffbbe7d0 | Mitsyanko Igor | } else if (EXYNOS4_I2C_MODE(s->i2cstat) == |
195 | ffbbe7d0 | Mitsyanko Igor | I2CMODE_MASTER_Rx) { |
196 | ffbbe7d0 | Mitsyanko Igor | exynos4210_i2c_data_receive(s); |
197 | ffbbe7d0 | Mitsyanko Igor | } |
198 | ffbbe7d0 | Mitsyanko Igor | } else {
|
199 | ffbbe7d0 | Mitsyanko Igor | s->i2ccon |= I2CCON_INT_PEND; |
200 | ffbbe7d0 | Mitsyanko Igor | qemu_irq_raise(s->irq); |
201 | ffbbe7d0 | Mitsyanko Igor | } |
202 | ffbbe7d0 | Mitsyanko Igor | } |
203 | ffbbe7d0 | Mitsyanko Igor | } |
204 | ffbbe7d0 | Mitsyanko Igor | break;
|
205 | ffbbe7d0 | Mitsyanko Igor | case I2CSTAT_ADDR:
|
206 | ffbbe7d0 | Mitsyanko Igor | s->i2cstat = |
207 | ffbbe7d0 | Mitsyanko Igor | (s->i2cstat & I2CSTAT_START_BUSY) | (v & ~I2CSTAT_START_BUSY); |
208 | ffbbe7d0 | Mitsyanko Igor | |
209 | ffbbe7d0 | Mitsyanko Igor | if (!(s->i2cstat & I2CSTAT_OUTPUT_EN)) {
|
210 | ffbbe7d0 | Mitsyanko Igor | s->i2cstat &= ~I2CSTAT_START_BUSY; |
211 | ffbbe7d0 | Mitsyanko Igor | s->scl_free = true;
|
212 | ffbbe7d0 | Mitsyanko Igor | qemu_irq_lower(s->irq); |
213 | ffbbe7d0 | Mitsyanko Igor | break;
|
214 | ffbbe7d0 | Mitsyanko Igor | } |
215 | ffbbe7d0 | Mitsyanko Igor | |
216 | ffbbe7d0 | Mitsyanko Igor | /* Nothing to do if in i2c slave mode */
|
217 | ffbbe7d0 | Mitsyanko Igor | if (!I2C_IN_MASTER_MODE(s->i2cstat)) {
|
218 | ffbbe7d0 | Mitsyanko Igor | break;
|
219 | ffbbe7d0 | Mitsyanko Igor | } |
220 | ffbbe7d0 | Mitsyanko Igor | |
221 | ffbbe7d0 | Mitsyanko Igor | if (v & I2CSTAT_START_BUSY) {
|
222 | ffbbe7d0 | Mitsyanko Igor | s->i2cstat &= ~I2CSTAT_LAST_BIT; |
223 | ffbbe7d0 | Mitsyanko Igor | s->i2cstat |= I2CSTAT_START_BUSY; /* Line is busy */
|
224 | ffbbe7d0 | Mitsyanko Igor | s->scl_free = false;
|
225 | ffbbe7d0 | Mitsyanko Igor | |
226 | ffbbe7d0 | Mitsyanko Igor | /* Generate start bit and send slave address */
|
227 | ffbbe7d0 | Mitsyanko Igor | if (i2c_start_transfer(s->bus, s->i2cds >> 1, s->i2cds & 0x1) && |
228 | ffbbe7d0 | Mitsyanko Igor | (s->i2ccon & I2CCON_ACK_GEN)) { |
229 | ffbbe7d0 | Mitsyanko Igor | s->i2cstat |= I2CSTAT_LAST_BIT; |
230 | ffbbe7d0 | Mitsyanko Igor | } else if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Rx) { |
231 | ffbbe7d0 | Mitsyanko Igor | exynos4210_i2c_data_receive(s); |
232 | ffbbe7d0 | Mitsyanko Igor | } |
233 | ffbbe7d0 | Mitsyanko Igor | exynos4210_i2c_raise_interrupt(s); |
234 | ffbbe7d0 | Mitsyanko Igor | } else {
|
235 | ffbbe7d0 | Mitsyanko Igor | i2c_end_transfer(s->bus); |
236 | ffbbe7d0 | Mitsyanko Igor | if (!(s->i2ccon & I2CCON_INT_PEND)) {
|
237 | ffbbe7d0 | Mitsyanko Igor | s->i2cstat &= ~I2CSTAT_START_BUSY; |
238 | ffbbe7d0 | Mitsyanko Igor | } |
239 | ffbbe7d0 | Mitsyanko Igor | s->scl_free = true;
|
240 | ffbbe7d0 | Mitsyanko Igor | } |
241 | ffbbe7d0 | Mitsyanko Igor | break;
|
242 | ffbbe7d0 | Mitsyanko Igor | case I2CADD_ADDR:
|
243 | ffbbe7d0 | Mitsyanko Igor | if ((s->i2cstat & I2CSTAT_OUTPUT_EN) == 0) { |
244 | ffbbe7d0 | Mitsyanko Igor | s->i2cadd = v; |
245 | ffbbe7d0 | Mitsyanko Igor | } |
246 | ffbbe7d0 | Mitsyanko Igor | break;
|
247 | ffbbe7d0 | Mitsyanko Igor | case I2CDS_ADDR:
|
248 | ffbbe7d0 | Mitsyanko Igor | if (s->i2cstat & I2CSTAT_OUTPUT_EN) {
|
249 | ffbbe7d0 | Mitsyanko Igor | s->i2cds = v; |
250 | ffbbe7d0 | Mitsyanko Igor | s->scl_free = true;
|
251 | ffbbe7d0 | Mitsyanko Igor | if (EXYNOS4_I2C_MODE(s->i2cstat) == I2CMODE_MASTER_Tx &&
|
252 | ffbbe7d0 | Mitsyanko Igor | (s->i2cstat & I2CSTAT_START_BUSY) && |
253 | ffbbe7d0 | Mitsyanko Igor | !(s->i2ccon & I2CCON_INT_PEND)) { |
254 | ffbbe7d0 | Mitsyanko Igor | exynos4210_i2c_data_send(s); |
255 | ffbbe7d0 | Mitsyanko Igor | } |
256 | ffbbe7d0 | Mitsyanko Igor | } |
257 | ffbbe7d0 | Mitsyanko Igor | break;
|
258 | ffbbe7d0 | Mitsyanko Igor | case I2CLC_ADDR:
|
259 | ffbbe7d0 | Mitsyanko Igor | s->i2clc = v; |
260 | ffbbe7d0 | Mitsyanko Igor | break;
|
261 | ffbbe7d0 | Mitsyanko Igor | default:
|
262 | ffbbe7d0 | Mitsyanko Igor | DPRINT("ERROR: Bad write offset 0x%x\n", (unsigned int)offset); |
263 | ffbbe7d0 | Mitsyanko Igor | break;
|
264 | ffbbe7d0 | Mitsyanko Igor | } |
265 | ffbbe7d0 | Mitsyanko Igor | } |
266 | ffbbe7d0 | Mitsyanko Igor | |
267 | ffbbe7d0 | Mitsyanko Igor | static const MemoryRegionOps exynos4210_i2c_ops = { |
268 | ffbbe7d0 | Mitsyanko Igor | .read = exynos4210_i2c_read, |
269 | ffbbe7d0 | Mitsyanko Igor | .write = exynos4210_i2c_write, |
270 | ffbbe7d0 | Mitsyanko Igor | .endianness = DEVICE_NATIVE_ENDIAN, |
271 | ffbbe7d0 | Mitsyanko Igor | }; |
272 | ffbbe7d0 | Mitsyanko Igor | |
273 | ffbbe7d0 | Mitsyanko Igor | static const VMStateDescription exynos4210_i2c_vmstate = { |
274 | ffbbe7d0 | Mitsyanko Igor | .name = TYPE_EXYNOS4_I2C, |
275 | ffbbe7d0 | Mitsyanko Igor | .version_id = 1,
|
276 | ffbbe7d0 | Mitsyanko Igor | .minimum_version_id = 1,
|
277 | ffbbe7d0 | Mitsyanko Igor | .fields = (VMStateField[]) { |
278 | ffbbe7d0 | Mitsyanko Igor | VMSTATE_UINT8(i2ccon, Exynos4210I2CState), |
279 | ffbbe7d0 | Mitsyanko Igor | VMSTATE_UINT8(i2cstat, Exynos4210I2CState), |
280 | ffbbe7d0 | Mitsyanko Igor | VMSTATE_UINT8(i2cds, Exynos4210I2CState), |
281 | ffbbe7d0 | Mitsyanko Igor | VMSTATE_UINT8(i2cadd, Exynos4210I2CState), |
282 | ffbbe7d0 | Mitsyanko Igor | VMSTATE_UINT8(i2clc, Exynos4210I2CState), |
283 | ffbbe7d0 | Mitsyanko Igor | VMSTATE_BOOL(scl_free, Exynos4210I2CState), |
284 | ffbbe7d0 | Mitsyanko Igor | VMSTATE_END_OF_LIST() |
285 | ffbbe7d0 | Mitsyanko Igor | } |
286 | ffbbe7d0 | Mitsyanko Igor | }; |
287 | ffbbe7d0 | Mitsyanko Igor | |
288 | ffbbe7d0 | Mitsyanko Igor | static void exynos4210_i2c_reset(DeviceState *d) |
289 | ffbbe7d0 | Mitsyanko Igor | { |
290 | ffbbe7d0 | Mitsyanko Igor | Exynos4210I2CState *s = EXYNOS4_I2C(d); |
291 | ffbbe7d0 | Mitsyanko Igor | |
292 | ffbbe7d0 | Mitsyanko Igor | s->i2ccon = 0x00;
|
293 | ffbbe7d0 | Mitsyanko Igor | s->i2cstat = 0x00;
|
294 | ffbbe7d0 | Mitsyanko Igor | s->i2cds = 0xFF;
|
295 | ffbbe7d0 | Mitsyanko Igor | s->i2clc = 0x00;
|
296 | ffbbe7d0 | Mitsyanko Igor | s->i2cadd = 0xFF;
|
297 | ffbbe7d0 | Mitsyanko Igor | s->scl_free = true;
|
298 | ffbbe7d0 | Mitsyanko Igor | } |
299 | ffbbe7d0 | Mitsyanko Igor | |
300 | ffbbe7d0 | Mitsyanko Igor | static int exynos4210_i2c_realize(SysBusDevice *dev) |
301 | ffbbe7d0 | Mitsyanko Igor | { |
302 | ffbbe7d0 | Mitsyanko Igor | Exynos4210I2CState *s = EXYNOS4_I2C(dev); |
303 | ffbbe7d0 | Mitsyanko Igor | |
304 | ffbbe7d0 | Mitsyanko Igor | memory_region_init_io(&s->iomem, &exynos4210_i2c_ops, s, TYPE_EXYNOS4_I2C, |
305 | ffbbe7d0 | Mitsyanko Igor | EXYNOS4_I2C_MEM_SIZE); |
306 | ffbbe7d0 | Mitsyanko Igor | sysbus_init_mmio(dev, &s->iomem); |
307 | ffbbe7d0 | Mitsyanko Igor | sysbus_init_irq(dev, &s->irq); |
308 | ffbbe7d0 | Mitsyanko Igor | s->bus = i2c_init_bus(&dev->qdev, "i2c");
|
309 | ffbbe7d0 | Mitsyanko Igor | return 0; |
310 | ffbbe7d0 | Mitsyanko Igor | } |
311 | ffbbe7d0 | Mitsyanko Igor | |
312 | ffbbe7d0 | Mitsyanko Igor | static void exynos4210_i2c_class_init(ObjectClass *klass, void *data) |
313 | ffbbe7d0 | Mitsyanko Igor | { |
314 | ffbbe7d0 | Mitsyanko Igor | DeviceClass *dc = DEVICE_CLASS(klass); |
315 | ffbbe7d0 | Mitsyanko Igor | SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass); |
316 | ffbbe7d0 | Mitsyanko Igor | |
317 | ffbbe7d0 | Mitsyanko Igor | dc->vmsd = &exynos4210_i2c_vmstate; |
318 | ffbbe7d0 | Mitsyanko Igor | dc->reset = exynos4210_i2c_reset; |
319 | ffbbe7d0 | Mitsyanko Igor | sbdc->init = exynos4210_i2c_realize; |
320 | ffbbe7d0 | Mitsyanko Igor | } |
321 | ffbbe7d0 | Mitsyanko Igor | |
322 | ffbbe7d0 | Mitsyanko Igor | static const TypeInfo exynos4210_i2c_type_info = { |
323 | ffbbe7d0 | Mitsyanko Igor | .name = TYPE_EXYNOS4_I2C, |
324 | ffbbe7d0 | Mitsyanko Igor | .parent = TYPE_SYS_BUS_DEVICE, |
325 | ffbbe7d0 | Mitsyanko Igor | .instance_size = sizeof(Exynos4210I2CState),
|
326 | ffbbe7d0 | Mitsyanko Igor | .class_init = exynos4210_i2c_class_init, |
327 | ffbbe7d0 | Mitsyanko Igor | }; |
328 | ffbbe7d0 | Mitsyanko Igor | |
329 | ffbbe7d0 | Mitsyanko Igor | static void exynos4210_i2c_register_types(void) |
330 | ffbbe7d0 | Mitsyanko Igor | { |
331 | ffbbe7d0 | Mitsyanko Igor | type_register_static(&exynos4210_i2c_type_info); |
332 | ffbbe7d0 | Mitsyanko Igor | } |
333 | ffbbe7d0 | Mitsyanko Igor | |
334 | ffbbe7d0 | Mitsyanko Igor | type_init(exynos4210_i2c_register_types) |