0. i2c的一些说明
0.1 关于i2c驱动上的一些术语自己理解
i2c_adapter --> i2c 总线控制器 (板子上有5个i2c总线控制器,即有5个adapter)
i2c_algorithm --> i2c 总线控制器的核心通信算法数据传输方法 (1个algroithm)
i2c_client --> 挂在i2c总线上的一个个设备 (如:bma2x2, sp0a19)
0.2 i2c控制器的目录结构
cong@ubuntu:/rk/rk3188/kernel/drivers/i2c$ tree
├── busses
│ ├── i2c-rk30-adapter.c
│ ├── i2c-rk30.c
│ └── i2c-rk30.h
├── i2c-boardinfo.c
├── i2c-core.c
├── i2c-core.h
├── i2c-dev.c
├── i2c-mux.c
└── i2c-smbus.c
i2c控制器的初始化包括以下三个方面:
a. i2c-rk30.c --> rk30_i2c_probe
这个是rk3188中i2c控制器的初始化,主要是形成一个i2c_adapter结构体并与i2c_algorithm关联起来
b. i2c-dev.c --> i2c_dev_init --> i2cdev_attach_adapter
c. i2c-rk30.c --> i2c_detect_rk610
一. i2c控制器的初始化
1. i2c 控制器硬件设备的定义及注册过程
在arch/arm/mach-rk30/devices.c中
一共定义了5个i2c的设备
-
static struct rk30_i2c_platform_data default_i2c0_data = {
-
.bus_num = 0, //0-4 共5个adapter
-
.is_div_from_arm = 1,
-
.adap_type = I2C0_ADAP_TYPE,
-
.sda_mode = I2C0_SDA,
-
.scl_mode = I2C0_SCL,
-
};
-
-
static struct resource resources_i2c0[] = {
-
{
-
.start = IRQ_I2C0,
-
.end = IRQ_I2C0,
-
.flags = IORESOURCE_IRQ,
-
},
-
{
-
.start = I2C0_START,
-
.end = I2C0_END,
-
.flags = IORESOURCE_MEM,
-
},
-
};
-
-
static struct platform_device device_i2c0 = {
-
.name = "rk30_i2c",
-
.id = 0, //id从0-4
-
.num_resources = ARRAY_SIZE(resources_i2c0),
-
.resource = resources_i2c0,
-
.dev = {
-
.platform_data = &default_i2c0_data,
-
},
-
}
2. i2c 驱动器驱动的初始化
在drivers/i2c/busses/i2c-rk30.c中
-
static struct platform_driver rk30_i2c_driver = {
-
.probe = rk30_i2c_probe,
-
.remove = rk30_i2c_remove,
-
.driver = {
-
.owner = THIS_MODULE,
-
.name = "rk30_i2c", //这个name跟i2c_devices的name是一样的
-
.pm = rk30_DEV_PM_OPS,
-
},
-
};
-
-
static int __init i2c_adap_init(void)
-
{
-
return platform_driver_register(&rk30_i2c_driver);
-
}
-
subsys_initcall(i2c_adap_init);
根据arch/arm/mach-rk30/devices.c中名为rk30-i2c的设备,为每一个i2c设备创建一个i2c_adapter结构体,
这儿一共是5个i2c 设备,所以这个rk30_i2c_probe要调用5次
-
static int rk30_i2c_probe(struct platform_device *pdev)
-
{
-
struct rk30_i2c *i2c = NULL;
-
struct rk30_i2c_platform_data *pdata = NULL;
-
struct resource *res;
-
int ret;
-
//读取i2c dvices中的读取
-
pdata = pdev->dev.platform_data;
-
i2c = kzalloc(sizeof(struct rk30_i2c), GFP_KERNEL);
-
i2c->con_base = (void __iomem *)GRF_I2C_CON_BASE;
-
i2c_adap_sel(i2c, pdata->bus_num, pdata->adap_type);
-
i2c->sda_mode = pdata->sda_mode;
-
i2c->scl_mode = pdata->scl_mode;
-
-
//初始化结构体i2c
-
strlcpy(i2c->adap.name, "rk30_i2c", sizeof(i2c->adap.name));
-
i2c->adap.owner = THIS_MODULE;
-
i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
-
i2c->tx_setup = TX_SETUP;
-
i2c->adap.retries = 2;
-
i2c->adap.timeout = msecs_to_jiffies(100);
-
-
spin_lock_init(&i2c->lock);
-
init_waitqueue_head(&i2c->wait);
-
mutex_init(&i2c->m_lock);
-
-
//使能i2c时钟
-
i2c->dev = &pdev->dev;
-
i2c->clk = clk_get(&pdev->dev, "i2c");
-
clk_enable(i2c->clk);
-
-
//ioreamp i2c控制器寄存器
-
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));
-
i2c->adap.algo_data = i2c;
-
i2c->adap.dev.parent = &pdev->dev;
-
i2c->adap.nr = pdata->bus_num;
-
-
//将i2c adapter与i2c algorithm关联起来
-
i2c_add_rk30_adapter(&i2c->adap);
-
--> i2c_add_numbered_adapter
-
-->i2c_register_adapter
-
//此处设置了adapter的name为:i2c-0,i2c-1,i2c-2 ..
-
//然后通过 device_register创建了设备结点 /dev/i2c-0 /dev-i2c-1 ..
-
//class_create 是在 drivers/i2c/i2c_dev.c中
-
--> i2c_scan_static_board_info
-
//将i2c_board_list上的设备用i2c_new_devices添加到i2c总线上去.
-
//这也年出为什么i2c_client的注册一定要先于i2c_adapter的注册,
-
//因为只有i2c_client都注册过了,i2c_adapter才可以在注册时搜到i2c_client.
-
static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
-
{
-
struct i2c_devinfo *devinfo;
-
down_read(&__i2c_board_lock);
-
list_for_each_entry(devinfo, &__i2c_board_list, list) {
-
//dbmsg("boad_info.type=%s", devinfo->board_info.type);
-
//将i2c_board_list上的设备用i2c_new_devices添加到i2c总线上去.
-
if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter, &devinfo->board_info))
-
dev_err(&adapter->dev, "Can't create device at 0x%02x\n", devinfo->board_info.addr);
-
}
-
up_read(&__i2c_board_lock);
-
}
//申请i2c中断,因为每次进入probe时pdev都不一样,所以这儿的中断号也不会重复
-
i2c->irq = ret = platform_get_irq(pdev, 0);
-
request_irq(i2c->irq, i2c->i2c_irq, IRQF_DISABLED, dev_name(&pdev->dev), i2c);
-
-
ret = rk30_i2c_register_cpufreq(i2c);
-
platform_set_drvdata(pdev, i2c);
-
i2c->is_div_from_arm[i2c->adap.nr] = pdata->is_div_from_arm;
-
i2c->i2c_init_hw(i2c, 100 * 1000);
-
i2c_max_adap++;
-
return 0;
-
}
二.I2c设备的初始化
2.1 i2c设备的静态注册
注册过程如下:
a. 初始化 i2c_board_info结构体,即声明i2c_client
b. 调用i2c_register_board_info将i2c_board_info结构体添加到i2c_board_list中
c. 在i2c_add_adapter的最后,即添加完成i2c_adapter之后对i2c_board_list进行遍历,将找到的i2c_client添加
a.定义i2c_board_info结构体
在arch/arm/mach-rk3188/board-rk3188-ds1006h.c中,
-
static struct i2c_board_info __initdata i2c0_info[] = {
-
{
-
.type = "gs_mma8452",
-
.addr = 0x1d,
-
.flags = 0,
-
.irq = MMA8452_INT_PIN,
-
.platform_data = &mma8452_info,
-
},
-
}
b.将i2c_board_info添加到i2c_board_list中去
在arch/arm/mach-rk3188/board-rk3188-ds1006h.c中
machine_rk30_board_init
//在平台的初始化函数中调用register
--> rk30_i2c_register_board_info
-
static void __init rk30_i2c_register_board_info(void)
-
{
-
i2c_register_board_info(0, i2c0_info, ARRAY_SIZE(i2c0_info));
-
int __init i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len)
-
{
-
//这个函数的作用就是把定义的i2c_board_info添加到i2c_board_list中去
-
for (status = 0; len; len--, info++) {
-
struct i2c_devinfo *devinfo;
-
devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
-
devinfo->busnum = busnum;
-
devinfo->board_info = *info;
-
list_add_tail(&devinfo->list, &__i2c_board_list);
-
}
-
return status;
-
}
i2c_register_board_info(1, i2c1_info, ARRAY_SIZE(i2c1_info));
-
i2c_register_board_info(2, i2c2_info, ARRAY_SIZE(i2c2_info));
-
i2c_register_board_info(3, i2c3_info, ARRAY_SIZE(i2c3_info));
-
i2c_register_board_info(4, i2c4_info, ARRAY_SIZE(i2c4_info));
-
i2c_register_board_info(5, i2c_gpio_info, ARRAY_SIZE(i2c_gpio_info));
-
}
利用函数i2c_register_board_info将i2c_board_info结构体添加到i2c设备列表中.
这一步要先于i2c_adapter的注册,因为只有i2c_client都注册过了,i2c_adapter才可以在注册时搜到i2c_client.
c. 调用i2c_new_device添加i2c_client
然后在i2c_adapter的注册最后,调用i2c_scan_static_board_info遍历i2c_board_list添加i2c_client.
-
static int i2c_register_adapter(struct i2c_adapter *adap)
-
{
-
rt_mutex_init(&adap->bus_lock);
-
mutex_init(&adap->userspace_clients_lock);
-
INIT_LIST_HEAD(&adap->userspace_clients);
-
-
dev_set_name(&adap->dev, "i2c-%d", adap->nr);
-
adap->dev.bus = &i2c_bus_type;
-
adap->dev.type = &i2c_adapter_type;
-
res = device_register(&adap->dev); //注册完i2c_adapter之后
-
if (adap->nr < __i2c_first_dynamic_bus_num)
-
i2c_scan_static_board_info(adap); //对i2c_register_board_info添加到i2c_board_list的设备
-
//调用i2c_new_device添加设备
-
-
mutex_lock(&core_lock);
-
bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
-
mutex_unlock(&core_lock);
-
-
return 0;
-
}
调用i2c_scan_static_board_info遍历i2c_board_list添加i2c_client.
-
static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
-
{
-
struct i2c_devinfo *devinfo;
-
down_read(&__i2c_board_lock);
-
list_for_each_entry(devinfo, &__i2c_board_list, list) {
-
if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter, &devinfo->board_info))
-
dev_err(&adapter->dev, "Can't create device at 0x%02x\n", devinfo->board_info.addr);
-
}
-
up_read(&__i2c_board_lock);
-
}
2.2 i2c设备的动态注册
一个问题: 不知道camera 的 i2c 设备是哪儿定义的.
a. 我在看sp0a19 camera驱动的时候发现在i2c0_info, i2c1_info, ... , i2c4_info的时候没有发现sp0a19
b. 在注册i2c 设备的时候 i2c_register_board_info中 ARRAY_SIZE(i2c3_info) =0;
c. 但是在 sp0a19的i2c_driver_probe函数中 adapter->nr==3;
然后在 drivers/media/video/sp0a19.c中的i2c_driver_probe加上dump_stack();发现打印如下
-
<5>[ 3.604848] cong:drivers/media/video/sp0a19.c:sensor_probe[2921]: in i2c->probe sp0a19:adapter->nr = 3
-
<4>[ 3.604910] [<c043e3b0>] (unwind_backtrace+0x0/0xf8) from [<c06f9a7c>] (sensor_probe+0x38/0x384)
-
<4>[ 3.604960] [<c06f9a7c>] (sensor_probe+0x38/0x384) from [<c06ddf74>] (i2c_device_probe+0xc0/0xfc)
-
<4>[ 3.605009] [<c06ddf74>] (i2c_device_probe+0xc0/0xfc) from [<c063f5a8>] (driver_probe_device+0x90/0x1ac)
-
<4>[ 3.605059] [<c063f5a8>] (driver_probe_device+0x90/0x1ac) from [<c063e384>] (bus_for_each_drv+0x118/0x278)
-
<4>[ 3.605108] [<c063e384>] (bus_for_each_drv+0x118/0x278) from [<c063f4d8>] (device_attach+0x94/0xb8)
-
<4>[ 3.605153] [<c063f4d8>] (device_attach+0x94/0xb8) from [<c063ed28>] (bus_probe_device+0x24/0x40)
-
<4>[ 3.605198] [<c063ed28>] (bus_probe_device+0x24/0x40) from [<c063d2ec>] (device_add+0x4bc/0x588)
-
<4>[ 3.605244] [<c063d2ec>] (device_add+0x4bc/0x588) from [<c06dea0c>] (i2c_new_device+0x104/0x1e4)
-
<4>[ 3.605294] [<c06dea0c>] (i2c_new_device+0x104/0x1e4) from [<c06f4ae0>] (v4l2_i2c_new_subdev_board+0x22c/0x268)
-
<4>[ 3.605348] [<c06f4ae0>] (v4l2_i2c_new_subdev_board+0x22c/0x268) from [<c0700f5c>] (soc_camera_probe+0x2cc/0x8d4)
-
<4>[ 3.605401] [<c0700f5c>] (soc_camera_probe+0x2cc/0x8d4) from [<c063f5a8>] (driver_probe_device+0x90/0x1ac)
-
<4>[ 3.605449] [<c063f5a8>] (driver_probe_device+0x90/0x1ac) from [<c063e384>] (bus_for_each_drv+0x118/0x278)
-
<4>[ 3.605497] [<c063e384>] (bus_for_each_drv+0x118/0x278) from [<c063f4d8>] (device_attach+0x94/0xb8)
-
<4>[ 3.605543] [<c063f4d8>] (device_attach+0x94/0xb8) from [<c063ed28>] (bus_probe_device+0x24/0x40)
-
<4>[ 3.605587] [<c063ed28>] (bus_probe_device+0x24/0x40) from [<c063d2ec>] (device_add+0x4bc/0x588)
-
<4>[ 3.605631] [<c063d2ec>] (device_add+0x4bc/0x588) from [<c070082c>] (soc_camera_host_register+0x268/0x2d0)
-
<4>[ 3.605682] [<c070082c>] (soc_camera_host_register+0x268/0x2d0) from [<c0705588>] (rk_camera_probe+0x488/0x7ec)
-
<4>[ 3.605733] [<c0705588>] (rk_camera_probe+0x488/0x7ec) from [<c06407c0>] (platform_drv_probe+0x18/0x1c)
-
<4>[ 3.605781] [<c06407c0>] (platform_drv_probe+0x18/0x1c) from [<c063f5a8>] (driver_probe_device+0x90/0x1ac)
-
<4>[ 3.605829] [<c063f5a8>] (driver_probe_device+0x90/0x1ac) from [<c063f750>] (__driver_attach+0x8c/0x90)
-
<4>[ 3.605876] [<c063f750>] (__driver_attach+0x8c/0x90) from [<c063e7b4>] (bus_for_each_dev+0x5c/0x88)
-
<4>[ 3.605921] [<c063e7b4>] (bus_for_each_dev+0x5c/0x88) from [<c063ef80>] (bus_add_driver+0x180/0x254)
-
<4>[ 3.605967] [<c063ef80>] (bus_add_driver+0x180/0x254) from [<c063fbfc>] (driver_register+0x78/0x13c)
-
<4>[ 3.606014] [<c063fbfc>] (driver_register+0x78/0x13c) from [<c0701b98>] (rk_camera_init_async+0x10/0x18)
-
<4>[ 3.606061] [<c0701b98>] (rk_camera_init_async+0x10/0x18) from [<c048c8c4>] (kthread+0x80/0x88)
最终发现i2c的设备注册还有另外一种方式---> i2c设备的动态注册
2.2.1 I2C camera 的定义
在arch/arm/plat-rk/rk_camera.c中
-
static struct rk29camera_platform_data rk_camera_platform_data = {
-
.io_init = rk_sensor_io_init,
-
.io_deinit = rk_sensor_io_deinit,
-
.iomux = rk_sensor_iomux,
-
.sensor_ioctrl = rk_sensor_ioctrl,
-
.sensor_register = rk_sensor_register,
-
.register_dev = {
-
{
-
.i2c_cam_info = {
-
I2C_BOARD_INFO(SENSOR_NAME_1, CONFIG_SENSOR_IIC_ADDR_1>>1) //sp0a19,
-
},
-
.device_info = {
-
.name = "soc-camera-pdrv",
-
.dev = {
-
.init_name = SENSOR_DEVICE_NAME_1,
-
}
-
}
-
},
-
},
-
.register_dev_new = new_camera,
-
};
在module_init(rk_register_camera_devices)中定义了I2C_BOARD_INFO,但是没有像静态注册一样调用i2c_register_board_info.
那动态注册时的i2c_register_board_info是如何实现的呢?
在drivers/media/video/soc_camera.c中
-
static int soc_camera_probe(struct device *dev)
-
{
-
if (icl->board_info) {
-
soc_camera_init_i2c(icd, icl);
-
}
-
}
在drivers/media/video/soc_camera.c中
-
static int soc_camera_init_i2c(struct soc_camera_device *icd,
-
struct soc_camera_link *icl)
-
{
-
struct i2c_client *client;
-
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
-
struct i2c_adapter *adap = i2c_get_adapter(icl->i2c_adapter_id);
-
struct v4l2_subdev *subdev;
-
-
icl->board_info->platform_data = icd;
-
-
subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap, icl->board_info, NULL);
-
-
client = v4l2_get_subdevdata(subdev);
-
-
dev_set_drvdata(&icd->dev, &client->dev);
-
-
return 0;
-
}
soc_camera_probe
--> soc_camera_init_i2c(icd, icl);
--> v4l2_i2c_new_subdev_board
在drivers/media/video/v4l2-common.c中
-
struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
-
struct i2c_adapter *adapter, struct i2c_board_info *info,
-
const unsigned short *probe_addrs)
-
{
-
struct v4l2_subdev *sd = NULL;
-
struct i2c_client *client;
-
-
request_module(I2C_MODULE_PREFIX "%s", info->type);
-
-
if (info->addr == 0 && probe_addrs)
-
client = i2c_new_probed_device(adapter, info, probe_addrs, NULL);
-
else
-
client = i2c_new_device(adapter, info); //终于又出来i2c_new_device了
-
-
sd = i2c_get_clientdata(client);
-
-
v4l2_device_register_subdev(v4l2_dev, sd))
-
-
module_put(client->driver->driver.owner);
-
return sd;
-
}
-
EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board);
三. 传输过程
ret = sensor_read(client, 0x02, &pid);
-
static int sensor_read(struct i2c_client *client, u8 reg, u8 *val)
-
{
-
阅读(4881) | 评论(0) | 转发(1) |