]>
Commit | Line | Data |
---|---|---|
7abb479c AR |
1 | /* |
2 | * Copyright (C) 2014 Freescale Semiconductor, Inc. All rights reserved. | |
3 | * | |
4 | * Author: Amit Tomar, <[email protected]> | |
5 | * | |
6 | * Description: | |
7 | * This file is derived from IMX I2C controller, | |
8 | * by Jean-Christophe DUBOIS . | |
9 | * | |
10 | * Thanks to Scott Wood and Alexander Graf for their kind help on this. | |
11 | * | |
12 | * This program is free software; you can redistribute it and/or modify | |
13 | * it under the terms of the GNU General Public License, version 2 or later, | |
14 | * as published by the Free Software Foundation. | |
15 | * | |
16 | * You should have received a copy of the GNU Lesser General Public | |
17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
20 | #include "qemu/osdep.h" | |
21 | #include "hw/i2c/i2c.h" | |
64552b6b | 22 | #include "hw/irq.h" |
7abb479c | 23 | #include "qemu/log.h" |
0b8fa32f | 24 | #include "qemu/module.h" |
7abb479c AR |
25 | #include "hw/sysbus.h" |
26 | ||
27 | /* #define DEBUG_I2C */ | |
28 | ||
29 | #ifdef DEBUG_I2C | |
30 | #define DPRINTF(fmt, ...) \ | |
31 | do { fprintf(stderr, "mpc_i2c[%s]: " fmt, __func__, ## __VA_ARGS__); \ | |
32 | } while (0) | |
33 | #else | |
34 | #define DPRINTF(fmt, ...) do {} while (0) | |
35 | #endif | |
36 | ||
37 | #define TYPE_MPC_I2C "mpc-i2c" | |
38 | #define MPC_I2C(obj) \ | |
39 | OBJECT_CHECK(MPCI2CState, (obj), TYPE_MPC_I2C) | |
40 | ||
41 | #define MPC_I2C_ADR 0x00 | |
42 | #define MPC_I2C_FDR 0x04 | |
43 | #define MPC_I2C_CR 0x08 | |
44 | #define MPC_I2C_SR 0x0c | |
45 | #define MPC_I2C_DR 0x10 | |
46 | #define MPC_I2C_DFSRR 0x14 | |
47 | ||
48 | #define CCR_MEN (1 << 7) | |
49 | #define CCR_MIEN (1 << 6) | |
50 | #define CCR_MSTA (1 << 5) | |
51 | #define CCR_MTX (1 << 4) | |
52 | #define CCR_TXAK (1 << 3) | |
53 | #define CCR_RSTA (1 << 2) | |
54 | #define CCR_BCST (1 << 0) | |
55 | ||
56 | #define CSR_MCF (1 << 7) | |
57 | #define CSR_MAAS (1 << 6) | |
58 | #define CSR_MBB (1 << 5) | |
59 | #define CSR_MAL (1 << 4) | |
60 | #define CSR_SRW (1 << 2) | |
61 | #define CSR_MIF (1 << 1) | |
62 | #define CSR_RXAK (1 << 0) | |
63 | ||
64 | #define CADR_MASK 0xFE | |
65 | #define CFDR_MASK 0x3F | |
66 | #define CCR_MASK 0xFC | |
67 | #define CSR_MASK 0xED | |
68 | #define CDR_MASK 0xFF | |
69 | ||
70 | #define CYCLE_RESET 0xFF | |
71 | ||
72 | typedef struct MPCI2CState { | |
73 | SysBusDevice parent_obj; | |
74 | ||
75 | I2CBus *bus; | |
76 | qemu_irq irq; | |
77 | MemoryRegion iomem; | |
78 | ||
79 | uint8_t address; | |
80 | uint8_t adr; | |
81 | uint8_t fdr; | |
82 | uint8_t cr; | |
83 | uint8_t sr; | |
84 | uint8_t dr; | |
85 | uint8_t dfssr; | |
86 | } MPCI2CState; | |
87 | ||
88 | static bool mpc_i2c_is_enabled(MPCI2CState *s) | |
89 | { | |
90 | return s->cr & CCR_MEN; | |
91 | } | |
92 | ||
93 | static bool mpc_i2c_is_master(MPCI2CState *s) | |
94 | { | |
95 | return s->cr & CCR_MSTA; | |
96 | } | |
97 | ||
98 | static bool mpc_i2c_direction_is_tx(MPCI2CState *s) | |
99 | { | |
100 | return s->cr & CCR_MTX; | |
101 | } | |
102 | ||
103 | static bool mpc_i2c_irq_pending(MPCI2CState *s) | |
104 | { | |
105 | return s->sr & CSR_MIF; | |
106 | } | |
107 | ||
108 | static bool mpc_i2c_irq_is_enabled(MPCI2CState *s) | |
109 | { | |
110 | return s->cr & CCR_MIEN; | |
111 | } | |
112 | ||
113 | static void mpc_i2c_reset(DeviceState *dev) | |
114 | { | |
115 | MPCI2CState *i2c = MPC_I2C(dev); | |
116 | ||
117 | i2c->address = 0xFF; | |
118 | i2c->adr = 0x00; | |
119 | i2c->fdr = 0x00; | |
120 | i2c->cr = 0x00; | |
121 | i2c->sr = 0x81; | |
122 | i2c->dr = 0x00; | |
123 | } | |
124 | ||
125 | static void mpc_i2c_irq(MPCI2CState *s) | |
126 | { | |
127 | bool irq_active = false; | |
128 | ||
129 | if (mpc_i2c_is_enabled(s) && mpc_i2c_irq_is_enabled(s) | |
130 | && mpc_i2c_irq_pending(s)) { | |
131 | irq_active = true; | |
132 | } | |
133 | ||
134 | if (irq_active) { | |
135 | qemu_irq_raise(s->irq); | |
136 | } else { | |
137 | qemu_irq_lower(s->irq); | |
138 | } | |
139 | } | |
140 | ||
141 | static void mpc_i2c_soft_reset(MPCI2CState *s) | |
142 | { | |
143 | /* This is a soft reset. ADR is preserved during soft resets */ | |
144 | uint8_t adr = s->adr; | |
145 | mpc_i2c_reset(DEVICE(s)); | |
146 | s->adr = adr; | |
147 | } | |
148 | ||
149 | static void mpc_i2c_address_send(MPCI2CState *s) | |
150 | { | |
151 | /* if returns non zero slave address is not right */ | |
152 | if (i2c_start_transfer(s->bus, s->dr >> 1, s->dr & (0x01))) { | |
153 | s->sr |= CSR_RXAK; | |
154 | } else { | |
155 | s->address = s->dr; | |
156 | s->sr &= ~CSR_RXAK; | |
157 | s->sr |= CSR_MCF; /* Set after Byte Transfer is completed */ | |
158 | s->sr |= CSR_MIF; /* Set after Byte Transfer is completed */ | |
159 | mpc_i2c_irq(s); | |
160 | } | |
161 | } | |
162 | ||
163 | static void mpc_i2c_data_send(MPCI2CState *s) | |
164 | { | |
165 | if (i2c_send(s->bus, s->dr)) { | |
166 | /* End of transfer */ | |
167 | s->sr |= CSR_RXAK; | |
168 | i2c_end_transfer(s->bus); | |
169 | } else { | |
170 | s->sr &= ~CSR_RXAK; | |
171 | s->sr |= CSR_MCF; /* Set after Byte Transfer is completed */ | |
172 | s->sr |= CSR_MIF; /* Set after Byte Transfer is completed */ | |
173 | mpc_i2c_irq(s); | |
174 | } | |
175 | } | |
176 | ||
177 | static void mpc_i2c_data_recive(MPCI2CState *s) | |
178 | { | |
179 | int ret; | |
180 | /* get the next byte */ | |
181 | ret = i2c_recv(s->bus); | |
182 | if (ret >= 0) { | |
183 | s->sr |= CSR_MCF; /* Set after Byte Transfer is completed */ | |
184 | s->sr |= CSR_MIF; /* Set after Byte Transfer is completed */ | |
185 | mpc_i2c_irq(s); | |
186 | } else { | |
187 | DPRINTF("read failed for device"); | |
188 | ret = 0xff; | |
189 | } | |
190 | s->dr = ret; | |
191 | } | |
192 | ||
193 | static uint64_t mpc_i2c_read(void *opaque, hwaddr addr, unsigned size) | |
194 | { | |
195 | MPCI2CState *s = opaque; | |
196 | uint8_t value; | |
197 | ||
198 | switch (addr) { | |
199 | case MPC_I2C_ADR: | |
200 | value = s->adr; | |
201 | break; | |
202 | case MPC_I2C_FDR: | |
203 | value = s->fdr; | |
204 | break; | |
205 | case MPC_I2C_CR: | |
206 | value = s->cr; | |
207 | break; | |
208 | case MPC_I2C_SR: | |
209 | value = s->sr; | |
210 | break; | |
211 | case MPC_I2C_DR: | |
212 | value = s->dr; | |
213 | if (mpc_i2c_is_master(s)) { /* master mode */ | |
214 | if (mpc_i2c_direction_is_tx(s)) { | |
215 | DPRINTF("MTX is set not in recv mode\n"); | |
216 | } else { | |
217 | mpc_i2c_data_recive(s); | |
218 | } | |
219 | } | |
220 | break; | |
221 | default: | |
222 | value = 0; | |
223 | DPRINTF("ERROR: Bad read addr 0x%x\n", (unsigned int)addr); | |
224 | break; | |
225 | } | |
226 | ||
227 | DPRINTF("%s: addr " TARGET_FMT_plx " %02" PRIx32 "\n", __func__, | |
228 | addr, value); | |
229 | return (uint64_t)value; | |
230 | } | |
231 | ||
232 | static void mpc_i2c_write(void *opaque, hwaddr addr, | |
233 | uint64_t value, unsigned size) | |
234 | { | |
235 | MPCI2CState *s = opaque; | |
236 | ||
237 | DPRINTF("%s: addr " TARGET_FMT_plx " val %08" PRIx64 "\n", __func__, | |
238 | addr, value); | |
239 | switch (addr) { | |
240 | case MPC_I2C_ADR: | |
241 | s->adr = value & CADR_MASK; | |
242 | break; | |
243 | case MPC_I2C_FDR: | |
244 | s->fdr = value & CFDR_MASK; | |
245 | break; | |
246 | case MPC_I2C_CR: | |
247 | if (mpc_i2c_is_enabled(s) && ((value & CCR_MEN) == 0)) { | |
248 | mpc_i2c_soft_reset(s); | |
249 | break; | |
250 | } | |
251 | /* normal write */ | |
252 | s->cr = value & CCR_MASK; | |
253 | if (mpc_i2c_is_master(s)) { /* master mode */ | |
254 | /* set the bus to busy after master is set as per RM */ | |
255 | s->sr |= CSR_MBB; | |
256 | } else { | |
257 | /* bus is not busy anymore */ | |
258 | s->sr &= ~CSR_MBB; | |
259 | /* Reset the address for fresh write/read cycle */ | |
260 | if (s->address != CYCLE_RESET) { | |
261 | i2c_end_transfer(s->bus); | |
262 | s->address = CYCLE_RESET; | |
263 | } | |
264 | } | |
265 | /* For restart end the onging transfer */ | |
266 | if (s->cr & CCR_RSTA) { | |
267 | if (s->address != CYCLE_RESET) { | |
268 | s->address = CYCLE_RESET; | |
269 | i2c_end_transfer(s->bus); | |
270 | s->cr &= ~CCR_RSTA; | |
271 | } | |
272 | } | |
273 | break; | |
274 | case MPC_I2C_SR: | |
275 | s->sr = value & CSR_MASK; | |
276 | /* Lower the interrupt */ | |
277 | if (!(s->sr & CSR_MIF) || !(s->sr & CSR_MAL)) { | |
278 | mpc_i2c_irq(s); | |
279 | } | |
280 | break; | |
281 | case MPC_I2C_DR: | |
282 | /* if the device is not enabled, nothing to do */ | |
283 | if (!mpc_i2c_is_enabled(s)) { | |
284 | break; | |
285 | } | |
286 | s->dr = value & CDR_MASK; | |
287 | if (mpc_i2c_is_master(s)) { /* master mode */ | |
288 | if (s->address == CYCLE_RESET) { | |
289 | mpc_i2c_address_send(s); | |
290 | } else { | |
291 | mpc_i2c_data_send(s); | |
292 | } | |
293 | } | |
294 | break; | |
295 | case MPC_I2C_DFSRR: | |
296 | s->dfssr = value; | |
297 | break; | |
298 | default: | |
299 | DPRINTF("ERROR: Bad write addr 0x%x\n", (unsigned int)addr); | |
300 | break; | |
301 | } | |
302 | } | |
303 | ||
304 | static const MemoryRegionOps i2c_ops = { | |
305 | .read = mpc_i2c_read, | |
306 | .write = mpc_i2c_write, | |
307 | .valid.max_access_size = 1, | |
308 | .endianness = DEVICE_NATIVE_ENDIAN, | |
309 | }; | |
310 | ||
311 | static const VMStateDescription mpc_i2c_vmstate = { | |
312 | .name = TYPE_MPC_I2C, | |
313 | .version_id = 1, | |
314 | .minimum_version_id = 1, | |
315 | .fields = (VMStateField[]) { | |
316 | VMSTATE_UINT8(address, MPCI2CState), | |
317 | VMSTATE_UINT8(adr, MPCI2CState), | |
318 | VMSTATE_UINT8(fdr, MPCI2CState), | |
319 | VMSTATE_UINT8(cr, MPCI2CState), | |
320 | VMSTATE_UINT8(sr, MPCI2CState), | |
321 | VMSTATE_UINT8(dr, MPCI2CState), | |
322 | VMSTATE_UINT8(dfssr, MPCI2CState), | |
323 | VMSTATE_END_OF_LIST() | |
324 | } | |
325 | }; | |
326 | ||
327 | static void mpc_i2c_realize(DeviceState *dev, Error **errp) | |
328 | { | |
329 | MPCI2CState *i2c = MPC_I2C(dev); | |
330 | sysbus_init_irq(SYS_BUS_DEVICE(dev), &i2c->irq); | |
331 | memory_region_init_io(&i2c->iomem, OBJECT(i2c), &i2c_ops, i2c, | |
332 | "mpc-i2c", 0x14); | |
333 | sysbus_init_mmio(SYS_BUS_DEVICE(dev), &i2c->iomem); | |
334 | i2c->bus = i2c_init_bus(DEVICE(dev), "i2c"); | |
335 | } | |
336 | ||
337 | static void mpc_i2c_class_init(ObjectClass *klass, void *data) | |
338 | { | |
339 | DeviceClass *dc = DEVICE_CLASS(klass); | |
340 | ||
341 | dc->vmsd = &mpc_i2c_vmstate ; | |
342 | dc->reset = mpc_i2c_reset; | |
343 | dc->realize = mpc_i2c_realize; | |
344 | dc->desc = "MPC I2C Controller"; | |
345 | } | |
346 | ||
347 | static const TypeInfo mpc_i2c_type_info = { | |
348 | .name = TYPE_MPC_I2C, | |
349 | .parent = TYPE_SYS_BUS_DEVICE, | |
350 | .instance_size = sizeof(MPCI2CState), | |
351 | .class_init = mpc_i2c_class_init, | |
352 | }; | |
353 | ||
354 | static void mpc_i2c_register_types(void) | |
355 | { | |
356 | type_register_static(&mpc_i2c_type_info); | |
357 | } | |
358 | ||
359 | type_init(mpc_i2c_register_types) |