Patchwork [v2,12/20] arm: add Faraday FTSSP010 multi-function controller support

login
register
mail settings
Submitter Kuo-Jung Su
Date Jan. 25, 2013, 8:19 a.m.
Message ID <1359101996-11667-13-git-send-email-dantesu@gmail.com>
Download mbox | patch
Permalink /patch/215578/
State New
Headers show

Comments

Kuo-Jung Su - Jan. 25, 2013, 8:19 a.m.
From: Kuo-Jung Su <dantesu@faraday-tech.com>

The FTSSP010 is a synchronous serial port interface that allows
the host processor to serve as a master or a slave. Various devices
can be connected to this controller by using the serial protocol.

It supports the TI Synchronous Serial Port (SSP), the Motorola
Serial Peripheral Interface (SPI), National Semiconductor MICROWIRE,
Philips I2S, Intel AC-link, and SPDIF.

The serial data formats may range from 4 bits to 128 bits in length.
The Faraday SSP controller can be accessed with Faraday AHB/APB DMA
to directly transfer data between the external serial device and
the system memory without the intervention from the processor.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 hw/ftssp010.c |  552 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/ftssp010.h |   91 ++++++++++
 2 files changed, 643 insertions(+)
 create mode 100644 hw/ftssp010.c
 create mode 100644 hw/ftssp010.h

Patch

