金牌会员
- 积分
- 2178
- 金钱
- 2178
- 注册时间
- 2018-8-27
- 在线时间
- 258 小时
|
发表于 2021-4-13 15:48:36
|
显示全部楼层
- #include <linux/module.h>
- #include <linux/i2c.h>
- #include <linux/delay.h>
- #include <linux/miscdevice.h>
- #include <linux/uaccess.h>
- #include <linux/interrupt.h>
- #include <linux/fcntl.h>
- #include <linux/of_gpio.h>
- #define GESTURE_MODE 0
- #define PROXIMITY_MODE 1
- /* 应用层ioctl CMD */
- #define PAJ_CMD_SET_MODE 0x9000
- #define COUNTER_CLOCKWISE_MASK BIT(7) //逆时针
- #define CLOCKWISE_MASK BIT(6) //顺时针
- #define BACKWARD_MASK BIT(5) //向后
- #define FORWARD_MASK BIT(4) //向前
- #define RIGHT_MASK BIT(3) //向右
- #define LEFT_MASK BIT(2) //向左
- #define DOWN_MASK BIT(1) //向下
- #define UP_MASK BIT(0) //向上
- #define WAVE_MASK BIT(0) //挥动
- enum gesture_type_t {
- WAVE = 0,
- UP,
- DOWN,
- LEFT,
- RIGHT,
- FORWARD,
- BACKWARD,
- CLOCKWISE,
- COUNTER_CLOCKWISE,
- };
- struct p_mode_obj_attr {
- u8 brightness;
- u16 size;
- };
- struct paj7620u2_dev {
- struct i2c_client *client;
- struct miscdevice mdev; //定义一个杂散设备
- struct mutex lock; //互斥锁
- int mode; //当前模式
- int gpio; //中断引脚
- atomic_t count;
- struct fasync_struct *async_queue; //异步通知队列
- };
- struct paj7620u2_dev paj7620u2; //实例化paj7620u2设备
- static const u8 _init_cfg_table[][2] = {
- {0xEF,0x00},
- {0x37,0x07},
- {0x38,0x17},
- {0x39,0x06},
- {0x41,0x00},
- {0x42,0x00},
- {0x46,0x2D},
- {0x47,0x0F},
- {0x48,0x3C},
- {0x49,0x00},
- {0x4A,0x1E},
- {0x4C,0x20},
- {0x51,0x10},
- {0x5E,0x10},
- {0x60,0x27},
- {0x80,0x42},
- {0x81,0x44},
- {0x82,0x04},
- {0x8B,0x01},
- {0x90,0x06},
- {0x95,0x0A},
- {0x96,0x0C},
- {0x97,0x05},
- {0x9A,0x14},
- {0x9C,0x3F},
- {0xA5,0x19},
- {0xCC,0x19},
- {0xCD,0x0B},
- {0xCE,0x13},
- {0xCF,0x64},
- {0xD0,0x21},
- {0xEF,0x01},
- {0x02,0x0F},
- {0x03,0x10},
- {0x04,0x02},
- {0x25,0x01},
- {0x27,0x39},
- {0x28,0x7F},
- {0x29,0x08},
- {0x3E,0xFF},
- {0x5E,0x3D},
- {0x65,0x96},
- {0x67,0x97},
- {0x69,0xCD},
- {0x6A,0x01},
- {0x6D,0x2C},
- {0x6E,0x01},
- {0x72,0x01},
- {0x73,0x35},
- {0x74,0x00},
- {0x77,0x01},
- };
- static const u8 _proximity_cfg_table[][2] = {
- {0xEF,0x00},
- {0x41,0x00},
- {0x42,0x00},
- {0x48,0x3C},
- {0x49,0x00},
- {0x51,0x13},
- {0x83,0x20},
- {0x84,0x20},
- {0x85,0x00},
- {0x86,0x10},
- {0x87,0x00},
- {0x88,0x05},
- {0x89,0x18},
- {0x8A,0x10},
- {0x9f,0xf8},
- {0x69,0x96},
- {0x6A,0x02},
- {0xEF,0x01},
- {0x01,0x1E},
- {0x02,0x0F},
- {0x03,0x10},
- {0x04,0x02},
- {0x41,0x50},
- {0x43,0x34},
- {0x65,0xCE},
- {0x66,0x0B},
- {0x67,0xCE},
- {0x68,0x0B},
- {0x69,0xE9},
- {0x6A,0x05},
- {0x6B,0x50},
- {0x6C,0xC3},
- {0x6D,0x50},
- {0x6E,0xC3},
- {0x74,0x05},
- };
- static const u8 _gesture_cfg_table[][2] = {
- {0xEF,0x00},
- {0x41,0x00},
- {0x42,0x00},
- {0xEF,0x00},
- {0x48,0x3C},
- {0x49,0x00},
- {0x51,0x10},
- {0x83,0x20},
- {0x9F,0xF9},
- {0xEF,0x01},
- {0x01,0x1E},
- {0x02,0x0F},
- {0x03,0x10},
- {0x04,0x02},
- {0x41,0x40},
- {0x43,0x30},
- {0x65,0x96},
- {0x66,0x00},
- {0x67,0x97},
- {0x68,0x01},
- {0x69,0xCD},
- {0x6A,0x01},
- {0x6B,0xB0},
- {0x6C,0x04},
- {0x6D,0x2C},
- {0x6E,0x01},
- {0x74,0x00},
- {0xEF,0x00},
- {0x41,0xFF},
- {0x42,0x01},
- };
- static int paj7620u2_i2c_write(u8 addr, u8 val)
- {
- struct i2c_client *client = paj7620u2.client;
- struct i2c_msg msg;
- u8 buf[3] = {0};
- int ret;
- buf[0] = addr; //填充地址
- buf[1] = val; //填充写入数据
- msg.flags = 0; //i2c写
- msg.addr = client->addr;
- msg.buf = buf;
- msg.len = 2;
- ret = i2c_transfer(client->adapter, &msg, 1);
- if (1 == ret)
- return 0;
- else {
- dev_err(&client->dev, "%s: write error, addr=0x%x val=%d.\n",
- __func__, addr, val);
- return -1;
- }
- }
- static int paj7620u2_i2c_read(u8 addr, u8 *val)
- {
- struct i2c_client *client = paj7620u2.client;
- struct i2c_msg msg[2];
- int ret;
- msg[0].flags = 0; // i2c写
- msg[0].addr = client->addr;
- msg[0].buf = &addr;
- msg[0].len = 1;
- msg[1].flags = I2C_M_RD; //i2c读
- msg[1].addr = client->addr;
- msg[1].buf = val;
- msg[1].len = 1;
- ret = i2c_transfer(client->adapter, msg, 2);
- if (2 == ret)
- return 0;
- else {
- dev_err(&client->dev, "%s: read error, addr=0x%x.\n",
- __func__, addr);
- return -1;
- }
- }
- static int paj7620u2_proximity_mode(void)
- {
- int len = sizeof(_proximity_cfg_table) / 2;
- int i;
- int ret;
- for (i = 0; i < len; i++) {
- ret = paj7620u2_i2c_write(_proximity_cfg_table[i][0],
- _proximity_cfg_table[i][1]);
- if (ret)
- return ret;
- }
- paj7620u2.mode = PROXIMITY_MODE;
- return 0;
- }
- static int paj7620u2_gesture_mode(void)
- {
- int len = sizeof(_gesture_cfg_table) / 2;
- int i;
- int ret;
- for (i = 0; i < len; i++) {
- ret = paj7620u2_i2c_write(_gesture_cfg_table[i][0],
- _gesture_cfg_table[i][1]);
- if (ret)
- return ret;
- }
- paj7620u2.mode = GESTURE_MODE;
- return 0;
- }
- static void paj7620u2_send_write_cmd(void)
- {
- struct i2c_client *client = paj7620u2.client;
- struct i2c_msg msg;
- u8 buf[2] = {0};
- buf[0] = 0xFF;
- msg.flags = 0; //i2c写
- msg.addr = client->addr;
- msg.buf = buf;
- msg.len = 1;
- i2c_transfer(client->adapter, &msg, 1);
- }
- static int paj7620u2_wakeup(void)
- {
- u8 status = 0x00;
- int count = 0;
- int ret;
- /* 唤醒 */
- wakeup:
- count++;
- msleep(5);
- paj7620u2_send_write_cmd();
- msleep(5);
- paj7620u2_i2c_read(0x00, &status);
- if (0x20 != status) {
- if (2 == count)
- return -1;
- goto wakeup;
- }
- ret = paj7620u2_i2c_write(0xEF, 0x01); //进入BANK1寄存器组
- if (ret)
- return ret;
- ret = paj7620u2_i2c_write(0x72, 0x01); //使能
- if (ret)
- return ret;
- return 0;
- }
- static int paj7620u2_open(struct inode *inode, struct file *filp)
- {
- int count;
- if (!atomic_dec_and_test(&paj7620u2.count)) {
- printk(KERN_ERR "paj7620: Device is busy!\n");
- atomic_inc(&paj7620u2.count);
- return -EBUSY;
- }
- return 0;
- }
- static ssize_t paj7620u2_read(struct file *filp, char __user *buf,
- size_t cnt, loff_t *offt)
- {
- struct i2c_client *client = paj7620u2.client;
- u8 data[2] = {0};
- mutex_lock(&paj7620u2.lock);
- paj7620u2_i2c_write(0xEF, 0x00); //进入BANK0寄存器组
- if (GESTURE_MODE == paj7620u2.mode) {
- int gesture;
- paj7620u2_i2c_read(0x43, data);
- switch (data[0]) {
- case UP_MASK: gesture = UP; break;
- case DOWN_MASK: gesture = DOWN; break;
- case LEFT_MASK: gesture = LEFT; break;
- case RIGHT_MASK: gesture = RIGHT; break;
- case FORWARD_MASK: gesture = FORWARD; break;
- case BACKWARD_MASK: gesture = BACKWARD; break;
- case CLOCKWISE_MASK: gesture = CLOCKWISE; break;
- case COUNTER_CLOCKWISE_MASK:
- gesture = COUNTER_CLOCKWISE;
- break;
- default:
- gesture = -1;
- break;
- }
- paj7620u2_i2c_read(0x44, data);
- if (WAVE_MASK == data[0])
- gesture = WAVE;
- mutex_unlock(&paj7620u2.lock);
- return copy_to_user(buf, &gesture, sizeof(int));
- } else if (PROXIMITY_MODE == paj7620u2.mode) {
- struct p_mode_obj_attr attr;
- paj7620u2_i2c_read(0xB0, data);
- attr.brightness = data[0];
- paj7620u2_i2c_read(0xB1, data);
- paj7620u2_i2c_read(0xB2, &data[1]);
- attr.size = (((u16)data[1] & 0x0F) << 8) | (u16)data[0];
- mutex_unlock(&paj7620u2.lock);
- return copy_to_user(buf, &attr, sizeof(attr));
- }
- mutex_unlock(&paj7620u2.lock);
- dev_err(&client->dev, "Please set the working mode\n");
- return -1;
- }
- static long paj7620u2_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
- {
- u8 data;
- switch (cmd) {
- /* 设置模式 */
- case PAJ_CMD_SET_MODE: {
- mutex_lock(&paj7620u2.lock);
- if (GESTURE_MODE == arg &&
- GESTURE_MODE != paj7620u2.mode)
- paj7620u2_gesture_mode();
- else if (PROXIMITY_MODE == arg &&
- PROXIMITY_MODE != paj7620u2.mode)
- paj7620u2_proximity_mode();
- /* 清除中断标志位 */
- paj7620u2_i2c_write(0xEF, 0x00);
- paj7620u2_i2c_read(0x43, &data);
- paj7620u2_i2c_read(0x44, &data);
- mutex_unlock(&paj7620u2.lock);
- }
- break;
- default:
- break;
- }
- return 0;
- }
- static int paj7620u2_fasync(int fd, struct file *filp, int on)
- {
- return fasync_helper(fd, filp, on, &paj7620u2.async_queue);
- }
- static int paj7620u2_release(struct inode *inode, struct file *filp)
- {
- atomic_inc(&paj7620u2.count);
- return paj7620u2_fasync(-1, filp, 0);
- }
- static struct file_operations paj7620u2_fops = {
- .owner = THIS_MODULE,
- .open = paj7620u2_open,
- .read = paj7620u2_read,
- .release = paj7620u2_release,
- .unlocked_ioctl = paj7620u2_ioctl,
- .fasync = paj7620u2_fasync,
- };
- static irqreturn_t paj7620u2_i2c_isr(int irq, void *dev_id)
- {
- kill_fasync(&paj7620u2.async_queue, SIGIO, POLL_IN);
- return IRQ_HANDLED;
- }
- static int paj7620u2_irq_init(struct i2c_client *client)
- {
- struct device_node *node = client->dev.of_node;
- int ret;
- /* 获取中断引脚 */
- paj7620u2.gpio = of_get_named_gpio(node, "interrupt-gpio", 0);
- if (!gpio_is_valid(paj7620u2.gpio)) {
- dev_err(&client->dev, "Failed to get paj7620 interrupt gpio\n");
- return paj7620u2.gpio;
- }
- ret = devm_gpio_request_one(&client->dev, paj7620u2.gpio,
- GPIOF_OUT_INIT_HIGH, "interrupt gpio");
- if (ret < 0)
- return ret;
- /* 申请中断 */
- gpio_direction_input(paj7620u2.gpio);
- ret = devm_request_threaded_irq(&client->dev, gpio_to_irq(paj7620u2.gpio),
- NULL, paj7620u2_i2c_isr, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- client->name, NULL);
- if (ret) {
- dev_err(&client->dev, "Failed to request paj7620u2 IRQ.\n");
- return ret;
- }
- return 0;
- }
- static int paj7620u2_init(struct i2c_client *client)
- {
- int len = sizeof(_init_cfg_table) / 2;
- u8 status = 0x00;
- int i = 0;
- int ret;
- /* 唤醒 */
- ret = paj7620u2_wakeup();
- if (ret) {
- dev_err(&client->dev, "Failed to wakeup paj7620u2.\n");
- return ret;
- }
- /* 初始化 */
- for (i = 0; i < len; i++) {
- ret = paj7620u2_i2c_write(_init_cfg_table[i][0],
- _init_cfg_table[i][1]);
- if (ret)
- return ret;
- }
- /* 清除中断状态寄存器标志位 */
- ret = paj7620u2_i2c_write(0xEF, 0x00); //进入BANK0寄存器组
- if (ret)
- return ret;
- paj7620u2_i2c_read(0x43, &status); //读中断状态挂起寄存器
- paj7620u2_i2c_read(0x44, &status);
- /* 当前模式 */
- paj7620u2.mode = -1;
- return 0;
- }
- static int paj7620u2_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
- {
- struct miscdevice *mdev;
- int ret;
- paj7620u2.client = client;
- atomic_set(&paj7620u2.count, 1);
- /* 初始化互斥锁 */
- mutex_init(&paj7620u2.lock);
- /* 初始化paj7620u2 */
- ret = paj7620u2_init(client);
- if (ret)
- return ret;
- /* 注册中断服务函数 */
- ret = paj7620u2_irq_init(client);
- if (ret)
- return ret;
- /* struct miscdevice类型对象 */
- mdev = &paj7620u2.mdev;
- mdev->name = "paj7620u2";
- mdev->minor = MISC_DYNAMIC_MINOR;
- mdev->fops = &paj7620u2_fops;
- mdev->parent = NULL;
- /* 注册杂散类设备 */
- return misc_register(mdev);
- }
- static int paj7620u2_i2c_remove(struct i2c_client *client)
- {
- misc_deregister(&paj7620u2.mdev);
- return 0;
- }
- static const struct of_device_id paj7620u2_of_match[] = {
- { .compatible = "PixArt,paj7620u2", },
- {},
- };
- MODULE_DEVICE_TABLE(of, paj7620u2_of_match);
- static struct i2c_driver paj7620u2_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "paj7620u2",
- .of_match_table = paj7620u2_of_match,
- },
- .probe = paj7620u2_i2c_probe,
- .remove = paj7620u2_i2c_remove,
- };
- module_i2c_driver(paj7620u2_driver);
- MODULE_DESCRIPTION("PAJ7620U2 Integrated Gesture Recognition Sensor Driver");
- MODULE_AUTHOR("Deng Tao <773904075@qq.com>, ALIENTEK, Inc.");
- MODULE_LICENSE("GPL");
复制代码 |
|