1.Linux主机驱动和外设驱动分离思想
外设驱动→API→主机驱动→板机逻辑--具体的i2c设备(camera,ts,eeprom等等)
2.主机驱动
根据控制器硬件手册,操作具体的寄存器,产生波形。
- Linux应用工程师:屏蔽了驱动和硬件
- Linux驱动工程师:屏蔽硬件,提供标准的主机驱动。驱动工程师需要完成“外设驱动”
- 内核函数接口:(API)。主机驱动提供給外设驱动的函数接口
- 注册i2c设备:i2c_board_info
- 驱动注册和卸载函数以及结构体:i2c_del_driver/i2c_add_driver, i2c_driver
- 读写函数和结构体:i2c_transfer, i2c_msg
这些函数放之四海之内皆准
3.外设驱动
针对具体的外部器件的代码。
- 摄像头以及声卡中i2c用来配置外部设备(声卡和摄像头)→地址和配置的内容都不一样!
4.板级逻辑
描述主机和外部设备是怎么连接的
5.设备-i2c设备注册以及设备注册之后的查询方法
- 查询i2c设备地址:ls /sys/bus/i2c/devices/
- 怎么和原理图以及外部设备对应:3-0038→I2C_3_SCL(addr:datasheet中查0x38)
- 查询i2c设备名称:cat /sys/bus/i2c/devices/3-0038/name
menuconfig中去掉触摸的驱动
- Device Drivers --->
- Input device support --->
- Touchscreens --->
- FT5X0X based touchscreens(去掉)
添加i2c设备:i2c_devs3[]中添加
{
I2C_BOARD_INFO("i2c_test", 0x70>>1),
},
cat /sys/bus/i2c/devices/3-0038/name结果是i2c_test
6.驱动-i2c驱动注册和卸载
i2c设备初始化完成-进入probe函数
i2c_del_driver/i2c_add_driver, i2c_driver
module_init和late_initcall:前面的优先加载,后面的延迟加载
驱动代码:
#include <linux/kernel.h> #include <linux/module.h> #include <linux/i2c.h> #include <linux/input.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/gpio.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <mach/gpio.h> #include <plat/gpio-cfg.h> #include <plat/ft5x0x_touch.h> #define I2C_TEST_NAME "i2c_test" static int i2c_test_probe(struct i2c_client *client, const struct i2c_device_id *id) { printk("==%s: \n", __FUNCTION__); return 0; } static int __devexit i2c_test_remove(struct i2c_client *client) { i2c_set_clientdata(client, NULL); //设置client为NULL printk("==%s: \n", __FUNCTION__); return 0; } static const struct i2c_device_id i2c_test_id[] = { { "i2c_test", 0 }, { } }; static struct i2c_driver i2c_test_driver = { .probe = i2c_test_probe, .remove = __devexit_p(i2c_test_remove), .id_table = i2c_test_id, .driver = { .name = I2C_TEST_NAME, .owner = THIS_MODULE, }, }; static void i2c_io_init() { int ret; ret = gpio_request(EXYNOS4_GPL0(2), "TP1_EN"); if(ret) { printk(KERN_ERR "failed to request TP1_EN for I2C control\n"); } gpio_direction_output(EXYNOS4_GPL0(2), 1); s3c_gpio_cfgpin(EXYNOS4_GPL0(2), S3C_GPIO_OUTPUT); gpio_free(EXYNOS4_GPL0(2)); mdelay(5); ret = gpio_request(EXYNOS4_GPX0(3), "GPX0_3"); if(ret) { gpio_free(EXYNOS4_GPX0(3)); ret = gpio_request(EXYNOS4_GPX0(3), "GPX0_3"); if(ret) { printk("i2c_io_test: Fialed to request GPX0_3 \n"); } } gpio_direction_output(EXYNOS4_GPX0(3), 0); mdelay(200); gpio_direction_output(EXYNOS4_GPX0(3), 1); s3c_gpio_cfgpin(EXYNOS4_GPX0(3), S3C_GPIO_OUTPUT); gpio_free(EXYNOS4_GPX0(3)); msleep(300); } static int __init i2c_test_init(void) { printk("==%s: \n", __FUNCTION__); i2c_io_init(); printk("==%s: \n", __FUNCTION__); return i2c_add_driver(&i2c_test_driver); } static void __exit i2c_test_exit(void) { printk("==%s: \n", __FUNCTION__); i2c_del_driver(&i2c_test_driver); } late_initcall(i2c_test_init); module_exit(i2c_test_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("TSI2CTEST"); MODULE_AUTHOR("iTOP");