迅为嵌入式linux驱动开发笔记(十一)—触摸屏驱动

总结篇

这一小节内容是对之前学习的十节课进行总复习,综合性非常强,完成触摸屏驱动需要学会如下知识:
1、驱动开发原理
第一节

2、platform平台总线模型
第三节

3、设备树
第四节

4、gpio子系统
第五节

5、中断原理
第六节

6、工作队列
第七节

7、input子系统
第九节

8、iic驱动原理
第十节

为了清晰描述触摸屏驱动实验,对代码每一句进行详细注释:

触摸屏驱动代码

#include<linux/init.h>
/*驱动模块*/
#include<linux/module.h>
/*IIC*/
#include <linux/i2c.h>
/*GPIO*/
#include <linux/gpio.h>
/*of函数获取gpio*/
#include <linux/of_gpio.h>
/*of函数获取中断*/
#include <linux/of_irq.h>
/*中断*/
#include <linux/interrupt.h>
/*输入子系统*/
#include <linux/input.h>
/*延时函数*/
#include <linux/delay.h>
/*工作队列*/
#include <linux/workqueue.h>
/*初始化设备节点*/
struct device_node *ft5x06_device_node;
/*定义设备编号*/
#define DEVICE_NODE 0X00 
/*屏幕设备寄存器地址*/
#define ID_G_MODE 0Xa4
/*定义中断号*/
int irq;
/*定义输入子系统设备*/
static struct input_dev *ft5x06_dev;
/*定义IIC适配器*/
static struct i2c_client *ft5x06_client;
/*声明IIC写函数*/
static void ft5x06_write_reg(u8 reg_addr,u8 data,u8 len);
/*中断入口函数*/
static void ft5x06_func(struct work_struct *work);
/*初始化工作队列*/
DECLARE_WORK(ft5x06_work,ft5x06_func);

/*定义IIC写函数*/
static void ft5x06_write_reg(u8 reg_addr,u8 data,u8 len)
{
		/*定义缓冲区大小*/
    u8 buff[256];
	/*初始化i2c_msg结构体*/
    struct i2c_msg msgs[] = {
            [0] = {
            /*主机地址*/
            .addr = ft5x06_client->addr,
            /*0为写*/
            .flags = 0,
            /*读取长度*/
            .len = len+1,
            /*缓存区的地址*/
            .buf = buff,
            }
    };
		/*存放寄存器的地址*/
    buff[0] = reg_addr;
		/*拷贝len字节的数据长度到buff[1]之后位置*/
    memcpy(&buff[1],&data,len);
	 /*iic数据包传送,参数1:适配器,参数2:数据包,参数3:数量*/
    i2c_transfer(ft5x06_client->adapter,msgs,1);  
}

/*定义IIC读函数*/
static int ft5x06_read_reg(u8 reg_addr)
{
		/*定义读出数据的返回值*/
    u8 data;
		/*封装结构体*/
    struct i2c_msg msgs[] = {
        [0] = {
        		/*主机地址*/
            .addr = ft5x06_client->addr,
            /*flags为0表示写入*/
            .flags = 0,
            /*读出字节长度*/
            .len = sizeof(reg_addr),
            /*读取函数的地址*/
            .buf = &reg_addr,
        },

        [1] = {
        		
            .addr = ft5x06_client->addr,
            .flags = 1,
            .len = sizeof(data),
            .buf = &data,
        }
    };
		/*iic数据包传送,参数1:适配器,参数2:数据包,参数3:数量为2*/
    i2c_transfer(ft5x06_client->adapter,msgs,2);
		/*返回读取到的数据*/
    return data;

}



static const struct i2c_device_id ft5x06_id_ts[] = {
    {"xxx",0},
    {}
};

static const struct of_device_id ft5x06_id[] = 
{
    {.compatible = "edt,edt-ft5306",0,},
    {.compatible = "edt,edt-ft5x06",0,},
    {.compatible = "edt,edt-ft5406",0,},
    {}

};

