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

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 = <1>;
	#size-cells = <0>;
	compatible = "samsung,s3c2440-i2c";
	reg = <0x13890000 0x100>;
	interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
	clocks = <&clock CLK_I2C3>;
	clock-names = "i2c";
	samsung,i2c-sda-delay = <100>;
	samsung,i2c-slave-addr = <0x10>;
	samsung,i2c-max-bus-freq = <100000>;
	pinctrl-0 = <&i2c3_bus>;
	pinctrl-names = "default";
	status = "okay";

	codec: mma7660@1a {
		compatible = "mma7660";
		reg = <0x4c>;
		clocks = <&pmu_system_controller 0>;
		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 < 3; i++) {
		mma7660_read_xyz(mma7660_client, i, &axis[i]);
	}

	input_report_abs(mma7660_idev->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 < 0) ? status : data.byte;
}

s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
		   char read_write, u8 command, int protocol,
		   union i2c_smbus_data *data)
{
	
			res = adapter->algo->smbus_xfer(adapter, addr, flags,
							read_write, command,
							protocol, data);
			
	return res;
}

 

 

 

 

 

 

 

 

©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页