Wednesday, 24 June 2015

Initialization of i2c _Core in linux-2.6.10


Topic:
This document talks about writing an i2c client Driver for the basic functionality of RTC1338(Real Time Clock) with linux-2.6.10.This document will mainly focus on how to interact with the i2c bus.
Also starting with the the i2c-core initialization in the kernel for a specific i2c-controller of an SOC(System On Chip) (example taken as MPC8321/8323).
Ultimate Goal is to get or set the rtc time from user level commands example: hwclock ,or any other packages(Next blog).

Assumptions:
1.The linux kernel used is linux 2.6.xx not for the latest kernels.
2.The Rtc 1338 is connected externally using the i2c lines to the SOC.
3.Details about the initialization of the platform devices on SOC are not properly covered in this blog.
4.Basic knowledge of i2c protocol, device drivers in linux and Good 'C' is a must.

Courtesy:
I have learned about device driver from Linux Device Drivers – 2nd Edition by Alessandro Rubini & Jonathan Corbet from O’reilly publication,
Linux Kernel Devlopment by Robert Love ,Understanding Linux Nework internals, Various Datasheets and many other related documents published on internet.
And hacking Linux-2.6.10. :-)

Feedback
Your feedback is of is very important as a newbie to kernel level stuff. This is my attempt to share my understanding with others, so that jointly we can fine tune this document, which can become a starting point for device driver programmer. You are welcome to mail me your suggestion to my mail id of souravpunoriyar@gmail.com.

Let's BEGIN:------"<@
Before reaching to the interaction with the rtc ,the kernel need to have its i2c-subsystem initialized and working.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------



----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Begining with the     subsys_initcall(i2c_init) in the i2c-core.c
i.e to move its initialization very early in the boot sequence, the driver could use subsys_initcall().
In this i2c_init
All a/c to the Device Model Of Linux
1. bus_register(&i2c_bus_type): here we are registering the i2c_bus_type.i.e... nothing but assigning the name to the bus as "i2c" and assigning callbacks. (remember this is logical bus).
As per Linux Device Model.

2.driver_register(&i2c_adapter_driver);here we are registering device driver i2c_adapter_driver i.e. again assigning the     device-driver  name as "i2c    _adapter" and callbacks like     i2c_device_probe ,i2c_device_remove etc.As per Linux Device Model.


3.    class_register(&i2c_adapter_class): As per the linux Device model ,it abstracts the details of the underlying implementation to the user...simply for the sysfs enteries.

**Note: all the callbacks assigned Method's definitions can be found in the same i2c-core file.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Now we need to register our i2c-controller(the platform device), which is present on our SOC with the i2c-core.
For this we really need to study the SOC's datasheet to get the required addresses .For help we can go the /arch/ppc/platform folder
here we have two important files that are mpc83xx_devices.c and mpc_83xx_sys.c ,from mpc83xx_sys.c we get the required platform devices to be initialized for example
* .ppc_sys_name    = "8321E",
* .device_list    = (enum ppc_sys_devices[])
        {
            MPC83xx_IIC1,
and other details. here example MPC83xx _IIC1, tells the required platform device .

Check for the same MPC83xx    _IIC1 in  mpc83xx_devices.c here you have the detailed information of the required device in a structure.
example:
[MPC83xx_IIC1] = {
        .name = "fsl-i2c", (now remember the name "fsl-i2c")
        .id    = 1,
        .dev.platform_data = &mpc83xx_fsl_i2c1_pdata,---- (for this verify the file.)
        .num_resources     = 2,
        .resource = (struct resource[]) {
            {
                .start    = 0x3000,
                .end    = 0x30ff,
                .flags    = IORESOURCE_MEM,
            },
            {
                .start    = MPC83xx_IRQ_IIC1,
                .end    = MPC83xx_IRQ_IIC1,
                .flags    = IORESOURCE_IRQ,
         
*Need to study the datasheet of MPC8321 for the required start,end values and more specific details.
//----------------------------------------------------------------------------------------------------------------------------------------------
SO NOW WE HAVE OUR HARDWARE DETAILS AS WELL AS OUR I2C-CORE INITIALISED.......................

Lets initialze the i2c-controller present inside the SOC with the core.
Enabling the CONFIG_FSL_SOC enables the execution of the init function (fsl_i2c_init()) of the fsl-i2c driver in (i2c-mpc.c).

Now Going to linux-2.6.10/drivers/i2c/busses/ we have i2c-mpc.c .
Which would register the corresponding  (.probe = fsl_i2c_probe,    .remove = fsl_i2c_remove,.name= "fsl-i2c").

NOw for all the platform devices mentioned in  mpc_83xx_sys.c one by one their registered probe function are called hence when it comes to     MPC83xx    _IIC1 corresponding driver check registered name as "fsl-i2c" is found than its probe is called.

*Note:- if more clarification on the methods and probing ,if needed please comment so that i can verify everything more deeply and reply you positively...thank you

inside fsl_i2c_probe()................
Its main task is to register our i2c-controller as an i2c-adapter to the i2c-core.
brief explanation:-
Allocating proper structures like (struct mpc_i2c *i2c;), Getting the resource details from the mpc83xx files and then allocating proper resources, registering the irq, ioremapping the physical address so that we can get a virtual address which is used to access the controller.

At last  i2c_add_adapter(&i2c->adap))...is going to add our controller to the i2c-core adapter list.
For further small details we can refer the definition of  i2c_add_adapter in i2c-core.c
-----------------------------------------------------------------------------------------------------------------------------------------------
As this document has already become so big hence in the next blog an i will add an i2c peripheral to this i2c-controller (rtc1338).

Thanks for reading
As i am hobbyist and a newbie, this is all want i think is happening . Please comment wherever correction is to be done so that we can discuss and make the embedded linux world easy.

Bye.........

Sourav Kumar Punoriyar.