/** * Write Data in REPEATED START mode to LTC2943 Sensor * * @param: command to write, * * @return: ENDO_SUCCESS if the data is successfully copy to IIC TX FIFO * ENDO_FAILURE: fails when IIC device is not properly initialized * or LTC2943 state is not WaitForCommand * Author: Phuong Pham * Created: 1/12/2016 ******************************************************************************/ int16_t LTC2943_RepeatedStartWrite(u8 command) { /*Check if the IIC device is properly initialized*/ if(iic_ptr == NULL) return ENDO_FAILURE; /*Check for valid data length, * LTC2943 has only 23 register*/ //if((len == 0) && (len > 23)) // return ENDO_FAILURE; /*Check if the state of LTC2943 is LTC2943_WaitForCommand * If not return right away*/ if(s_ltc2943_state != LTC2943_WaitForCommand) return ENDO_FAILURE; int16_t status = EndoIicOpen(BATT_LTC2943); if((status != ENDO_SUCCESS) && (status !=(int16_t)IIC_ALREADY_USING)) return status; /*Set the status to transferring*/ s_iic_status = LTC2943_TRANSFERRING; /*Update the state to WriteWait*/ s_ltc2943_state = LTC2943_WriteRepeatedStartWait; /*Read Status Register*/ u32 option = XIic_GetOptions(iic_ptr); XIic_SetOptions(iic_ptr, option | XII_REPEATED_START_OPTION); /*Send data by copying data to IIC device*/ (void)XIic_MasterSend(iic_ptr, command, 1); return ENDO_SUCCESS; }
static int xiic_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) { struct xiic_data *dev = (struct xiic_data *) i2c_adap; struct i2c_msg *pmsg; u32 options; int i, retries; u32 Status; u32 writeop; for (i = 0; i < num; i++) { pmsg = &msgs[i]; if (!pmsg->len) /* If length is zero */ continue; /* on to the next request. */ /* * This code checks up to 16 times for the * bus busy condition. */ retries = 4; while((XIic_IsIicBusy(&dev->Iic) == TRUE) && (retries-- != 0)) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/250); } /* If bus is still busy, bail */ if (XIic_IsIicBusy(&dev->Iic) == TRUE) { printk(KERN_WARNING "%s #%d: Could not talk to device 0x%2x (%d), bus always busy, trying to reset\n", dev->adap.name, dev->index, pmsg->addr, dev->status_intr_flag); /* Try stopping, reseting and starting device to clear condition */ if (XIic_Stop(&dev->Iic) != XST_SUCCESS) { /* The bus was in use.. */ printk(KERN_WARNING "%s #%d: Could not stop device. Restart from higher layer.\n", dev->adap.name, dev->index); return -ENXIO; } else { XIic_Reset(&dev->Iic); if (XIic_Start(&dev->Iic) != XST_SUCCESS) { printk(KERN_ERR "%s #%d: Could not start device.\n", dev->adap.name, dev->index); return -ENODEV; } return -ENXIO; } } options = 0; if (pmsg->flags & I2C_M_TEN) options |= XII_SEND_10_BIT_OPTION; XIic_SetOptions(&dev->Iic, options); if (XIic_SetAddress(&dev->Iic, XII_ADDR_TO_SEND_TYPE, pmsg->addr) != XST_SUCCESS) { printk(KERN_WARNING "%s #%d: Could not set address to 0x%2x.\n", dev->adap.name, dev->index, pmsg->addr); return -EIO; } dev->transmit_intr_flag = 0xFFFFFFFF; dev->receive_intr_flag = 0xFFFFFFFF; dev->status_intr_flag = 0xFFFFFFFF; /* set the writeop flag to 0 so the adapter does not wait * at bottom of loop */ writeop = 0; dev->Iic.Stats.TxErrors = 0; if (pmsg->flags & I2C_M_RD) { Status = XIic_MasterRecv(&dev->Iic, pmsg->buf, pmsg->len); } else { Status = XIic_MasterSend(&dev->Iic, pmsg->buf, pmsg->len); } if (Status != XST_SUCCESS) { printk(KERN_WARNING "%s #%d: Unexpected error %d.\n", dev->adap.name, dev->index, (int)Status); return -EIO; } /* * Wait till the data is transmitted or received. If there is an error * retry for 10 times. */ retries = 10; if(pmsg->flags & I2C_M_RD) { while((((volatile int)(dev->receive_intr_flag)) != 0) && (retries != 0)) { if ( dev->Iic.Stats.TxErrors != 0) { udelay(25); Status = XIic_MasterRecv(&dev->Iic, pmsg->buf, pmsg->len); dev->Iic.Stats.TxErrors = 0; retries--; } /* the udelay was not working for Microblaze and this seems like a better solution */ schedule_timeout_interruptible(1); } } else { while((((volatile int)(dev->transmit_intr_flag)) != 0) && (retries != 0)) { if ( dev->Iic.Stats.TxErrors != 0) { udelay(25); Status = XIic_MasterSend(&dev->Iic, pmsg->buf, pmsg->len); dev->Iic.Stats.TxErrors = 0; retries--; } /* the udelay was not working for Microblaze and this seems like a better solution */ schedule_timeout_interruptible(1); } } if(retries == 0) { printk("Unable to talk to Device\n"); printk("Wrong Slave address or Slave device Busy\n"); } } return num; }
/* * ********************************************************* * IicReadData with address added as an input parameter - Repeated Start * ********************************************************* */ int IicReadData(u8 IicAddr, u8 addr, u8 *BufferPtr, u16 ByteCount) { int Status; u8 IicOptions; u32 IicTimeoutCounter = 0; /* * Set Receive Flag */ ReceiveComplete = 1; IicOptions = XIic_GetOptions(&IicInstance); XIic_SetOptions(&IicInstance, IicOptions | XII_REPEATED_START_OPTION); /* * Start Iic Device */ Status = XIic_Start(&IicInstance); if (Status != XST_SUCCESS) { #ifdef IIC_DEBUG xil_printf("IicReadData: IIC Start failed with status %x\r\n", Status); #endif return XST_FAILURE; } /* * Set Iic Address */ Status = XIic_SetAddress(&IicInstance, XII_ADDR_TO_SEND_TYPE, IicAddr); if (Status != XST_SUCCESS) { #ifdef IIC_DEBUG xil_printf("IicReadData: IIC Set Address failed with status %x\r\n", Status); #endif return XST_FAILURE; } /* * Write addr to the device */ // Mark the Transmit Flag TransmitComplete = 1; IicInstance.Stats.TxErrors = 0; /* * Send the Data */ Status = XIic_MasterSend(&IicInstance, &addr, 1); if (Status != XST_SUCCESS) { #ifdef IIC_DEBUG xil_printf("IicReadData: IIC Master Send failed with status %x\r\n", Status); #endif return XST_FAILURE; } /* * Wait till the transmission is completed */ while((TransmitComplete) && IicTimeoutCounter <= IIC_TIMEOUT) { IicTimeoutCounter ++; } /* * Clear Repeated Start option */ XIic_SetOptions(&IicInstance, IicOptions); /* * Handle Tx Timeout */ if (IicTimeoutCounter > IIC_TIMEOUT) { XIic_Reset(&IicInstance); Status = XIic_Stop(&IicInstance); #ifdef IIC_DEBUG xil_printf("IicReadData: IIC Write Timeout!\r\n"); if (Status != XST_SUCCESS) { xil_printf("IicReadData: IIC Stop Failed with status %x\r\n", Status); } #endif return XST_FAILURE; } /* * Receive Data */ Status = XIic_MasterRecv(&IicInstance, BufferPtr, ByteCount); if(Status != XST_SUCCESS) { if (Status != XST_SUCCESS) { #ifdef IIC_DEBUG xil_printf("IicReadData: IIC Master Recv Failed with status %x\r\n", Status); #endif return XST_FAILURE; } } /* * Wait until all the data is received */ IicTimeoutCounter = 0; while(((ReceiveComplete) || (XIic_IsIicBusy(&IicInstance)==TRUE)) && IicTimeoutCounter <= IIC_TIMEOUT) { IicTimeoutCounter ++; } /* * Handle Rx Timeout */ if (IicTimeoutCounter > IIC_TIMEOUT) { XIic_Reset(&IicInstance); Status = XIic_Stop(&IicInstance); #ifdef IIC_DEBUG xil_printf("IicReadData: IIC Recv Timeout!\r\n"); if (Status != XST_SUCCESS) { xil_printf("IicReadData: IIC Stop Failed with status %x\r\n", Status); } #endif return XST_FAILURE; } /* * Stop Iic */ Status = XIic_Stop(&IicInstance); if (Status != XST_SUCCESS) { #ifdef IIC_DEBUG xil_printf("IicReadData: IIC Stop Failed with status %x\r\n", Status); #endif return XST_FAILURE; } return XST_SUCCESS; }
static int xiic_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) { struct xiic_data *dev = container_of(i2c_adap, struct xiic_data, adap); struct i2c_msg *pmsg; u32 options; int i, retries; XStatus Status; for (i = 0; i < num; i++) { pmsg = &msgs[i]; if (!pmsg->len) /* If length is zero */ continue; /* on to the next request. */ options = 0; if (pmsg->flags & I2C_M_TEN) options |= XII_SEND_10_BIT_OPTION; if (i != num - 1) options |= XII_REPEATED_START_OPTION; XIic_SetOptions(&dev->Iic, options); if (XIic_SetAddress(&dev->Iic, XII_ADDR_TO_SEND_TYPE, pmsg->addr) != XST_SUCCESS) { printk(KERN_WARNING "%s #%d: Could not set address to 0x%2x.\n", dev->adap.name, dev->index, pmsg->addr); return -EIO; } dev->interrupt_status = ~(XStatus) 0; /* * The Xilinx layer does not handle bus busy conditions yet * so this code retries a request up to 16 times if it * receives a bus busy condition. If and when the underlying * code is enhanced, the retry code can be removed. */ retries = 16; init_completion(&dev->complete); if (pmsg->flags & I2C_M_RD) { while ((Status = XIic_MasterRecv(&dev->Iic, pmsg->buf, pmsg->len)) == XST_IIC_BUS_BUSY && retries--) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ / 10); } } else { while ((Status = XIic_MasterSend(&dev->Iic, pmsg->buf, pmsg->len)) == XST_IIC_BUS_BUSY && retries--) { printk("retry %d\n", retries); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ / 10); } } if (Status != XST_SUCCESS) { printk(KERN_WARNING "%s #%d: Unexpected error %d.\n", dev->adap.name, dev->index, Status); return -EIO; } wait_for_completion(&dev->complete); if (dev->interrupt_status != XST_SUCCESS) { printk(KERN_WARNING "%s #%d: Could not talk to device 0x%2x (%d).\n", dev->adap.name, dev->index, pmsg->addr, dev->interrupt_status); return -EIO; } } return num; }
void TaskRun_Batt_LTC2943(void) { int16_t status; u32 iic_option; /*Wait for IIC data transfer*/ if(s_iic_status == LTC2943_TRANSFERRING) return; else if(s_iic_status == LTC2943_TRANSFERRED_DONE) { switch(s_ltc2943_state) { /*Done data write operation*/ case LTC2943_WriteWait: /*Release IIC Resource*/ status = EndoIicClose(BATT_LTC2943); /*Set the status to transferring*/ s_iic_status = LTC2943_IDLE ; /*Finish a write operation, and wait for next command*/ s_ltc2943_state = LTC2943_WaitForCommand; break; case LTC2943_WriteRepeatedStartWait: iic_option = XIic_GetOptions(iic_ptr); XIic_SetOptions(iic_ptr, iic_option &= XII_REPEATED_START_OPTION); /*Set the status to transferring*/ s_iic_status = LTC2943_TRANSFERRING; /*Read 14 bytes of data from LTC2943_VOLTAGE_MSB_REG * to LTC2943_TEMPERATURE_LSB_REG*/ //memset(rx_buffer,0, 16); (void)XIic_MasterRecv(iic_ptr, rx_buffer, 24); /*Update the LTC2943 state*/ s_ltc2943_state = LTC2943_ReadAdcValueWait; break; case LTC2943_ReadAdcValueWait: /*Finish a repeated START read*/ status = EndoIicClose(BATT_LTC2943); if(status == ENDO_SUCCESS) { /*Convert raw data to voltage, current, temperature*/ LTC2943_ConvertData(rx_buffer+8, 14); } /*Set the status to transferring*/ s_iic_status = LTC2943_IDLE ; /*Finish the write-read operation, and wait for next command*/ s_ltc2943_state = LTC2943_WaitForCommand; break; default: /*Error happen here*/ s_iic_status = LTC2943_IDLE ; s_ltc2943_state = LTC2943_Error; break; } } else /*s_iic_status == LTC2943_IDLE*/ { switch(s_ltc2943_state) { case LTC2943_Init: status = EndoIicSensorInit(BATT_LTC2943, iic_ptr, LTC2943_SendHandler, LTC2943_RecvHandler, LTC2943_StatusHandler); if(status == ENDO_SUCCESS) s_ltc2943_state = LTC2943_WaitForCommand; break; case LTC2943_WaitForCommand: break; case LTC2943_Error: s_ltc2943_state = LTC2943_WaitForCommand; break; default: break; } } }