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.

control TVP5146 from user space

Other Parts Discussed in Thread: TVP5146, TMS320DM355

Hello!

I read Documentation/i2c/dev-interface and write probe programm:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include "tvp5146control.h"

int main(int argc, char** argv)
{
    int file, res;
    char filename[10] = "/dev/i2c-0";
   
    printf("Device File: %s.\n", filename);
    printf("Device Address: 0x%x.\n", TVP5146_ADDR);
   
    ((file = open(filename, O_RDWR)) < 0) ?
    printf("Error opening Device File.\n") :
    printf("Device File opened successfully.\n");
   
    res = ioctl(file, I2C_SLAVE, TVP5146_ADDR);
    if (res < 0)
    {
        printf("IOCTL error with err = %d.\n", res);
        exit(1);
    } printf("IOCTL good.\n");
   
   close(filename);
    return 0;
}

I have succsefully compile and runing it, but I have error:

# ./tvp5146control
Device File: /dev/i2c-0.
Device Address: 0x5d.
Device File opened successfully.
IOCTL error with err = -1.

System contained only one i2c device:

# ls -l /dev | grep i2c
drwxr-xr-x    2 1000     1000         4096 Jul 21  2008 i2c
crw-rw----    1 1000     1000      89,   0 Aug 27  2008 i2c-0

# ls -l /sys/bus/i2c/drivers/TVP5146\ Video\ Decoder\ I2C\ drive/
lrwxrwxrwx    1 root     root            0 Jan  1 00:33 0-005d -> ../../../../devices/platform/i2c-0/0-005d

I have found device address in TMS320DM355  Evalution Module Technical Reference (509905-0001 Rev. E April 2008) on page 2-5.

But I have TMX320DM355 Evalution Module 702065 Rev C 30 Nov 07 manufactured by SpectrumDigital.

What problem and how I can solve it?

