[RK3128][Android7.1]android鼠标按键板驱动模版

touchpad.c

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>

#include <linux/io.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/regulator/consumer.h>
#include <linux/of_platform.h>
#include <linux/moduleparam.h>
#include <linux/pm.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/debugfs.h>

#include<asm-generic/uaccess.h>      //copy_to_user     copy_from_user
#include<linux/cdev.h>       		//Linux2.6标准字符设备注册文件
#include<linux/device.h>     		//自动创建设备类头文件
#include<linux/fs.h>         		//file_operations文件操作方法集合
#include <linux/slab.h>      		//kfree释放内存头文件
#include <linux/input.h>			//input设备
#include <linux/ioctl.h>			//iocrl函数
#include "touchpad.h"  //ioctl命令
#include <linux/list.h>              //定时器
#include <linux/i2c.h> 				 //I2C设备
#include <linux/pwm.h>
#include <linux/of_gpio.h>

#include <linux/delay.h>
#include <asm/gpio.h>
#include<linux/gpio.h>

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/rockchip/iomap.h>
#include <linux/rockchip/cpu.h>
#include <linux/of.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/rockchip/common.h>
#include <linux/kthread.h>

#define grf_writel(v, offset) \
	do { writel_relaxed(v, RK_GRF_VIRT + offset); dsb(); } while (0)


#if 1
#define DPP_DBG(x...) printk(x)
#else
#define DPP_DBG(x...) do { } while (0)
#endif

#define touch_STATE_ON 	281
#define touch_STATE_OFF 	282

#define POWER_ON	0x00
#define POWER_OFF	0x01

#define DEVICE_NAME "touch"  //平台驱动设备模型设备名,在/dev/目录下生成
#define I2C_SPEED 100*1000

static struct i2c_client *touch_client;  //I2C结构体
struct i2c_adapter *touch_i2c_adapter; 




static struct input_dev *input;
struct delayed_work power_touch_delay_work;
struct workqueue_struct *power_touch_workqueue;

int state = 0;
int gpio_int;
int amimouse_lastx = 0;
int amimouse_lasty = 0;
bool mode = 0;

static struct Touch_data touch_data ={
	.power_flag 	= touch_STATE_ON,  
	.major 			= 0,
	.minor 			= 0,
	.devid 			= 0, 
};

void send_touch(int code)
{
	if (!input)
		return;
	input_event(input, EV_KEY, code, 1);
	input_sync(input);
	msleep(100);
	input_event(input, EV_KEY, code, 0);
	input_sync(input);
}





int touch_write_ext(unsigned char addr,unsigned char length,unsigned char *value)
{
	int ret;
	
    DPP_DBG(KERN_EMERG "line:%d,%s is called\n", __LINE__, __FUNCTION__);

	ret = i2c_smbus_write_i2c_block_data(touch_client, addr ,length,value);

	if(ret < 0)
		return -1;
	else
		return 0;
}

int touch_read_ext(unsigned char addr,unsigned char length,unsigned char *value)
{
	int ret;
	
	DPP_DBG(KERN_EMERG "line:%d,%s is called\n", __LINE__, __FUNCTION__);
	
	ret = i2c_smbus_read_i2c_block_data(touch_client, addr,length+1,value);
	
	if(ret < 0)
		return -1;
	else
		return 0;
}
static int i2c_master_reg8_send(const struct i2c_client *client, const char reg, const char *buf, int count, int scl_rate)
{
    struct i2c_adapter *adap=client->adapter;
    struct i2c_msg msg;
    int ret;
    char *tx_buf = (char *)kzalloc(count + 1, GFP_KERNEL);
    if(!tx_buf)
        return -ENOMEM;
    tx_buf[0] = reg;
    memcpy(tx_buf+1, buf, count); 
 
    msg.addr = client->addr;
    msg.flags = client->flags;
    msg.len = count + 1;
    msg.buf = (char *)tx_buf;
    msg.scl_rate = scl_rate;
 
    ret = i2c_transfer(adap, &msg, 1); 
    kfree(tx_buf);
    return (ret == 1) ? count : ret;
 
}

static int i2c_master_reg8_recv(const struct i2c_client *client, const char reg, char *buf, int count, int scl_rate)
{
    struct i2c_adapter *adap=client->adapter;
    struct i2c_msg msg;
    int ret;
    //char reg_buf = reg;
 
    msg.addr = client->addr;
    msg.flags = client->flags | I2C_M_RD;
    msg.len = count;
    msg.buf = (char *)buf;
    msg.scl_rate = scl_rate;
 
    ret = i2c_transfer(adap, &msg, 1); 
 
    return (ret == 2)? count : ret;
}

