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