⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lh79524_i2c_driver.c

📁 SHARP_ARM720T_LH79524/5软件开发包_支持TFT_LCD_NAND_FLASH_ETH_USB
💻 C
📖 第 1 页 / 共 2 页
字号:
 *      cleared for future reads or writes.
 *
 **********************************************************************/
INT_32 i2c_write (INT_32 devid, CHAR byte, UNS_32 attrib)
{
    INT_32  old_abort = i2c_state.tx_aborts;
    i2c_state.num_writes++;
    
    /* verify that we are talking to the correct device */
    if(I2C_BASE != devid)
    {
		while(1);    
        return SMA_BAD_HANDLE;
    }

    /* verify that the device is opened */
    if(!(i2c_state.state & I2C_STATE_OPEN))
    {
		while(1);    
        return SMA_NOT_OPEN;
    }

    /* set the internal busy flag for the next transfer */
    i2c_state.state |= I2C_STATE_BUSY;

    /* send the byte with the flags specified by the user */
    i2c_state.regs->icdata = byte;
    i2c_state.regs->iccon = I2C_MODE_BITS(i2c_state.regs->iccon) |
                                                 I2C_ICCON_START | attrib;

    /* wait for the busy flag to be cleared by the interrupt */
    if(i2c_state.state & I2C_STATE_POLL)
    {   /* wait for the interrupt bit to be set */
        if(i2c_wait_int())
        {
			while(1);    
            return _ERROR;
        }
    }
    else
    {   /* default is to wait for the interrupt */
        if(i2c_wait_busy())
        {
			while(1);    
            return _ERROR;
        }
    }

    /*check if the write operation was aborted*/
    if(old_abort != i2c_state.tx_aborts)
    {
		while(1);    
        return _ERROR;
    }


    /* Return number of bytes written */
    return 1;
}

/***********************************************************************
 *
 *  Function: i2c_ioctl
 *
 *  Purpose:
 *      handle i2c control requests.
 *
 *  Processing:
 *      Set/resets designated state in the device.  See comments below
 *      for inforamtion about parameters for commands.
 *
 *  Parameters:
 *      devid - device id
 *      cmd   - request to process
 *      arg   - generic argument
 *
 *  Outputs: None
 *
 *  Returns:
 *      _NO_ERROR if device controlled successfully.
 *      _ERROR something went wrong with the device.
 *      SMA_BAD_HANDLE invalid handle supplied
 *      SMA_NOT_OPEN device is not opened
 *
 *  Notes: None
 *
 **********************************************************************/
