Example #1
0
int
nanospin(const struct timespec *rqtp) {
    if(rqtp->tv_sec > 0) {
		return E2BIG;
	}
	return nanospin_ns(rqtp->tv_nsec);
}
static int _hsmci_wait_stat (SIM_HBA *hba, mmc_cmd_t *cmd)
{
	SIM_MMC_EXT	*ext;
	hsmci_ext_t	*hsmci;
	uintptr_t	base;
	uint32_t	mask = CMDRDY;

	ext = (SIM_MMC_EXT *)hba->ext;
	hsmci = (hsmci_ext_t *)ext->handle;
	base = hsmci->base;

	if (cmd->eflags & MMC_CMD_DATA)  {
		mask |= NOTBUSY | XFRDONE;
	}

	int timeout = TIMEOUT_LOOPS/100;
	while (((READ32(MCI_SR) & mask) != mask) && timeout--)
		nanospin_ns(100);

	if (timeout <= 0) {
		slogf (_SLOGC_SIM_MMC, _SLOG_ERROR, "MMC: timeout on waiting for MCI_SR: 0x%x for CMD%d, mask: 0x%x", READ32(MCI_SR), cmd->opcode, mask);
		return MMC_FAILURE;
	}

	return MMC_SUCCESS;
}
Example #3
0
static void seromap_enable(DEV_OMAP *dev, int enable)
{
	uintptr_t		*port = dev->port;

	write_omap(port[OMAP_UART_LCR], 0x80);

	if (!enable) {
		atomic_set(&dev->pwm_flag, SEROMAP_PWM_PAGED);

		// If HW flow control is ON, assert the RTS line
		if (dev->tty.c_cflag & IHFLOW)
			set_port(port[OMAP_UART_MCR], OMAP_MCR_DTR|OMAP_MCR_RTS, 0);

		while (!(read_omap(port[OMAP_UART_LSR]) & OMAP_LSR_TSRE))
			;
		nanospin_ns(1000000);			// pause for 1ms
		write_omap(port[OMAP_UART_MDR1], 0x07);
		write_omap(port[OMAP_UART_DLL], 0xFF);
		write_omap(port[OMAP_UART_DLH], 0xFF);
	}
	else {
		write_omap(port[OMAP_UART_DLL], dev->brd);
		write_omap(port[OMAP_UART_DLH], (dev->brd >> 8) & 0xff);
		write_omap(port[OMAP_UART_MDR1], 0x00);

		// If HW flow control is ON, de-assert the RTS line
		if(dev->tty.c_cflag & IHFLOW)
			set_port(port[OMAP_UART_MCR], OMAP_MCR_DTR|OMAP_MCR_RTS, OMAP_MCR_DTR|OMAP_MCR_RTS);

		// Allow data transmission to resume
		atomic_clr(&dev->pwm_flag, SEROMAP_PWM_PAGED);
	}

	write_omap(port[OMAP_UART_LCR], dev->lcr);
}
Example #4
0
static int omap_pio_done( SIM_HBA *hba, char *buf, int len, int dir )
{
	SIM_MMC_EXT		*ext;
	omap_ext_t		*oext;
	uintptr_t		base;
	int				cnt;
	int				nbytes;
	uint32_t		*pbuf;

	ext		= (SIM_MMC_EXT *)hba->ext;
	oext	= (omap_ext_t *)ext->handle;
	base	= oext->mmc_base;
	pbuf	= (uint32_t *)buf;

	cnt = nbytes = len < MMCHS_FIFO_SIZE ? len : MMCHS_FIFO_SIZE;

	if( dir == MMC_DIR_IN ) {
		if( !( in32( base + OMAP_MMCHS_PSTATE ) & PSTATE_BRE ) ) {
			out32( base + OMAP_MMCHS_IE, INTR_BRR );
			return( 0 );
		}

		for( ; nbytes > 0; nbytes -= 4 ) {
			*pbuf++ = in32( base + OMAP_MMCHS_DATA );
		}

		if( len < MMCHS_FIFO_SIZE ) {
			int		cnt;

			for( cnt = 2000; cnt; cnt-- ) {
				if( !( in32( base + OMAP_MMCHS_PSTATE ) & PSTATE_RTA ) ) {
					break;
				}
				nanospin_ns( 1000 );
			}
		}
	}
	else {
		if( !( in32( base + OMAP_MMCHS_PSTATE ) & PSTATE_BWE ) ) {
			out32( base + OMAP_MMCHS_IE, INTR_BWR );
			return( 0 );
		}

		for( ; nbytes > 0; nbytes -= 4 ) {
			out32( base + OMAP_MMCHS_DATA, *pbuf++ );
		}

		if( len == cnt ) {
			out32( base + OMAP_MMCHS_IE, INTR_TC );
		}
	}

	return( cnt );
}
Example #5
0
static	int	mpc5125_set_clock (mpc5125_ext_t *ext, int divisor)