Thank you and excuse me for my bad english.

 

  • OK!

    This problem solved with res = ioctl(file, I2C_SLAVE_FORCE, TVP5146_ADDR).

    But, this is a good solve?

  • I think the I2C_SLAVE_FORCE will tell the I2C driver to access an I2C device regardless of if the address has already been claimed by an existing driver, so this will mean you could potentially be conflicting with another accessor, in this case most likely the video capture driver. This is probably ok as long as you are aware of that fact and your code does not make accesses at times that there could be a conflict.

    From an architectual point of view, to follow the concept of Linux driver architecture technically you should have these sorts of commands within your video capture driver and than have your user space application make calls into the capture driver to adjust TVP5146 settings. This abstracts the application code a bit more from the hardware which could be nice for future portability and makes it so that only one piece of code will own that TVP5146 I2C address which should rule out conflicts.

  • Thank you for your answer!

    I have inserted in my preview code command for read from registr:

    #define INPUT_SELECT        0x00

    buf[0] = INPUT_SELECT;
    res = read(file, buf, 1);
    if (res != 1)
    {
          printf("I2C read fail with res = 0x%x.\n", res);
          exit(1);
    } printf("I2C read INPUT_SELECT registr value = 0x%x.\n", buf[0]);

    But when I run programm I see strange output:

    # ./tvp5146control
    Device File: /dev/i2c-0.
    Device Address: 0x5d.
    Device File opened successfully.
    IOCTL good.
    I2C read INPUT_SELECT registr value = 0x0.
    I2C read INPUT_SELECT registr value = 0x80.
    # ./tvp5146control
    Device File: /dev/i2c-0.
    Device Address: 0x5d.
    Device File opened successfully.
    IOCTL good.
    I2C read INPUT_SELECT registr value = 0x0.
    I2C read INPUT_SELECT registr value = 0x0.
    # ./tvp5146control
    Device File: /dev/i2c-0.
    Device Address: 0x5d.
    Device File opened successfully.
    IOCTL good.
    I2C read INPUT_SELECT registr value = 0x0.
    I2C read INPUT_SELECT registr value = 0x0.
    # ./tvp5146control
    Device File: /dev/i2c-0.
    Device Address: 0x5d.
    Device File opened successfully.
    IOCTL good.
    I2C read INPUT_SELECT registr value = 0x1e.
    I2C read INPUT_SELECT registr value = 0x0.
    # ./tvp5146control
    Device File: /dev/i2c-0.
    Device Address: 0x5d.
    Device File opened successfully.
    IOCTL good.
    I2C read INPUT_SELECT registr value = 0x0.
    I2C read INPUT_SELECT registr value = 0x0.

    Why registr value changed?

    Thank you.

     

  • How come you are getting the print statement "I2C read INPUT_SELECT registr value = 0x%x" twice (does not match the code segment you sent)?

    FYI, when you do a read in i2c, you must first set 'buf' to the address you want to read and then issue a write, followed by a read.

    write(file,buf,1);

    read(file,buf,1)

    You can use the same 'buf' variable for write and read, the read will simply overwrite whatever data was in 'buf'.

     

  • Juan Gonzales said:

    How come you are getting the print statement "I2C read INPUT_SELECT registr value = 0x%x" twice (does not match the code segment you sent)?

    I have inserted twice read command.

     

    Follow my full test programm:

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <sys/ioctl.h>
    //#include <linux/i2c.h>
    #include <linux/i2c-dev.h>
    #include "tvp5146control.h"

    int main(int argc, char** argv)
    {
        int file, res;
        char filename[10] = "/dev/i2c-0";
        char buf[5];
       
        printf("Device File: %s.\n", filename);
        printf("Device Address: 0x%x.\n", TVP5146_ADDR);
       
        ((file = open(filename, O_RDWR)) < 0) ?
        printf("Error opening Device File.\n") :
        printf("Device File opened successfully.\n");
       
        res = ioctl(file, I2C_SLAVE_FORCE, TVP5146_ADDR);
        if (res < 0)
        {
            printf("IOCTL error with err = %d.\n", res);
            exit(1);
        } printf("IOCTL good.\n");
       
        buf[0] = INPUT_SELECT;
            res = read(file, buf, 1);
        if (res != 1)
        {
            printf("I2C read fail with res = 0x%x.\n", res);
            exit(1);
        } printf("I2C read INPUT_SELECT registr value = 0x%x.\n", buf[0]);
       
       
        //buf[0] = INPUT_SELECT;
        //buf[1] = 0xDE;
        ////buf[2] = 0x01;
        //res = write(file, buf, 2);
        //if (res != 2)
        //{
            //printf("I2C read fail with res = 0x%x.\n", res);
            //exit(1);
        //} 
        //printf("I2C write INPUT_SELECT registr value = 0x%x.\n", buf[1]);
        ////printf("I2C write INPUT_SELECT registr value = 0x%x.\n", buf[2]);
       
        buf[0] = INPUT_SELECT;
            res = read(file, buf, 1);
        if (res != 1)
        {
            printf("I2C read fail with res = 0x%x.\n", res);
            exit(1);
        } printf("I2C read INPUT_SELECT registr value = 0x%x.\n", buf[0]);
       
           
        close(filename);
        return 0;
    }

    I also have tried with MSP430 address (0x25) and it works with I2C_SLAVE without problem.

    What may cause this difference between TVP5146, that works only with I2C_SLAVE_FORCE, and MSP430.

  • You need to use I2C_SLAVE_FORCE when the i2c device address you are trying to access is already being used by another software component. 

    It is actually a bit more complex than this at the kernel level; since many components can be accessing (using) an i2c device; however, only one can register to access the device.  But when working at the application level, you do not need to worry about these details.  Just know that if I2C_SLAVE fails and I2C_SLAVE_FORCE suceeds, then the device is being used by another software component already and care should be taken when accessing this device since you are not the only one accessing (reading/writting to) this i2c device.

  • Juan Gonzales said:
    You need to use I2C_SLAVE_FORCE when the i2c device address you are trying to access is already being used by another software component. 

    This is what I was getting at in my prior post. If you are seeing the I2C value change back randomly than it is possible that the program that is claiming the I2C address you are writing to (probably the capture driver) is setting the values back. Alternatively there could be come other conflict going on, but I would think that the ability of the I2C driver is fairly solid since it is used by so many other drivers.

  • Bernie, this is a very good point and could explain why Kirill is seeing varying values when reading data.

  • Thank you for your answers!

    OK, I see possible root my problem. But I do not undestaund how this problem appear and how can I solve it?

    I have read documentation and I have used data from there.

    May there be other I2C addresses than that I have seen in documentation or can I find I2C addresses used in my device by myself?

  • Optimally you would solve any conflicts by digging into the capture driver and adding this functionality there as opposed to at the user level, in theory any writes to the TVP5146 with the out of the box kernel should only happen from the capture driver code, so if you are getting a conflict it should be coming from there. If this is still seen when the only known accessor to the TVP5146 I2C is the capture driver than we may have to look into alternate possible reasons for failure, but my suspicion is that the capture driver is what is doing this since the capture driver should be adjusting the TVP5146 I2C register values as necessary. To start if you do not want to outright jump into the driver modification you may want to take a look at the source and see if anything could be causing this conflict, in particular lsp\ti-davinci\drivers\media\video\dm355_vpfe.c and tvp5146.c.

  • Kirill said:

    OK, I see possible root my problem. But I do not undestaund how this problem appear and how can I solve it?

    Normally, direct accessed to hardware (e.g. i2c device such as tvp5146) occurs at the kernel level.   User applications use more abstracted driver APIs to access hardware (e.g. V4L2 APIs).  In this particular case, V4L2 capture driver controls TVP5146, so having a user application trying to access tvp5146 as well causes conflicts.

    The one good reason I can think of for wanting to control tvp5146 from user level is when you are trying out different TVP5146 configurations and want to quickly test prior to porting this resgister configuration(s) to the driver level.  In this case, you want to modify the capture driver code so that it temporarily does not access TVP5146.  Once you have tested the desired TVP5146 configuration at the user level and are happy with it, you would port this over to the driver level and give capture driver control of TVP5146 again. 

    Kirill said:

    May there be other I2C addresses than that I have seen in documentation or can I find I2C addresses used in my device by myself?

    Not sure I understand this question.  Can you expand on it?

  • Wich device I can use to control TVP5146 from user space via kernel driver or where I can see example?

  • The TVP5146 is controlled by the V4L2 capture driver behind the scenes; from a user space perspective, you probably cannot do much to change the way the TVP5146 is being used underneath.  If you require more control of the TVP5146, you will have to make these changes at the Linux Kernel level or implement your own proprietary ioctls to give you such control from the user level.

  • Hello again!

    I have read this article http://tldp.org/LDP/lkmpg/2.6/html/x892.html and modify drivers/media/video/davinci/tvp5146.c, also I rewrite programm to work via ioctl.

    But this did not solved problem.

    Before encodedecode demo:

    # /opt/test
    ioctl_read(0)
    device_read register 0x0 = 0xe4
    i2c_read_reg ret = 1
    ioctl_read(0x1)
    device_read register 0x1 = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0x2)
    device_read register 0x2 = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0x3)
    device_read register 0x3 = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0x4)
    device_read register 0x4 = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0x5)
    device_read register 0x5 = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0x6)
    device_read register 0x6 = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0x7)
    device_read register 0x7 = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0x8)
    device_read register 0x8 = 0xb6
    i2c_read_reg ret = 1
    ioctl_read(0x9)
    device_read register 0x9 = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0xa)
    device_read register 0xa = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0xb)
    device_read register 0xb = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0xc)
    device_read register 0xc = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0xd)
    device_read register 0xd = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0xe)
    device_read register 0xe = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0xf)
    device_read register 0xf = 0x31
    i2c_read_reg ret = 1

    # /opt/test
    ioctl_read(0)
    device_read register 0x0 = 0xd4
    i2c_read_reg ret = 1
    ioctl_read(0x1)
    device_read register 0x1 = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0x2)
    device_read register 0x2 = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0x3)
    device_read register 0x3 = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0x4)
    device_read register 0x4 = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0x5)
    device_read register 0x5 = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0x6)
    device_read register 0x6 = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0x7)
    device_read register 0x7 = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0x8)
    device_read register 0x8 = 0xbb
    i2c_read_reg ret = 1
    ioctl_read(0x9)
    device_read register 0x9 = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0xa)
    device_read register 0xa = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0xb)
    device_read register 0xb = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0xc)
    device_read register 0xc = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0xd)
    device_read register 0xd = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0xe)
    device_read register 0xe = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0xf)
    device_read register 0xf = 0x31
    i2c_read_reg ret = 1

     

    After encodedecode demo:

    # ./test
    ioctl_read(0)
    device_read register 0x0 = 0x64
    i2c_read_reg ret = 1
    ioctl_read(0x1)
    device_read register 0x1 = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0x2)
    device_read register 0x2 = 0x90
    i2c_read_reg ret = 1
    ioctl_read(0x3)
    device_read register 0x3 = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0x4)
    device_read register 0x4 = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0x5)
    device_read register 0x5 = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0x6)
    device_read register 0x6 = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0x7)
    device_read register 0x7 = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0x8)
    device_read register 0x8 = 0x69
    i2c_read_reg ret = 1
    ioctl_read(0x9)
    device_read register 0x9 = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0xa)
    device_read register 0xa = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0xb)
    device_read register 0xb = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0xc)
    device_read register 0xc = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0xd)
    device_read register 0xd = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0xe)
    device_read register 0xe = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0xf)
    device_read register 0xf = 0x31
    i2c_read_reg ret = 1

    # ./test
    ioctl_read(0)
    device_read register 0x0 = 0xc4
    i2c_read_reg ret = 1
    ioctl_read(0x1)
    device_read register 0x1 = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0x2)
    device_read register 0x2 = 0x90
    i2c_read_reg ret = 1
    ioctl_read(0x3)
    device_read register 0x3 = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0x4)
    device_read register 0x4 = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0x5)
    device_read register 0x5 = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0x6)
    device_read register 0x6 = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0x7)
    device_read register 0x7 = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0x8)
    device_read register 0x8 = 0x1a
    i2c_read_reg ret = 1
    ioctl_read(0x9)
    device_read register 0x9 = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0xa)
    device_read register 0xa = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0xb)
    device_read register 0xb = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0xc)
    device_read register 0xc = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0xd)
    device_read register 0xd = 0x31
    i2c_read_reg ret = 1
    ioctl_read(0xe)
    device_read register 0xe = 0x0
    i2c_read_reg ret = 1
    ioctl_read(0xf)
    device_read register 0xf = 0x31
    i2c_read_reg ret = 1

    I have different result when I make request directly from driver (loop in driver):

    device_read register 0x0 = 0xbb
    i2c_read_reg ret = 1
    device_read register 0x1 = 0xc0
    i2c_read_reg ret = 1
    device_read register 0x2 = 0xf8
    i2c_read_reg ret = 1
    device_read register 0x3 = 0xf8
    i2c_read_reg ret = 1
    device_read register 0x4 = 0xbe
    i2c_read_reg ret = 1
    device_read register 0x5 = 0x0
    i2c_read_reg ret = 1
    device_read register 0x6 = 0xf8
    i2c_read_reg ret = 1
    device_read register 0x7 = 0xf8
    i2c_read_reg ret = 1
    device_read register 0x8 = 0x18
    i2c_read_reg ret = 1
    device_read register 0x9 = 0xec
    i2c_read_reg ret = 1
    device_read register 0xa = 0xec
    i2c_read_reg ret = 1
    device_read register 0xb = 0xec
    i2c_read_reg ret = 1
    device_read register 0xc = 0xf8
    i2c_read_reg ret = 1
    device_read register 0xd = 0xf8
    i2c_read_reg ret = 1
    device_read register 0xe = 0xeb
    i2c_read_reg ret = 1

     

    Why some registers change their value and why value don't compliance with value from datasheet?