#ifndef PARASOFT_CPPTEST

#ifdef  __cplusplus
extern "C"
{
#endif

#include "DSPCommon.h"
#include "adrs_map.h"
#include "proc_def_sio.h"

void init_sio(void)
{
    // clkin = 72MHz, clkout = 6MHz

    SetReg32(REG_SIO0_SSPCR0, ((1 << 8) |  // bit15-8 SCR
			       (1 << 7) |  // bit7    SPH
			       (1 << 6) |  // bit6    SPO
			       (0 << 4) |  // bit5-4  FRF
			       (7 << 0))); // bit3-0  DSS

    SetReg32(REG_SIO0_SSPCR1, ((0 << 3) |  // bit3    SOD
			       (0 << 2) |  // bit2    MS
			       (0 << 1) |  // bit1    SSE
			       (0 << 0))); // bit0    LBM


    SetReg32(REG_SIO0_SSPCPSR, 6);         // bit7-0  CPSDVSR
}

void set_sio_fifo(UInt8 *wdata, UInt8 size, UInt8 lsbf)
{
    int i;
    UInt8 wdata_msbf, wdata_lsbf, wdata_q;

    for (i = 0; i < size; i++) {
        wdata_msbf = *wdata;
        wdata_lsbf = ((((wdata_msbf & 0x1)  >> 0) << 7) |
                      (((wdata_msbf & 0x2)  >> 1) << 6) |
                      (((wdata_msbf & 0x4)  >> 2) << 5) |
                      (((wdata_msbf & 0x8)  >> 3) << 4) |
                      (((wdata_msbf & 0x10) >> 4) << 3) |
                      (((wdata_msbf & 0x20) >> 5) << 2) |
                      (((wdata_msbf & 0x40) >> 6) << 1) |
                      (((wdata_msbf & 0x80) >> 7) << 0));

        wdata_q = (lsbf != 0) ? wdata_lsbf : wdata_msbf;

	SetReg32(REG_SIO0_SSPDR, wdata_q);
	wdata++;
    }
}

void get_sio_fifo(UInt8 *rdata, UInt8 size, UInt8 lsbf)
{
    int i;
    UInt8 rdata_msbf;

    for (i = 0; i < size; i++) {
	rdata_msbf = GetReg32(REG_SIO0_SSPDR) & 0xff;

        if (lsbf != 0) {
            *rdata = ((((rdata_msbf & 0x1)  >> 0) << 7) |
                      (((rdata_msbf & 0x2)  >> 1) << 6) |
                      (((rdata_msbf & 0x4)  >> 2) << 5) |
                      (((rdata_msbf & 0x8)  >> 3) << 4) |
                      (((rdata_msbf & 0x10) >> 4) << 3) |
                      (((rdata_msbf & 0x20) >> 5) << 2) |
                      (((rdata_msbf & 0x40) >> 6) << 1) |
                      (((rdata_msbf & 0x80) >> 7) << 0));
        } else {
            *rdata = rdata_msbf;
        }

	rdata++;
    }
}

UInt8 get_sio_status(void)
{
    // bit0 : TXFIFO empty
    // bit1 : TXFIFO not full
    // bit2 : RXFIFO not empty
    // bit3 : RXFIFO full
    // bit4 : SIO busy
    return (GetReg32(REG_SIO0_SSPSR) & 0xff);
}

void wait_sio_status(UInt8 mask, UInt8 comp)
{
/* xtensa PC(sim)時はskip */
#ifdef XT_GENERIC
    while(1) {
	if (comp == (get_sio_status() & mask))
	    break;
    }
#endif /* XT_GENERIC */
}

void start_sio(void)
{
    SetRegFld32(REG_SIO0_SSPCR1, (1 << 1));  // bit1    SSE
}

void stop_sio(void)
{
    ClrRegFld32(REG_SIO0_SSPCR1, (1 << 1));  // bit1    SSE
}


UInt8 _get_cmos_cid_base(UInt16 addr)
{
    return ((addr & 0xff00) >> 8);
}

void set_sio_cmos_register(UInt16 addr, UInt8 wdata)
{
    UInt8 wbuf[3], rbuf[3];
    wbuf[0] = _get_cmos_cid_base(addr);
    wbuf[1] = addr & 0xff;
    wbuf[2] = wdata;

    set_sio_fifo(wbuf, 3, 1);
    start_sio();
    wait_sio_status((SIO_SSPSR_BSY | SIO_SSPSR_TFE), (!SIO_SSPSR_BSY | SIO_SSPSR_TFE));
    stop_sio();
    get_sio_fifo(rbuf, 3, 1);
}

void set_sio_cmos_shutter(UInt16 addr, UInt32 wdata)
{
    UInt8 wbuf[5];
	UInt8 rbuf[5];	// for debug
    wbuf[0] = _get_cmos_cid_base(addr);
    wbuf[1] = addr & 0xff;
	wbuf[2] = (UInt8)(wdata & 0x000000FFL);
	wbuf[3] = (UInt8)((wdata >> 8) & 0x000000FFL);
	wbuf[4] = (UInt8)((wdata >> 16) & 0x00000001L);

    set_sio_fifo(wbuf, 5, 1);
    start_sio();
    wait_sio_status((SIO_SSPSR_BSY | SIO_SSPSR_TFE), (!SIO_SSPSR_BSY | SIO_SSPSR_TFE));
    stop_sio();
    get_sio_fifo(rbuf, 5, 1);	// for debug
}

void set_sio_cmos_gain(UInt16 addr, UInt32 wdata)
{
    UInt8 wbuf[5];
	UInt8 rbuf[5];	// for debug
    wbuf[0] = _get_cmos_cid_base(addr);
    wbuf[1] = addr & 0xff;
	wbuf[2] = (UInt8)(wdata & 0x000000FFL);
	wbuf[3] = (UInt8)((wdata >> 8) & 0x000000FFL);

    set_sio_fifo(wbuf, 4, 1);
    start_sio();
    wait_sio_status((SIO_SSPSR_BSY | SIO_SSPSR_TFE), (!SIO_SSPSR_BSY | SIO_SSPSR_TFE));
    stop_sio();
    get_sio_fifo(rbuf, 5, 1);	// for debug
}

UInt8 get_sio_cmos_register(UInt16 addr)
{
    UInt8 wbuf[3], rbuf[3];
    wbuf[0] = _get_cmos_cid_base(addr) | 0x80;
    wbuf[1] = addr & 0xff;
    wbuf[2] = 0;

    set_sio_fifo(wbuf, 3, 1);
    start_sio();
    wait_sio_status((SIO_SSPSR_BSY | SIO_SSPSR_TFE), (!SIO_SSPSR_BSY | SIO_SSPSR_TFE));
    stop_sio();
    get_sio_fifo(rbuf, 3, 1);

    return rbuf[2];
}

UInt32 get_sio_cmos_shutter(UInt16 addr)
{
    UInt8 wbuf[5], rbuf[5];
    wbuf[0] = _get_cmos_cid_base(addr) | 0x80;
    wbuf[1] = addr & 0xff;
    wbuf[2] = 0;
    wbuf[3] = 0;
    wbuf[4] = 0;

    set_sio_fifo(wbuf, 5, 1);
    start_sio();
    wait_sio_status((SIO_SSPSR_BSY | SIO_SSPSR_TFE), (!SIO_SSPSR_BSY | SIO_SSPSR_TFE));
    stop_sio();
    get_sio_fifo(rbuf, 5, 1);

	return (rbuf[2] | (rbuf[3] << 8) | (rbuf[4] << 16));
}
	
UInt32 get_sio_cmos_gain(UInt16 addr)
{
    UInt8 wbuf[5], rbuf[5];
    wbuf[0] = _get_cmos_cid_base(addr) | 0x80;
    wbuf[1] = addr & 0xff;
    wbuf[2] = 0;
    wbuf[3] = 0;

    set_sio_fifo(wbuf, 4, 1);
    start_sio();
    wait_sio_status((SIO_SSPSR_BSY | SIO_SSPSR_TFE), (!SIO_SSPSR_BSY | SIO_SSPSR_TFE));
    stop_sio();
    get_sio_fifo(rbuf, 4, 1);

	return (rbuf[2] | (rbuf[3] << 8) );
}

#ifdef  __cplusplus
}
#endif

#endif  //  PARASOFT_CPPTEST