int touch_rx_data(struct i2c_client *client, char *rxData, int length)
{
	int ret = 0;
	char reg = rxData[0];
	ret = i2c_master_reg8_recv(client, reg, rxData, length, I2C_SPEED);
	return (ret > 0)? 0 : ret;
}

static int touch_tx_data(struct i2c_client *client, char *txData, int length)
{
	int ret = 0;
	char reg = txData[0];
	ret = i2c_master_reg8_send(client, reg, &txData[1], length-1, I2C_SPEED);
	return (ret > 0)? 0 : ret;
}



int touch_write_reg(struct i2c_client *client,int addr,int value)
{
	char buffer[3];
	int ret = 0;

	buffer[0] = addr;
	buffer[1] = value;
	ret = touch_tx_data(client, &buffer[0], 2);
	return ret;
}


static void power_touch_work(struct work_struct *work)
{
	
	
	queue_delayed_work(power_touch_workqueue,
			   &power_touch_delay_work, msecs_to_jiffies(100));
			   
}



int touch_read_reg(struct i2c_client *client, int addr)
{
	char tmp[6];
	int ret = 0;
	
	int nx, ny;
	

	tmp[0] = addr;
	ret = touch_rx_data(client, tmp, 6);
	if (ret < 0) {
		return ret;
	}
	if (tmp[0] == 0x50){
		
		if (tmp[5]!=0){
			if (tmp[5] == 0x01){

				send_touch(KEY_VOLUMEDOWN);
			} else if (tmp[5] == 0x02){
				send_touch(KEY_VOLUMEUP);
			} else if (tmp[5] == 0x03){
				send_touch(KEY_MENU);
			} else if (tmp[5] == 0x04){
				send_touch(KEY_HOME);
			} else if (tmp[5] == 0x05){
				send_touch(KEY_BACK);
			} else if (tmp[5] == 0x06){
				send_touch(KEY_POWER);
			} else if (tmp[5] == 0x07){
				send_touch(KEY_POWER);
			}
		} else if (tmp[4]!=0) {
			nx = tmp[1];
			ny = tmp[4];
		
			if (tmp[1]==1){
				/*if (tmp[4]==1){
					input_report_rel(input, REL_X, 0);
					input_report_rel(input, REL_Y, 0);
					input_report_rel(input, REL_WHEEL, 1);  
				} else {
					input_report_rel(input, REL_X, 0);
					input_report_rel(input, REL_Y, 0);
					input_report_rel(input, REL_WHEEL, -1);  
				}
				
				printk(KERN_EMERG "point %s msgs nx:%d  ny:%d \n",__FUNCTION__, nx, ny);
				input_report_key(input, BTN_LEFT,   0);
				input_report_key(input, BTN_MIDDLE, 0);
				input_report_key(input, BTN_RIGHT,  0);
				 

				input_sync(input);*/
				if (tmp[4]==1){
					send_touch(KEY_UP);
				} else {
					send_touch(KEY_DOWN);
				}
			} else {
				if (tmp[4]==1){
					send_touch(KEY_PAGEDOWN);
				} else {
					send_touch(KEY_PAGEUP);
				}
			}
		} else if (tmp[2]!=0 || tmp[3]!=0){
			nx = tmp[2];
			ny = tmp[3];
		
			printk(KERN_EMERG "point %s msgs nx:%d  ny:%d \n",__FUNCTION__, nx, ny);
			if (nx >  128) nx = (nx - 256);
			if (ny >  128) ny = (ny - 256);

			
			input_report_rel(input, REL_X, nx);
			input_report_rel(input, REL_Y, ny);
			printk(KERN_EMERG "point %s msgs nx:%d  ny:%d \n",__FUNCTION__, nx, ny);
			input_report_key(input, BTN_LEFT,   0);
			input_report_key(input, BTN_MIDDLE, 0);
			input_report_key(input, BTN_RIGHT,  0);

			input_sync(input);
		} else if (tmp[1]==17){
			
			input_report_key(input, BTN_LEFT,   1);
			input_report_key(input, BTN_MIDDLE, 0);
			input_report_key(input, BTN_RIGHT,  0);

			input_sync(input);
			
			input_report_key(input, BTN_LEFT,   0);
			input_report_key(input, BTN_MIDDLE, 0);
			input_report_key(input, BTN_RIGHT,  0);
			input_sync(input);
		}else if (tmp[1]==33) {
			send_touch(KEY_BACK);
		}
		printk(KERN_EMERG "%s msgs %d %d %d %d %d %d \n",__FUNCTION__, tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5]);
	}
		
	return 0;
}





