Sunday, 4 January 2015

I2c Learning

https://www.kernel.org/doc/htmldocs/device-drivers/i2c.html

http://pete.akeo.ie/2011/08/writing-linux-device-driver-for-kernels.html#uds-search-results



Writing I2C Bus driver
-I2c was developed by Philips
-System management Bus(SMBus) is based on this protocol
-I2c has two line bus.One is Serial Data Line(SDL) and other is Serial Clock Line(SCL).
-Pull up resister are requied in SDL and SCL because pin in the chip can only put the line low or other wise the are floating VDD.
-In I2C mechanism, all the devices are considered as node connected to same medium.
-If a node wants to transmit some data, it can determine whether any other node is transmitting data by letting the pull up resistor to make the logical line to1 and monitor the line state.If any nodes pulls the line to 0, then other nodes can detect that some node is transmitting data.
-I2C protocol supports 10 bit addressing but most of the devices supports only 7 bit addressing (slave addresses). So a maximum of 127 devices can connect on a single bus.
Speed
Standard mode : 100 kbps
Fast mode : 400 kbps
 

More about I2C

  1. Every device connected to I2C lines has a unique address.
  2. Master-slave relationship exist between device and the chip.
  3. Master can be either transmitter or receivers.
  4. I2C is a multi-master bus which has collision detection and mechanisms to prevent data corruption when 2 or more master initiates data transfer at same time. 
  5. It is an 8 bit serial bus which bidirectional data transfer is possible.
Many number of devices can be connected to the same bus.                                        We can just try to see how we can configure I2C adapter, bus driver etc.            

Terminology
===========

When we talk about I2C, we use the following terms:
  Bus    -> Algorithm
            Adapter
  Device -> Driver
            Client


-An Algorithm driver contains general code that can be used for a whole class
of I2C adapters. Each specific adapter driver either depends on one algorithm
driver, or includes its own implementation

-A Driver driver (yes, this sounds ridiculous, sorry) contains the general
code to access some type of device. Each detected device gets its own
data in the Client structure. Usually, Driver and Client are more closely
integrated than Algorithm and Adapter.

-A Driver driver (yes, this sounds ridiculous, sorry) contains the general
code to access some type of device. Each detected device gets its own
data in the Client structure. Usually, Driver and Client are more closely
integrated than Algorithm and Adapter.

-At this time, Linux only operates I2C (or SMBus) in master mode; you can't
use these APIs to make a Linux system behave as a slave/device, either to
speak a custom protocol or to emulate some other device.

                                                                                                                    
Writing an I2C Driver
struct i2c_driver {
  unsigned int class;
  int (* attach_adapter) (struct i2c_adapter *);
  int (* probe) (struct i2c_client *, const struct i2c_device_id *);
  int (* remove) (struct i2c_client *);
  void (* shutdown) (struct i2c_client *);                               /* optional */
  int (* suspend) (struct i2c_client *, pm_message_t mesg);             /* optional */
 int (* resume) (struct i2c_client *);                                   /* optional */
  void (* alert) (struct i2c_client *, unsigned int data);
  int (* command) (struct i2c_client *client, unsigned int cmd, void *arg);/* optional deprecated */
  struct device_driver driver;
  const struct i2c_device_id * id_table;
  int (* detect) (struct i2c_client *, struct i2c_board_info *);
  const unsigned short * address_list;
  struct list_head clients;
};
 
struct i2c_client {
  unsigned short flags;
  unsigned short addr;
  char name[I2C_NAME_SIZE];
  struct i2c_adapter * adapter;
  struct device dev;
  int irq;
  struct list_head detected;
  i2c_slave_cb_t slave_cb;
}; 
 
-you will implement a single driver structure, and instantiate all clients from it.  
-a driver structure contains general access routines, and should be zero-initialized except for fields with data you provide.
-A client structure holds device-specific information like the driver model device node, and its I2C address.
-In driver strucure,Name field should match the module name.  If the driver name doesn't match the module name, the module won't be automatically loaded (hotplug/coldplug).


Accessing the client
====================
-To write/read information to client

-I have found it useful to define foo_read and foo_write functions for this.
For some cases, it will be easier to call the i2c functions directly,
but many chips have some kind of register-value idea that can easily
be encapsulated.
 

The below functions are simple examples, and should not be copied
literally. 

 int foo_read_value(struct i2c_client *client, u8 reg)
{
        if (reg < 0x10) /* byte-sized register */
                return i2c_smbus_read_byte_data(client, reg);
        else            /* word-sized register */
                return i2c_smbus_read_word_data(client, reg);
}

int foo_write_value(struct i2c_client *client, u8 reg, u16 value)
{
        if (reg == 0x10)        /* Impossible to write - driver error! */
                return -EINVAL;
        else if (reg < 0x10)    /* byte-sized register */
                return i2c_smbus_write_byte_data(client, reg, value);
        else                    /* word-sized register */
                return i2c_smbus_write_word_data(client, reg, value);
}
 


Device/Driver Binding
---------------------
-System infrastructure , typically  board-specific initialization code or boot firmware, reports what I2C devices exist.  For example, there may be a table, in the kernel or from the boot loader, identifying I2C devices and linking them to board-specific configuration information about IRQs and other wiring artifacts, chip type, and so on.

 That could be used to create i2c_client objects(device file) for each I2C device.

-I2C device drivers using this binding model work just like any other
kind of driver in Linux:  they provide a probe() method to bind to
those devices, and a remove() method to unbind.

        static int foo_probe(struct i2c_client *client,
                             const struct i2c_device_id *id);//for binding
        static int foo_remove(struct i2c_client *client);//for unbinding



-Remember that the i2c_driver does not create those client handles.  The handle may be used during foo_probe().  If foo_probe() reports success (zero not a negative status code) it may save the handle and use it until foo_remove() returns.
 

