This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

i2c-davinci.c driver behavior

#include <stdio.h>

#include <linux/i2c.h>

#include <linux/i2c-dev.h>

#include <fcntl.h>

 

#define msleep (udelay *1000)

int device_write(int *file, unsigned char reg, unsigned char *val, unsigned int length)

{

char buf[3];

        int msgsExec = 0;

 

 

         buf[0] = reg;

         buf[1] = val[0];

buf[2] = val[1];

        struct i2c_msg msg[1] = {

                { .addr = 0x08,

                        .flags = 0, .buf = &buf[0], .len = length},

        };

        struct i2c_rdwr_ioctl_data ioctl_data = {

            .msgs = (struct i2c_msg *)&msg,  /* ptr to array of simple messages */

            .nmsgs = 0x01             /* number of messages to exchange */

        };

 

        msgsExec = ioctl(*file, I2C_RDWR, &ioctl_data);

        printf("Executed messages : %d\n", msgsExec);

        printf("write : 0x%x,0x%x to :0x%x\n", buf[1], buf[2], buf[0]);

        return msgsExec; 

}

 

int device_read(int *file, unsigned char reg, unsigned char *val, unsigned char len)

{

        char buf[2];

        int msgsExec = 0;

        char bval[4] = { 0, 0, 0, 0 };

 

        buf[0] = reg;

        struct i2c_msg msg[2] = {

                { .addr = 0x08,

                        .flags = 0, .buf = &buf[0], .len = 1 },

                { .addr = 0x08,

                        .flags = I2C_M_RD, .buf = &bval[0], .len = len },

        };

 

        struct i2c_rdwr_ioctl_data ioctl_data = {

            .msgs = (struct i2c_msg *)&msg,  /* ptr to array of simple messages */

            .nmsgs = 0x02             /* number of messages to exchange */

        };

        msgsExec = ioctl(*file, I2C_RDWR, &ioctl_data);

        printf("Executed messages : %d\n", msgsExec);

        printf("read : 0x%x from :0x%x\n", bval[0], buf[0]);

val = bval;

return msgsExec;

}

 

 

int main()

{

int file;

int ret ,i;

 int adapter_nr = 1; /* probably dynamically determined */

 char filename[20];

 int addr = 0x08; /* The I2C address */

char buf[2]; 

         unsigned int regVal;

 snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);

        int msgsExec = 0;

        char bval[2] = { 0, 0 };

 

 file = open(filename, O_RDWR);

 if (file < 0) {

   /* ERROR HANDLING; you can check errno to see what went wrong */

printf("Failed to open i2c device \n");

   return 1; 

 }

 

 if (ioctl(file, I2C_SLAVE, addr) < 0) {

   /* ERROR HANDLING; you can check errno to see what went wrong */

printf("Failed to get i2c slave device \n");

   return;

 }

buf[0] = 0x78;

buf[1] = 0x48;

msgsExec = device_write(&file, 0x01, buf, 3);

 

 

msgsExec = device_read(&file, 0x01, &bval[0],1);

#if 0

buf[0] =0x20;

 ret = write(file, buf, 1);

if(ret < 0)

printf("Failed to write device \n");

   /* ERROR HANDLING: i2c transaction failed */

 

if (read(file, buf, 1) != 1) {

printf("Failed to read device \n");

   /* ERROR HANDLING: i2c transaction failed */

 } else {

printf("read byte %x at add %x \n",buf[0],i);

   /* buf[0] contains the read byte */

 }

#endif

close(file);

}

 

We are using above application to communicate with an i2c slave over dm6467T. Can we get some pointers on the below issues we are facing 

  • When we write 1 byte data on the i2c device, we get a read terminated error "RDR read not requested"
  • when we read 1 byte data from the i2c device we always read 0x00 data 
  • when we repeat the same steps in ccs application we get correct data without and errors and warnings.

Can we get some pointers as in why we are seeing this different behavior?

Thanks in advance

Sushant

  • I think you have programming error in device_read():

    int device_read(int *file, unsigned char reg, unsigned char *val, unsigned char len)

    {
    ...
            char bval[4] = { 0, 0, 0, 0 };
    ...
            *val = bval[0]; // Send value back.
            return msgsExec;
    }

    You use both read()/write() and ioctl() code. Some is ifdef'ed out. Which code is causing the errors?

     

  • Hi,

    I incorporated your suggestion but the problem still persists. We would like to understand the reason the driver executes the read session successfully and still reads 0x00. You can see in device_read() we print data that was read from the device(bval[0]). The driver always reads 0x00 from the device.

    If we introduce further prints in the device driver file i2c-davinci.c @ line 468 in function

    static int

    i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)

    {

    ....

            /* no error */       

            if (likely(!dev->cmd_err))

            {

                    printk("READ : 0x%x\n",msg->buf[0]);        

                    return msg->len;

            }

    ...
    }
    We still read 0x00 from the device. But when we read the same device from CCS it returns correct status.

  • Hi,

     Comparing ccs EVMDM6467_I2C_write/read() and git_linux i2c_davinci.c i2c_davinci_xfer_msg() it is learnt that ICMDR_FREE is never done under git but the bus is freed every time we do any read or write transaction under ccs.

    Any reason for not doing this under git / or is it being handled elsewhere in the driver.

     

    CCS implementation for read and write in evmdm6467_i2c.c contains:

    I2C_ICCNT = len; // Set length

     

    I2C_ICSAR = address; // Set I2C slave address

     

    I2C_ICMDR = ICMDR_STT // Set DSP for Master Write

                       | ICMDR_MST

                       | ICMDR_IRS

                       | ICMDR_FREE;

    The highlighted command is not issued under git i2c-davinci.c.

  • Just realized that you might return more than one
      memcpy(val, bval, len);

    You don't need to double buffer. You could pass val to ioctl. Not sure if you know this, the Linux I2C driver uses 7-bit addresses. The R/W bit is not included.

    I've never used the DaVinci processor but I used the same I2C calls on other Linux platforms. Your user space code looks valid. I believe the DaVinci I2C code is fairly mature and hopefully bugfree. Since your CCS app works, the HW must be connected properly. The only thing left is to check that the kernel is confiigured properly for I2C,  You could try to look in the directory /sys/bus/i2c for signs of activity. I don't rarely use the sysfs and don't know what should be there.