static void ft5x06_func(struct work_struct *work)
{
    //读取寄存器中的内容
    int TOUCH1_XH,TOUCH1_XL,x;

    int TOUCH1_YH,TOUCH1_YL,y;

    int TD_STATUS;

    //读取TOUCH1_XH寄存器的值
    TOUCH1_XH = ft5x06_read_reg(0x03);
    //读取TOUCH1_XL寄存器的值
    TOUCH1_XL = ft5x06_read_reg(0x04);

    //只想要12位,获取到X的坐标值
    x = ((TOUCH1_XH<<8)|TOUCH1_XL)&0x0fff;

     //读取TOUCH1_YH寄存器的值
    TOUCH1_YH = ft5x06_read_reg(0x05);
    //读取TOUCH1_XL寄存器的值
    TOUCH1_YL = ft5x06_read_reg(0x06);
    //只想要12位,获取到Y的坐标值
    y = ((TOUCH1_YH<<8)|TOUCH1_YL)&0x0fff;

    //读取寄存器TD_STATUS的值
    TD_STATUS = ft5x06_read_reg(0x02);
    //获取手指在屏幕上
    TD_STATUS = TD_STATUS&0xf;

    if (TD_STATUS == 0)//判断有没有手指按上,如果有的话,上报按下去的事件,如果没有的话,上报抬手事件
    {
        input_report_key(ft5x06_dev,BTN_TOUCH,0);//上报按键事件

        input_sync(ft5x06_dev);
    }
    else{
        input_report_key(ft5x06_dev,BTN_TOUCH,1);//上报按键事件

        input_report_abs(ft5x06_dev,ABS_X,x);

        input_report_abs(ft5x06_dev,ABS_Y,x);

        input_sync(ft5x06_dev);//上报完成

        

    }
    

}

static irqreturn_t ft5x06_handler(int irq,void* args)
{
    //启动中断下文
    schedule_work(&ft5x06_work);
    return IRQ_HANDLED;
}



int ft5x06_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
		/*定义返回值*/
    int ret;
		/*定义中断引脚*/
    int ft5x06_irq_gpio;
		/*定义复位引脚*/
    int ft5x06_reset_gpio;
    /*打印函数*/
    printk("ft5x06_probe\n");
	 /*因为要在别的地方用到client,所以要把他复制出来*/
    ft5x06_client = client;
    /*设备树位置,根据设备树信息查找屏幕挂载的位置信息,获得触摸芯片的节点*/
    ft5x06_device_node = of_find_node_by_path("/soc/aips-bus@02100000/i2c@021a4000/edt-ft5x06@38");
		/*出错判断*/
    if (ft5x06_device_node == NULL)
    {
        printk("of_find_node_by_path is error\n");
        return -1;
    }
    printk("ft5x06_device_node is %s \n",ft5x06_device_node->name);

    /*获得中断引脚的GPIO编号——节点名称,IO名称,第几个*/
    ft5x06_irq_gpio = of_get_named_gpio(ft5x06_device_node,"irq-gpios",0);
		/*出错判断*/
    if (ft5x06_irq_gpio<0)
    {
        printk("ft5x06_irq_gpio of_get_namd_gpio is error\n");
        return -2;
    }
    /*获得复位引脚的GPIO编号——节点名称,IO名称,第几个*/
    ft5x06_reset_gpio = of_get_named_gpio(ft5x06_device_node,"reset-gpios",0);
	 /*出错判断*/
    if (ft5x06_reset_gpio<0)
    {
        printk("ft5x06_reset_gpio of_get_namd_gpio is error\n");
        return -3;
    }
    printk("ft5x06_irq_gpio is %d \n",ft5x06_irq_gpio);
    printk("ft5x06_reset_gpio is %d \n",ft5x06_reset_gpio);
    /*避免申请失败*/
    gpio_free(ft5x06_irq_gpio);
    /*申请中断引脚*/
    ret = gpio_request(ft5x06_irq_gpio,"irq_gpio");
    /*出错判断*/
    if (ret<0)
    {
        printk("gpio_request is error\n");
        return -4;
    }
     /*申请复位引脚*/
    ret = gpio_request(ft5x06_reset_gpio,"reset_gpio");
    if (ret < 0)
    {
        printk("gpio_request is error\n");
        return -5;
    }
    /*设置中断引脚为输入*/
    gpio_direction_input(ft5x06_irq_gpio);
    /*操作一下复位的引脚,设置方向为输出,然后停止复位*/
    gpio_direction_output(ft5x06_reset_gpio,0);
    msleep(5);
    /*设置输出为高电平*/
    gpio_set_value(ft5x06_reset_gpio,1);

    /*获取中断号*/
    irq = gpio_to_irq(ft5x06_irq_gpio);
    /*中断号、触发方式、中断名称、传递参数*/
    ret = request_irq(irq,ft5x06_handler,IRQ_TYPE_EDGE_FALLING|IRQF_ONESHOT,"ft5x06_irq",NULL);
	/*出错判断*/
    if (ret<0)
    {
        printk("requset_irq is error\n");
        goto error_requset_irq;
    }
    
    /*工作模式为正常模式:地址:写入数据:数据长度*/
    ft5x06_write_reg(DEVICE_NODE,0,1);
    
    /*工作模式为中断模式:地址:写入数据:数据长度*/
    ft5x06_write_reg(ID_G_MODE,1,1);
		/*输入子系统申请设备*/
    ft5x06_dev = input_allocate_device();
		/*初始化设备名称*/
    ft5x06_dev->name = "ft5x06_input_test";
    /*支持按键事件*/
    __set_bit(EV_KEY,ft5x06_dev->evbit);
    /*支持绝对坐标事件*/
    __set_bit(EV_ABS,ft5x06_dev->evbit);
    /*支持触摸按键检测*/
    __set_bit(BTN_TOUCH,ft5x06_dev->keybit);
    /*支持X坐标*/
    __set_bit(ABS_X,ft5x06_dev->absbit);
    /*支持Y坐标*/
    __set_bit(ABS_Y,ft5x06_dev->absbit);
    /*支持压力检测*/
    __set_bit(ABS_PRESSURE,ft5x06_dev->keybit);

    input_set_abs_params(ft5x06_dev,ABS_X,0,1024,0,0);
    /*设置Y坐标*/
    input_set_abs_params(ft5x06_dev,ABS_Y,0,600,0,0);
    /*设置压力数值*/
    input_set_abs_params(ft5x06_dev,ABS_PRESSURE,0,255,0,0);
    /*注册到设备中*/
    ret = input_register_device(ft5x06_dev);
	 /*出错判断*/
    if (ret<0)
    {
        printk("input_register_device is error");
        goto error_input_register;
    }
   
    return 0;

