Hi
Please check the following code snippet to read and write on i2c, i2c read gives wrong data. I am trying to reads the chip id of SGTL5000's chip id on i.mx51 EVK board it should return 0xA000 but the code returns 0xff. Looking for quick solutions,
void mx6q_i2c_reset(void){
// Reset I2C registers
out16(dev_r->regbase + I2C_AR, 0);
out16(dev_r->regbase + I2C_IFDR, 0);
out16(dev_r->regbase + I2C_I2CR, 0);
out16(dev_r->regbase + I2C_I2SR, 0);
}
void i2c_init(void){
// I2C clock rate
out16(dev_r->regbase + I2C_IFDR, dev_r->div);
}
static int wait_op_done(int is_tx)
{
int i = 0;
volatile unsigned char stats;
i = WAIT_RXAK_LOOPS;
while ((((stats = in16(dev_r->regbase + I2C_I2SR)) & I2C_I2SR_ICF) == 0 )&& --i > 0){
//while ((((stats = in16(dev_r->regbase + I2C_I2SR)) & I2C_I2SR_IIF) == 0 ||
// (stats & I2C_I2SR_ICF) == 0)) {
if (stats & I2C_I2SR_IAL) {
printf("Arbitration lost\n");
return -1;
}
}
if (i <= 0) {
printf("wait op done timeout unexpected\n");
return -1;
}
if (is_tx) {
if (stats & I2C_I2SR_IAL) {
printf("Arbitration lost\n");
return -1;
}
if (stats & I2C_I2SR_RXAK) {
printf("No ack received\n");
return -1;
}
}
return 0;
}
static inline int wait_till_busy()
{
int i = I2C_WAIT_CNT;
while (((in16(dev_r->regbase + I2C_I2SR) & I2C_I2SR_IBB) == 0) && (--i > 0)) {
if (in16(dev_r->regbase + I2C_I2SR) & I2C_I2SR_IAL) {
printf("arbitration lost!\n");
return -1;
}
}
if (i <= 0) {
printf(" timeout unexpected\n");
return -1;
}
return 0;
}
static uint16_t tx_byte(uint16_t *data){
out16(dev_r->regbase + I2C_I2SR, 0);
printf("tx byte data 0x%x\n",*data);
out16(dev_r->regbase + I2C_I2DR, *data);
if (wait_op_done(1) != 0)
return -1;
return 0;
}
static uint16_t rx_byte(uint16_t *data)
{
unsigned short i2cr;
if (wait_op_done(0) != 0)
return -1;
out16(dev_r->regbase + I2C_I2SR, 0);
i2cr = in16(dev_r->regbase + I2C_I2CR);
out16(dev_r->regbase + I2C_I2CR, (i2cr & ~( I2C_I2CR_MSTA | I2C_I2CR_MTX)));
*data = in16(dev_r->regbase + I2C_I2DR);
printf("rx byte data 0x%x\n",*data); //when data is read from SGTL5000 chip id register gives wrong data.
return 0;
}
static uint16_t i2c_transaction(uint16_t reg, uint16_t * val, int dir){
volatile int i,i2cr=0;
uint16_t data;
int ret = 0;
i2cr |= I2C_I2CR_IEN;
out16(dev_r->regbase + I2C_I2CR,i2cr);
for (i = 0; i < 100; i++) ;
/* Check if bus is free */
if ((in16(dev_r->regbase + I2C_I2SR) & I2C_I2SR_IBB) != 0) {
printf(" Bus is not free\n");
return -1;
}
/* Set Device address to I2C Address Register*/
data = ((dev_r->slave << 1) | I2C_WRITE) & 0xFF;
out16(dev_r->regbase + I2C_AR , data);
/* Start I2C Transaction */
i2cr |= I2C_I2CR_MSTA | I2C_I2CR_MTX;
out16(dev_r->regbase + I2C_I2CR, i2cr);
/*Write Device Address to Data Register*/
if (tx_byte(&data) != 0) {
printf("Failed to transmit slave address\n");
return -1;
}
// make sure bus is busy after the START signal
if (wait_till_busy() != 0) {
printf("Bus is not busy\n");
return -1;
}
// send I2C device register address
data = reg & 0xFF;
if (tx_byte(&data) != 0) {
printf(" Failed to transmit device register address\n");
return -1;
}
if (dir == I2C_WRITE) {
data = *val & 0xFFFF;
if((ret = tx_byte(&data)) != 0) {
printf(" Failed to transmit data while write\n");
}
out16(dev_r->regbase + I2C_I2CR, (I2C_I2CR_IEN | I2C_I2CR_MTX));
}
else {
// do repeat-start
i2cr = in16(dev_r->regbase + I2C_I2CR);
out16(dev_r->regbase + I2C_I2CR, (i2cr | I2C_I2CR_RSTA));
// send slave address again, but indicate read operation
data = ((dev_r->slave << 1) | I2C_READ) & 0xFF;
if (tx_byte(&data) != 0) {
printf(" Failed to transmit slave address in read\n");
return -1;
}
// change to receive mode
i2cr = in16(dev_r->regbase + I2C_I2CR);
// read only one byte, make sure don't send ack
//i2cr |= I2C_I2CR_TXAK;
i2cr &= ~(I2C_I2CR_MTX);
out16(dev_r->regbase + I2C_I2CR, i2cr);
// dummy read
in16(dev_r->regbase + I2C_I2DR);
// now reading
if (rx_byte(&data) != 0) {
printf(" Failed to receive data\n");
return -1;
}
*val = data;
printf("data from i2c 0x%x\n",*val);
}
return ret;
}
/**** from read file operations sending the reg address to be read ***/
dev_r->reg = 0x0000;
/**** from write file operations sending the reg address to be read ***/
dev_r->reg = 0x0000;
dev_r->val = 0x0010;
Other initializations like slave address and setting up frequency divider value
dev->div = 0x16;
dev->slave = 0x0A;
Please provide suggestions where logics are going wrong.
Thanks
I think you may take the i.MX53 OBDS for reference. There is a I2C code.
Could atleast help me what are the necessary mux and pad configurations to be enabled for SGTL5000 to respond.
According to the schematic of i.MX51EVK, the ctrl_data and ctrl_clk of SGTL5000 is connect to the I2C2_SDA and I2C2_SCL. And these two I2C2 pins are the KEY_COL4 and KEY_COL5. So, please check the IOMUX and PAD setting for these two pins are proper.
For the IOMUX example, you can take the Linux BSP for reference.
This is the iomux-mx51.h:
linux-2.6-imx.git - Freescale i.MX Linux Tree
The iomux-mx51.h defined all the pin mux and pad setting. You can find below settings for I2C2 in this file.
#define MX51_I2C_PAD_CTRL (PAD_CTL_SRE_FAST | PAD_CTL_ODE | \ PAD_CTL_DSE_HIGH | PAD_CTL_PUS_100K_UP | \ PAD_CTL_HYS)
#define _MX51_PAD_KEY_COL4__I2C2_SCL IOMUX_PAD(0x65c, 0x26c, 0x13, 0x09b8, 1, 0)
#define _MX51_PAD_KEY_COL5__I2C2_SDA IOMUX_PAD(0x660, 0x270, 0x13, 0x09bc, 1, 0)
#define MX51_PAD_KEY_COL4__I2C2_SCL (_MX51_PAD_KEY_COL4__I2C2_SCL | MUX_PAD_CTRL(MX51_I2C_PAD_CTRL))
#define MX51_PAD_KEY_COL5__I2C2_SDA (_MX51_PAD_KEY_COL5__I2C2_SDA | MUX_PAD_CTRL(MX51_I2C_PAD_CTRL))
let take the _MX51_PAD_KEY_COL4__I2C2_SCL for example:
(0x65C is the PAD setting offset address,
0x26C is the IOMUX setting offset address,
0x13 is SION=1, ALT3
0x09b8 is the offset address of daisy chain input select
1 is the "input select" for KEY_COL4 for Mode:ALT3.)
For more details, please read the "IOMUXC" in i.MX51 Reference Manual.
Then for i.MX51EVK, the specific pin mux will be defined in board-mx51_babbage.c "mx51babbage_pads[]":
Thanks for the reply. could you identify what actual mux and pad configurations are required. Since I am working for QNX driver and trying to understand what configurations is missed. In the link shared I found the following function,
io_cfg_i2c(base);
and its implementation in hardware.c
But what actual configuration is been missed in the above shared snippet. Looking for suggestions.
Thanks