From: Vincent Sanders <vince@kyllikki.org>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH 10/16] S3C I2C peripheral
Date: Thu, 23 Apr 2009 19:07:00 +0100 [thread overview]
Message-ID: <20090423180700.GM4629@derik> (raw)
In-Reply-To: <20090423171503.GC4629@derik>
S3C I2C peripheral
Signed-off-by: Vincent Sanders <vince@simtec.co.uk>
---
s3c24xx_iic.c | 322 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 322 insertions(+)
diff -urN qemusvnclean/hw/s3c24xx_iic.c qemusvnpatches/hw/s3c24xx_iic.c
--- qemusvnclean/hw/s3c24xx_iic.c 1970-01-01 01:00:00.000000000 +0100
+++ qemusvnpatches/hw/s3c24xx_iic.c 2009-04-23 17:09:08.000000000 +0100
@@ -0,0 +1,322 @@
+/* hw/s3c24xx_iic.c
+ *
+ * Samsung S3C24XX emulation
+ *
+ * Copyright 2006, 2007, 2008 Daniel Silverstone, Ben Dooks
+ * and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "hw.h"
+#include "i2c.h"
+
+#include "s3c24xx.h"
+
+/* i2c controller registers */
+#define S3C_IICCON (0x00)
+#define S3C_IICSTAT (0x04)
+#define S3C_IICADD (0x08)
+#define S3C_IICDS (0x0C)
+#define S3C_IICLC (0x10)
+
+#define S3C_IICCON_ACKEN (1<<7)
+#define S3C_IICCON_TXDIV_16 (0<<6)
+#define S3C_IICCON_TXDIV_512 (1<<6)
+#define S3C_IICCON_IRQEN (1<<5)
+#define S3C_IICCON_IRQPEND (1<<4)
+#define S3C_IICCON_SCALE(x) ((x)&15)
+#define S3C_IICCON_SCALEMASK (0xf)
+
+#define S3C_IICSTAT_MASTER_RX (2<<6)
+#define S3C_IICSTAT_MASTER_TX (3<<6)
+#define S3C_IICSTAT_SLAVE_RX (0<<6)
+#define S3C_IICSTAT_SLAVE_TX (1<<6)
+#define S3C_IICSTAT_MODEMASK (3<<6)
+
+#define S3C_IICSTAT_START (1<<5)
+#define S3C_IICSTAT_BUSBUSY (1<<5)
+#define S3C_IICSTAT_TXRXEN (1<<4)
+#define S3C_IICSTAT_ARBITR (1<<3)
+#define S3C_IICSTAT_ASSLAVE (1<<2)
+#define S3C_IICSTAT_ADDR0 (1<<1)
+#define S3C_IICSTAT_LASTBIT (1<<0)
+
+#define S3C_IICLC_SDA_DELAY0 (0 << 0)
+#define S3C_IICLC_SDA_DELAY5 (1 << 0)
+#define S3C_IICLC_SDA_DELAY10 (2 << 0)
+#define S3C_IICLC_SDA_DELAY15 (3 << 0)
+#define S3C_IICLC_SDA_DELAY_MASK (3 << 0)
+
+#define S3C_IICLC_FILTER_ON (1<<2)
+
+/* IIC-bus serial interface */
+struct s3c24xx_i2c_state_s {
+ i2c_slave slave;
+ i2c_bus *bus;
+ target_phys_addr_t base;
+ qemu_irq irq;
+
+ uint8_t control;
+ uint8_t status;
+ uint8_t data;
+ uint8_t addy;
+ int busy;
+ int newstart;
+};
+
+static void s3c24xx_i2c_irq(struct s3c24xx_i2c_state_s *s)
+{
+ s->control |= 1 << 4;
+
+ if (s->control & (1 << 5)) {
+ qemu_irq_raise(s->irq);
+ }
+}
+
+static void s3c24xx_i2c_reset(struct s3c24xx_i2c_state_s *s)
+{
+ s->control = 0x00;
+ s->status = 0x00;
+ s->busy = 0;
+ s->newstart = 0;
+}
+
+static void s3c24xx_i2c_event(i2c_slave *i2c, enum i2c_event event)
+{
+ struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *) i2c;
+
+ if (!(s->status & (1 << 4)))
+ return;
+
+ switch (event) {
+ case I2C_START_RECV:
+
+ case I2C_START_SEND:
+ s->status |= 1 << 2;
+ s3c24xx_i2c_irq(s);
+ break;
+
+ case I2C_FINISH:
+ s->status &= ~6;
+ break;
+
+ case I2C_NACK:
+ s->status |= 1 << 0;
+ break;
+
+ default:
+ break;
+ }
+}
+
+static int s3c24xx_i2c_tx(i2c_slave *i2c, uint8_t data)
+{
+ struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *) i2c;
+ if (!(s->status & (1 << 4)))
+ return 1;
+
+ if ((s->status >> 6) == 0)
+ s->data = data; /* TODO */
+
+ s->status &= ~(1 << 0);
+ s3c24xx_i2c_irq(s);
+
+ return !(s->control & (1 << 7));
+}
+
+static int s3c24xx_i2c_rx(i2c_slave *i2c)
+{
+ struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *) i2c;
+ if (!(s->status & (1 << 4)))
+ return 1;
+
+ if ((s->status >> 6) == 1) {
+ s->status &= ~(1 << 0);
+ s3c24xx_i2c_irq(s);
+ return s->data;
+ }
+
+ return 0x00;
+}
+
+static void s3c_master_work(void *opaque)
+{
+ struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *) opaque;
+ int start = 0, stop = 0, ack = 1;
+
+ if (s->control & (1 << 4)) /* Interrupt pending */
+ return;
+ if ((s->status & 0x90) != 0x90) /* Master */
+ return;
+
+ stop = ~s->status & (1 << 5);
+ if (s->newstart && s->status & (1 << 5)) { /* START */
+ s->busy = 1;
+ start = 1;
+ }
+ s->newstart = 0;
+
+ if (!s->busy) {
+ return;
+ }
+
+ if (start) {
+ ack = !i2c_start_transfer(s->bus, s->data >> 1, (~s->status >> 6) & 1);
+ } else if (stop) {
+ i2c_end_transfer(s->bus);
+ } else if (s->status & (1 << 6)) {
+ ack = !i2c_send(s->bus, s->data);
+ } else {
+ s->data = i2c_recv(s->bus);
+
+ if (!(s->control & (1 << 7))) /* ACK */
+ i2c_nack(s->bus);
+ }
+
+ if (!(s->status & (1 << 5))) {
+ s->busy = 0;
+ return;
+ }
+
+ s->status &= ~1;
+ s->status |= !ack;
+
+ if (!ack) {
+ s->busy = 0;
+ }
+ s3c24xx_i2c_irq(s);
+}
+
+static uint32_t s3c24xx_i2c_read(void *opaque, target_phys_addr_t addr)
+{
+ struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *) opaque;
+
+ switch (addr) {
+ case S3C_IICCON:
+ return s->control;
+
+ case S3C_IICSTAT:
+ return s->status & ~(1 << 5); /* Busy signal */
+
+ case S3C_IICADD:
+ return s->addy;
+
+ case S3C_IICDS:
+ return s->data;
+
+ default:
+ printf("%s: Bad register 0x%lx\n", __func__, addr);
+ break;
+ }
+ return 0;
+}
+
+static void s3c24xx_i2c_write(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *) opaque;
+
+ switch (addr) {
+ case S3C_IICCON:
+ s->control = (s->control | 0xef) & value;
+ if (s->busy || ((s->control & (1<<4)) == 0))
+ s3c_master_work(s);
+ break;
+
+ case S3C_IICSTAT:
+ s->status &= 0x0f;
+ s->status |= value & 0xf0;
+ if (s->status & (1 << 5))
+ s->newstart = 1;
+ s3c_master_work(s);
+ break;
+
+ case S3C_IICADD:
+ s->addy = value & 0x7f;
+ i2c_set_slave_address(&s->slave, s->addy);
+ break;
+
+ case S3C_IICDS:
+ s->data = value & 0xff;
+ s->busy = 1;
+ break;
+
+ default:
+ printf("%s: Bad register 0x%lx\n", __func__, addr);
+ break;
+ }
+}
+
+static CPUReadMemoryFunc *s3c24xx_i2c_readfn[] = {
+ s3c24xx_i2c_read,
+ s3c24xx_i2c_read,
+ s3c24xx_i2c_read,
+};
+
+static CPUWriteMemoryFunc *s3c24xx_i2c_writefn[] = {
+ s3c24xx_i2c_write,
+ s3c24xx_i2c_write,
+ s3c24xx_i2c_write,
+};
+
+static void s3c24xx_i2c_save(QEMUFile *f, void *opaque)
+{
+ struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *) opaque;
+ qemu_put_8s(f, &s->control);
+ qemu_put_8s(f, &s->status);
+ qemu_put_8s(f, &s->data);
+ qemu_put_8s(f, &s->addy);
+
+ qemu_put_be32(f, s->busy);
+ qemu_put_be32(f, s->newstart);
+
+ /* i2c_bus_save(f, s->bus); */
+ i2c_slave_save(f, &s->slave);
+}
+
+static int s3c24xx_i2c_load(QEMUFile *f, void *opaque, int version_id)
+{
+ struct s3c24xx_i2c_state_s *s = (struct s3c24xx_i2c_state_s *) opaque;
+ qemu_get_8s(f, &s->control);
+ qemu_get_8s(f, &s->status);
+ qemu_get_8s(f, &s->data);
+ qemu_get_8s(f, &s->addy);
+
+ s->busy = qemu_get_be32(f);
+ s->newstart = qemu_get_be32(f);
+
+ /* i2c_bus_load(f, s->bus); */
+ i2c_slave_load(f, &s->slave);
+ return 0;
+}
+
+void s3c24xx_iic_init(S3CState *soc, target_phys_addr_t base_addr)
+{
+ int iomemtype;
+ struct s3c24xx_i2c_state_s *s = qemu_mallocz(sizeof(struct s3c24xx_i2c_state_s));
+
+ s->base = base_addr;
+ s->irq = soc->irqs[27];
+ s->slave.event = s3c24xx_i2c_event;
+ s->slave.send = s3c24xx_i2c_tx;
+ s->slave.recv = s3c24xx_i2c_rx;
+ s->bus = i2c_init_bus();
+
+ s3c24xx_i2c_reset(s);
+
+ iomemtype = cpu_register_io_memory(0, s3c24xx_i2c_readfn,
+ s3c24xx_i2c_writefn, s);
+ cpu_register_physical_memory(base_addr, 0xffffff, iomemtype);
+
+ register_savevm("s3c24xx_i2c", 0, 0, s3c24xx_i2c_save, s3c24xx_i2c_load, s);
+
+ soc->iic = s;
+}
+
+i2c_bus *s3c24xx_i2c_bus(struct s3c24xx_i2c_state_s *s)
+{
+ return s->bus;
+}
+
--
Regards Vincent
http://www.kyllikki.org/
next prev parent reply other threads:[~2009-04-23 18:07 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-04-23 17:15 [Qemu-devel] [PATCH 0/16] ARM Add S3C SOC core, drivers and boards Vincent Sanders
2009-04-23 17:45 ` [Qemu-devel] [PATCH 1/16] ARM Add ARM 920T identifiers Vincent Sanders
2009-04-30 16:08 ` Paul Brook
2009-05-23 16:50 ` Vincent Sanders
2009-05-24 18:31 ` Paul Brook
2009-05-26 9:39 ` Vincent Sanders
2009-05-26 9:42 ` Laurent Desnogues
2009-05-26 9:56 ` Jamie Lokier
2009-05-26 10:08 ` Laurent Desnogues
2009-05-26 11:29 ` Jamie Lokier
2009-05-26 11:46 ` Laurent Desnogues
2009-05-26 10:16 ` Paul Brook
2009-05-26 11:18 ` Vincent Sanders
2009-04-23 17:48 ` [Qemu-devel] [PATCH 2/16] Add s3c SOC header Vincent Sanders
2009-04-23 17:50 ` [Qemu-devel] [PATCH 3/16] S3C SDRAM memory controller Peripheral Vincent Sanders
2009-04-23 17:52 ` [Qemu-devel] [PATCH 4/16] S3C irq controller Vincent Sanders
2009-04-23 17:58 ` [Qemu-devel] [PATCH 05/16] S3C Clock controller peripheral Vincent Sanders
2009-04-23 18:00 ` [Qemu-devel] [PATCH 7/16] S3C serial peripheral Vincent Sanders
2009-04-23 18:02 ` [Qemu-devel] [PATCH 6/16] S3C Timers Vincent Sanders
2009-04-23 18:04 ` [Qemu-devel] [PATCH 8/16] S3C Real Time Clock Vincent Sanders
2009-04-23 18:05 ` [Qemu-devel] [PATCH 9/16] S3C General Purpose IO Vincent Sanders
2009-04-23 18:07 ` Vincent Sanders [this message]
2009-04-23 18:08 ` [Qemu-devel] [PATCH 11/16] S3C LCD display Vincent Sanders
2009-04-23 18:09 ` [Qemu-devel] [PATCH 12/16] S3C NAND controller Vincent Sanders
2009-04-23 18:11 ` [Qemu-devel] [PATCH 13/16] S3C2410 SOC implementation Vincent Sanders
2009-04-23 18:14 ` [Qemu-devel] [PATCH 14/16] S3C2440 SOC impementation Vincent Sanders
2009-04-23 18:15 ` [Qemu-devel] [PATCH 15/16] Add S3C SOC files to Makefile Vincent Sanders
2009-04-23 18:17 ` [Qemu-devel] [PATCH 16/16] Add two boards which use S3C2410 SOC Vincent Sanders
2009-04-25 12:44 ` Jean-Christophe PLAGNIOL-VILLARD
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090423180700.GM4629@derik \
--to=vince@kyllikki.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.