-The probe function is called when an entry in the id_table name field
matches the device's name. It is passed the entry that was matched so
the driver knows which one in the table matched.


Device Creation
---------------
-If you know for a fact that an I2C device is connected to a given I2C bus, you can instantiate that device by simply filling an i2c_board_info structure with the device address and driver name, and calling i2c_new_device(). This will create device.

-Then the driver core will take care of finding the right driver and will call its probe() method.
-If a driver supports different device types, you can specify the type you want using the type field.  You can also specify an IRQ and platform data if needed.
-Sometimes you know that a device is connected to a given I2C bus, but you don't know the exact address it uses.
-Sometimes you know that a device is connected to a given I2C bus, but you
don't know the exact address it uses.

- In that case, you can use the i2c_new_probed_device() variant, which is
similar to i2c_new_device(), except that it takes an additional list of
possible I2C addresses to probe.

-The call to i2c_new_device() or i2c_new_probed_device() typically happens
in the I2C bus driver.




Device Detection
----------------





Device Deletion
---------------

-Each I2C device which has been created using i2c_new_device() or i2c_new_probed_device() can be unregistered by calling i2c_unregister_device(). 
- If you don't call it explicitly, it will be called automatically before the underlying I2C bus itself is removed, as a device can't survive its parent in the device driver model.

Initializing the driver
=======================
static int __init foo_init(void)
{
        return i2c_add_driver(&foo_driver);
}

static void __exit foo_cleanup(void)
{
        i2c_del_driver(&foo_driver);
}

/* Substitute your own name and email address */
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"
MODULE_DESCRIPTION("Driver for Barf Inc. Foo I2C devices");

/* a few non-GPL license types are also allowed */
MODULE_LICENSE("GPL");

module_init(foo_init);
module_exit(foo_cleanup);
-Note that some functions are marked by `__init'.  These functions can be removed after kernel booting (or module loading) is completed. Likewise, functions marked by `__exit' are dropped by the compiler when the code is built into the kernel, as they would never be called.



Power Management
================
-activating a system wakeup mechanism -- do that in the suspend() method.
The resume() method should reverse what the suspend() method does.




System Shutdown
===============

If your I2C device needs special handling when the system shuts down
or reboots (including kexec) -- like turning something off -- use a
shutdown() method.

Again, this is a standard driver model call, working just like it
would for any other driver stack:  the calls can sleep, and can use
I2C messaging.

Command function
================

A generic ioctl-like function call back is supported. You will seldom
need this, and its use is deprecated anyway, so newer design should not
use it.


Sending and receiving
=====================

If you want to communicate with your device, there are several functions
to do this. You can find all of them in <linux/i2c.h>.

If you can choose between plain I2C communication and SMBus level
communication, please use the latter. All adapters understand SMBus level
commands, but only some of them understand plain I2C!



Documentation of I2C (user space):(ref dev-interface)

- i2c devices are controlled by a kernel driver. But it is also possible to access all devices on an adapter from userspace, through the /dev interface.
-Each registered i2c adapter gets a number, counting from 0.
-You can examine /sys/class/i2c-dev/ to see what number corresponds to which adapter.
-Alternatively, you can run "i2cdetect -l" to obtain a formated list of all
i2c adapters present on your system at a given time.

-I2C device files are character device files with major device number 89
and a minor device number corresponding to the number assigned as
explained above.


C example
=========
-So let's say you want to access an i2c adapter from a C program

-The first thing to do is "#include <linux/i2c-dev.h>".

-Please note that there are two files named "i2c-dev.h" out there, one is distributed
with the Linux kernel and is meant to be included from kernel driver code, the other one is distributed with i2c-tools and is meant to be included from user-space programs. You obviously want the second one here 


-Next thing, open the device file, as follows:

  int file;
  int adapter_nr = 2; /* probably dynamically determined */
  char filename[20];

  snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
  file = open(filename, O_RDWR);
  if (file < 0) {
    /* ERROR HANDLING; you can check errno to see what went wrong */
    exit(1);
  }

-When you have opened the device, you must specify with what device
address you want to communicate:

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

  if (ioctl(file, I2C_SLAVE, addr) < 0) {
    /* ERROR HANDLING; you can check errno to see what went wrong */
    exit(1);
  }

-Well, you are all set up now. You can now use SMBus commands or plain I2C to communicate with your device. SMBus commands are preferred if the device supports them. Both are illustrated below.


 __u8 register = 0x10; /* Device register to access */
  __s32 res;
  char buf[10];

  /* Using SMBus commands */
  res = i2c_smbus_read_word_data(file, register);
  if (res < 0) {
    /* ERROR HANDLING: i2c transaction failed */
  } else {
    /* res contains the read word */
  }

  /* Using I2C Write, equivalent of
     i2c_smbus_write_word_data(file, register, 0x6543) */
  buf[0] = register;
  buf[1] = 0x43;
  buf[2] = 0x65;
  if (write(file, buf, 3) ! =3) {
    /* ERROR HANDLING: i2c transaction failed */
  }

  /* Using I2C Read, equivalent of i2c_smbus_read_byte(file) */
  if (read(file, buf, 1) != 1) {
    /* ERROR HANDLING: i2c transaction failed */
  } else {
    /* buf[0] contains the read byte */
  }
-Note that only a subset of the I2C and SMBus protocols can be achieved by the means of read() and write() calls. In particular, so-called combined transactions (mixing read and write messages in the same transaction) aren't supported. For this reason, this interface is almost never used by user-space programs.


I2C Core-The I2C core is a code base consisting of routines and data structures available to host adapter drivers and client drivers.

Comment to this blog if any query




No comments:

Post a Comment