📄 lh79524_i2c_driver.c
字号:
* 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 + -