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.

Need help with I2C linux device driver

Other Parts Discussed in Thread: DM3730

Hi,

        I have a custom board built with ADV7403 from analog devices. ADV7403 is connected as client to a Beagleboard-xM Rev.C on which linux Angstrom is ported with the kernel version 2.6.32.

Im trying to write a device driver for ADV7403 for RGB input signal. In order to configure ADV7403, i2c communication is used.

So far in the linux device drivers i have been able to include support for module_init and module_exit. and when i insert my module(i.e., .ko file) module_init is triggered. (this is done by using '    insmod adv7403.ko   ' command)

According to my knowledge, after module_init next function called is Probe(). but i dont see the probe() function being called and executed in the run time.. reason for this may be adv7403 hardware is not getting detected on the i2c line which triggers the probe() function.

one of the straight reason for this could be the adv7403's i2c slave address. the slave address of adv7403 is 0x21. but i dont know how to and where to give the i2c slave address in the linux device driver structure. Any suggestions or hint in this matter would be helpful.

Im new to writing linux device drivers and i might have missed out some important and simple things due to my insufficient knowledge on linux device drivers. If anything of this sort is found, please point it out.

I have pasted the code that is written so far below..

 

 

#include <linux/module.h>

#include <linux/init.h>

#include <linux/errno.h>

#include <linux/kernel.h>

#include <linux/interrupt.h>

#include <linux/i2c.h>

#include <linux/i2c-id.h>

#include <linux/videodev2.h>

#include <linux/mutex.h>

#include <linux/slab.h>

#include <linux/log2.h>

 

#include <media/v4l2-ioctl.h>

#include <media/v4l2-device.h>

#include <media/v4l2-chip-ident.h>

#include <media/v4l2-subdev.h>

#include <media/soc_camera.h>

 

#include "adv7403_regs.h"

 

#define DRIVER_NAME "adv7403"

 

struct adv7403_state {

          struct v4l2_subdev subdev;

};

 

static __devinit int adv7403_probe(struct i2c_client *client,

                              const struct i2c_device_id *id)

{

          struct adv7403_state *state;

          int ret;

 

          /* Check if the adapter supports the needed features */

          if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))

                    return -EIO;

 

          v4l_info(client, "chip found @ 0x%02x (%s)\n",

                              client->addr << 1, client->adapter->name);

 

          state = kzalloc(sizeof(struct adv7403_state), GFP_KERNEL);

          if (state == NULL) {

                    ret = -ENOMEM;

                    goto err;

          }

        else{

                    printk(KERN_ERR DRIVER_NAME ": Detected %d\n");

          }

 

err:

          printk(KERN_ERR DRIVER_NAME ": Failed to probe: %d\n", ret);

          return ret;

}

 

 

static __devexit int adv7403_remove(struct i2c_client *client)

{

          struct v4l2_subdev *sd = i2c_get_clientdata(client);

 

          v4l2_device_unregister_subdev(sd);

          return 0;

}

 

static const struct i2c_device_id adv7403_id[] = {

          {DRIVER_NAME, 0},

          {},

};

 

MODULE_DEVICE_TABLE(i2c, adv7403_id);

 

static struct i2c_driver adv7403_driver = {

          .driver = {

                    .owner          = THIS_MODULE,

                    .name          = DRIVER_NAME,

          },

        .probe                    = adv7403_probe,

        .remove                    = adv7403_remove,

          .id_table          = adv7403_id

};

 

static int __init adv7403_mod_init(void)

{

          printk(" ADV7403 Video Decoder Device Driver inserted to kernel \n");

          return i2c_add_driver(&adv7403_driver);

}

 

static void __exit adv7403_mod_exit(void)

{

        printk(" ADV7403 Video Decoder Device Driver removed from kernel \n");

          i2c_del_driver(&adv7403_driver);

}

 

module_init(adv7403_mod_init);

module_exit(adv7403_mod_exit);

 

MODULE_DESCRIPTION("Analog Devices ADV7403 video driver");

 

thanking you,

Shravan Kulkarni

 

P.S :

My system configuration:

Processor: intel core 2 duo 2.4 GHz

Ram : 2GB

O.S : Ubuntu 10.04 (kernel: 2.6.32-39)

 

BeagleBoard-xM Rev.C configuration( which host to ADV7403)

Processor : DM3730 1GHz

Ram: 512MB

O.S : Linux Angstrom ( kernel 2.6.32 )

  • Hello, shravan!

    You added the description your device in board-specific file, usually it in arch/arm/mach-<you mach>?

  • Hi Shravan,

    Probe is called when your device is recognized by the platform (device initialization should be happen in board init code, will be in arch/arm/mach-omap2/ folder board-omap3evm.c or devices.c file). Generally registering the device requires the device name and this device name is compared with the driver name(when you are registering the driver you would be specifying the driver name,which should match with the device name).

    Once the device gets detected by the kernel it will call the corresponding driver probe for that device.

    Regards

    AnilKumar

    Please mark this Forum post as answered via the Verify Answer button below if it helps answer your question.  Thanks!

  • Here's some fairly good description of i2c clients:

    http://www.kernel.org/doc/Documentation/i2c/writing-clients

    Based upon info in that link, some possible code that might work. Never tried it myself. I've usually went the built-in module with platform data route suggested by Anil.

    static struct i2c_client *client;

    static int __init adv7403_mod_init(void)
    {
      int ret;
      struct i2c_adapter *adapter;
      struct i2c_board_info info = {
        .type = "adv7403",
        .addr = 0x21,
      };

      ret = i2c_add_driver(&adv7403_driver);
      if(ret) return(ret);

      adapter = i2c_get_adapter(YOUR_ADAPTER_NUMBER);
      if (!adapter) return -EINVAL;

      client = i2c_new_device(adapter, &info);
      if (!client) return -EINVAL;

      return(0);
    }

    static void __exit adv7403_mod_exit(void)
    {
      i2c_unregister_device(client);
      i2c_del_driver(&adv7403_driver);
    }

    Remember that this sort of approach cannot be used for a built-in module. Only for a loadable module.

  • Thanks Norman!

    You really helped me out on a similar problem to that of "shravan kulkarni".

    Getting the kernel to call my probe() methode worked exactly the way you described. Also http://www.kernel.org/doc/Documentation/i2c/writing-clients is a good place to start with when you are trying to write a i2c driver using the kernels i2c core functions.

    Cheers Stefan

  • Thanks for the feedback. Nice to know if theoretical untested code works.

  • Hi Norman,

     I have wrote a same i2c driver for my usb hub device.It is working fine when i loaded it as a module(using insmod from user space).But it fails at i2c_get_adapter function  when i loaded it as a part of kernel(During system start up i need to initialize usb hub so i make it as built in module). Can you tell about this?

    Regards,

    akil

  • It's been while since I worked with Linux. Some guesses. Your driver probably fails to load because the i2c core/adaptor has not loaded yet. As far as I know there is no way to specify a load order to built-in modules. I vaguely remember that built-modules are loaded in alphabetical order. I suppose you could try naming your driver starting with a "z". Doubt it would work though.

    The typical way to load a built-in is to define some platform data and register the driver from board.c file. Through the magic of Linux, this ensures the correct init sequence.

    I vaguely remember the code I noted for loadable would be bad for built-in modules. I can't remember why.