touchpad.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include //copy_to_user copy_from_user
#include //Linux2.6标准字符设备注册文件
#include //自动创建设备类头文件
#include //file_operations文件操作方法集合
#include //kfree释放内存头文件
#include //input设备
#include //iocrl函数
#include "touchpad.h" //ioctl命令
#include //定时器
#include //I2C设备
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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