diff --git a/hw/ftssp010.c b/hw/ftssp010.c
new file mode 100644
index 0000000..4b85bd6
--- /dev/null
+++ b/hw/ftssp010.c
@@ -0,0 +1,552 @@ 
+/*
+ * QEMU model of the FTSSP010 Controller
+ *
+ * Copyright (C) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is licensed under GNU GPL v2.
+ */
+
+#include "sysbus.h"
+#include "sysemu/sysemu.h"
+#include "fifo.h"
+#include "i2c.h"
+#include "ssi.h"
+#include "ftssp010.h"
+
+#define CFG_FIFO_DEPTH    16
+
+#define TYPE_FTSSP010   "ftssp010"
+
+typedef struct Ftssp010State {
+    SysBusDevice busdev;
+    MemoryRegion mmio;
+
+    qemu_irq irq;
+    SSIBus *spi;
+
+    uint8_t num_cs;
+    qemu_irq *cs_lines;
+
+    Fifo8 rx_fifo;
+    Fifo8 tx_fifo;
+
+    uint8_t tx_thres;
+    uint8_t rx_thres;
+
+    int busy;
+    uint8_t bw;
+
+    /* I2S */
+    void *codec_i2c;
+    char *codec_name;
+    uint8_t codec_addr;
+    void *codec;
+    void (*codec_out)(void *, uint32_t);
+    uint32_t (*codec_in)(void *);
+
+    /* DMA hardware handshake */
+    qemu_irq req[2];    /* 0 - Tx, 1 - Rx */
+
+    /* HW register caches */
+
+    uint32_t cr0;
+    uint32_t cr1;
+    uint32_t cr2;
+    uint32_t icr;    /* interrupt control register */
+    uint32_t isr;    /* interrupt status register */
+
+} ftssp010_state;
+
+#define FTSSP010(obj) \
+    OBJECT_CHECK(ftssp010_state, obj, TYPE_FTSSP010)
+
+/* Update interrupts.  */
+static void ftssp010_update(ftssp010_state *s)
+{
+    if (!(s->cr2 & CR2_SSPEN)) {
+        return;
+    }
+
+    /* tx fifo status update */
+    if ((s->tx_fifo.num / (s->bw >> 3)) <= s->tx_thres) {
+        s->isr |=  ISR_TFTHI;
+        if (s->icr & ICR_TFDMA) {
+            qemu_set_irq(s->req[0], 1);
+        }
+    } else {
+        s->isr &= ~ISR_TFTHI;
+    }
+
+    /* rx fifo status update */
+    switch (s->cr0 & 0x00007000) {
+    case CR0_FFMT_SPI:
+        s->isr |=  ISR_RFTHI;
+        if (s->icr & ICR_RFDMA) {
+            qemu_set_irq(s->req[1], 1);
+        }
+        break;
+    default:
+        if ((s->rx_fifo.num / (s->bw >> 3)) >= s->rx_thres) {
+            s->isr |=  ISR_RFTHI;
+            if (s->icr & ICR_RFDMA) {
+                qemu_set_irq(s->req[1], 1);
+            }
+        } else {
+            s->isr &= ~ISR_RFTHI;
+        }
+        break;
+    }
+
+    /* update the interrupt signal */
+    if ((s->icr & s->isr) & 0x0f) {
+        qemu_set_irq(s->irq, 1);
+    } else {
+        qemu_set_irq(s->irq, 0);
+    }
+}
+
+static void ftssp010_handle_ack(void *opaque, int line, int level)
+{
+    ftssp010_state *s = FTSSP010(opaque);
+
+    switch (line) {
+    case 0:    /* Tx */
+        if (s->icr & ICR_TFDMA) {
+            if (level) {
+                qemu_set_irq(s->req[0], 0);
+            }
+            if ((s->tx_fifo.num / (s->bw >> 3)) <= s->tx_thres) {
+                qemu_set_irq(s->req[0], 1);
+            }
+        }
+        break;
+    case 1:    /* Rx */
+        if (s->icr & ICR_RFDMA) {
+            if (level) {
+                qemu_set_irq(s->req[1], 0);
+            }
+            switch (s->cr0 & 0x00007000) {
+            case CR0_FFMT_SPI:
+                qemu_set_irq(s->req[1], 1);
+                break;
+            default:
+                if ((s->rx_fifo.num / (s->bw >> 3)) >= s->rx_thres) {
+                    qemu_set_irq(s->req[1], 1);
+                }
+                break;
+            }
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static void ftssp010_i2s_data_req(void *opaque, int tx, int rx)
+{
+    int len;
+    uint32_t sample;
+    ftssp010_state *s = FTSSP010(opaque);
+
+    if (!(s->cr2 & CR2_SSPEN)) {
+        return;
+    }
+
+    if ((s->cr0 & 0x00007000) != CR0_FFMT_I2S) {
+        return;
+    }
+
+    s->busy = 1;
+
+    if ((s->cr2 & (CR2_TXEN | CR2_TXDOE)) == (CR2_TXEN | CR2_TXDOE)) {
+        len = tx * (s->bw / 8);
+        while (!fifo8_is_empty(&s->tx_fifo) && len > 0) {
+            sample = fifo8_pop(&s->tx_fifo) << 0;
+            --len;
+            if (s->bw > 8) {
+                sample |= fifo8_pop(&s->tx_fifo) << 8;
+                --len;
+            }
+            if (s->bw > 16) {
+                sample |= fifo8_pop(&s->tx_fifo) << 16;
+                --len;
+            }
+            if (s->bw > 24) {
+                sample |= fifo8_pop(&s->tx_fifo) << 24;
+                --len;
+            }
+            s->codec_out(s->codec, sample);
+        }
+
+        if (fifo8_is_empty(&s->tx_fifo) && len > 0) {
+            s->isr |= ISR_TFURI;
+        }
+    }
+
+    if (s->cr2 & CR2_RXEN) {
+        len = rx * (s->bw / 8);
+        while (!fifo8_is_full(&s->rx_fifo) && len > 0) {
+            sample = s->codec_in(s->codec);
+            fifo8_push(&s->rx_fifo, (sample >>  0) & 0xff);
+            --len;
+            if (s->bw > 8) {
+                fifo8_push(&s->rx_fifo, (sample >>  8) & 0xff);
+                --len;
+            }
+            if (s->bw > 16) {
+                fifo8_push(&s->rx_fifo, (sample >> 16) & 0xff);
+                --len;
+            }
+            if (s->bw > 24) {
+                fifo8_push(&s->rx_fifo, (sample >> 24) & 0xff);
+                --len;
+            }
+        }
+
+        if (fifo8_is_full(&s->rx_fifo) && len > 0) {
+            s->isr |= ISR_RFORI;
+        }
+    }
+
+    s->busy = 0;
+
+    ftssp010_update(s);
+}
+
+static void ftssp010_spi_tx(ftssp010_state *s)
+{
+    if (!(s->cr2 & CR2_TXEN)) {
+        return;
+    }
+
+    s->busy = 1;
+
+    if (fifo8_is_empty(&s->tx_fifo)) {
+        s->isr |= ISR_TFURI;
+    }
+
+    while (!fifo8_is_empty(&s->tx_fifo)) {
+        ssi_transfer(s->spi, fifo8_pop(&s->tx_fifo));
+    }
+
+    s->busy = 0;
+}
+
+static uint64_t ftssp010_mem_read(void *opaque, hwaddr addr, unsigned size)
+{
+    ftssp010_state *s = FTSSP010(opaque);
+    uint32_t rc = 0;
+
+    switch (addr) {
+    case REG_CR0:    /* Control Register 0 */
+        return s->cr0;
+    case REG_CR1:    /* Control Register 1 */
+        return s->cr1;
+    case REG_CR2:    /* Control Register 2 */
+        return s->cr2;
+    case REG_STR:    /* Status Register */
+        rc |= s->busy ? 0x04 : 0x00;
+        /* tx fifo status */
+        rc |= STR_TFVE(s->tx_fifo.num / (s->bw >> 3));
+        if (!fifo8_is_full(&s->tx_fifo)) {
+            rc |= STR_TFNF;
+        }
+        /* rx fifo status */
+        switch (s->cr0 & 0x00007000) {
+        case CR0_FFMT_SPI:
+            rc |= STR_RFF | STR_RFVE(CFG_FIFO_DEPTH);
+            break;
+        case CR0_FFMT_I2S:
+            rc |= STR_RFVE(s->rx_fifo.num / (s->bw >> 3));
+            if (fifo8_is_full(&s->rx_fifo)) {
+                rc |= STR_RFF;
+            }
+            break;
+        default:
+            break;
+        }
+        break;
+    case REG_ICR:    /* Interrupt Control Register */
+        return s->icr;
+    case REG_ISR:    /* Interrupt Status Register */
+        rc = s->isr;
+        s->isr &= 0xffffffec;    /* Clear BIT0, BIT1, BIT4 */
+        ftssp010_update(s);
+        break;
+    case REG_DTR:    /* Data Register */
+        if (!(s->cr2 & CR2_SSPEN)) {
+            break;
+        }
+        if (!(s->cr2 & CR2_RXEN)) {
+            break;
+        }
+        switch (s->cr0 & 0x00007000) {
+        case CR0_FFMT_SPI:
+            rc |= (uint32_t)(ssi_transfer(s->spi, 0x00) & 0xff) << 0;
+            if (s->bw > 8) {
+                rc |= (uint32_t)(ssi_transfer(s->spi, 0x00) & 0xff) << 8;
+            }
+            if (s->bw > 16) {
+                rc |= (uint32_t)(ssi_transfer(s->spi, 0x00) & 0xff) << 16;
+            }
+            if (s->bw > 24) {
+                rc |= (uint32_t)(ssi_transfer(s->spi, 0x00) & 0xff) << 24;
+            }
+            break;
+        case CR0_FFMT_I2S:
+            if (!fifo8_is_empty(&s->rx_fifo)) {
+                rc |= fifo8_pop(&s->rx_fifo);
+            }
+            if (!fifo8_is_empty(&s->rx_fifo) && s->bw > 8) {
+                rc |= fifo8_pop(&s->rx_fifo) << 8;
+            }
+            if (!fifo8_is_empty(&s->rx_fifo) && s->bw > 16) {
+                rc |= fifo8_pop(&s->rx_fifo) << 16;
+            }
+            if (!fifo8_is_empty(&s->rx_fifo) && s->bw > 24) {
+                rc |= fifo8_pop(&s->rx_fifo) << 24;
+            }
+            break;
+        default:
+            break;
+        }
+        ftssp010_update(s);
+        break;
+    case REG_VER:
+        return 0x00011901;    /* ver. 1.19.1 */
+    case REG_FEA:
+        return 0x660f0f1f;    /* SPI+I2S, FIFO=16 */
+    default:
+        break;
+    }
+
+    return rc;
+}
+
+static void ftssp010_mem_write(void    *opaque,
+                               hwaddr   addr,
+                               uint64_t val,
+                               unsigned size)
+{
+    ftssp010_state *s = FTSSP010(opaque);
+
+    switch (addr) {
+    case REG_CR0:    /* Control Register 0 */
+        s->cr0 = (uint32_t)val;
+        break;
+    case REG_CR1:    /* Control Register 1 */
+        s->cr1 = (uint32_t)val;
+        s->bw  = ((s->cr1 >> 16) & 0x3f) + 1;
+        break;
+    case REG_CR2:    /* Control Register 2 */
+        s->cr2 = (uint32_t)val;
+        if (s->cr2 & CR2_SSPRST) {
+            fifo8_reset(&s->tx_fifo);
+            fifo8_reset(&s->rx_fifo);
+            s->busy = 0;
+            s->cr2 &= ~(CR2_SSPRST | CR2_TXFCLR | CR2_RXFCLR);
+            if (s->cr0 & CR0_FLASH) {
+                int cs = (s->cr2 >> 10) & 0x03;
+                qemu_set_irq(s->cs_lines[cs], 1);
+                s->cr2 |= CR2_FS;
+            };
+        }
+        if (s->cr2 & CR2_TXFCLR) {
+            fifo8_reset(&s->tx_fifo);
+            s->cr2 &= ~CR2_TXFCLR;
+        }
+        if (s->cr2 & CR2_RXFCLR) {
+            fifo8_reset(&s->rx_fifo);
+            s->cr2 &= ~CR2_RXFCLR;
+        }
+        if (s->cr0 & CR0_FLASH) {
+            int cs = (s->cr2 >> 10) & 0x03;
+            qemu_set_irq(s->cs_lines[cs], (s->cr2 & CR2_FS) ? 1 : 0);
+        }
+        if (s->cr2 & CR2_SSPEN) {
+            switch (s->cr0 & 0x00007000) {
+            case CR0_FFMT_SPI:
+                ftssp010_spi_tx(s);
+                break;
+            default:
+                break;
+            }
+        }
+        ftssp010_update(s);
+        break;
+    case REG_ICR:    /* Interrupt Control Register */
+        s->icr = (uint32_t)val;
+        s->tx_thres = (s->icr >> 12) & 0x1f;
+        s->rx_thres = (s->icr >>  7) & 0x1f;
+        break;
+    case REG_DTR:    /* Data Register */
+        if (!(s->cr2 & CR2_SSPEN)) {
+            break;
+        }
+        if (!fifo8_is_full(&s->tx_fifo)) {
+            fifo8_push(&s->tx_fifo, (uint8_t)val);
+        }
+        if (!fifo8_is_full(&s->tx_fifo) && s->bw > 8) {
+            fifo8_push(&s->tx_fifo, (uint8_t)(val >> 8));
+        }
+        if (!fifo8_is_full(&s->tx_fifo) && s->bw > 16) {
+            fifo8_push(&s->tx_fifo, (uint8_t)(val >> 16));
+        }
+        if (!fifo8_is_full(&s->tx_fifo) && s->bw > 24) {
+            fifo8_push(&s->tx_fifo, (uint8_t)(val >> 24));
+        }
+        switch (s->cr0 & 0x00007000) {
+        case CR0_FFMT_SPI:
+            ftssp010_spi_tx(s);
+            break;
+        default:
+            break;
+        }
+        ftssp010_update(s);
+        break;
+    default:
+        break;
+    }
+}
+
+static const MemoryRegionOps ftssp010_ops = {
+    .read  = ftssp010_mem_read,
+    .write = ftssp010_mem_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 4
+    }
+};
+
+static void ftssp010_reset(DeviceState *ds)
+{
+    SysBusDevice *busdev = SYS_BUS_DEVICE(ds);
+    ftssp010_state *s = FTSSP010(FROM_SYSBUS(ftssp010_state, busdev));
+
+    s->busy = 0;
+    s->bw   = 8;
+
+    s->cr0 = 0;
+    s->cr1 = 0;
+    s->cr2 = 0;
+    s->icr = 0x00002200;
+    s->isr = 0x00000008;
+
+    s->tx_thres = 0;
+    s->rx_thres = 0;
+
+    fifo8_reset(&s->tx_fifo);
+    fifo8_reset(&s->rx_fifo);
+
+    ftssp010_update(s);
+}
+
+static int ftssp010_init(SysBusDevice *dev)
+{
+    ftssp010_state *s = FTSSP010(FROM_SYSBUS(ftssp010_state, dev));
+    int i;
+
+    s->spi = ssi_create_bus(&dev->qdev, "spi");
+
+    fifo8_create(&s->tx_fifo, CFG_FIFO_DEPTH * 4);
+    fifo8_create(&s->rx_fifo, CFG_FIFO_DEPTH * 4);
+
+    memory_region_init_io(&s->mmio,
+                          &ftssp010_ops,
+                          s,
+                          TYPE_FTSSP010,
+                          0x1000);
+    sysbus_init_mmio(dev, &s->mmio);
+    sysbus_init_irq(dev, &s->irq);
+
+    s->num_cs = 4;
+    s->cs_lines = g_new(qemu_irq, s->num_cs);
+    ssi_auto_connect_slaves(DEVICE(s), s->cs_lines, s->spi);
+    for (i = 0; i < s->num_cs; ++i) {
+        sysbus_init_irq(dev, &s->cs_lines[i]);
+    }
+
+    /* DMA hardware handshake */
+    qdev_init_gpio_in(&s->busdev.qdev, ftssp010_handle_ack, 2);
+    qdev_init_gpio_out(&s->busdev.qdev, s->req, 2);
+
+    /* I2S */
+    if (s->codec_i2c) {
+        DeviceState *wm;
+        const char *id = s->codec_name ? s->codec_name : "wm8731";
+
+        printf("[qemu] ftssp010: i2c bus registered,"
+               " connecting codec[%s:0x%x]...\n",
+               id, s->codec_addr);
+
+        /* Attach a codec to the bus */
+        wm = i2c_create_slave(s->codec_i2c, id, s->codec_addr);
+        s->codec = wm;
+        if (!strcmp(id, "wm8731")) {
+            s->codec_out = wm8731_dac_dat;
+            s->codec_in  = wm8731_adc_dat;
+            wm8731_data_req_set(wm, ftssp010_i2s_data_req, s);
+        } else if (!strcmp(id, "wm8750")) {
+            s->codec_out = wm8750_dac_dat;
+            s->codec_in  = wm8750_adc_dat;
+            wm8750_data_req_set(wm, ftssp010_i2s_data_req, s);
+        } else {
+            printf("[qemu] ftssp010: unknown codec [%s] ?\n", id);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static Property ftssp010_properties[] = {
+    DEFINE_PROP_PTR("codec_i2c",  ftssp010_state, codec_i2c),
+    DEFINE_PROP_STRING("codec_name", ftssp010_state, codec_name),
+    DEFINE_PROP_UINT8("codec_addr", ftssp010_state, codec_addr, 0x1B),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription vmstate_ftssp010 = {
+    .name = TYPE_FTSSP010,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(cr0, ftssp010_state),
+        VMSTATE_UINT32(cr1, ftssp010_state),
+        VMSTATE_UINT32(cr2, ftssp010_state),
+        VMSTATE_UINT32(icr, ftssp010_state),
+        VMSTATE_UINT32(isr, ftssp010_state),
+        VMSTATE_FIFO8(tx_fifo, ftssp010_state),
+        VMSTATE_FIFO8(rx_fifo, ftssp010_state),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void ftssp010_class_init(ObjectClass *klass, void *data)
+{
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    k->init     = ftssp010_init;
+    dc->vmsd    = &vmstate_ftssp010;
+    dc->props   = ftssp010_properties;
+    dc->reset   = ftssp010_reset;
+    dc->no_user = 1;
+}
+
+static const TypeInfo ftssp010_info = {
+    .name           = TYPE_FTSSP010,
+    .parent         = TYPE_SYS_BUS_DEVICE,
+    .instance_size  = sizeof(ftssp010_state),
+    .class_init     = ftssp010_class_init,
+};
+
+static void ftssp010_register_types(void)
+{
+    type_register_static(&ftssp010_info);
+}
+
+type_init(ftssp010_register_types)
diff --git a/hw/ftssp010.h b/hw/ftssp010.h
new file mode 100644
index 0000000..8dacb6d
--- /dev/null
+++ b/hw/ftssp010.h
@@ -0,0 +1,91 @@ 
+/*
+ * QEMU model of the FTSSP010 Controller
+ *
+ * Copyright (C) 2012 Faraday Technology
+ * Written by Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is licensed under GNU GPL.
+ */
+
+#ifndef FTSSP010_H
+#define FTSSP010_H
+
+/* FTSSP010: Registers */
+#define REG_CR0             0x00
+#define REG_CR1             0x04
+#define REG_CR2             0x08
+#define REG_STR             0x0C
+#define REG_ICR             0X10
+#define REG_ISR             0x14
+#define REG_DTR             0x18
+#define REG_VER             0x60
+#define REG_FEA             0x64
+
+/* Control register 0  */
+
+#define CR0_FFMT_SSP        (0 << 12)
+#define CR0_FFMT_SPI        (1 << 12)
+#define CR0_FFMT_MICROWIRE  (2 << 12)
+#define CR0_FFMT_I2S        (3 << 12)
+#define CR0_FFMT_AC97       (4 << 12)
+#define CR0_FLASH           (1 << 11)
+#define CR0_FSDIST(x)       (((x) & 0x03) << 8)
+#define CR0_LBM             (1 << 7)  /* Loopback mode */
+#define CR0_LSB             (1 << 6)  /* LSB first */
+#define CR0_FSPO            (1 << 5)  /* Frame sync atcive low */
+#define CR0_FSJUSTIFY       (1 << 4)
+#define CR0_OPM_SLAVE       (0 << 2)
+#define CR0_OPM_MASTER      (3 << 2)
+#define CR0_OPM_I2S_MSST    (3 << 2)  /* Master stereo mode */
+#define CR0_OPM_I2S_MSMO    (2 << 2)  /* Master mono mode */
+#define CR0_OPM_I2S_SLST    (1 << 2)  /* Slave stereo mode */
+#define CR0_OPM_I2S_SLMO    (0 << 2)  /* Slave mono mode */
+#define CR0_SCLKPO          (1 << 1)  /* SCLK Remain HIGH */
+#define CR0_SCLKPH          (1 << 0)  /* Half CLK cycle */
+
+/* Control Register 1 */
+
+/* padding data length */
+#define CR1_PDL(x)          (((x) & 0xff) << 24)
+/* serial data length(actual data length-1) */
+#define CR1_SDL(x)          ((((x) - 1) & 0x1f) << 16)
+/*  clk divider */
+#define CR1_CLKDIV(x)       ((x) & 0xffff)
+
+/* Control Register 2 */
+#define CR2_FSOS(x)         (((x) & 0x03) << 10)        /* FS/CS Select */
+#define CR2_FS              (1 << 9)    /* FS/CS Signal Level */
+#define CR2_TXEN            (1 << 8)    /* Tx Enable */
+#define CR2_RXEN            (1 << 7)    /* Rx Enable */
+#define CR2_SSPRST          (1 << 6)    /* SSP reset */
+#define CR2_TXFCLR          (1 << 3)    /* TX FIFO Clear */
+#define CR2_RXFCLR          (1 << 2)    /* RX FIFO Clear */
+#define CR2_TXDOE           (1 << 1)    /* TX Data Output Enable */
+#define CR2_SSPEN           (1 << 0)    /* SSP Enable */
+
+/*
+ * Status Register
+ */
+#define STR_TFVE(reg)       (((reg) & 0x1F) << 12)
+#define STR_RFVE(reg)       (((reg) & 0x1F) << 4)
+#define STR_BUSY            (1 << 2)
+#define STR_TFNF            (1 << 1)    /* Tx FIFO Not Full */
+#define STR_RFF             (1 << 0)    /* Rx FIFO Full */
+
+/* Interrupr Control Register */
+#define ICR_TFTHOD(x)       (((x) & 0x0f) << 12)/* TX FIFO Threshold */
+#define ICR_RFTHOD(x)       (((x) & 0x0f) << 8) /* RX FIFO Threshold */
+#define ICR_TFDMA           0x20      /* TX DMA Enable */
+#define ICR_RFDMA           0x10      /* RX DMA Enable */
+#define ICR_TFTHI           0x08      /* TX FIFO Int Enable */
+#define ICR_RFTHI           0x04      /* RX FIFO Int Enable */
+#define ICR_TFURI           0x02      /* TX FIFO Underrun int enable */
+#define ICR_RFORI           0x01      /* RX FIFO Overrun int enable */
+
+/* Interrupr Status Register */
+#define ISR_TFTHI           0x08      /* TX FIFO Int Enable */
+#define ISR_RFTHI           0x04      /* RX FIFO Int Enable */
+#define ISR_TFURI           0x02      /* TX FIFO Underrun int enable */
+#define ISR_RFORI           0x01      /* RX FIFO Overrun int enable */
+
+#endif