STATUS i2c_ioctl (INT_32 devid,
                    I2C_IOCTLS_T cmd,
                    UNS_32 arg)
{
    STATUS          status = _NO_ERROR;
    I2C_CONFIG_T    *conf;

    /* verify that we are talking to the correct device */
    if(I2C_BASE != devid)
    {
        return SMA_BAD_HANDLE;
    }

    /* verify that the device is opened */
    if(!(i2c_state.state & I2C_STATE_OPEN))
    {
        return SMA_NOT_OPEN;
    }

    switch(cmd)
    {
        /* Return the current configuration in the config data structure. */
        case I2C_IOCTL_GET_CONFIG:
            if(arg == 0)
            {
                status = _ERROR;
                break;
            }

            ((I2C_CONFIG_T *)arg)->mode = i2c_state.regs->iccon & I2C_ICCON_MODE;
            ((I2C_CONFIG_T *)arg)->speed = i2c_state.regs->iccon & I2C_ICCON_SPEED;
            ((I2C_CONFIG_T *)arg)->low_slave_addr = i2c_state.regs->icsar;
            ((I2C_CONFIG_T *)arg)->high_slave_addr = i2c_state.regs->icusar;
            break;

        /* Set the configuration using the config data structure. */
        case I2C_IOCTL_SET_CONFIG_EX:
            if((conf = (I2C_CONFIG_T *)arg) == NULL)
            {
                status = _ERROR;
                break;
            }

            switch(conf->mode)
            {
                case I2C_MODE_7BIT_SLAVE:
                case I2C_MODE_10BIT_SLAVE:
                case I2C_MODE_7BIT_MASTER:
                case I2C_MODE_10BIT_MASTER:
                    /* implicitly set low speed */
                    i2c_state.regs->iccon = conf->mode | I2C_ICCON_EN;
                    break;
                default:
                    /* invalid mode */
                    status = _ERROR;
            }

            /* switch to high speed */
            if(conf->speed)
            {
                i2c_state.regs->iccon |= I2C_ICCON_SPEED;
                i2c_state.regs->ichcnt = I2C_FAST_HIGH_COUNTER;
                i2c_state.regs->iclcnt = I2C_FAST_LOW_COUNTER;
            }
            else
            {
                i2c_state.regs->iccon &= ~I2C_ICCON_SPEED;
                i2c_state.regs->ichcnt = I2C_SLOW_HIGH_COUNTER;
                i2c_state.regs->iclcnt = I2C_SLOW_LOW_COUNTER;
            }

            i2c_state.regs->icsar = conf->low_slave_addr;
            i2c_state.regs->icusar = conf->high_slave_addr;

            break;

        /* Return the current status in the status data strucutre. */
        case I2C_IOCTL_GET_STATUS:
            if(arg != 0)
                *((UNS_32 *)arg) = i2c_state.regs->icstat;
            else
                status = _ERROR;
            break;

        /* Set the speed bit and the timer registers using the i2c speed
            data structure. */
        case I2C_IOCTL_SET_SPEED:
            if(arg)
            {
                i2c_state.regs->iccon |= I2C_ICCON_SPEED;
                i2c_state.regs->ichcnt = I2C_FAST_HIGH_COUNTER;
                i2c_state.regs->iclcnt = I2C_FAST_LOW_COUNTER;
            }
            else
            {
                i2c_state.regs->iccon &= ~I2C_ICCON_SPEED;
                i2c_state.regs->ichcnt = I2C_SLOW_HIGH_COUNTER;
                i2c_state.regs->iclcnt = I2C_SLOW_LOW_COUNTER;
            }
            break;

        /* Return the speed data strucutre in the buffer provided. */
        case I2C_IOCTL_GET_SPEED:
            if(arg != 0)
                *((UNS_32 *)arg) = i2c_state.regs->iccon & I2C_ICCON_SPEED;
            else
                status = _ERROR;
            break;

        /* Wait (spin) until the i2c interface is idle */
        case I2C_IOCTL_WAIT_IDLE:
            if(i2c_wait_idle() != 0)
                status = _ERROR;
            break;

        /* Return the number of transmit aborts that have taken place since the
            driver was opened. */
        case I2C_IOCTL_GET_TXABORTS:
            if(arg != 0)
                *((UNS_32 *)arg) = i2c_state.tx_aborts;
            else
                status = _ERROR;
            break;

        /* Return the number of recieve aborts that have taken place since the
            driver was opened. */
        case I2C_IOCTL_GET_RXABORTS:
            if(arg != 0)
                *((UNS_32 *)arg) = i2c_state.rx_aborts;
            else
                status = _ERROR;
            break;

        /* Return the number of reads that have taken place since the
            driver was opened. */
        case I2C_IOCTL_GET_READS:
            if(arg != 0)
                *((UNS_32 *)arg) = i2c_state.num_reads;
            else
                status = _ERROR;
            break;

        /* Return the number of writes that have taken place since the
            driver was opened. */
        case I2C_IOCTL_GET_WRITES:
            if(arg != 0)
                *((UNS_32 *)arg) = i2c_state.num_writes;
            else
                status = _ERROR;
            break;

        /* Return the number of writes that have taken place since the
            driver was opened. */
        case I2C_IOCTL_GET_INTERRUPTS:
            if(arg != 0)
                *((UNS_32 *)arg) = i2c_state.interrupts;
            else
                status = _ERROR;
            break;

        /* Set all of the status counters back to 0 */
        case I2C_IOCTL_RESET_STATS:
            i2c_state.num_reads = 0;
            i2c_state.num_writes = 0;
            i2c_state.tx_aborts = 0;
            i2c_state.rx_aborts = 0;
            i2c_state.interrupts = 0;
            break;

        /* Return a pointer to the ISR */
        case I2C_IOCTL_GET_ISR:
            if(arg != 0)
                *((UNS_32 **)arg) = (void *)i2c_isr;
            else
                status = _ERROR;
            break;

        /* Switch between using polling and interrupts. Default is
            interrupts. The caller should disable this interrupt
            at the VIC.  */
        case I2C_IOCTL_ENA_POLLING:
            i2c_state.state &= ~I2C_STATE_INT;
            i2c_state.state |= I2C_STATE_POLL;
            break;

        /* Switch between using polling and interrupts. Default is
            interrupts. The caller should re-enable this interrupt
            at the VIC.  */
        case I2C_IOCTL_ENA_INTERRUPT:
            i2c_state.state &= ~I2C_STATE_POLL;
            i2c_state.state |= I2C_STATE_INT;
            break;

        /* set the counter value */
        case I2C_IOCTL_SET_COUNTER:
            if(arg == 0)
            {
                status = _ERROR;
                break;
            }

            i2c_state.regs->ichcnt = ((I2C_COUNTER_T *)arg)->high_count;
            i2c_state.regs->iclcnt = ((I2C_COUNTER_T *)arg)->low_count;
            break;

        /* get the counter value */
        case I2C_IOCTL_GET_COUNTER:
            if(arg == 0)
            {
                status = _ERROR;
                break;
            }

            ((I2C_COUNTER_T *)arg)->high_count = i2c_state.regs->ichcnt;
            ((I2C_COUNTER_T *)arg)->low_count = i2c_state.regs->iclcnt;
            break;

        default:
            /* invalid IOCTL command */
            status = _ERROR;
            break;
    }

    /* Return the io control status */
    return (status);
}


