Bus driver
4.1 Overview
The I²C bus driver is the software implementation of the I²C adapter, which provides the ability of the I²C adapter to complete data communication from the device, such as start, stop, response signal and master_xfer implementation function.
The I²C bus driver is described by I2c_adapter and I2c_algorithm.
Hardware description of the 4.2 S3C2440I2C controller
The s3c2440 processor incorporates an I²C controller with four registers for control:
Iiccon i²c Control Register
Iicstat i²c Status Register
Iicds I²C Transceiver Data Shift Register
Iicadd i²c Address Register
With the Iiccon,iicds,iicadd register operation, the start bit, stop bit, data and address are generated on the I²c bus, while the transmitted state is obtained through the Iicstat register.
4.3 i2c-s3c2410 bus driver analysis (platform_driver)
I²c bus driver code in DRIVERS/I2C/BUSSES/I2C-S3C2410.C, this code also supports the S3C2410,S3C6410,S5PC110 and other Samsung series of chips.
Initializing modules and unloading modules
[CPP]View Plaincopy
- static int __init i2c_adap_s3c_init (void)
- {
- Returnplatform_driver_register (&s3c24xx_i2c_driver);
- }
- static void __exit i2c_adap_s3c_exit (void)
- {
- Platform_driver_unregister (&s3c24xx_i2c_driver);
- }
Bus driver is based on platform, which conforms to the idea of device-driven model.
[CPP]View Plaincopy
- static struct Platform_drivers3c24xx_i2c_driver = {
- . Probe = S3c24xx_i2c_probe,
- . remove = S3c24xx_i2c_remove,
- . id_table = S3c24xx_driver_ids,
- . Driver = {
- . Owner = This_module,
- . Name = "S3C-I2C",
- . PM = S3c24xx_dev_pm_ops,
- . of_match_table= S3c24xx_i2c_match,
- },
- };
S3c24xx_i2c_probe function
When the Platform_driver_register function is called to register the platform_driver struct, if Platformdevice and platform driver match successfully, the probe function is called to initialize the adapter hardware.
[CPP]View Plaincopy
- static int S3c24xx_i2c_probe (structplatform_device *pdev)
- {
- ......
- / * Initialize Adapter information * /
- strlcpy (I2c->adap.name,"S3C2410-I2C", sizeof (i2c->adap.name));
- I2c->adap.owner = This_module;
- I2c->adap.algo = &s3c24xx_i2c_algorithm;
- I2c->adap.retries= 2;
- I2c->adap. class = I2c_class_hwmon | I2C_CLASS_SPD;
- I2c->tx_setup = 50;
- /* Initialize spin lock and wait queue header */
- Spin_lock_init (&i2c->lock);
- Init_waitqueue_head (&i2c->wait);
- / * Map Register * /
- Res= Platform_get_resource (Pdev, Ioresource_mem, 0);
- I2c->ioarea= request_mem_region (Res->start, Resource_size (res),
- Pdev->name);
- I2c->regs= Ioremap (Res->start, Resource_size (res));
- / * Set the information required for the I²C core * /
- I2c->adap.algo_data= I²c;
- I2c->adap.dev.parent= &pdev->dev;
- / * Initialize the I²C controller * /
- ret= S3c24xx_i2c_init (I²C);
- / * Request interrupted * /
- i2c->irq= ret = PLATFORM_GET_IRQ (pdev, 0);
- Ret= Request_irq (I2C->IRQ, S3C24XX_I2C_IRQ, 0,
- Dev_name (&pdev->dev), i²c);
- / * Register the I²C adapter * /
- ret= I2c_add_numbered_adapter (&I2C->ADAP);
- ......
- }
Probe main work is when the hardware and request the I²C adapter to use the IO address, interrupt number, etc., and then add this adapter to the I²c core. I2c_adapter Registration Process I2c_add_numbered_adapter->i2c_register_adapter
I²c Bus Communication method
[CPP]View Plaincopy
- static const struct i2c_algorithms3c24xx_i2c_algorithm = {
- . Master_xfer = S3c24xx_i2c_xfer,
- . functionality = S3c24xx_i2c_func,
- };
S3c24xx_i2c_xfer function is the realization of bus communication mode, which relies on two functions of S3c24xx_i2c_doxfer and S3c24xx_i2c_message_start;
[CPP]View Plaincopy
- static int S3c24xx_i2c_doxfer (STRUCTS3C24XX_I2C *i2c,
- struct i2c_msg *msgs, int num)
- {
- RET =s3c24xx_i2c_set_master (I²C);
- I2c->msg = msgs;
- i2c->msg_num= num;
- I2c->msg_ptr= 0;
- i2c->msg_idx= 0;
- I2c->state = State_start;
- S3c24xx_i2c_message_start (I2C,MSGS);
- }
First set the S3C i²c device as the primary device, and then call the S3c24xx_i2c_message_start function to start the I²C message transfer.
The S3c24xx_i2c_func function returns the communication capabilities supported by the adapter.
4.4 Device Resources for adapters (Platform_device)
S3C2440 's I²c bus driver is based on the platform to achieve, we analyzed the Platformdriver section, and then look at the platform device part.
The resource information for the Platform_device struct and the I²C controller is defined in the arch/arm/plat-samsung/dev-i2c0.c file:
[CPP]View Plaincopy
- Static struct resource s3c_i2c_resource[] ={
- [0]= {
- . start= S3C_PA_IIC,
- . end = S3c_pa_iic + Sz_4k-1,
- . flags= Ioresource_mem,
- },
- [1]= {
- . start= IRQ_IIC,
- . end = IRQ_IIC,
- . flags= Ioresource_irq,
- },
- };
- struct Platform_device s3c_device_i2c0 = {
- . Name = "S3C2410-I2C",/ * Device name * /
- #ifdef CONFIG_S3C_DEV_I2C1
- . id = 0,
- #else
- . id =-1,
- #endif
- . Num_resources =array_size (S3c_i2c_resource),
- . Resource =s3c_i2c_resource,
- };
- struct S3c2410_platform_i2cdefault_i2c_data __initdata = {
- . Flags = 0,
- . slave_addr = 0x10,/ */i²c Adapter Address * /
- . frequency = 100*1000,/ * Bus frequency * /
- . Sda_delay = +,/ * SDA Edge delay Time NS * /
- };
- void __init S3c_i2c0_set_platdata (structs3c2410_platform_i2c *pd)
- {
- STRUCTS3C2410_PLATFORM_I2C *NPD;
- if (!PD)
- Pd= &default_i2c_data;
- Npd= S3c_set_platdata (PD, sizeof (struct S3C2410_PLATFORM_I2C),
- &S3C_DEVICE_I2C0);
- if (!npd->cfg_gpio)
- Npd->cfg_gpio= S3c_i2c0_cfg_gpio;
- }
Register the Platform_device into the kernel in the board file:
[CPP]View Plaincopy
- Static struct platform_device*mini2440_devices[] __initdata = {
- ......
- &S3C_DEVICE_I2C0,
- ......
- };
Call the S3c_i2c0_set_platdata function to assign the adapter specific data to Dev.platform_data:
[CPP]View Plaincopy
- static void __init mini2440_init (void)
- {
- ......
- S3c_i2c0_set_platdata (NULL);
- }
The I²c bus driver is analyzed here.
Linux I²C Subsystem Architecture