linux驱动之I2C总线驱动框架分析

Bonnie ·
更新时间:2024-11-11
· 807 次阅读

Table of Contents

1、I2C模型框图

2、设备信息层

2.1、非设备树形式

2.2、设备树形式

3、芯片控制器层adapter

3.1、控制器初始化 

3.2、控制器底层传输函数(起始,数据,应答,停止)

4、核心层core.c   i2c_bus

4.1、i2c_bus总线初始化

4.2、client(设备)和i2c_driver(设备驱动)匹配过程

4.2.1、创建client(设备)时匹配i2c_driver(驱动)过程

4.2.2、注册i2c_driver(驱动)时匹配client(设备)过程

4.3、总线探测probe

5、设备驱动层

5.1、设备驱动注册

5.2、设备驱动探测probe,并初始化i2c器件

5.3、数据传输

1、I2C模型框图

2、设备信息层 2.1、非设备树形式 static struct mma7660_platform_data mma7660_pdata = { .irq = IRQ_EINT(25), .poll_interval = 100, .input_fuzz = 4, .input_flat = 4, }; static struct i2c_board_info smdk4x12_i2c_devs3[] __initdata = { { I2C_BOARD_INFO("mma7660", 0x4c), .platform_data = &mma7660_pdata, }, };

    i2c_register_board_info(3, smdk4x12_i2c_devs3,ARRAY_SIZE(smdk4x12_i2c_devs3));

                   list_add_tail(&devinfo->list, &__i2c_board_list);

2.2、设备树形式

参考文章:I2C、SPI设备树驱动对设备子节点的处理

&i2c_3 { #address-cells = ; #size-cells = ; compatible = "samsung,s3c2440-i2c"; reg = ; interrupts = ; clocks = ; clock-names = "i2c"; samsung,i2c-sda-delay = ; samsung,i2c-slave-addr = ; samsung,i2c-max-bus-freq = ; pinctrl-0 = ; pinctrl-names = "default"; status = "okay"; codec: mma7660@1a { compatible = "mma7660"; reg = ; clocks = ; clock-names = "MCLK1"; }; }; 3、芯片控制器层adapter 3.1、控制器初始化 

参考文章:I2C、SPI设备树驱动对设备子节点的处理

处理器有n个i2c控制器,那么就需要注册n个adapter 一个i2c控制器(接口)下可能接有多个i2c器件,因此一个adapter可能对应多个client static struct platform_driver s3c24xx_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 = of_match_ptr(s3c24xx_i2c_match), }, }; static int __init i2c_adap_s3c_init(void) { return platform_driver_register(&s3c24xx_i2c_driver); } static int s3c24xx_i2c_probe(struct platform_device *pdev) { ret = s3c24xx_i2c_init(i2c); //初始化i2c硬件控制器 ret = i2c_add_numbered_adapter(&i2c->adap); //注册adapter,并转化设备信息为client of_i2c_register_devices(&i2c->adap); //转化设备树节点为client return ret; } 3.2、控制器底层传输函数(起始,数据,应答,停止) static const struct i2c_algorithm s3c24xx_i2c_algorithm = { .master_xfer = s3c24xx_i2c_xfer, .functionality = s3c24xx_i2c_func, }; static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data; ret = s3c24xx_i2c_doxfer(i2c, msgs, num); return -EREMOTEIO; } static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int num) { unsigned long timeout; int ret; if (i2c->suspended) return -EIO; ret = s3c24xx_i2c_set_master(i2c); if (ret != 0) { dev_err(i2c->dev, "cannot get bus (error %d)\n", ret); ret = -EAGAIN; goto out; } i2c->msg = msgs; i2c->msg_num = num; i2c->msg_ptr = 0; i2c->msg_idx = 0; i2c->state = STATE_START; s3c24xx_i2c_enable_irq(i2c); s3c24xx_i2c_message_start(i2c, msgs); //开始传输 } 4、核心层core.c   i2c_bus 4.1、i2c_bus总线初始化 struct bus_type i2c_bus_type = { .name = "i2c", .match = i2c_device_match, .probe = i2c_device_probe, .remove = i2c_device_remove, .shutdown = i2c_device_shutdown, .pm = &i2c_device_pm_ops, }; static int __init i2c_init(void) { retval = bus_register(&i2c_bus_type); } 4.2、client(设备)和i2c_driver(设备驱动)匹配过程 4.2.1、创建client(设备)时匹配i2c_driver(驱动)过程 i2c_new_device device_register device_add bus_probe_device device_attach bus_for_each_drv __device_attach driver_match_device //匹配 drv->bus->match driver_probe_device //探测 really_probe dev->bus->probe 4.2.2、注册i2c_driver(驱动)时匹配client(设备)过程 i2c_add_driver i2c_register_driver driver_register bus_add_driver driver_attach bus_for_each_dev __driver_attach driver_match_device //匹配 drv->bus->match driver_probe_device //探测 really_probe dev->bus->probe 4.3、总线探测probe static int i2c_device_probe(struct device *dev) { driver = to_i2c_driver(dev->driver); //获得设备驱动 client->driver = driver; //调用设备驱动probe函数 status = driver->probe(client, i2c_match_id(driver->id_table, client)); return status; } 5、设备驱动层 5.1、设备驱动注册 static struct i2c_driver i2c_mma7660_driver = { .driver = { .name = MMA7660_NAME, }, .probe = mma7660_probe, .remove = __devexit_p(mma7660_remove), .suspend = mma7660_suspend, .resume = mma7660_resume, .id_table = mma7660_ids, }; static int __init init_mma7660(void) { int ret; ret = i2c_add_driver(&i2c_mma7660_driver); //注册驱动 printk(KERN_INFO "MMA7660 sensor driver registered.\n"); return ret; } 5.2、设备驱动探测probe,并初始化i2c器件 static int __devinit mma7660_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); //得到i2c控制器信息 mma7660_initialize(client); //i2c器件初始化 ret = input_register_polled_device(mma7660_idev);//把i2c设备当输入设备访问 return 0; } 5.3、数据传输

整体调用过程

mma7660_read_xyz
       i2c_smbus_read_byte_data
               i2c_smbus_xfer
                      adapter->algo->smbus_xfer

详细调用过程 

static void mma7660_dev_poll(struct input_polled_dev *dev) { mma7660_report_abs(); } static void mma7660_report_abs(void) { int axis[3]; int i; for (i = 0; i input, ABS_X, axis[0]); input_report_abs(mma7660_idev->input, ABS_Y, axis[1]); input_report_abs(mma7660_idev->input, ABS_Z, axis[2]); input_sync(mma7660_idev->input); //printk("3-Axis ... %3d, %3d, %3d\n", axis[0], axis[1], axis[2]); } static int mma7660_read_xyz(struct i2c_client *client, int idx, int *xyz) { val = i2c_smbus_read_byte_data(client, idx + MMA7660_XOUT); return 0; } s32 i2c_smbus_read_byte_data(const struct i2c_client *client, u8 command) { union i2c_smbus_data data; int status; status = i2c_smbus_xfer(client->adapter, client->addr, client->flags, I2C_SMBUS_READ, command, I2C_SMBUS_BYTE_DATA, &data); return (status algo->smbus_xfer(adapter, addr, flags, read_write, command, protocol, data); return res; } shenlong1356 原创文章 144获赞 144访问量 9万+ 关注 私信 展开阅读全文
作者:shenlong1356



i2c总线 i2c Linux 框架

需要 登录 后方可回复, 如果你还没有账号请 注册新账号