/***********************************************************************
 *
 * Function: i2c_isr
 *
 * Purpose:
 *   handle i2c interrupts.
 *
 * Processing:
 *   Handle i2c interrupts.  This interrupt clears a flag called
 *
 * Parameters:
 *   none
 *
 * Outputs:
 *   none
 *
 * Returns:
 *   nothing
 *
 * Notes:
 *   none
 *
 *********************************************************************/
static void i2c_isr(void)
{
    UNS_32 status;

    /* Clear the interrupt at the source by teading the status.  Many
       of the status indicators are read-to-clear bits.  */
    status = i2c_state.regs->icstat;

    /* set the global status counters */
    if(status & I2C_ICSTAT_TXABORT)
    {
    	while(1);
        i2c_state.tx_aborts++;
    }

    if(status & I2C_ICSTAT_RXABORT)
        i2c_state.rx_aborts++;

    /* clear the state flag to show that the action is completed */
    i2c_state.state &= ~I2C_STATE_BUSY;
    i2c_state.interrupts++;

}

/**********************************************************************
 *
 * Function: i2c_wait_int
 *
 * Purpose:
 *      Poll on the interrupt.  Used for polling to tell when a byte
 *      is finished being sent.
 *
 * Processing:
 *      If the loop spins for I2C_WAIT_TIME cycles, then the function
 *      returns with a timeout error.
 *
 * Parameters:
 *      none
 *
 * Outputs:
 *      none
 *
 * Returns:
 *      Returns 0 upon success, else returns !0;
 *
 * Notes:
 *      This funciton has an improper dependancy on the vectored
 *      interrupt controler.
 *
 *********************************************************************/
static INT_32 i2c_wait_int(void)
{
    int i, retv = 1;
    volatile int temp;

    for(i = 0; i < I2C_WAIT_TIME; i++)
    {
        /* polling on the virtual interrupt controller register. */
        if(VIC->rawintr & _BIT(VIC_I2C))
        {
            /* must read the status register to clear the local
                interrupt bit. */
            temp = i2c_state.regs->iccon;
            /* not timed out */
            retv = 0;
        }
    }
    /* timed out */
    return retv;
}

/**********************************************************************
 *
 * Function: i2c_wait_idle
 *
 * Purpose:
 *      Poll on the idle bit and return when it is set.
 *
 * Processing:
 *      If the loop spins for I2C_WAIT_TIME cycles, then the function
 *      returns with a timeout error.
 *
 * Parameters:
 *      none
 *
 * Outputs:
 *      none
 *
 * Returns:
 *      Returns 0 normally, 1 upon timeout error.
 *
 * Notes:
 *      none
*
**********************************************************************/
static INT_32 i2c_wait_idle(void)
{
    int i;

    for(i = 0; i < I2C_WAIT_TIME; i++)
    {
        /* wait until the idle bit is set */
        if(I2C->icstat == I2C_ICSTAT_IDLE)
            /* not timed out */
            return 0;
    }
    /* timed out */
    return 1;
}

/**********************************************************************
 *
 * Function: i2c_wait_busy
 *
 * Purpose:
 *      Poll on the busy flag set by the interrupt.  Used to tell when
 *      a byte is finished being sent.
 *
 * Processing:
 *      If the loop spins for I2C_WAIT_TIME cycles, then the function
 *      returns with a timeout error.
 *
 * Parameters:
 *      none
 *
 * Outputs:
 *      none
 *
 * Returns:
 *      Returns 0 upon success, else returns !0;
 *
 * Notes:
 *      none
 *
 *********************************************************************/
static INT_32 i2c_wait_busy(void)
{
    int i, retv = 1;

    for(i = 0; i < I2C_WAIT_TIME; i++)
    {
        // polling on the internal busy flag 
        if(!(i2c_state.state & I2C_STATE_BUSY))
        {
            // not timed out 
            retv = 0;
            break;
        }
    }
    // timed out 
    
    return retv;
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -