iicps_v2_4: Implemented repeated start feature.

This patch adds the repeated start feature in the iicps driver.

Signed-off-by: P L Sai Krishna <lakshmis@xilinx.com>
This commit is contained in:
P L Sai Krishna 2014-12-08 16:57:18 +05:30 committed by Suneel Garapati
parent aeae1a8d96
commit 5ae0b34872
4 changed files with 103 additions and 39 deletions

View file

@ -50,6 +50,7 @@
* 2.3 sk 10/07/14 Repeated start feature removed.
* 2.4 sk 11/03/14 Modified TimeOut Register value to 0xFF
* in XIicPs_Reset.
* 12/06/14 Implemented Repeated start feature.
*
* </pre>
*
@ -132,6 +133,9 @@ int XIicPs_CfgInitialize(XIicPs *InstancePtr, XIicPs_Config *ConfigPtr,
*/
InstancePtr->Options = XIicPs_GetOptions(InstancePtr);
/* Initialize repeated start flag to 0 */
InstancePtr->IsRepeatedStart = 0;
return XST_SUCCESS;
}

View file

@ -134,6 +134,12 @@
* thread mutual exclusion, virtual memory, or cache control must be satisfied by
* the layer above this driver.
*
*<b>Repeated Start</b>
*
* The I2C controller does not indicate completion of a receive transfer if HOLD
* bit is set. Due to this errata, repeated start cannot be used if a receive
* transfer is followed by any other transfer.
*
* <pre> MODIFICATION HISTORY:
*
* Ver Who Date Changes
@ -170,6 +176,7 @@
* 2.3 sk 10/07/14 Repeated start feature deleted.
* 2.4 sk 11/03/14 Modified TimeOut Register value to 0xFF
* in XIicPs_Reset.
* 12/06/14 Implemented Repeated start feature.
*
* </pre>
*
@ -202,6 +209,7 @@ extern "C" {
#define XIICPS_7_BIT_ADDR_OPTION 0x01 /**< 7-bit address mode */
#define XIICPS_10_BIT_ADDR_OPTION 0x02 /**< 10-bit address mode */
#define XIICPS_SLAVE_MON_OPTION 0x04 /**< Slave monitor mode */
#define XIICPS_REP_START_OPTION 0x08 /**< Repeated Start */
/*@}*/
/** @name Callback events
@ -277,6 +285,7 @@ typedef struct {
int UpdateTxSize; /* If tx size register has to be updated */
int IsSend; /* Whether master is sending or receiving */
int IsRepeatedStart; /* Indicates if user set repeated start */
XIicPs_IntrHandler StatusHandler; /* Event handler function */
void *CallBackRef; /* Callback reference for event handler */

View file

@ -56,6 +56,7 @@
* 2.3 sk 10/06/14 Fill transmit fifo before address register when sending.
* Replaced XIICPS_DATA_INTR_DEPTH with XIICPS_FIFO_DEPTH.
* Repeated start feature removed.
* 12/06/14 Implemented Repeated start feature.
*
* </pre>
*
@ -116,21 +117,21 @@ void XIicPs_MasterSend(XIicPs *InstancePtr, u8 *MsgPtr, int ByteCount,
InstancePtr->RecvBufferPtr = NULL;
InstancePtr->IsSend = 1;
/*
* Set repeated start if sending more than FIFO of data.
*/
if ((InstancePtr->IsRepeatedStart) ||
(ByteCount > XIICPS_FIFO_DEPTH)) {
XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) |
XIICPS_CR_HOLD_MASK);
}
/*
* Setup as a master sending role.
*/
XIicPs_SetupMaster(InstancePtr, SENDING_ROLE);
/*
* Set HOLD bit if sending more than FIFO of data.
*/
if (ByteCount > XIICPS_FIFO_DEPTH) {
XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) |
XIICPS_CR_HOLD_MASK);
}
TransmitFifoFill(InstancePtr);
/*
@ -181,7 +182,9 @@ void XIicPs_MasterRecv(XIicPs *InstancePtr, u8 *MsgPtr, int ByteCount,
InstancePtr->IsSend = 0;
InstancePtr->UpdateTxSize = 0;
if (ByteCount > XIICPS_FIFO_DEPTH) {
if ((ByteCount > XIICPS_FIFO_DEPTH) ||
(InstancePtr->IsRepeatedStart))
{
XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) |
XIICPS_CR_HOLD_MASK);
@ -257,7 +260,8 @@ int XIicPs_MasterSendPolled(XIicPs *InstancePtr, u8 *MsgPtr,
InstancePtr->SendBufferPtr = MsgPtr;
InstancePtr->SendByteCount = ByteCount;
if (ByteCount > XIICPS_FIFO_DEPTH) {
if ((InstancePtr->IsRepeatedStart) ||
(ByteCount > XIICPS_FIFO_DEPTH)) {
XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) |
XIICPS_CR_HOLD_MASK);
@ -323,9 +327,11 @@ int XIicPs_MasterSendPolled(XIicPs *InstancePtr, u8 *MsgPtr,
}
}
XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
XIicPs_ReadReg(BaseAddr,XIICPS_CR_OFFSET) &
(~XIICPS_CR_HOLD_MASK));
if (!(InstancePtr->IsRepeatedStart)) {
XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
XIicPs_ReadReg(BaseAddr,XIICPS_CR_OFFSET) &
(~XIICPS_CR_HOLD_MASK));
}
return XST_SUCCESS;
}
@ -372,15 +378,17 @@ int XIicPs_MasterRecvPolled(XIicPs *InstancePtr, u8 *MsgPtr,
InstancePtr->RecvBufferPtr = MsgPtr;
InstancePtr->RecvByteCount = ByteCount;
XIicPs_SetupMaster(InstancePtr, RECVING_ROLE);
if(ByteCount > XIICPS_FIFO_DEPTH) {
if((ByteCount > XIICPS_FIFO_DEPTH) ||
(InstancePtr->IsRepeatedStart))
{
XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) |
XIICPS_CR_HOLD_MASK);
IsHold = 1;
}
XIicPs_SetupMaster(InstancePtr, RECVING_ROLE);
/*
* Clear the interrupt status register before use it to monitor.
*/
@ -419,7 +427,8 @@ int XIicPs_MasterRecvPolled(XIicPs *InstancePtr, u8 *MsgPtr,
while (StatusReg & XIICPS_SR_RXDV_MASK) {
if ((InstancePtr->RecvByteCount <
XIICPS_DATA_INTR_DEPTH) && IsHold) {
XIICPS_DATA_INTR_DEPTH) && IsHold &&
(!(InstancePtr->IsRepeatedStart))) {
IsHold = 0;
XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
XIicPs_ReadReg(BaseAddr,
@ -465,9 +474,11 @@ int XIicPs_MasterRecvPolled(XIicPs *InstancePtr, u8 *MsgPtr,
IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET);
}
XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
XIicPs_ReadReg(BaseAddr,XIICPS_CR_OFFSET) &
(~XIICPS_CR_HOLD_MASK));
if (!(InstancePtr->IsRepeatedStart)) {
XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
XIicPs_ReadReg(BaseAddr,XIICPS_CR_OFFSET) &
(~XIICPS_CR_HOLD_MASK));
}
if (IntrStatusReg & Intrs) {
return XST_FAILURE;
@ -674,7 +685,8 @@ void XIicPs_MasterInterruptHandler(XIicPs *InstancePtr)
while (XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET) &
XIICPS_SR_RXDV_MASK) {
if ((InstancePtr->RecvByteCount <
XIICPS_DATA_INTR_DEPTH) && IsHold) {
XIICPS_DATA_INTR_DEPTH) && IsHold &&
(!(InstancePtr->IsRepeatedStart))) {
IsHold = 0;
XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
XIicPs_ReadReg(BaseAddr,
@ -724,10 +736,12 @@ void XIicPs_MasterInterruptHandler(XIicPs *InstancePtr)
* If all done, tell the application.
*/
if (InstancePtr->RecvByteCount == 0){
XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
XIicPs_ReadReg(BaseAddr,
XIICPS_CR_OFFSET) &
(~XIICPS_CR_HOLD_MASK));
if (!(InstancePtr->IsRepeatedStart)) {
XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
XIicPs_ReadReg(BaseAddr,
XIICPS_CR_OFFSET) &
(~XIICPS_CR_HOLD_MASK));
}
StatusEvent |= XIICPS_EVENT_COMPLETE_RECV;
}
}
@ -741,10 +755,12 @@ void XIicPs_MasterInterruptHandler(XIicPs *InstancePtr)
}
if (0 != (IntrStatusReg & XIICPS_IXR_NACK_MASK)) {
XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
XIicPs_ReadReg(BaseAddr,
XIICPS_CR_OFFSET) &
(~XIICPS_CR_HOLD_MASK));
if (!(InstancePtr->IsRepeatedStart)) {
XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
XIicPs_ReadReg(BaseAddr,
XIICPS_CR_OFFSET) &
(~XIICPS_CR_HOLD_MASK));
}
StatusEvent |= XIICPS_EVENT_NACK;
}
@ -754,10 +770,12 @@ void XIicPs_MasterInterruptHandler(XIicPs *InstancePtr)
if (0 != (IntrStatusReg & (XIICPS_IXR_NACK_MASK |
XIICPS_IXR_ARB_LOST_MASK | XIICPS_IXR_RX_UNF_MASK |
XIICPS_IXR_TX_OVR_MASK | XIICPS_IXR_RX_OVR_MASK))) {
XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
XIicPs_ReadReg(BaseAddr,
XIICPS_CR_OFFSET) &
(~XIICPS_CR_HOLD_MASK));
if (!(InstancePtr->IsRepeatedStart)) {
XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
XIicPs_ReadReg(BaseAddr,
XIICPS_CR_OFFSET) &
(~XIICPS_CR_HOLD_MASK));
}
StatusEvent |= XIICPS_EVENT_ERROR;
}
@ -800,7 +818,7 @@ static int XIicPs_SetupMaster(XIicPs *InstancePtr, int Role)
/*
* Only check if bus is busy when HOLD bit is not set.
* Only check if bus is busy when repeated start option is not set.
*/
if ((ControlReg & XIICPS_CR_HOLD_MASK) == 0) {
if (XIicPs_BusIsBusy(InstancePtr)) {
@ -849,10 +867,18 @@ static void MasterSendData(XIicPs *InstancePtr)
* Clear hold bit if done, so stop can be sent out.
*/
if (InstancePtr->SendByteCount == 0) {
XIicPs_WriteReg(InstancePtr->Config.BaseAddress,
XIICPS_CR_OFFSET,
XIicPs_ReadReg(InstancePtr->Config.BaseAddress,
XIICPS_CR_OFFSET) & ~ XIICPS_CR_HOLD_MASK);
/*
* If user has enabled repeated start as an option,
* do not disable it.
*/
if (!(InstancePtr->IsRepeatedStart)) {
XIicPs_WriteReg(InstancePtr->Config.BaseAddress,
XIICPS_CR_OFFSET,
XIicPs_ReadReg(InstancePtr->Config.BaseAddress,
XIICPS_CR_OFFSET) & ~ XIICPS_CR_HOLD_MASK);
}
}
return;

View file

@ -51,6 +51,7 @@
* selected. This is a hardware limitation. CR#779290.
* 2.1 hk 04/24/14 Fix for CR# 761060 - provision for repeated start.
* 2.3 sk 10/07/14 Repeated start feature removed.
* 2.4 sk 12/06/14 Implemented Repeated start feature.
*
* </pre>
*
@ -87,6 +88,7 @@ static OptionsMap OptionsTable[] = {
{XIICPS_7_BIT_ADDR_OPTION, XIICPS_CR_NEA_MASK},
{XIICPS_10_BIT_ADDR_OPTION, XIICPS_CR_NEA_MASK},
{XIICPS_SLAVE_MON_OPTION, XIICPS_CR_SLVMON_MASK},
{XIICPS_REP_START_OPTION, XIICPS_CR_HOLD_MASK},
};
#define XIICPS_NUM_OPTIONS (sizeof(OptionsTable) / sizeof(OptionsMap))
@ -124,6 +126,16 @@ int XIicPs_SetOptions(XIicPs *InstancePtr, u32 Options)
ControlReg = XIicPs_ReadReg(InstancePtr->Config.BaseAddress,
XIICPS_CR_OFFSET);
/*
* If repeated start option is requested, set the flag.
* The hold bit in CR will be written by driver when the next transfer
* is initiated.
*/
if (Options & XIICPS_REP_START_OPTION) {
InstancePtr->IsRepeatedStart = 1;
Options = Options & (~XIICPS_REP_START_OPTION);
}
/*
* Loop through the options table, turning the option on.
*/
@ -193,6 +205,16 @@ int XIicPs_ClearOptions(XIicPs *InstancePtr, u32 Options)
ControlReg = XIicPs_ReadReg(InstancePtr->Config.BaseAddress,
XIICPS_CR_OFFSET);
/*
* If repeated start option is cleared, set the flag.
* The hold bit in CR will be cleared by driver when the
* following transfer ends.
*/
if (Options & XIICPS_REP_START_OPTION) {
InstancePtr->IsRepeatedStart = 0;
Options = Options & (~XIICPS_REP_START_OPTION);
}
/*
* Loop through the options table and clear the specified options.
*/
@ -276,6 +298,9 @@ u32 XIicPs_GetOptions(XIicPs *InstancePtr)
}
}
if (InstancePtr->IsRepeatedStart) {
OptionsFlag |= XIICPS_REP_START_OPTION;
}
return OptionsFlag;
}