最近在做camera和ts的自动识别。因为平台上各种品牌的camera和ts种类繁多,而且有的i2c地址有冲突,通常是在board-device里面配置i2c设备,如果遇到不同机型有相同i2c地址则会造成设备创建失败,只能在编译的时候去改代码,这样调试多种机型就很繁琐,所以有了以下代码。
这里先看下camera的代码:
static int gc0309_lookfor_bus(struct gc0309_info *info)
{
uint8_t val;
uint32_t ver;
info->i2c_dev->adapter = i2c_get_adapter(i2c_bus);
gc0309_i2c_rx_receive(info->i2c_dev, 0x00, &val, 1);
ver = val;
cam_notice("read ver=%x\n", ver);
if (ver == 0xa0) {
cam_notice("gc0309 sensor detected...\n");
return 0;
}
cam_notice("gc0309 not found on all i2c bus.\n");
return -ENODEV;
}
static int gc0309_register_i2c_device(struct gc0309_info *info)
{
struct i2c_board_info board_info;
memset(&board_info, 0, sizeof(struct i2c_board_info));
board_info.addr = info->i2c_dev->addr;
strlcpy(board_info.type, "gc0309", I2C_NAME_SIZE);
info->i2c_dev = i2c_new_device(info->i2c_dev->adapter, &board_info);
if (info->i2c_dev == NULL) {
cam_err("can't add i2c device at 0x%x\n", (unsigned int)board_info.addr);
return -ENODEV;
}
return 0;
}
static int __init gc0309_init(void)
{
int ret;
struct v4l2_subdev *sd;
struct gc0309_info *info;
info = kzalloc(sizeof(struct gc0309_info), GFP_KERNEL);
if (info == NULL)
return -ENOMEM;
info->i2c_dev = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
if (info->i2c_dev == NULL)
return -ENOMEM;
/* get CAMERA clock */
info->camera = clk_get(&info->i2c_dev->dev, "camera");
if (IS_ERR(info->camera)) {
cam_err("failed to acquire camera divider\n");
ret = -ENODEV;
goto exit;
}
clk_set_rate(info->camera, GC0309_SENSOR_CLOCK);
clk_enable(info->camera);
/* request gpio */
gpio_request(GPIO_CAM_PWDN_B, "cam_pwdn_b");
gpio_request(GPIO_CAM_PWDN_F, "cam_pwdn_f");
gpio_request(GPIO_CAM_RST_F, "cam_rst_f");
/* firstly poweron */
gc0309_gpio_preset();
gc0309_poweron();
gc0309_gpio_reset();
info->i2c_dev->addr = 0x21;
if(gc0309_lookfor_bus(info)) goto exit_power;
if(gc0309_register_i2c_device(info)) goto exit_power;
/* after detection finished, poweroff */
gc0309_standby_mode();
gc0309_poweroff();
sd = &info->sd;
info->i2c_dev->driver = &gc0309_driver;
v4l2_i2c_subdev_init(sd, info->i2c_dev, &gc0309_ops);
ret = i2c_add_driver(&gc0309_driver);
if (ret) {
cam_err("gc0309_dev camera module gc0309 i2c driver add failed\n");
return ret;
}
return 0;
exit_power:
gc0309_standby_mode();
gc0309_poweroff();
clk_disable(info->camera);
clk_put(info->camera);
exit:
kfree(info->i2c_dev);
kfree(info);
return -EFAULT;
}
static void __exit gc0309_exit(void)
{
i2c_del_driver(&gc0309_driver);
}
module_param(i2c_bus, int , 0);
MODULE_PARM_DESC(i2c_bus, "gc0309 i2c bus number");
刚开始写的时候只管实现这个功能,没有注意优化,感觉很多地方没考虑周全,所以花时间优化了一下,下面就是优化后的ts代码:
static int ft5x0x_add_i2c_device(void)
{
int ret;
int reg_value;
struct i2c_board_info info;
struct i2c_adapter *adapter;
adapter = i2c_get_adapter(i2c_bus);
if (!adapter) {
atxxtp_err("can't get i2c adapter %d\n", i2c_bus);
return -ENODEV;
}
memset(&info, 0, sizeof(struct i2c_board_info));
info.addr = i2c_addr;
strlcpy(info.type, FT5X0X_NAME, I2C_NAME_SIZE);
this_client = i2c_new_device(adapter, &info);
i2c_put_adapter(adapter);
if (!this_client) {
atxxtp_err("can't add i2c device at 0x%x\n", i2c_addr);
return -ENODEV;
}
reg_value = ft5x0x_read_fw_ver(); //读取ts的版本号 以此判断设备是否存在
if(reg_value < 0 ) {
atxxtp_err("can't read ft5x06 firmware version\n");
ret = -ENODEV;
goto exit;
}
ret = i2c_add_driver(&ft5x0x_ts_driver);
if (ret) {
atxxtp_err("can't addd ft5x0x_ts i2c driver\n");
goto exit;
}
return 0;
exit:
i2c_unregister_device(this_client);
return ret;
}
static int __init ft5x0x_ts_init(void)
{
int ret;
ret = gpio_request(GPIO_TP_RESETn, FT5X0X_NAME);
if (ret != 0) {
atxxtp_err( "can't request GPIO %d!\n", GPIO_TP_RESETn);
return -EFAULT;
}
init_reset_tp();
mdelay(100);
if(ft5x0x_add_i2c_device())
goto exit;
return 0;
exit:
gpio_free(GPIO_TP_RESETn);
return -EFAULT;
}
static void __exit ft5x0x_ts_exit(void)
{
i2c_del_driver(&ft5x0x_ts_driver);
i2c_unregister_device(this_client);
}
module_param(i2c_bus, int, 0);
MODULE_PARM_DESC(i2c_bus, "ft5x0x_ts i2c bus number");
module_param(i2c_addr, ushort, 0);
MODULE_PARM_DESC(i2c_addr, "ft5x0x_ts i2c address");
还好之前看过i2c的核心代码并且总结了一下,不然还真得花些时间才能完成这个。