3 * Samsung S3C24XX i2c peripheral emulation
5 * Copyright 2006, 2007, 2008 Daniel Silverstone, Ben Dooks
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"
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 */
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
{
75 static void s3c24xx_i2c_irq(struct s3c24xx_i2c_state_s
*s
)
79 if (s
->control
& (1 << 5)) {
80 qemu_irq_raise(s
->irq
);
84 static void s3c24xx_i2c_reset(struct s3c24xx_i2c_state_s
*s
)
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 */
100 if ((s
->status
& 0x90) != 0x90) /* Master */
103 stop
= ~s
->status
& (1 << 5);
104 if (s
->newstart
&& s
->status
& (1 << 5)) { /* START */
115 ack
= !i2c_start_transfer(s
->bus
, s
->data
>> 1, (~s
->status
>> 6) & 1);
117 i2c_end_transfer(s
->bus
);
118 } else if (s
->status
& (1 << 6)) {
119 ack
= !i2c_send(s
->bus
, s
->data
);
121 s
->data
= i2c_recv(s
->bus
);
123 if (!(s
->control
& (1 << 7))) /* ACK */
127 if (!(s
->status
& (1 << 5))) {
141 static uint64_t s3c24xx_i2c_read(void *opaque
, hwaddr addr
,
144 struct s3c24xx_i2c_state_s
*s
= opaque
;
151 return s
->status
& ~(1 << 5); /* Busy signal */
160 printf("%s: Bad register 0x" TARGET_FMT_plx
"\n", __func__
, addr
);
166 static void s3c24xx_i2c_write(void *opaque
, hwaddr addr
,
167 uint64_t value
, unsigned size
)
169 struct s3c24xx_i2c_state_s
*s
= opaque
;
173 s
->control
= (s
->control
| 0xef) & value
;
174 if (s
->busy
|| ((s
->control
& (1<<4)) == 0))
180 s
->status
|= value
& 0xf0;
181 if (s
->status
& (1 << 5))
187 s
->addy
= value
& 0x7f;
191 s
->data
= value
& 0xff;
196 printf("%s: Bad register 0x" TARGET_FMT_plx
"\n", __func__
, addr
);
201 static const MemoryRegionOps s3c24xx_i2c_ops
= {
202 .read
= s3c24xx_i2c_read
,
203 .write
= s3c24xx_i2c_write
,
204 .endianness
= DEVICE_NATIVE_ENDIAN
,
206 .min_access_size
= 1,
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
);
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
,
246 MemoryRegion
*system_memory
= get_system_memory();
247 struct s3c24xx_i2c_state_s
*s
= g_malloc0(sizeof(struct s3c24xx_i2c_state_s
));
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
);
263 I2CBus
*s3c24xx_i2c_bus(struct s3c24xx_i2c_state_s
*s
)