Signed-off-by: Kuo-Jung Su <dant...@faraday-tech.com>
---
 hw/fti2c010.c |  209 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/fti2c010.h |   77 +++++++++++++++++++++
 2 files changed, 286 insertions(+)
 create mode 100644 hw/fti2c010.c
 create mode 100644 hw/fti2c010.h

diff --git a/hw/fti2c010.c b/hw/fti2c010.c
new file mode 100644
index 0000000..3073314
--- /dev/null
+++ b/hw/fti2c010.c
@@ -0,0 +1,209 @@
+/*
+ * QEMU model of the FTSSP010 Controller
+ *
+ * Copyright (C) 2012 Faraday Technology
+ * Copyright (C) 2012 Dante Su <dant...@faraday-tech.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sysbus.h"
+#include "sysemu/sysemu.h"
+#include "i2c.h"
+#include "fti2c010.h"
+
+#define I2C_RD        1
+#define I2C_WR        0
+
+typedef struct {
+    SysBusDevice busdev;
+    MemoryRegion mmio;
+
+    qemu_irq irq;
+    i2c_bus *bus;
+
+    uint32_t cr;
+    uint32_t sr;
+    uint32_t cdr;
+    uint32_t dr;
+    uint32_t tgsr;
+    
+    uint8_t  recv;    /* I2C RD = 1; I2C WR = 0 */
+    uint8_t  addr;    /* 7-bits device address */
+
+} fti2c010_state;
+
+static uint64_t
+fti2c010_mem_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    fti2c010_state *s = opaque;
+    uint32_t rc = 0;
+
+    switch (addr) {
+    case REG_CR:
+        return s->cr;
+    case REG_SR:
+        rc = s->sr | (i2c_bus_busy(s->bus) ? SR_BB : 0);
+        s->sr &= 0xfffff00f;
+        qemu_set_irq(s->irq, 0);        
+        break;
+    case REG_CDR:
+        return s->cdr;
+    case REG_DR:
+        return s->dr;
+    case REG_TGSR:
+        return s->tgsr;
+    case REG_BMR:
+        return 0x00000003;
+    case 0x30:    /* revision register */
+        return 0x00011000;
+    default:
+        break;
+    }
+
+    return rc;
+}
+
+static void
+fti2c010_mem_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int 
size)
+{
+    fti2c010_state *s = opaque;
+    
+    switch (addr) {
+    case REG_CR:
+        s->cr = (uint32_t)val64;
+        if (s->cr & CR_I2CRST) {
+            s->dr = 0;
+            s->sr = 0;
+        } else if ((s->cr & (CR_MASTER_EN | CR_TBEN)) == (CR_MASTER_EN | 
CR_TBEN)) {
+            s->sr &= ~SR_ACK;
+            if (s->cr & CR_START) {
+                s->recv = (s->dr & I2C_RD) ? 1 : 0;
+                s->addr = (s->dr >> 1) & 0x7f;
+                if (i2c_start_transfer(s->bus, s->addr, s->recv) == 0)
+                    s->sr |= SR_DT | SR_ACK;
+                else
+                    s->sr &= ~SR_DT;
+            } else {
+                if (s->recv) {
+                    s->dr = i2c_recv(s->bus);
+                    s->sr |= SR_DR;
+                } else {
+                    i2c_send(s->bus, (uint8_t)s->dr);
+                    s->sr |= SR_DT;
+                }
+                if (s->cr & CR_NACK)
+                    i2c_nack(s->bus);
+                s->sr |= SR_ACK;
+                if (s->cr & CR_STOP)
+                    i2c_end_transfer(s->bus);
+            }
+        }
+        s->cr &= 0xffffff7e;    /* clear TB_EN, I2C_RST */
+        if ((s->sr >> 4) & (s->cr >> 8))
+            qemu_set_irq(s->irq, 1);
+        break;
+    case REG_CDR:
+        s->cdr = (uint32_t)val64;
+        break;
+    case REG_DR:
+        s->dr  = (uint32_t)val64 & 0xff;
+        break;
+    case REG_TGSR:
+        s->tgsr = (uint32_t)val64;
+        break;
+    default:
+        break;
+    }
+}
+
+static const MemoryRegionOps bus_ops = {
+    .read  = fti2c010_mem_read,
+    .write = fti2c010_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static void fti2c010_reset(DeviceState *d)
+{
+    fti2c010_state *s = DO_UPCAST(fti2c010_state, busdev.qdev, d);
+
+    s->cr = 0;
+    s->sr = 0;
+    s->cdr = 0;
+    s->tgsr = 0x00000401;
+
+    qemu_set_irq(s->irq, 0);
+}
+
+static int fti2c010_init(SysBusDevice *dev)
+{
+    fti2c010_state *s = FROM_SYSBUS(typeof(*s), dev);
+
+    s->bus = i2c_init_bus(&dev->qdev, "i2c");
+    
+    memory_region_init_io(&s->mmio, &bus_ops, s, "fti2c010", 0x1000);
+    sysbus_init_mmio(dev, &s->mmio);
+    sysbus_init_irq(dev, &s->irq);
+    
+    return 0;
+}
+
+static const VMStateDescription vmstate_fti2c010 = {
+    .name = "fti2c010",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(cr, fti2c010_state),
+        VMSTATE_UINT32(sr, fti2c010_state),
+        VMSTATE_UINT32(cdr, fti2c010_state),
+        VMSTATE_UINT32(dr, fti2c010_state),
+        VMSTATE_UINT32(tgsr, fti2c010_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void fti2c010_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *k = DEVICE_CLASS(klass);
+
+    sdc->init  = fti2c010_init;
+    k->vmsd    = &vmstate_fti2c010;
+    k->reset   = fti2c010_reset;
+    k->no_user = 1;
+}
+
+static TypeInfo fti2c010_info = {
+    .name           = "fti2c010",
+    .parent         = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(fti2c010_state),
+    .class_init     = fti2c010_class_init,
+};
+
+static void fti2c010_register_types(void)
+{
+    type_register_static(&fti2c010_info);
+}
+
+type_init(fti2c010_register_types)
diff --git a/hw/fti2c010.h b/hw/fti2c010.h
new file mode 100644
index 0000000..deb12ec
--- /dev/null
+++ b/hw/fti2c010.h
@@ -0,0 +1,77 @@
+/*
+ * (C) Copyright 2010
+ * Faraday Technology Inc. <www.faraday-tech.com>
+ * Dante Su <dant...@gmail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef FTI2C010_H
+#define FTI2C010_H
+
+/*
+ * FTI2C010 registers
+ */
+#define REG_CR            0x00
+#define REG_SR            0x04
+#define REG_CDR            0x08
+#define REG_DR            0x0C
+#define REG_SAR            0x10
+#define REG_TGSR        0x14
+#define REG_BMR            0x18
+
+/*
+ * REG_CR
+ */
+#define CR_STARTIEN        0x4000  /* start condition */
+#define CR_ALIEN        0x2000  /* Arbitration lose */
+#define CR_SAMIEN        0x1000  /* slave address match */
+#define CR_STOPIEN        0x800   /* stop condition */
+#define CR_BERRIEN        0x400   /* non ACK response */
+#define CR_DRIEN        0x200   /* data receive */
+#define CR_DTIEN        0x100   /* data transmit */
+#define CR_TBEN            0x80    /* transfer byte enable */
+#define CR_NACK            0x40    /* with this bit set, fti2c010 will not 
drive ACK signal */
+#define CR_STOP            0x20    /* stop */
+#define CR_START        0x10    /* start */
+#define CR_GCEN            0x8     /* general call */
+#define CR_SCLEN        0x4     /* enable clock */
+#define CR_I2CEN        0x2     /* enable I2C */
+#define CR_I2CRST        0x1     /* reset I2C */
+#define CR_MASTER_INTR    (CR_ALIEN | CR_BERRIEN | CR_DRIEN | CR_DTIEN)
+#define CR_MASTER_EN    (CR_SCLEN | CR_I2CEN)
+#define CR_MASTER_MODE    (CR_MASTER_INTR | CR_MASTER_EN)
+
+/*
+ * REG_SR
+ */
+#define SR_START        0x800
+#define SR_AL            0x400
+#define SR_GC            0x200
+#define SR_SAM            0x100
+#define SR_STOP            0x80
+#define SR_BERR            0x40
+#define SR_DR            0x20    /* received one new data byte */
+#define SR_DT            0x10    /* trandmitted one data byte */
+#define SR_BB            0x8        /* set when i2c bus is busy, but fti2c010 
is not */
+#define SR_I2CB            0x4        /* set when fti2c010 is busy */
+#define SR_ACK            0x2
+#define SR_RW            0x1
+
+#endif /* EOF */
-- 
1.7.9.5


********************* Confidentiality Notice ************************
This electronic message and any attachments may contain
confidential and legally privileged information or
information which is otherwise protected from disclosure.
If you are not the intended recipient,please do not disclose
the contents, either in whole or in part, to anyone,and
immediately delete the message and any attachments from
your computer system and destroy all hard copies.
Thank you for your cooperation.
***********************************************************************


Reply via email to