static int touch_open(struct inode *pinode, struct file *pfile)
{
	
    DPP_DBG(KERN_EMERG "line:%d,%s is called\n", __LINE__, __FUNCTION__);
	
    return 0;
}

static int touch_release(struct inode *pinode, struct file *pfile)
{	
    DPP_DBG(KERN_EMERG "line:%d,%s is call\n", __LINE__, __FUNCTION__);
	
    return 0;
}

static ssize_t touch_read(struct file *pfile, char __user *user_buff, size_t size, loff_t *off)
{
	
    DPP_DBG(KERN_EMERG "line:%d,%s is called\n", __LINE__, __FUNCTION__);

    return 0;
}

static ssize_t touch_write(struct file *pfile, const char __user *user_buff, size_t size, loff_t *off)
{
	
	DPP_DBG(KERN_EMERG "line:%d,%s is called\n", __LINE__, __FUNCTION__);
    return 0;
}


static long touch_ioctl (struct file *filp, unsigned int cmd, unsigned long arg)
{
	
	
	return 0;
}

static struct file_operations touch_file = 
{
    .owner          = THIS_MODULE,
    .open           = touch_open,
	.write			= touch_write,
    .read           = touch_read,
	.unlocked_ioctl	= touch_ioctl,
    .release        = touch_release,
};

static int touch_loop_fun(void *_data)
{
	bool exit = true;
	while (exit) {
		if (gpio_get_value(gpio_int) == 0)
				touch_read_reg(touch_client,0x00);
			//msleep(8);
	}
	return 0;
}
static int touch_parse_dt_property(struct device *dev)
{
	struct device_node *node = dev->of_node;
	
	enum of_gpio_flags flags;
	int ret;

	printk("Enter %s()\n", __FUNCTION__);

	if (!node)
		return -ENODEV;
	
		gpio_int = of_get_named_gpio_flags(node, "gpio_int", 0, &flags);
		if (gpio_int <= 0) { 
			DPP_DBG("%s() Can not read property gpio_int\n", __FUNCTION__);
		} else {
			ret = devm_gpio_request(dev, gpio_int, "gpio_int");
			if(ret){
				printk("%s() gpio_int request ERROR", __FUNCTION__);
				return ret; 
			}	 
			printk("%s(%d), flags: %d\n", __FUNCTION__, __LINE__, flags);
				 
		}
		
		return 0;

}

