From 5ae0b34872aa317a02facd15040e577ec1e1d0cb Mon Sep 17 00:00:00 2001 From: P L Sai Krishna Date: Mon, 8 Dec 2014 16:57:18 +0530 Subject: [PATCH] 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 --- .../drivers/iicps_v2_4/src/xiicps.c | 4 + .../drivers/iicps_v2_4/src/xiicps.h | 9 ++ .../drivers/iicps_v2_4/src/xiicps_master.c | 104 +++++++++++------- .../drivers/iicps_v2_4/src/xiicps_options.c | 25 +++++ 4 files changed, 103 insertions(+), 39 deletions(-) diff --git a/XilinxProcessorIPLib/drivers/iicps_v2_4/src/xiicps.c b/XilinxProcessorIPLib/drivers/iicps_v2_4/src/xiicps.c index baf78716..a1876bec 100755 --- a/XilinxProcessorIPLib/drivers/iicps_v2_4/src/xiicps.c +++ b/XilinxProcessorIPLib/drivers/iicps_v2_4/src/xiicps.c @@ -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. * * * @@ -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; } diff --git a/XilinxProcessorIPLib/drivers/iicps_v2_4/src/xiicps.h b/XilinxProcessorIPLib/drivers/iicps_v2_4/src/xiicps.h index 37bb98ab..3c7420e9 100755 --- a/XilinxProcessorIPLib/drivers/iicps_v2_4/src/xiicps.h +++ b/XilinxProcessorIPLib/drivers/iicps_v2_4/src/xiicps.h @@ -134,6 +134,12 @@ * thread mutual exclusion, virtual memory, or cache control must be satisfied by * the layer above this driver. * +*Repeated Start +* +* 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. +* *
 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.
 *
 * 
* @@ -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 */ diff --git a/XilinxProcessorIPLib/drivers/iicps_v2_4/src/xiicps_master.c b/XilinxProcessorIPLib/drivers/iicps_v2_4/src/xiicps_master.c index 73cd075d..636c37c2 100755 --- a/XilinxProcessorIPLib/drivers/iicps_v2_4/src/xiicps_master.c +++ b/XilinxProcessorIPLib/drivers/iicps_v2_4/src/xiicps_master.c @@ -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. * * * @@ -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; diff --git a/XilinxProcessorIPLib/drivers/iicps_v2_4/src/xiicps_options.c b/XilinxProcessorIPLib/drivers/iicps_v2_4/src/xiicps_options.c index 07303d93..959a9635 100755 --- a/XilinxProcessorIPLib/drivers/iicps_v2_4/src/xiicps_options.c +++ b/XilinxProcessorIPLib/drivers/iicps_v2_4/src/xiicps_options.c @@ -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. * * * @@ -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; }