Merge tag 'v9.0.0-rc3'
[qemu/ar7.git] / hw / arm / s3c24xx_iic.c
blob6affc1b2187ef8f07d7d495bdb8baebb79bf06b0
1 /* hw/s3c24xx_iic.c
3 * Samsung S3C24XX i2c peripheral emulation
5 * Copyright 2006, 2007, 2008 Daniel Silverstone, Ben Dooks
6 * and Vincent Sanders
8 * Copyright 2010, 2013, 2020 Stefan Weil
10 * This file is under the terms of the GNU General Public License Version 2.
13 #include "qemu/osdep.h"
14 #include "cpu.h"
15 #include "hw/hw.h"
16 #include "exec/address-spaces.h" /* get_system_memory */
17 #include "hw/i2c/i2c.h"
18 #include "hw/irq.h" /* qemu_set_irq */
19 #include "migration/qemu-file-types.h" /* qemu_put_be32s */
20 #include "migration/register.h" /* register_savevm_live */
22 #include "s3c24xx.h"
24 /* i2c controller registers */
25 #define S3C_IICCON (0x00)
26 #define S3C_IICSTAT (0x04)
27 #define S3C_IICADD (0x08)
28 #define S3C_IICDS (0x0C)
29 #define S3C_IICLC (0x10)
31 #define S3C_IICCON_ACKEN (1<<7)
32 #define S3C_IICCON_TXDIV_16 (0<<6)
33 #define S3C_IICCON_TXDIV_512 (1<<6)
34 #define S3C_IICCON_IRQEN (1<<5)
35 #define S3C_IICCON_IRQPEND (1<<4)
36 #define S3C_IICCON_SCALE(x) ((x)&15)
37 #define S3C_IICCON_SCALEMASK (0xf)
39 #define S3C_IICSTAT_MASTER_RX (2<<6)
40 #define S3C_IICSTAT_MASTER_TX (3<<6)
41 #define S3C_IICSTAT_SLAVE_RX (0<<6)
42 #define S3C_IICSTAT_SLAVE_TX (1<<6)
43 #define S3C_IICSTAT_MODEMASK (3<<6)
45 #define S3C_IICSTAT_START (1<<5)
46 #define S3C_IICSTAT_BUSBUSY (1<<5)
47 #define S3C_IICSTAT_TXRXEN (1<<4)
48 #define S3C_IICSTAT_ARBITR (1<<3)
49 #define S3C_IICSTAT_ASSLAVE (1<<2)
50 #define S3C_IICSTAT_ADDR0 (1<<1)
51 #define S3C_IICSTAT_LASTBIT (1<<0)
53 #define S3C_IICLC_SDA_DELAY0 (0 << 0)
54 #define S3C_IICLC_SDA_DELAY5 (1 << 0)
55 #define S3C_IICLC_SDA_DELAY10 (2 << 0)
56 #define S3C_IICLC_SDA_DELAY15 (3 << 0)
57 #define S3C_IICLC_SDA_DELAY_MASK (3 << 0)
59 #define S3C_IICLC_FILTER_ON (1<<2)
61 /* IIC-bus serial interface */
62 struct s3c24xx_i2c_state_s {
63 MemoryRegion mmio;
64 I2CBus *bus;
65 qemu_irq irq;
67 uint8_t control;
68 uint8_t status;
69 uint8_t data;
70 uint8_t addy;
71 int busy;
72 int newstart;
75 static void s3c24xx_i2c_irq(struct s3c24xx_i2c_state_s *s)
77 s->control |= 1 << 4;
79 if (s->control & (1 << 5)) {
80 qemu_irq_raise(s->irq);
84 static void s3c24xx_i2c_reset(struct s3c24xx_i2c_state_s *s)
86 s->control = 0x00;
87 s->status = 0x00;
88 s->busy = 0;
89 s->newstart = 0;
93 static void s3c_master_work(void *opaque)
95 struct s3c24xx_i2c_state_s *s = opaque;
96 int start = 0, stop = 0, ack = 1;
98 if (s->control & (1 << 4)) /* Interrupt pending */
99 return;
100 if ((s->status & 0x90) != 0x90) /* Master */
101 return;
103 stop = ~s->status & (1 << 5);
104 if (s->newstart && s->status & (1 << 5)) { /* START */
105 s->busy = 1;
106 start = 1;
108 s->newstart = 0;
110 if (!s->busy) {
111 return;
114 if (start) {
115 ack = !i2c_start_transfer(s->bus, s->data >> 1, (~s->status >> 6) & 1);
116 } else if (stop) {
117 i2c_end_transfer(s->bus);
118 } else if (s->status & (1 << 6)) {
119 ack = !i2c_send(s->bus, s->data);
120 } else {
121 s->data = i2c_recv(s->bus);
123 if (!(s->control & (1 << 7))) /* ACK */
124 i2c_nack(s->bus);
127 if (!(s->status & (1 << 5))) {
128 s->busy = 0;
129 return;
132 s->status &= ~1;
133 s->status |= !ack;
135 if (!ack) {
136 s->busy = 0;
138 s3c24xx_i2c_irq(s);
141 static uint64_t s3c24xx_i2c_read(void *opaque, hwaddr addr,
142 unsigned size)
144 struct s3c24xx_i2c_state_s *s = opaque;
146 switch (addr) {
147 case S3C_IICCON:
148 return s->control;
150 case S3C_IICSTAT:
151 return s->status & ~(1 << 5); /* Busy signal */
153 case S3C_IICADD:
154 return s->addy;
156 case S3C_IICDS:
157 return s->data;
159 default:
160 printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
161 break;
163 return 0;
166 static void s3c24xx_i2c_write(void *opaque, hwaddr addr,
167 uint64_t value, unsigned size)
169 struct s3c24xx_i2c_state_s *s = opaque;
171 switch (addr) {
172 case S3C_IICCON:
173 s->control = (s->control | 0xef) & value;
174 if (s->busy || ((s->control & (1<<4)) == 0))
175 s3c_master_work(s);
176 break;
178 case S3C_IICSTAT:
179 s->status &= 0x0f;
180 s->status |= value & 0xf0;
181 if (s->status & (1 << 5))
182 s->newstart = 1;
183 s3c_master_work(s);
184 break;
186 case S3C_IICADD:
187 s->addy = value & 0x7f;
188 break;
190 case S3C_IICDS:
191 s->data = value & 0xff;
192 s->busy = 1;
193 break;
195 default:
196 printf("%s: Bad register 0x" TARGET_FMT_plx "\n", __func__, addr);
197 break;
201 static const MemoryRegionOps s3c24xx_i2c_ops = {
202 .read = s3c24xx_i2c_read,
203 .write = s3c24xx_i2c_write,
204 .endianness = DEVICE_NATIVE_ENDIAN,
205 .valid = {
206 .min_access_size = 1,
207 .max_access_size = 4
211 static void s3c24xx_i2c_save(QEMUFile *f, void *opaque)
213 struct s3c24xx_i2c_state_s *s = opaque;
214 qemu_put_8s(f, &s->control);
215 qemu_put_8s(f, &s->status);
216 qemu_put_8s(f, &s->data);
217 qemu_put_8s(f, &s->addy);
219 qemu_put_be32(f, s->busy);
220 qemu_put_be32(f, s->newstart);
224 static int s3c24xx_i2c_load(QEMUFile *f, void *opaque, int version_id)
226 struct s3c24xx_i2c_state_s *s = opaque;
227 qemu_get_8s(f, &s->control);
228 qemu_get_8s(f, &s->status);
229 qemu_get_8s(f, &s->data);
230 qemu_get_8s(f, &s->addy);
232 s->busy = qemu_get_be32(f);
233 s->newstart = qemu_get_be32(f);
235 return 0;
238 static SaveVMHandlers savevm_s3c24xx_i2c = {
239 .save_state = s3c24xx_i2c_save,
240 .load_state = s3c24xx_i2c_load
243 struct s3c24xx_i2c_state_s *s3c24xx_iic_init(qemu_irq irq,
244 hwaddr base_addr)
246 MemoryRegion *system_memory = get_system_memory();
247 struct s3c24xx_i2c_state_s *s = g_malloc0(sizeof(struct s3c24xx_i2c_state_s));
249 s->irq = irq;
250 s->bus = i2c_init_bus(NULL, "i2c");
252 s3c24xx_i2c_reset(s);
254 memory_region_init_io(&s->mmio, OBJECT(s),
255 &s3c24xx_i2c_ops, s, "s3c24xx-i2c", 0x1000000);
256 memory_region_add_subregion(system_memory, base_addr, &s->mmio);
258 register_savevm_live("s3c24xx_i2c", 0, 0, &savevm_s3c24xx_i2c, s);
260 return s;
263 I2CBus *s3c24xx_i2c_bus(struct s3c24xx_i2c_state_s *s)
265 return s->bus;