static int touch_probe(struct i2c_client *client,
		const struct i2c_device_id *id)
{				 		
	int val, i, ret;
char codes[10] = { KEY_PAGEDOWN,  KEY_PAGEUP, KEY_DOWN,  KEY_UP,  KEY_POWER,  KEY_HOME,  KEY_VOLUMEUP,  KEY_VOLUMEDOWN,  KEY_MENU, KEY_BACK};
	printk(KERN_EMERG"%s is calleded\r\n", __FUNCTION__);
	
	input = input_allocate_device();
	if (!input) {
		val = -ENOMEM;
		goto fail0;
	}
	input->name = "touch";
	input->phys = "i2ctouch";
	input->id.bustype = BUS_I2C;
	input->id.vendor = 0x0008;
	input->id.product = 0x0101;
	input->id.version = 0100;
	
	for (i=0; i < 10; i++){
		input_set_capability(input, EV_KEY, codes[i]);
	}
	
	input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
	input->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y) | BIT_MASK(REL_WHEEL);
	input->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) |
		BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
	
	ret = input_register_device(input);
	if (ret) {
		printk(KERN_ALERT "Probe: Unable to register %s input device\n", input->name);
		return -1;
	}
	
	
	power_touch_workqueue = create_singlethread_workqueue("touch");
	INIT_DELAYED_WORK(&power_touch_delay_work, power_touch_work);
	queue_delayed_work(power_touch_workqueue,
			   &power_touch_delay_work, msecs_to_jiffies(10));
	
	
	touch_client = client;
    touch_data.touch_cdev = cdev_alloc();
    if(!touch_data.touch_cdev)
    {
        printk(KERN_EMERG"cdev_alloc err .%d\n", __LINE__);

        val = -ENOMEM;
        goto cdev_alloc_error;
    }
	
    val = alloc_chrdev_region(&touch_data.devid, touch_data.minor, 1, DEVICE_NAME);
    if (val<0) 
    {
        printk(KERN_EMERG"alloc_chrdev_region err .%d\n", __LINE__);
        val = val;
        goto  alloc_chrdev_region_error;
    }

		touch_data.major = MAJOR(touch_data.devid);
    touch_data.minor = MINOR(touch_data.devid);	
		printk(KERN_EMERG "touch_data.major:%d,touch_data.minor:%d\n", touch_data.major, touch_data.minor);
		
    cdev_init(touch_data.touch_cdev, &touch_file);

    val = cdev_add(touch_data.touch_cdev, touch_data.devid, 1);
    if (val)
    {
        printk(KERN_EMERG"cdev_add err .%d\n", __LINE__);
        val = val;

        goto cdev_add_error;
    }

    touch_data.touch_class = class_create(THIS_MODULE, DEVICE_NAME);
    if (IS_ERR(touch_data.touch_class)) 
    {
        printk(KERN_EMERG"class_create failed.%d\n", __LINE__);
        val = PTR_ERR(touch_data.touch_class);

        goto class_create_error;
    }
	
    touch_data.touch_device = device_create(touch_data.touch_class, NULL, touch_data.devid, NULL, "%s", DEVICE_NAME);
    if (IS_ERR(touch_data.touch_device)) 
    {
        printk(KERN_EMERG"class_create failed.%d\n", __LINE__);
        val = PTR_ERR(touch_data.touch_device);

        goto device_create_error;

    }
    
    ret = touch_parse_dt_property(&client->dev);
    
    
		kthread_run(touch_loop_fun, NULL, "touch");
	
    printk(KERN_EMERG "%s driver OK! \n",__FUNCTION__);

    return 0;

device_create_error:
    class_destroy(touch_data.touch_class);           

class_create_error:
    cdev_del(touch_data.touch_cdev);                     

cdev_add_error:
    kfree(touch_data.touch_cdev);                         

cdev_alloc_error:  
    unregister_chrdev_region(touch_data.devid, 1);     
alloc_chrdev_region_error: 
fail0:
	input_free_device(input);

    return val;
}

static int touch_remove(struct i2c_client *client)
{
	
	

    cdev_del(touch_data.touch_cdev);             
    device_destroy(touch_data.touch_class, touch_data.devid);  
    class_destroy(touch_data.touch_class);           
    unregister_chrdev_region(touch_data.devid, 1); 

	i2c_unregister_device(touch_client);
    DPP_DBG(KERN_EMERG"%s all free is OK !!!\r\n", __FUNCTION__);

    return 0;
}
	
static const struct i2c_device_id touch_i2c_id[] = {
	{ "touch"},{ }};
MODULE_DEVICE_TABLE(i2c, touch_i2c_id);
	
static struct i2c_driver touch_driver =
{ 
	.probe  = touch_probe, 
	.remove = touch_remove, 
	.driver =
	{ 
		.name  ="touch", 
		.owner = THIS_MODULE,
	}, 
	.id_table = touch_i2c_id,
};

static int __init touch_init(void)
{
    printk(KERN_EMERG"%s is called\r\n", __FUNCTION__);	
	//pwm2_init();
    i2c_add_driver(&touch_driver);
	
    return 0;
}


static void __exit touch_exit(void)
{
    printk(KERN_EMERG"%s is called\r\n", __FUNCTION__);
	
    i2c_del_driver(&touch_driver);

}
module_init(touch_init);
module_exit(touch_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("touch<...>");
MODULE_DESCRIPTION("This is touch device driver 2018.08.10\r\n");

touchpad.h

#ifndef __TOUCH__
#define __TOUCH__


struct Touch_data{

	int power_flag;    				   		//OPD22工作状态
	int touch;							//OPD22上报标志

	//注册Linux2.6标准字符设备的参数定义
	unsigned int  major;         	 //主设备号动态注册设置0
	unsigned int  minor;         	 //次设备号
	dev_t   devid;               	    //保存设备号
	struct cdev    *touch_cdev;       //保存cdev结构空间首地址
	struct class   *touch_class;      //保存cdev设备类指针
	struct device  *touch_device;     //保存设备模型指针
};

int touch_write_ext(unsigned char addr,unsigned char length,unsigned char *value);
int touch_read_ext(unsigned char addr,unsigned char length,unsigned char *value);

#endif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值