{
mpc5125_mmc_reg	*mmc = (mpc5125_mmc_reg *) ext->mmc_base;
int				to;

	if (mmc->sd_status & 0x100) {
		mmc->sd_str_stp_clk = 1;

		for (to = MPC5125_MMC_TMOUT; to > 0; to--) {
			if ((mmc->sd_status & 0x100) == 0)
				break;
			nanospin_ns(100);;
			}

		if (to == 0) {
			slogf (_SLOGC_SIM_MMC, _SLOG_ERROR, "MMC: mpc5125_set_clock(): timeout to get SD clock stopped");
			return -1;
			}
		}

	if (divisor < 8) {
		divisor = 0x80;
		}
	mmc->sd_clk_rate = divisor;
	mmc->sd_str_stp_clk = 2;

	for (to = MPC5125_MMC_TMOUT; to > 0; to--) {
		if (mmc->sd_status & 0x100) {
			return (MMC_SUCCESS);
			}
		nanospin_ns(100);;
		}

	return (-1);
}
Example #6
0
int nand_wait_busy(struct chipio *cio, uint32_t usec) {
	/* 
	 * Wait for NAND 
	 * Wait pins start at bit 8 of GPMC status register
	 * WAITxSTATUS Is a copy of input pin WAITx. (Reset value is WAITx input R xpin sampled at IC reset)
	 * 0x0: WAITx asserted (inactive state)
	 * 0x1: WAITx de-asserted
	 */
	while (usec--){
		if(OMAP_READ_GPMC_STATUS() & (OMAP_GPMC_WAITPIN0<<cio->wp))
			return 0;
		else
			nanospin_ns(1000);
	}
	return (-1);
}
Example #7
0
int esdhc_prsstat( SIM_HBA *hba, uint32_t value, uint32_t mask, uint32_t timeo )
{
    SIM_MMC_EXT		*ext;
    esdhc_ext_t		*esdhc;
    uintptr_t		base;
    uint32_t		prsstat;

    ext		= (SIM_MMC_EXT *)hba->ext;
    esdhc	= (esdhc_ext_t *)ext->handle;
    base	= esdhc->base;

    for( ; timeo && ( ( prsstat = in32( base + ESDHC_PRSSTAT ) ) & mask ) != value; timeo-- ) {
        nanospin_ns( 100 );
    }
    return( timeo ? MMC_SUCCESS : MMC_FAILURE );
}
Example #8
0
int omap_waitmask( SIM_HBA *hba, uint32_t reg, uint32_t mask, uint32_t val, uint32_t usec )
{
	SIM_MMC_EXT		*ext;
	omap_ext_t		*oext;
	uintptr_t		base;
	uint32_t		cnt;
	int				stat;
	int				rval;
	uint32_t		iter;

	ext		= (SIM_MMC_EXT *)hba->ext;
	oext	= (omap_ext_t *)ext->handle;
	base	= oext->mmc_base;
	stat	= MMC_FAILURE;
	rval	= MMC_SUCCESS;

		// fast poll for 1ms - 1us intervals
	for( cnt = min( usec, 1000 ); cnt; cnt-- ) {
		if( ( ( rval = in32( base + reg ) ) & mask ) == val ) {
			stat = MMC_SUCCESS;
			break;
		}
		nanospin_ns( 1000L );
	}

	if( usec > 1000 && stat ) {
		iter	= usec / 1000L;
		for( cnt = iter; cnt; cnt-- ) {
			if( ( ( rval = in32( base + reg ) ) & mask ) == val ) {
				stat = MMC_SUCCESS;
				break;
			}
			delay( 1 );
		}
	}

#ifdef OMAP_DEBUG
	if( !cnt ) {
		mmc_slogf( hba, _SLOGC_SIM_MMC, _SLOG_ERROR, 3, "%s: reg %x, mask %x, val %x, rval %x", __FUNCTION__, reg, mask, val, in32( base + reg ) ); 
	}
#endif

	return( stat );
}
static int omap3_interrupt(SIM_HBA *hba, int irq, int resp_type, uint32_t *resp)
{
    SIM_MMC_EXT		*ext;
    omap3_ext_t		*omap3;
    uint32_t		sts;
    int				intr = 0;
    uintptr_t		base;

    ext   = (SIM_MMC_EXT *)hba->ext;
    omap3 = (omap3_ext_t *)ext->handle;
    base  = omap3->mmc_base;

    sts = in32(base + OMAP3_MMCHS_STAT);
    sts &= in32(base + OMAP3_MMCHS_IE) | INTR_ERRI;
    out32(base + OMAP3_MMCHS_STAT, sts);

    if (sts & INTR_ERRI) {	// Any errors ?
        slogf(_SLOGC_SIM_MMC, _SLOG_ERROR, "OMAP3 interrupt error = %x", sts);
        intr |= MMC_INTR_ERROR | MMC_INTR_COMMAND;
        if (sts & INTR_DTO) {
            intr |= MMC_ERR_DATA_TO;
            out32(base + OMAP3_MMCHS_SYSCTL, in32(base + OMAP3_MMCHS_SYSCTL) | SYSCTL_SRD);
            while (in32(base + OMAP3_MMCHS_SYSCTL) & SYSCTL_SRD);
        }
        if (sts & INTR_DCRC)
            intr |= MMC_ERR_DATA_CRC;
        if (sts & INTR_DEB)
            intr |= MMC_ERR_DATA_END;

        if (sts & INTR_CTO) {
            intr |= MMC_ERR_CMD_TO;
            out32(base + OMAP3_MMCHS_SYSCTL, in32(base + OMAP3_MMCHS_SYSCTL) | SYSCTL_SRC);
            while (in32(base + OMAP3_MMCHS_SYSCTL) & SYSCTL_SRC);
        }
        if (sts & INTR_CCRC)
            intr |= MMC_ERR_CMD_CRC;
        if (sts & INTR_CEB)
            intr |= MMC_ERR_CMD_END;
        if (sts & INTR_CIE)
            intr |= MMC_ERR_CMD_IDX;
    } else {
        if (sts & INTR_CC) {
            intr |= MMC_INTR_COMMAND;
            if (resp) {
                if (resp_type & MMC_RSP_136) {
                    resp[3] = in32(base + OMAP3_MMCHS_RSP76);
                    resp[2] = in32(base + OMAP3_MMCHS_RSP54);
                    resp[1] = in32(base + OMAP3_MMCHS_RSP32);
                    resp[0] = in32(base + OMAP3_MMCHS_RSP10);
                } else if (resp_type & MMC_RSP_PRESENT)
                    resp[0] = in32(base + OMAP3_MMCHS_RSP10);
            }

            // Busy check?
            if (resp_type & MMC_RSP_BUSY) {
                int		i;

                for (i = 1024 * 256; i > 0; i--) {
                    if (in32(base + OMAP3_MMCHS_PSTATE) & PSTATE_DLA) {
                        nanospin_ns(1024);
                        continue;
                    }
                    break;
                }
                if (i <= 0) {
                    intr |= MMC_ERR_CMD_TO | MMC_INTR_ERROR;
                    slogf(_SLOGC_SIM_MMC, _SLOG_ERROR, "OMAP3 busy check time out");
                }
            }
        }

        if (sts & (INTR_TC | INTR_BWR | INTR_BRR)) {
            if (sts & INTR_TC)
                intr |= MMC_INTR_DATA;
            if (sts & INTR_BRR)
                intr |= MMC_INTR_RBRDY;
            if (sts & INTR_BWR)
                intr |= MMC_INTR_WBRDY;

        }
    }

    if (intr)
        out32(base + OMAP3_MMCHS_IE, 0);

    return intr;
}
Example #10
0
DEV_OMAP *
create_device(TTYINIT_OMAP *dip, unsigned unit, unsigned maxim_xcvr_kick) {
	DEV_OMAP 			*dev;
	unsigned			i;
	uintptr_t			port;
	unsigned char		msr;
	unsigned char		tlr = 0, tcr = 0;
#ifdef PWR_MAN
    clk_enable_t        clk_cfg = clk_enable_none;
#endif

	// Get a device entry and the input/output buffers for it.
	if ((dev = malloc(sizeof(*dev))) == NULL)
	{
		slogf(_SLOG_SETCODE(_SLOGC_CHAR, 0), _SLOG_ERROR, "io-char: Allocation of device entry failed (%d)", errno);
		return (dev);
	}	
	memset(dev, 0, sizeof(*dev));

	// Get buffers.
	dev->tty.ibuf.head = dev->tty.ibuf.tail = dev->tty.ibuf.buff = malloc(dev->tty.ibuf.size = dip->tty.isize);
	if (dev->tty.ibuf.buff == NULL)
	{
		slogf(_SLOG_SETCODE(_SLOGC_CHAR, 0), _SLOG_ERROR, "io-char: Allocation of input buffer failed (%d)", errno);
		free(dev);
		return (NULL);
	}
						   
	dev->tty.obuf.head = dev->tty.obuf.tail = dev->tty.obuf.buff = malloc(dev->tty.obuf.size = dip->tty.osize);
	if (dev->tty.obuf.buff == NULL)
	{
		slogf(_SLOG_SETCODE(_SLOGC_CHAR, 0), _SLOG_ERROR, "io-char: Allocation of output buffer failed (%d)", errno);
		free(dev->tty.ibuf.buff);
		free(dev);
		return (NULL);
	}

	dev->tty.cbuf.head = dev->tty.cbuf.tail = dev->tty.cbuf.buff = malloc(dev->tty.cbuf.size = dip->tty.csize);
	if (dev->tty.cbuf.buff == NULL)
	{
		slogf(_SLOG_SETCODE(_SLOGC_CHAR, 0), _SLOG_ERROR, "io-char: Allocation of canonical buffer failed (%d)", errno);
		free(dev->tty.ibuf.buff);
		free(dev->tty.obuf.buff);
		free(dev);
		return (NULL);
	}

	if (dip->tty.highwater)
		dev->tty.highwater = dip->tty.highwater;
	else
		dev->tty.highwater = dev->tty.ibuf.size - (FIFO_SIZE * 2);

	strcpy(dev->tty.name, dip->tty.name);

	dev->tty.baud = dip->tty.baud;
	dev->tty.fifo = dip->tty.fifo;
	dev->tty.verbose = dip->tty.verbose;

	port = mmap_device_io(OMAP_UART_SIZE, dip->tty.port);
	for (i = 0; i < OMAP_UART_SIZE; i += 4)
		dev->port[i] = port + i;

	dev->intr = dip->tty.intr;
	dev->clk = dip->tty.clk;
	dev->div = dip->tty.div;

	dev->tty.flags = EDIT_INSERT | LOSES_TX_INTR;
	dev->tty.c_cflag = dip->tty.c_cflag;
	dev->tty.c_iflag = dip->tty.c_iflag;
	dev->tty.c_lflag = dip->tty.c_lflag;
	dev->tty.c_oflag = dip->tty.c_oflag;
	dev->tty.lflags = dip->tty.lflags;
	if (dip->tty.logging_path[0] != NULL)
		dev->tty.logging_path = strdup(dip->tty.logging_path);

#ifdef PWR_MAN
	dev->physbase = dip->tty.port;
	
	if (omap_clock_toggle_init(dev) != EOK)
	{
		slogf(_SLOG_SETCODE(_SLOGC_CHAR, 0), _SLOG_ERROR, "io-char: Fail to initialize clocks for PM!");
		free(dev->tty.ibuf.buff);
		free(dev->tty.obuf.buff);
		free(dev);
		return (NULL);
	}
#ifdef WINBT
    clk_cfg = clk_enable_smart_wkup;
    
	if (omap_force_rts_init(dev) != EOK)
	{
		slogf(_SLOG_SETCODE(_SLOGC_CHAR, 0), _SLOG_ERROR, "io-char: Fail to initialize force_rts for PM!");
		free(dev->tty.ibuf.buff);
		free(dev->tty.obuf.buff);
		free(dev);
		return (NULL);
	}
#endif

	omap_clock_enable(dev, clk_cfg);

#ifdef WINBT	
	bt_ctrl_init();
#endif	
#endif

	/* Set auto_rts mode */
	dev->auto_rts_enable = dip->auto_rts_enable;
	
	// Do not enable MSR interrupt                                                                                                        
	dev->no_msr_int  = dip->no_msr_int;   

	// Initialize termios cc codes to an ANSI terminal.
	ttc(TTC_INIT_CC, &dev->tty, 0);

	// Initialize the device's name.
	// Assume that the basename is set in device name.  This will attach
	// to the path assigned by the unit number/minor number combination
	unit = SET_NAME_NUMBER(unit) | NUMBER_DEV_FROM_USER;
	ttc(TTC_INIT_TTYNAME, &dev->tty, unit);

	// see if we have a maxim rs-232 transceiver that needs to be
	// kicked after it goes to sleep
	dev->kick_maxim = maxim_xcvr_kick;

	// Only setup IRQ handler for non-pcmcia devices.
	// Pcmcia devices will have this done later when card is inserted.
	if (dip->tty.port != 0 && dip->tty.intr != _NTO_INTR_SPARE) {
#ifdef OMAP5910
		/*
		 * Don't change default mode set in the very distant past. Even though
		 * MODE_SELECT should be DISABLE before changing DLH, DLL.
		 */
                // enable the UART
                write_omap(dev->port[OMAP_UART_MDR1], OMAP_MDR1_MODE_16X);
#else
		/*
		 * TRM states: Before initializing or modifying clock parameter controls
		 * (DLH, DLL), MODE_SELECT must be set to 0x7 (DISABLE). Failure to observe
		 * this rule can result in unpredictable module behavior.
		 */
		write_omap(dev->port[OMAP_UART_MDR1], OMAP_MDR1_MODE_DISABLE);
#endif
		/* Work around for silicon errata i202 states: */
		/* Need a delay = 5 L4 clock cycles + 5 UART functional clock cycle (@48MHz = ~0.2uS) */
		nanospin_ns(200);
		/* Clear FIFOs */
		set_port(dev->port[OMAP_UART_FCR], OMAP_FCR_RXCLR | OMAP_FCR_TXCLR, OMAP_FCR_RXCLR | OMAP_FCR_TXCLR);
		/* Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and TX_FIFO_E bit is 1 */
		i = 5;
		while ((read_omap(dev->port[OMAP_UART_LSR]) & (OMAP_UART_LSR_THRE | OMAP_UART_LSR_DR)) != OMAP_UART_LSR_THRE)
		{
		   nanospin_ns(200);
		   if (--i == 0)
		   {
		      break;  /* No need to do anything drastic if FIFO is still not empty */
		   }
		}
		// enable access to divisor registers
		write_omap(dev->port[OMAP_UART_LCR], OMAP_LCR_DLAB);
		write_omap(dev->port[OMAP_UART_DLL], 0);
		write_omap(dev->port[OMAP_UART_DLH], 0);

		/* Switch to config mode B to get access to EFR Register */
		write_omap(dev->port[OMAP_UART_LCR], 0xBF);
		/* Enable access to TLR register */
		set_port(dev->port[OMAP_UART_EFR], OMAP_EFR_ENHANCED, OMAP_EFR_ENHANCED);
		/* Switch to operational mode to get acces to MCR register */
		write_omap(dev->port[OMAP_UART_LCR], 0x00);
		/* set MCR bit 6 to enable access to TCR and TLR registers */
	    set_port(dev->port[OMAP_UART_MCR], OMAP_MCR_TCRTLR, OMAP_MCR_TCRTLR);
		write_omap(dev->port[OMAP_UART_FCR], OMAP_FCR_ENABLE|OMAP_FCR_RXCLR|OMAP_FCR_TXCLR);

		tcr = 0x0e; 	/* set auto-rts assert at 56 bytes, restore at 0 bytes */
    	if (dev->tty.fifo) 
		{
        	/* Set RX fifo trigger level */
	        switch (dev->tty.fifo >> 4) {
    	        case FIFO_TRIG_8:
				default:   
					tlr = 0x20; 
					break;
        	    case FIFO_TRIG_16:  tlr = 0x40; break;
	            case FIFO_TRIG_32:  tlr = 0x80; break;
    	        case FIFO_TRIG_56:  tlr = 0xe0; break;
        	    case FIFO_TRIG_60:  
					tlr = 0xf0; 
					tcr = 0x0f; /* Ensure auto-rts trigger is not less the RX trigger */
					break;
	        }

    	    /* Set TX fifo trigger level */
        	switch (dev->tty.fifo & 0x0f) {
	            case FIFO_TRIG_8:   
				default:
					tlr |= 0x02;
					break;
    	        case FIFO_TRIG_16:  tlr |= 0x04; break;
        	    case FIFO_TRIG_32:  tlr |= 0x08; break;
            	case FIFO_TRIG_56:  tlr |= 0x0e; break;
	            case FIFO_TRIG_60:  tlr |= 0x0f; break;
    	    }
	    }

	    write_omap(dev->port[OMAP_UART_TCR], tcr);
	    write_omap(dev->port[OMAP_UART_TLR], tlr);
#ifdef PWR_MAN
	    write_omap(dev->port[OMAP_UART_SCR], OMAP_SCR_WAKEUPEN);
#else
		write_omap(dev->port[OMAP_UART_SCR], 0x00);
#endif
		/* Switch back to Config mode B to gain access to EFR again */
		write_omap(dev->port[OMAP_UART_LCR], 0xBF);
		/* remove access to TLR register */
		set_port(dev->port[OMAP_UART_EFR], OMAP_EFR_ENHANCED, 0);
		/* Switch to operational mode to get acces to MCR register */
		write_omap(dev->port[OMAP_UART_LCR], 0x00);
		/* clr MCR bit 6 to remove access to TCR and TLR registers */
	    set_port(dev->port[OMAP_UART_MCR], OMAP_MCR_TCRTLR, 0);

		ser_stty(dev);
		ser_attach_intr(dev);
	}
void *omap3_xfer(void *hdl, uint32_t device, uint8_t *buf, int *len)
{
	omap3_spi_t	*dev = hdl;
	uintptr_t		base = dev->vbase;
	uint32_t	 	id;
	int 			i;
	int 			timeout, expected;
	uint32_t 		reg_value = 0;

	id = device & SPI_DEV_ID_MASK;
	if (id >=dev->num_cs) {
		*len = -1;
		return buf;
	}

	dev->xlen = *len;
	// Cannot set more than 64KB of data at one time
	if(dev->xlen>(64 * 1024))
	{
		*len = -1;
		return buf;
	}
	dev->rlen = 0;
	dev->tlen = min(OMAP3_SPI_FIFOLEN, dev->xlen);
	dev->pbuf = buf;
	dev->dlen = ((devlist[id].cfg.mode & SPI_MODE_CHAR_LEN_MASK) + 7) >> 3;
	
    // Estimate transfer time in us... The calculated dtime is only used for
    // the timeout, so it doesn't have to be that accurate.  At higher clock
    // rates, a calcuated dtime of 0 would mess-up the timeout calculation, so
    // round up to 1 us
	dev->dtime = dev->dlen * 1000 * 1000 / devlist[id].cfg.clock_rate;
    if (dev->dtime == 0)
		dev->dtime = 1;

	omap3_setup(dev, device);

	/* force CS */
	set_port((base + OMAP3_MCSPI_CH1_CONFIG_OFFSET + 0x14*id),OMAP3_MCSPI_FORCE_MODE_ONE, OMAP3_MCSPI_FORCE_MODE_ONE);

	/*set FIFO */
	set_port((base + OMAP3_MCSPI_CH1_CONFIG_OFFSET + 0x14*id),  OMAP3_MCSPI_FFER | OMAP3_MCSPI_FFEW ,  OMAP3_MCSPI_FFER | OMAP3_MCSPI_FFEW );  
	out32(base + OMAP3_MCSPI_XFERLEVEL_OFFSET , (dev->xlen<<16) | 0xF<<8 | 0xF);   /* set transfer levels :MCBSP_FIFO_THRESHOLD= 16-1*/

	/* Configue the SPI control register to enable the corresponding channel of the SPI */
 	set_port(base + OMAP3_MCSPI_CH1_CTRL_OFFSET+0x14*id, OMAP3_MCSPI_CHANNEL_ENABLE, OMAP3_MCSPI_CHANNEL_ENABLE);

	// Clear any pending interrupts
	out32(base + OMAP3_MCSPI_IRQ_STATUS_OFFSET, 0xF );

	/* start the data transmit.....this happens by writing data to
	* the corresponding transmit register. This module has been  
	* designed for Transmit/Recieve Mode. This part will change  
	* according to the design. 
	*/
	for(i=0; i<dev->tlen; i++){ 
		out32(base + OMAP3_MCSPI_CH1_TX_BUFFER_OFFSET + 0x14*id, dev->pbuf[i]);
	}	

	/* Enable Interrupts */
	out32(base + OMAP3_MCSPI_IRQ_ENABLE_OFFSET, INTR_TYPE_EOWKE + (INTR_TYPE_RX0_FULL << (id * OMAP3_INTERRUPT_BITS_PER_SPI_CHANNEL)) );

	/*
	* Wait for exchange to finish
	*/
	if (omap3_wait(dev, dev->xlen * 10)) {
		fprintf(stderr, "OMAP3 SPI: XFER Timeout!!!\n");
		dev->rlen = -1;
	}

	// Read the last spi words
	if(dev->rlen < dev->xlen && dev->rlen != -1) {
		reg_value = in32(base + OMAP3_MCSPI_CH1_STATUS_OFFSET + (OMAP3_SPI_DEVICE_OFFSET * id));
		timeout = 1000;
		while( timeout-- && ((reg_value & OMAP3_MCSPI_CH_RX_REG_FULL) == 0) ) {
			nanospin_ns(100);
			reg_value = in32(base + OMAP3_MCSPI_CH1_STATUS_OFFSET + (OMAP3_SPI_DEVICE_OFFSET * id));
		}
		
		if(timeout <= 0) {
			dev->rlen = -1;
		}
		else {
			// last words to read from buffer
			expected = dev->tlen - dev->rlen;
			for(i = 0; i < expected; i++) {
				dev->pbuf[dev->rlen++] = in32(base + OMAP3_MCSPI_CH1_RX_BUFFER_OFFSET + (OMAP3_SPI_DEVICE_OFFSET * id));
			}
		}
	}

	//disable interrupts
    out32(base + OMAP3_MCSPI_IRQ_ENABLE_OFFSET, 0);	

	/*un-force CS */
	set_port((base + OMAP3_MCSPI_CH1_CONFIG_OFFSET + 0x14*id),OMAP3_MCSPI_FORCE_MODE_ONE, 0);

	set_port(base + OMAP3_MCSPI_CH1_CTRL_OFFSET + 0x14*id, OMAP3_MCSPI_CHANNEL_ENABLE, 0);
	set_port(base + OMAP3_MCSPI_CH1_CONFIG_OFFSET + 0x14*id,  OMAP3_MCSPI_FFER|OMAP3_MCSPI_FFEW, 0);
	out32(base + OMAP3_MCSPI_XFERLEVEL_OFFSET , 0);  
	
    *len = dev->rlen;

    return buf;
}
void *omap3_init(void *hdl, char *options)
{
	omap3_spi_t	*dev;
	uintptr_t	base;
	int		i;
	uint32_t        reg;	
	dev = calloc(1, sizeof(omap3_spi_t));

	if (dev == NULL)
		return NULL;
		
	//Set defaults
	dev->pbase = OMAP3_SPI1_BASE;
	dev->irq_spi = OMAP3_SPI_SPI1_INTR;
	dev->clock = OMAP3_SPI_INPUT_CLOCK;
	dev->channel_num = 1;
	dev->force = 0;
	dev->edmapbase = DM816x_EDMA_BASE;
	dev->irq_edma = 0;	/* We use interrupt of receive channel   */
	dev->edma = 0;
	dev->num_cs = 1;
	dev->cs_delay = 0;
	dev->edma_tx_chid = dev->edma_rx_chid = -1;
	if (omap3_options(dev, options))
		goto fail0;

	/*
     	* Map in SPI registers
	*/
	if ((base = mmap_device_io(OMAP3_SPI_REGLEN, dev->pbase)) == (uintptr_t)MAP_FAILED)
		goto fail0;
	dev->vbase = base;
	
	/* Reset the SPI interface
	 * and wait for the reset to complete
	 */
	set_port(base + OMAP3_MCSPI_SYS_CONFIG, OMAP3_MCSPI_CONFIG_SOFT_RESET, OMAP3_MCSPI_CONFIG_SOFT_RESET);
	while ( !(in32(base + OMAP3_MCSPI_SYS_CONFIG) & 1)) {
		nanospin_ns(20);
	} 

	/*Set Master mode -- single channel mode*/
	out32((base + OMAP3_MCSPI_MODCTRL_OFFSET), (in32(base + OMAP3_MCSPI_MODCTRL_OFFSET) & OMAP3_MCSPI_MODCTRL_MASTER_SEL)|OMAP3_MCSPI_MODCTRL_MULTI_CH_SEL);
	 
    /*
	 * Calculate all device configuration here
	 */
	for (i = 0; i < dev->num_cs; i++){ //we have just one device defined in the driver till now....
		devctrl[i] = omap3_cfg(dev, &devlist[i].cfg);
		if(dev->force){
			/* if we need to set the default CSx level to other than defaul low, we need to kick it*/
			out32((base + OMAP3_MCSPI_CH1_CONFIG_OFFSET + 0x14 * i), devctrl[i]|SPI_COMM_TX_RX <<12);
			set_port(base + OMAP3_MCSPI_CH1_CTRL_OFFSET+0x14*i, OMAP3_MCSPI_CHANNEL_ENABLE, OMAP3_MCSPI_CHANNEL_ENABLE);
			/* force CS */
			set_port((base + OMAP3_MCSPI_CH1_CONFIG_OFFSET + 0x14*i),OMAP3_MCSPI_FORCE_MODE_ONE, OMAP3_MCSPI_FORCE_MODE_ONE);
			delay(1);
			/*un force CS */
			set_port((base + OMAP3_MCSPI_CH1_CONFIG_OFFSET + 0x14*i),OMAP3_MCSPI_FORCE_MODE_ONE, 0);
			set_port(base + OMAP3_MCSPI_CH1_CTRL_OFFSET+0x14*i, OMAP3_MCSPI_CHANNEL_ENABLE, 0);
		}
	}

	/*
	 * Attach SPI interrupt
	 */
	if (omap3_attach_intr(dev))
		goto fail1;
	
	dev->spi.hdl = hdl;

	/* Clear the appropriate Interrupts if any*/
	reg= in32(base + OMAP3_MCSPI_IRQ_STATUS_OFFSET) ;
  	out32((base + OMAP3_MCSPI_IRQ_STATUS_OFFSET), reg);

	if (dev->edma) {
		if (omap3_init_edma(dev))	dev->edma=0;

		/*
		 * Attach SDMA interrupt
	 	*/
		if (omap3_edma_attach_intr(dev)){
			printf("%s(%d): omap3_edma_attach_intr failed\n", __func__, __LINE__);
			goto fail2;
		}

	}
   	return dev;
	
fail2:
	munmap_device_memory ((void *)dev->edmavbase, DM6446_EDMA_SIZE); 
fail1:
	munmap_device_io(dev->vbase, OMAP3_SPI_REGLEN);
fail0:
	free(dev);
	return NULL;
}