/*错误处理*/
error_requset_irq:
    free_irq(irq,NULL);  
    
/*错误处理*/
error_input_register:
		/*释放中断*/
    free_irq(irq,NULL);
    /*注销设备*/
    input_unregister_device(ft5x06_dev);
    /*是否输入子系统*/
    input_free_device(ft5x06_dev);
    return ret;
}

/*remove函数*/
int ft5x06_remove(struct i2c_client *i2c_client)
{
    return 0;
}

/*初始化i2c_driver结构体*/
static struct i2c_driver ft5x06_driver = { 
			/*必须初始化的成员*/
			//int (*probe)(struct i2c_client *, const struct i2c_device_id *); 	
			//int (*remove)(struct i2c_client *); 
			//struct device_driver driver; 
			//const struct i2c_device_id *id_table;

			/*driver成员初始化*/
        .driver = {
        	/*表示当前模块下*/
            .owner = THIS_MODULE,
            /*驱动名称*/
            .name = "ft5x06_test",
            /*匹配id名称*/
            .of_match_table = ft5x06_id,
        },
		/*probe函数*/
        .probe = ft5x06_probe,
       /*remove函数*/
        .remove = ft5x06_remove,
        /*设备名称匹配*/
        .id_table = ft5x06_id_ts
         
}; 


/*驱动初始化*/
static int ft5x06_driver_init(void)
{
    /*返回值定义*/
    int ret;
		/*添加iic驱动*/
    ret = i2c_add_driver(&ft5x06_driver);
    /*出错判断*/
    if (ret < 0)
    {
        printk("i2c_add_driver is error\n");
        return ret;
    }
    printk("i2c_add_driver init\n");
    return 0;
}


/*定义驱动退出函数*/
static void ft5x06_driver_exit(void)
{
    /*删除iic设备*/
    i2c_del_driver(&ft5x06_driver);
	/*释放中断*/
    free_irq(irq,NULL);
	/*注销输入子系统*/
    input_unregister_device(ft5x06_dev);
	/*释放设备*/
    input_free_device(ft5x06_dev);
    printk("i2c_del_driver exit\n");

}
/*模块初始化*/
module_init(ft5x06_driver_init);
/*模块退出*/
module_exit(ft5x06_driver_exit);
MODULE_LICENSE("GPL");
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值