mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-25 14:13:01 -04:00
ldc2114_mmi: report raw data through debugfs
Replace character device with debugfs for reporting raw data. Multiple instances of driver and raw data reports supported. Source files moved to ldc2114_mmi folder to align with other drivers. Change-Id: I0357117962f5d492459091c28e8fe1cd403490a2 Signed-off-by: Konstantin Makariev <hcv867@motorola.com> Reviewed-on: https://gerrit.mot.com/1277626 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Reviewed-by: Konstantin Makariev <kmakariev@motorola.com> Submit-Approved: Jira Key
This commit is contained in:
parent
8c6e814168
commit
4f16051c59
8 changed files with 413 additions and 362 deletions
|
|
@ -1,13 +0,0 @@
|
|||
# add -Wall to try to catch everything we can.
|
||||
EXTRA_CFLAGS += -Wall
|
||||
EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/include -I$(TOP)/motorola/kernel/modules/drivers/input/misc
|
||||
|
||||
ldc2114_keys-objs := ldc2114.o
|
||||
|
||||
ifeq ($(TARGET_BUILD_VARIANT),userdebug)
|
||||
# Following line is in control of extra debug
|
||||
EXTRA_CFLAGS += -DLDC2114_POLL_DEBUG -DLDC2114_CFG_DEBUG #-DLDC2114_CHARDEV
|
||||
#ldc2114_keys-objs += ldc2114-cdev.o
|
||||
endif
|
||||
|
||||
obj-m = ldc2114_keys.o
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
#ifndef _LDC2114_CDEV_HDR_
|
||||
#define _LDC2114_CDEV_HDR_
|
||||
|
||||
#include <linux/notifier.h>
|
||||
|
||||
#if defined(LDC2114_CHARDEV)
|
||||
int ldc2114_cdev_init(void);
|
||||
void ldc2114_cdev_remove(void);
|
||||
int ldc2114_buffer(int d0, int d1, int d2, int d3);
|
||||
int ldc2114_register_client(struct notifier_block *nb);
|
||||
#else
|
||||
static int ldc2114_cdev_init(void)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
static void ldc2114_cdev_remove(void)
|
||||
{
|
||||
}
|
||||
static int ldc2114_buffer(int d0, int d1, int d2, int d3)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static int ldc2114_register_client(struct notifier_block *nb)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -6,5 +6,3 @@ LOCAL_MODULE := ldc2114_keys.ko
|
|||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
||||
|
||||
include $(call first-makefiles-under,$(LOCAL_PATH))
|
||||
12
drivers/input/misc/ldc2114_mmi/Kbuild
Normal file
12
drivers/input/misc/ldc2114_mmi/Kbuild
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# add -Wall to try to catch everything we can.
|
||||
EXTRA_CFLAGS += -Wall
|
||||
EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/include
|
||||
|
||||
ldc2114_keys-objs := ldc2114.o ldc2114-debugfs.o
|
||||
|
||||
ifeq ($(TARGET_BUILD_VARIANT),userdebug)
|
||||
# Following line is in control of extra debug
|
||||
EXTRA_CFLAGS += -DLDC2114_POLL_DEBUG -DLDC2114_CFG_DEBUG
|
||||
endif
|
||||
|
||||
obj-m = ldc2114_keys.o
|
||||
10
drivers/input/misc/ldc2114_mmi/Makefile
Normal file
10
drivers/input/misc/ldc2114_mmi/Makefile
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS)
|
||||
|
||||
modules_install:
|
||||
$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/* linux/drivers/input/misc/ldc2114-cdev.c
|
||||
/* linux/drivers/input/misc/ldc2114-debugfs.c
|
||||
*
|
||||
* LDC2114 chardev driver. Allows user space access to raw data.
|
||||
* LDC2114 debugfs driver. Allows user space access to raw data.
|
||||
* Copyright (C) 2017 Motorola, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
|
@ -12,50 +12,21 @@
|
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*/
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/memory.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "ldc2114.h"
|
||||
|
||||
#define DRVNAME "ldc2114_raw"
|
||||
#define BUFFER_SIZE 256
|
||||
|
||||
typedef struct data {
|
||||
int d[4];
|
||||
} item_t;
|
||||
|
||||
struct buffer {
|
||||
struct mutex mutex;
|
||||
int capacity;
|
||||
unsigned long opened;
|
||||
atomic_t start;
|
||||
atomic_t end;
|
||||
atomic_t active;
|
||||
item_t **data;
|
||||
wait_queue_head_t wait;
|
||||
};
|
||||
|
||||
struct ldc2114_drv {
|
||||
struct class *class;
|
||||
struct cdev cdev;
|
||||
struct platform_device *pdev;
|
||||
dev_t devid;
|
||||
int major;
|
||||
struct buffer ds;
|
||||
struct blocking_notifier_head nhead;
|
||||
};
|
||||
|
||||
static struct ldc2114_drv *cxt;
|
||||
|
||||
static int buffer_init(struct buffer *buffer, size_t capacity)
|
||||
{
|
||||
|
|
@ -84,8 +55,17 @@ static void inline buffer_destroy(struct buffer *buffer)
|
|||
{
|
||||
int i;
|
||||
|
||||
mutex_lock(&buffer->mutex);
|
||||
buffer->capacity = 0;
|
||||
atomic_set(&buffer->start, 0);
|
||||
atomic_set(&buffer->end, 0);
|
||||
atomic_set(&buffer->active, 0);
|
||||
/* wait for remaining msgs */
|
||||
wait_event_interruptible(buffer->wait,
|
||||
!atomic_read(&buffer->active));
|
||||
for (i = 0; i < buffer->capacity; i++)
|
||||
kfree(buffer->data[i]);
|
||||
mutex_unlock(&buffer->mutex);
|
||||
kfree(buffer->data);
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +82,7 @@ static void buffer_push(struct buffer *buffer,
|
|||
cstart = atomic_read(&buffer->start);
|
||||
cend = atomic_read(&buffer->end);
|
||||
|
||||
dev_dbg(&context->pdev->dev, "%s: writing at pos %d\n", __func__, cend);
|
||||
dev_dbg(context->dev, "%s: writing at pos %d\n", __func__, cend);
|
||||
memcpy(&buffer->data[cend], data, length);
|
||||
|
||||
cend = (cend + 1) % buffer->capacity;
|
||||
|
|
@ -116,7 +96,7 @@ static void buffer_push(struct buffer *buffer,
|
|||
atomic_set(&buffer->start, cstart);
|
||||
}
|
||||
|
||||
dev_dbg(&context->pdev->dev, "%s: next write=%d, read=%d\n",
|
||||
dev_dbg(context->dev, "%s: next write=%d, read=%d\n",
|
||||
__func__, cend, cstart);
|
||||
|
||||
mutex_unlock(&buffer->mutex);
|
||||
|
|
@ -141,14 +121,14 @@ static size_t buffer_pop(struct buffer *buffer, item_t *item)
|
|||
cstart = atomic_read(&buffer->start);
|
||||
|
||||
memcpy(item, &buffer->data[cstart], sizeof(item_t));
|
||||
dev_dbg(&context->pdev->dev, "%s: reading from pos %d\n",
|
||||
dev_dbg(context->dev, "%s: reading from pos %d\n",
|
||||
__func__, cstart);
|
||||
|
||||
count += sizeof(item_t);
|
||||
|
||||
cactive--;
|
||||
cstart = (cstart + 1) % buffer->capacity;
|
||||
dev_dbg(&context->pdev->dev, "%s: next read pos %d\n",
|
||||
dev_dbg(context->dev, "%s: next read pos %d\n",
|
||||
__func__, cstart);
|
||||
|
||||
atomic_set(&buffer->start, cstart);
|
||||
|
|
@ -162,28 +142,51 @@ static size_t buffer_pop(struct buffer *buffer, item_t *item)
|
|||
/*
|
||||
* External function called by polling work
|
||||
*/
|
||||
int ldc2114_buffer(int d0, int d1, int d2, int d3)
|
||||
int ldc2114_buffer(struct ldc2114_data *ldc, int type, ...)
|
||||
{
|
||||
struct ldc2114_drv *cxt = dev_get_drvdata(ldc->dev);
|
||||
va_list vp;
|
||||
item_t data;
|
||||
int ret = 0;
|
||||
int rc = 0;
|
||||
|
||||
if (cxt && test_bit(0, &cxt->ds.opened)) {
|
||||
data.d[0] = d0;
|
||||
data.d[1] = d1;
|
||||
data.d[2] = d2;
|
||||
data.d[3] = d3;
|
||||
buffer_push(&cxt->ds, &data, sizeof(data));
|
||||
} else
|
||||
ret = -ENODEV;
|
||||
if (!(cxt && test_bit(0, &cxt->ds.opened)))
|
||||
return -ENODEV;
|
||||
|
||||
return ret;
|
||||
va_start(vp, type);
|
||||
data.type = type;
|
||||
switch (type) {
|
||||
case LDC2114_EV_DATA:
|
||||
data.de = va_arg(vp, struct ldc2114_raw_ext);
|
||||
break;
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
goto leave_now;
|
||||
}
|
||||
buffer_push(&cxt->ds, &data, sizeof(data));
|
||||
|
||||
leave_now:
|
||||
va_end(vp);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int inline comp2_12b(struct ldc2114_16bit *data)
|
||||
{
|
||||
int result;
|
||||
/* 12bits 2's compliment data */
|
||||
if (data->msb & 0x8)
|
||||
result = (data->lsb | (data->msb << 8) | 0xFFFFF000);
|
||||
else
|
||||
result = (data->lsb | (data->msb << 8));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static ssize_t ldc2114_read(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ldc2114_drv *context = file->private_data;
|
||||
int ret;
|
||||
int i, ret;
|
||||
item_t data;
|
||||
char out[128];
|
||||
|
||||
|
|
@ -191,8 +194,18 @@ static ssize_t ldc2114_read(struct file *file, char __user *buf,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
count = snprintf(out, sizeof(out), "%5d %5d %5d %5d\n",
|
||||
data.d[0], data.d[1], data.d[2], data.d[3]);
|
||||
switch(data.type) {
|
||||
case LDC2114_EV_DATA:
|
||||
count = snprintf(out, sizeof(out), "I:%d",
|
||||
(data.de.status & LDC2114_REG_STATUS_OUT) != 0);
|
||||
for (i = 0; i < MAX_KEYS; i++) {
|
||||
count += snprintf(out+count, sizeof(out)-count, " [%d]:%d/%d",
|
||||
i, (data.de.data.out & (1 << i)) != 0,
|
||||
comp2_12b(&data.de.data.values[i]));
|
||||
}
|
||||
count += snprintf(out+count, sizeof(out)-count, "\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (copy_to_user(buf, out, count))
|
||||
count = -EFAULT;
|
||||
|
|
@ -202,6 +215,7 @@ static ssize_t ldc2114_read(struct file *file, char __user *buf,
|
|||
|
||||
static int ldc2114_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct ldc2114_drv *cxt = inode->i_private;
|
||||
int ret;
|
||||
|
||||
if (!cxt)
|
||||
|
|
@ -218,8 +232,8 @@ static int ldc2114_open(struct inode *inode, struct file *file)
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
dev_dbg(cxt->dev, "%s: allocated circular buffer\n", __func__);
|
||||
blocking_notifier_call_chain(&cxt->nhead, cxt->ds.opened, NULL);
|
||||
dev_dbg(&cxt->pdev->dev, "allocated circular buffer\n");
|
||||
|
||||
return nonseekable_open(inode, file);
|
||||
}
|
||||
|
|
@ -228,16 +242,17 @@ static int ldc2114_release(struct inode *inode, struct file *file)
|
|||
{
|
||||
struct ldc2114_drv *context = file->private_data;
|
||||
|
||||
__clear_bit_unlock(0, &context->ds.opened);
|
||||
clear_bit_unlock(0, &context->ds.opened);
|
||||
dev_dbg(context->dev, "%s: opend flag %lu\n", __func__, context->ds.opened);
|
||||
blocking_notifier_call_chain(&context->nhead, context->ds.opened, NULL);
|
||||
buffer_destroy(&context->ds);
|
||||
|
||||
dev_dbg(&cxt->pdev->dev, "destroyed circular buffer\n");
|
||||
dev_dbg(context->dev, "%s: destroyed circular buffer\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct file_operations ldc2114_cdev_fops = {
|
||||
const struct file_operations ldc2114_debugfs_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = ldc2114_open,
|
||||
.read = ldc2114_read,
|
||||
|
|
@ -245,79 +260,72 @@ const struct file_operations ldc2114_cdev_fops = {
|
|||
.llseek = no_llseek,
|
||||
};
|
||||
|
||||
int ldc2114_register_client(struct notifier_block *nb)
|
||||
int ldc2114_register_client(struct ldc2114_data *ldc, struct notifier_block *nb)
|
||||
{
|
||||
struct ldc2114_drv *cxt = dev_get_drvdata(ldc->dev);
|
||||
|
||||
dev_dbg(ldc->dev, "cxt %p\n", cxt);
|
||||
if (!cxt)
|
||||
return -ENODEV;
|
||||
dev_dbg(ldc->dev, "%s: registering notifier\n", __func__);
|
||||
|
||||
return blocking_notifier_chain_register(&cxt->nhead, nb);
|
||||
}
|
||||
|
||||
int ldc2114_cdev_init(void)
|
||||
static char *INSTANCE(char *string, struct ldc2114_data *ldc)
|
||||
{
|
||||
struct device *cd;
|
||||
int rc;
|
||||
char instance[64];
|
||||
snprintf(instance, sizeof(instance), "%s.%d",
|
||||
string, ldc->instance);
|
||||
return kstrdup(instance, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static struct dentry *root_dir;
|
||||
|
||||
int ldc2114_debugfs_init(struct ldc2114_data *ldc)
|
||||
{
|
||||
struct ldc2114_drv *cxt;
|
||||
int rc = 0;
|
||||
|
||||
if (!root_dir)
|
||||
root_dir = debugfs_create_dir(DRVNAME, NULL);
|
||||
|
||||
if (!root_dir)
|
||||
return -ENODEV;
|
||||
|
||||
cxt = kzalloc(sizeof(*cxt), GFP_KERNEL);
|
||||
if (!cxt)
|
||||
return -ENOMEM;
|
||||
|
||||
cxt->pdev = platform_device_alloc(DRVNAME, 0);
|
||||
if (!cxt->pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = platform_device_add(cxt->pdev);
|
||||
if (rc)
|
||||
goto undo_malloc;
|
||||
|
||||
rc = register_chrdev(0, DRVNAME, &ldc2114_cdev_fops);
|
||||
if (rc < 0) {
|
||||
dev_err(&cxt->pdev->dev, "error register chardev: %d\n", rc);
|
||||
goto undo_platform_device_add;
|
||||
if (!cxt) {
|
||||
rc = -ENOMEM;
|
||||
goto remove_dbg_root;
|
||||
}
|
||||
|
||||
cxt->major = rc;
|
||||
cxt->name = INSTANCE(DRVNAME, ldc);
|
||||
cxt->dev = ldc->dev;
|
||||
dev_set_drvdata(ldc->dev, cxt);
|
||||
|
||||
cxt->class = class_create(THIS_MODULE, DRVNAME "-dev");
|
||||
if (IS_ERR(cxt->class)) {
|
||||
rc = PTR_ERR(cxt->class);
|
||||
dev_err(&cxt->pdev->dev, "error chrdev: %d\n", rc);
|
||||
goto undo_register_chrdev;
|
||||
}
|
||||
|
||||
cd = device_create(cxt->class, NULL, MKDEV(cxt->major, 0), NULL, DRVNAME);
|
||||
if (IS_ERR(cd)) {
|
||||
rc = PTR_ERR(cd);
|
||||
dev_err(&cxt->pdev->dev, "error chrdev create: %d\n", rc);
|
||||
goto undo_class_create;
|
||||
}
|
||||
cxt->dentry = debugfs_create_file(cxt->name,
|
||||
0444, root_dir, cxt, &ldc2114_debugfs_fops);
|
||||
dev_dbg(ldc->dev, "%s: debugfs file '%s' created\n", __func__, cxt->name);
|
||||
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(&cxt->nhead);
|
||||
|
||||
return 0;
|
||||
|
||||
undo_class_create:
|
||||
class_destroy(cxt->class);
|
||||
undo_register_chrdev:
|
||||
unregister_chrdev(cxt->major, DRVNAME);
|
||||
undo_platform_device_add:
|
||||
platform_device_del(cxt->pdev);
|
||||
undo_malloc:
|
||||
platform_device_put(cxt->pdev);
|
||||
kfree(cxt);
|
||||
remove_dbg_root:
|
||||
debugfs_remove(root_dir);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void ldc2114_cdev_remove(void)
|
||||
void ldc2114_debugfs_remove(struct ldc2114_data *ldc)
|
||||
{
|
||||
struct ldc2114_drv *cxt = dev_get_drvdata(ldc->dev);
|
||||
|
||||
if (!cxt)
|
||||
return;
|
||||
|
||||
device_destroy(cxt->class, MKDEV(cxt->major, 0));
|
||||
class_destroy(cxt->class);
|
||||
unregister_chrdev(cxt->major, DRVNAME);
|
||||
platform_device_unregister(cxt->pdev);
|
||||
debugfs_remove(cxt->dentry);
|
||||
kfree(cxt);
|
||||
dev_set_drvdata(ldc->dev, NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -14,13 +14,10 @@
|
|||
* General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/gpio.h>
|
||||
|
|
@ -28,10 +25,14 @@
|
|||
#include <linux/input.h>
|
||||
#include <linux/reboot.h>
|
||||
|
||||
#include "ldc2114_cdev.h"
|
||||
#include "ldc2114.h"
|
||||
|
||||
#define LDC2114_DRIVER_NAME "ldc2114"
|
||||
|
||||
#define LDC2114_EV_DATA 1
|
||||
#define LDC2114_EV_IRQ 2
|
||||
#define LDC2114_EV_PRESS 3
|
||||
|
||||
#define LDC2114_SHORT_DELAY 100
|
||||
#define LDC2114_LONG_DELAY (LDC2114_SHORT_DELAY * 5)
|
||||
#define LDC2114_MAX_RETRIES 10
|
||||
|
|
@ -43,7 +44,6 @@
|
|||
#define WAIT_USEC_LOW (LDC2114_SHORT_DELAY * USEC_PER_MSEC)
|
||||
#define WAIT_USEC_HIGH (WAIT_USEC_LOW + (WAIT_USEC_LOW >> 3))
|
||||
|
||||
#define MAX_KEYS 4
|
||||
#define irq_to_gpio(irq) ((irq) - gpio_to_irq(0))
|
||||
|
||||
/* LDC2114 registers */
|
||||
|
|
@ -87,71 +87,7 @@
|
|||
#define LDC2114_DEVICE_ID_LSB 0xFE
|
||||
#define LDC2114_DEVICE_ID_MSB 0xFF
|
||||
|
||||
enum ldc2114_fields {
|
||||
/* Status */
|
||||
F_STATUS_TIMEOUT, F_STATUS_LC_WD, F_STATUS_FSM_WD, F_STATUS_MAXOUT,
|
||||
F_STATUS_RDY_TO_WRITE, F_STATUS_CHIP_READY, F_STATUS_OUT_STATUS,
|
||||
|
||||
/* Output */
|
||||
F_OUT_OUT0, F_OUT_OUT1, F_OUT_OUT2, F_OUT_OUT3,
|
||||
|
||||
/* Reset */
|
||||
F_RESET_STATE_RESET, F_RESET_FULL_RESET,
|
||||
|
||||
/* Enable */
|
||||
F_EN_EN0, F_EN_EN1, F_EN_EN2, F_EN_EN3,
|
||||
F_EN_LPEN0, F_EN_LPEN1, F_EN_LPEN2, F_EN_LPEN3,
|
||||
|
||||
/* Scan rate */
|
||||
F_NP_SCAN_RATE_NPSR, F_LP_SCAN_RATE_LPSR,
|
||||
|
||||
/* Gain */
|
||||
F_GAIN0_GAIN0, F_GAIN1_GAIN1, F_GAIN2_GAIN2, F_GAIN3_GAIN3,
|
||||
|
||||
/* Interrupt polarity */
|
||||
F_INTPOL_INTPOL,
|
||||
|
||||
/* Base Increment */
|
||||
F_LP_BASE_INC_LPBI, F_NP_BASE_INC_NPBI,
|
||||
|
||||
/* Max-win */
|
||||
F_MAXWIN_MAXWIN0, F_MAXWIN_MAXWIN1, F_MAXWIN_MAXWIN2, F_MAXWIN_MAXWIN3,
|
||||
|
||||
/* Frequency divider */
|
||||
F_LC_DIVIDER_LCDIV,
|
||||
|
||||
/* Hysteresis */
|
||||
F_HYST_HYST,
|
||||
|
||||
/* Anti-twist */
|
||||
F_TWIST_ANTITWST,
|
||||
|
||||
/* Anti-deform */
|
||||
F_COMMON_DEFORM_ANTIDFRM0, F_COMMON_DEFORM_ANTIDFRM1,
|
||||
F_COMMON_DEFORM_ANTIDFRM2, F_COMMON_DEFORM_ANTIDFRM3,
|
||||
|
||||
/* Anti-common */
|
||||
F_COMMON_DEFORM_ANTICM0, F_COMMON_DEFORM_ANTICM1,
|
||||
F_COMMON_DEFORM_ANTICM2, F_COMMON_DEFORM_ANTICM3,
|
||||
|
||||
/* Output Polarity */
|
||||
F_OPOL_OPOL0, F_OPOL_OPOL1, F_OPOL_OPOL2, F_OPOL_OPOL3,
|
||||
|
||||
/* Counter Scale */
|
||||
F_CNTSC_CNTSC0, F_CNTSC_CNTSC1, F_CNTSC_CNTSC2, F_CNTSC_CNTSC3,
|
||||
|
||||
/* Sensor configuration */
|
||||
F_SENSOR0_CONFIG_SENCYC0, F_SENSOR0_CONFIG_FREQ0, F_SENSOR0_CONFIG_RP0,
|
||||
F_SENSOR1_CONFIG_SENCYC1, F_SENSOR1_CONFIG_FREQ1, F_SENSOR1_CONFIG_RP1,
|
||||
F_SENSOR2_CONFIG_SENCYC2, F_SENSOR2_CONFIG_FREQ2, F_SENSOR2_CONFIG_RP2,
|
||||
F_SENSOR3_CONFIG_SENCYC3, F_SENSOR3_CONFIG_FREQ3, F_SENSOR3_CONFIG_RP3,
|
||||
|
||||
/* Fast Tracking Factor */
|
||||
F_FTF0_FTF0, F_FTF1_2_FTF1, F_FTF1_2_FTF2, F_FTF3_FTF3,
|
||||
|
||||
/* sentinel */
|
||||
F_MAX_FIELDS
|
||||
};
|
||||
static int drv_instance_counter;
|
||||
|
||||
static const struct reg_field ldc2114_reg_fields[] = {
|
||||
[F_STATUS_TIMEOUT] = REG_FIELD(LDC2114_STATUS, 1, 1),
|
||||
|
|
@ -225,63 +161,6 @@ static const struct reg_field ldc2114_reg_fields[] = {
|
|||
[F_FTF3_FTF3] = REG_FIELD(LDC2114_FTF3, 0, 1),
|
||||
};
|
||||
|
||||
struct ldc2114_cfg_data {
|
||||
uint8_t address, value;
|
||||
};
|
||||
|
||||
struct ldc2114_config {
|
||||
int size;
|
||||
struct ldc2114_cfg_data data[0];
|
||||
};
|
||||
|
||||
struct ldc2114_cfg_info {
|
||||
struct ldc2114_config *normal;
|
||||
struct ldc2114_config *lpm;
|
||||
struct ldc2114_config *active;
|
||||
int attempts;
|
||||
int delay_ms;
|
||||
bool toggled;
|
||||
bool reschedulable;
|
||||
struct completion done;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ldc2114_data - Instance data for LDC2114
|
||||
* @dev: Device structure
|
||||
* @regmap - Register map of the device
|
||||
* @fields: Register fields of the device
|
||||
* @irq: INTB line interrupt number
|
||||
*/
|
||||
struct ldc2114_data {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct regmap_field *fields[F_MAX_FIELDS];
|
||||
atomic_t irq_work_running;
|
||||
atomic_t poll_work_running;
|
||||
struct semaphore semaphore;
|
||||
int intb_gpio;
|
||||
int lpwm_gpio;
|
||||
int signal_gpio;
|
||||
int intb_polarity;
|
||||
int irq;
|
||||
int failures;
|
||||
bool irq_enabled;
|
||||
bool btn_enabled;
|
||||
bool data_polling;
|
||||
bool not_connected;
|
||||
unsigned int poll_interval;
|
||||
unsigned int button_map[MAX_KEYS];
|
||||
struct delayed_work polling_work;
|
||||
struct delayed_work irq_work;
|
||||
struct delayed_work config_work;
|
||||
struct input_dev *input;
|
||||
struct notifier_block poll_nb;
|
||||
struct notifier_block reboot_nb;
|
||||
unsigned int verno;
|
||||
struct ldc2114_cfg_info config;
|
||||
struct workqueue_struct *wq;
|
||||
};
|
||||
|
||||
struct ldc2114_attr {
|
||||
struct device_attribute dev_attr;
|
||||
unsigned int field;
|
||||
|
|
@ -710,46 +589,6 @@ static const struct regmap_config ldc2114_regmap_config = {
|
|||
.volatile_table = &ldc2114_volatile_table,
|
||||
};
|
||||
|
||||
#define LDC2114_REG_STATUS_OUT (0x80)
|
||||
#define LDC2114_REG_STATUS_CHIP_READY (0x40)
|
||||
#define LDC2114_REG_STATUS_RDY_TO_WRITE (0x20)
|
||||
#define LDC2114_REG_STATUS_MAXOUT (0x10)
|
||||
#define LDC2114_REG_STATUS_FSM_WD (0x08)
|
||||
#define LDC2114_REG_STATUS_LC_WD (0x04)
|
||||
#define LDC2114_REG_STATUS_TIMEOUT (0x02)
|
||||
#define LDC2114_REG_STATUS_INTEGRITY (0x01)
|
||||
#define LDC2114_REG_STATUS_ERROR_MASK (0x0f)
|
||||
#define LDC2114_REG_STATUS_ERROR_OTHERS (0x1b) /* (ERROR_MASK & ~LC_WD) | MAX_OUT */
|
||||
|
||||
#define LDC2114_REG_RESET_FULL (0x10)
|
||||
#define LDC2114_REG_RESET_CONFIG_MODE (0x01)
|
||||
#define LDC2114_REG_RESET_NONE (0x00)
|
||||
|
||||
struct ldc2114_16bit {
|
||||
uint8_t lsb;
|
||||
uint8_t msb;
|
||||
};
|
||||
|
||||
struct ldc2114_raw {
|
||||
uint8_t out;
|
||||
struct ldc2114_16bit values[MAX_KEYS];
|
||||
};
|
||||
|
||||
static int buttons[MAX_KEYS];
|
||||
static int output_bits;
|
||||
|
||||
static int inline comp2_12b(struct ldc2114_16bit *data)
|
||||
{
|
||||
int result;
|
||||
/* 12bits 2's compliment data */
|
||||
if (data->msb & 0x8)
|
||||
result = (data->lsb | (data->msb << 8) | 0xFFFFF000);
|
||||
else
|
||||
result = (data->lsb | (data->msb << 8));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int ldc2114_input_device(struct ldc2114_data *ldc)
|
||||
{
|
||||
int i, ret;
|
||||
|
|
@ -807,16 +646,18 @@ static void ldc2114_toggle(struct ldc2114_data *ldc,
|
|||
}
|
||||
}
|
||||
|
||||
static int ldc2114_poll(struct ldc2114_data *ldc,
|
||||
struct ldc2114_raw *data)
|
||||
static int ldc2114_poll(struct ldc2114_data *ldc, uint8_t *out)
|
||||
{
|
||||
int ret;
|
||||
struct ldc2114_raw_ext de;
|
||||
static unsigned long executed;
|
||||
|
||||
if (ldc->failures >= CONFIG_LDC2114_MAX_FAILURES)
|
||||
return -EFAULT;
|
||||
|
||||
ret = ldc2114_read_bulk(ldc->dev, LDC2114_OUT, data, sizeof(*data));
|
||||
ret = ldc2114_read_bulk(ldc->dev, LDC2114_STATUS, &de, sizeof(de));
|
||||
if (out)
|
||||
*out = de.data.out;
|
||||
if (ret) {
|
||||
ldc->failures++;
|
||||
|
||||
|
|
@ -826,15 +667,13 @@ static int ldc2114_poll(struct ldc2114_data *ldc,
|
|||
}
|
||||
} else {
|
||||
ldc->failures = 0;
|
||||
ret = ldc2114_buffer(
|
||||
comp2_12b(&data->values[0]), comp2_12b(&data->values[1]),
|
||||
comp2_12b(&data->values[2]), comp2_12b(&data->values[3]));
|
||||
ret = ldc2114_buffer(ldc, LDC2114_EV_DATA, de);
|
||||
if (ret)
|
||||
dev_err(ldc->dev, "buffer is not ready\n");
|
||||
}
|
||||
|
||||
if (!(executed++%10))
|
||||
dev_err(ldc->dev, "polled %lu\n", executed);
|
||||
dev_info(ldc->dev, "polled %lu\n", executed);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -866,20 +705,12 @@ static void ldc2114_polling_work(struct work_struct *work)
|
|||
container_of(work, struct delayed_work, work);
|
||||
struct ldc2114_data *ldc =
|
||||
container_of(dw, struct ldc2114_data, polling_work);
|
||||
struct ldc2114_raw data;
|
||||
int ret;
|
||||
|
||||
if (!ldc->irq_enabled) {
|
||||
uint8_t status;
|
||||
|
||||
ret = ldc2114_read_reg8(ldc->dev, LDC2114_STATUS, &status);
|
||||
dev_dbg(ldc->dev, "status = 0x%02x\n", status);
|
||||
}
|
||||
|
||||
ret = ldc2114_poll(ldc, &data);
|
||||
ret = ldc2114_poll(ldc, NULL);
|
||||
|
||||
if (atomic_read(&ldc->poll_work_running))
|
||||
queue_delayed_work(ldc->wq, &ldc->polling_work,
|
||||
schedule_delayed_work(&ldc->polling_work,
|
||||
msecs_to_jiffies(ldc->poll_interval));
|
||||
}
|
||||
|
||||
|
|
@ -895,13 +726,15 @@ static void ldc2114_input_report(struct ldc2114_data *ldc,
|
|||
|
||||
for (i = 0, s = 0; i < MAX_KEYS; i++) {
|
||||
status = (output_bits >> i) & 1;
|
||||
if (status == buttons[i])
|
||||
if (status == ldc->buttons[i])
|
||||
continue;
|
||||
buttons[i] = status;
|
||||
input_report_key(ldc->input, ldc->button_map[i], status);
|
||||
s++;
|
||||
dev_dbg(ldc->dev, "sent key code = %d(%d)\n",
|
||||
ldc->button_map[i], status);
|
||||
ldc->buttons[i] = status;
|
||||
if (ldc->btn_enabled) {
|
||||
input_report_key(ldc->input, ldc->button_map[i], status);
|
||||
s++;
|
||||
dev_dbg(ldc->dev, "sent key code = %d(%d)\n",
|
||||
ldc->button_map[i], status);
|
||||
}
|
||||
}
|
||||
|
||||
if (s) { /* only send sync if there were keys reported */
|
||||
|
|
@ -932,13 +765,12 @@ static void ldc2114_irq_work(struct work_struct *work)
|
|||
if (status_reg & LDC2114_REG_STATUS_OUT) {
|
||||
ret = ldc2114_read_bulk(ldc->dev,
|
||||
LDC2114_OUT, &data, sizeof(data));
|
||||
if (data.out != output_bits) {
|
||||
output_bits = data.out;
|
||||
dev_dbg(ldc->dev, "OUTPUT bits 0x%x\n", output_bits);
|
||||
if (data.out != ldc->output_bits) {
|
||||
ldc->output_bits = data.out;
|
||||
dev_dbg(ldc->dev, "OUTPUT bits 0x%x\n", ldc->output_bits);
|
||||
}
|
||||
|
||||
if (ldc->btn_enabled)
|
||||
ldc2114_input_report(ldc, output_bits);
|
||||
ldc2114_input_report(ldc, ldc->output_bits);
|
||||
}
|
||||
|
||||
if (atomic_read(&ldc->irq_work_running)) {
|
||||
|
|
@ -949,8 +781,8 @@ static void ldc2114_irq_work(struct work_struct *work)
|
|||
up(&ldc->semaphore);
|
||||
} else {
|
||||
#ifdef LDC2114_POLL_DEBUG
|
||||
dev_info(ldc->dev, "polled %d times within %llums\n",
|
||||
polling_counter,
|
||||
dev_info(ldc->dev, "%s: polled %d times within %llums\n",
|
||||
__func__, polling_counter,
|
||||
timediff_ms(ktime_to_timespec(start_polling_tm),
|
||||
ktime_to_timespec(ktime_get())));
|
||||
polling_counter = 0;
|
||||
|
|
@ -960,7 +792,7 @@ static void ldc2114_irq_work(struct work_struct *work)
|
|||
if (ldc->btn_enabled)
|
||||
ldc2114_input_report(ldc, 0);
|
||||
|
||||
memset(buttons, 0, sizeof(buttons));
|
||||
memset(ldc->buttons, 0, sizeof(ldc->buttons));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1117,6 +949,11 @@ static int ldc2114_of_init(struct i2c_client *client)
|
|||
dev_info(ldc->dev, "has keymap\n");
|
||||
}
|
||||
|
||||
if (of_property_read_bool(np, "ldc2114,do-polling")) {
|
||||
ldc->data_polling = true;
|
||||
dev_info(ldc->dev,"supports data polling\n");
|
||||
}
|
||||
|
||||
config_np = of_find_node_by_name(np, "configs");
|
||||
if (!config_np) {
|
||||
dev_info(ldc->dev, "does not support configs\n");
|
||||
|
|
@ -1284,12 +1121,12 @@ error_workaround:
|
|||
} else {
|
||||
/* reading OUT helps with issues when INTB gets stuck due */
|
||||
/* to internal issues between LDC2114 and Silego parts */
|
||||
struct ldc2114_raw data;
|
||||
uint8_t out;
|
||||
|
||||
ldc2114_poll(ldc, &data);
|
||||
ldc2114_poll(ldc, &out);
|
||||
#ifdef LDC2114_CFG_DEBUG
|
||||
dev_info(ldc->dev, "OUT 0x%02x, INTB %d\n",
|
||||
data.out, gpio_get_value(ldc->intb_gpio));
|
||||
out, gpio_get_value(ldc->intb_gpio));
|
||||
#endif
|
||||
/* some errors require STATUS register to be read twice, */
|
||||
/* thus do STATUS read again here if errors detected */
|
||||
|
|
@ -1326,16 +1163,16 @@ static int ldc2114_poll_enable_cb(struct notifier_block *n,
|
|||
container_of(n, struct ldc2114_data, poll_nb);
|
||||
int state = test_bit(0, &val) ? 1 : 0;
|
||||
|
||||
dev_info(ldc->dev, "polling flag %d; state=%d\n",
|
||||
ldc->data_polling, state);
|
||||
|
||||
if (!ldc->data_polling)
|
||||
return 0;
|
||||
|
||||
atomic_set(&ldc->poll_work_running, state);
|
||||
dev_info(ldc->dev, "polling state changed to %d\n", state);
|
||||
|
||||
if (state) {
|
||||
queue_delayed_work(ldc->wq, &ldc->polling_work, 0);
|
||||
dev_dbg(ldc->dev, "polling resumed\n");
|
||||
}
|
||||
if (state)
|
||||
schedule_work(&ldc->polling_work.work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1406,6 +1243,7 @@ static int ldc2114_probe(struct i2c_client *client,
|
|||
i2c_set_clientdata(client, ldc);
|
||||
ldc->dev = &client->dev;
|
||||
ldc->irq = client->irq;
|
||||
ldc->data_polling = true;
|
||||
|
||||
if (client->dev.of_node) {
|
||||
ret = ldc2114_of_init(client);
|
||||
|
|
@ -1445,6 +1283,7 @@ static int ldc2114_probe(struct i2c_client *client,
|
|||
return ret;
|
||||
}
|
||||
|
||||
ldc->instance = ++drv_instance_counter;
|
||||
sema_init(&ldc->semaphore, 0);
|
||||
|
||||
if (!ldc->not_connected) {
|
||||
|
|
@ -1469,16 +1308,17 @@ static int ldc2114_probe(struct i2c_client *client,
|
|||
if (ldc->btn_enabled)
|
||||
ldc2114_input_device(ldc);
|
||||
|
||||
ret = ldc2114_cdev_init();
|
||||
if (ret < 0 && ret != -ENODEV)
|
||||
dev_warn(ldc->dev, "Error registering chardev: %d\n", ret);
|
||||
else {
|
||||
ldc->data_polling = true;
|
||||
ret = ldc2114_debugfs_init(ldc);
|
||||
if (ret < 0) {
|
||||
ldc->data_polling = false;
|
||||
if (ret != -ENODEV)
|
||||
dev_warn(ldc->dev, "Error registering debugfs: %d\n", ret);
|
||||
} else {
|
||||
ldc->poll_interval = 250;
|
||||
INIT_DELAYED_WORK(&ldc->polling_work, ldc2114_polling_work);
|
||||
|
||||
ldc->poll_nb.notifier_call = ldc2114_poll_enable_cb;
|
||||
ret = ldc2114_register_client(&ldc->poll_nb);
|
||||
ret = ldc2114_register_client(ldc, &ldc->poll_nb);
|
||||
if (ret < 0)
|
||||
dev_warn(ldc->dev, "Unable to register notifier: %d\n", ret);
|
||||
}
|
||||
|
|
@ -1512,7 +1352,7 @@ static int ldc2114_remove(struct i2c_client *client)
|
|||
if (ldc->input)
|
||||
input_unregister_device(ldc->input);
|
||||
|
||||
ldc2114_cdev_remove();
|
||||
ldc2114_debugfs_remove(ldc);
|
||||
|
||||
sysfs_remove_group(&client->dev.kobj, &ldc2114_attr_group);
|
||||
|
||||
224
drivers/input/misc/ldc2114_mmi/ldc2114.h
Normal file
224
drivers/input/misc/ldc2114_mmi/ldc2114.h
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
#ifndef _LDC2114_HDR_
|
||||
#define _LDC2114_HDR_
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define MAX_KEYS 4
|
||||
#define BUFFER_SIZE 256
|
||||
|
||||
#define LDC2114_EV_DATA 1
|
||||
#define LDC2114_EV_IRQ 2
|
||||
#define LDC2114_EV_PRESS 3
|
||||
|
||||
#define LDC2114_REG_RESET_FULL (0x10)
|
||||
#define LDC2114_REG_RESET_CONFIG_MODE (0x01)
|
||||
#define LDC2114_REG_RESET_NONE (0x00)
|
||||
|
||||
#define LDC2114_REG_STATUS_OUT (0x80)
|
||||
#define LDC2114_REG_STATUS_CHIP_READY (0x40)
|
||||
#define LDC2114_REG_STATUS_RDY_TO_WRITE (0x20)
|
||||
#define LDC2114_REG_STATUS_MAXOUT (0x10)
|
||||
#define LDC2114_REG_STATUS_FSM_WD (0x08)
|
||||
#define LDC2114_REG_STATUS_LC_WD (0x04)
|
||||
#define LDC2114_REG_STATUS_TIMEOUT (0x02)
|
||||
#define LDC2114_REG_STATUS_INTEGRITY (0x01)
|
||||
#define LDC2114_REG_STATUS_ERROR_MASK (0x0f)
|
||||
#define LDC2114_REG_STATUS_ERROR_OTHERS (0x1b) /* (ERROR_MASK & ~LC_WD) | MAX_OUT */
|
||||
|
||||
enum ldc2114_fields {
|
||||
/* Status */
|
||||
F_STATUS_TIMEOUT, F_STATUS_LC_WD, F_STATUS_FSM_WD, F_STATUS_MAXOUT,
|
||||
F_STATUS_RDY_TO_WRITE, F_STATUS_CHIP_READY, F_STATUS_OUT_STATUS,
|
||||
|
||||
/* Output */
|
||||
F_OUT_OUT0, F_OUT_OUT1, F_OUT_OUT2, F_OUT_OUT3,
|
||||
|
||||
/* Reset */
|
||||
F_RESET_STATE_RESET, F_RESET_FULL_RESET,
|
||||
|
||||
/* Enable */
|
||||
F_EN_EN0, F_EN_EN1, F_EN_EN2, F_EN_EN3,
|
||||
F_EN_LPEN0, F_EN_LPEN1, F_EN_LPEN2, F_EN_LPEN3,
|
||||
|
||||
/* Scan rate */
|
||||
F_NP_SCAN_RATE_NPSR, F_LP_SCAN_RATE_LPSR,
|
||||
|
||||
/* Gain */
|
||||
F_GAIN0_GAIN0, F_GAIN1_GAIN1, F_GAIN2_GAIN2, F_GAIN3_GAIN3,
|
||||
|
||||
/* Interrupt polarity */
|
||||
F_INTPOL_INTPOL,
|
||||
|
||||
/* Base Increment */
|
||||
F_LP_BASE_INC_LPBI, F_NP_BASE_INC_NPBI,
|
||||
|
||||
/* Max-win */
|
||||
F_MAXWIN_MAXWIN0, F_MAXWIN_MAXWIN1, F_MAXWIN_MAXWIN2, F_MAXWIN_MAXWIN3,
|
||||
|
||||
/* Frequency divider */
|
||||
F_LC_DIVIDER_LCDIV,
|
||||
|
||||
/* Hysteresis */
|
||||
F_HYST_HYST,
|
||||
|
||||
/* Anti-twist */
|
||||
F_TWIST_ANTITWST,
|
||||
|
||||
/* Anti-deform */
|
||||
F_COMMON_DEFORM_ANTIDFRM0, F_COMMON_DEFORM_ANTIDFRM1,
|
||||
F_COMMON_DEFORM_ANTIDFRM2, F_COMMON_DEFORM_ANTIDFRM3,
|
||||
|
||||
/* Anti-common */
|
||||
F_COMMON_DEFORM_ANTICM0, F_COMMON_DEFORM_ANTICM1,
|
||||
F_COMMON_DEFORM_ANTICM2, F_COMMON_DEFORM_ANTICM3,
|
||||
|
||||
/* Output Polarity */
|
||||
F_OPOL_OPOL0, F_OPOL_OPOL1, F_OPOL_OPOL2, F_OPOL_OPOL3,
|
||||
|
||||
/* Counter Scale */
|
||||
F_CNTSC_CNTSC0, F_CNTSC_CNTSC1, F_CNTSC_CNTSC2, F_CNTSC_CNTSC3,
|
||||
|
||||
/* Sensor configuration */
|
||||
F_SENSOR0_CONFIG_SENCYC0, F_SENSOR0_CONFIG_FREQ0, F_SENSOR0_CONFIG_RP0,
|
||||
F_SENSOR1_CONFIG_SENCYC1, F_SENSOR1_CONFIG_FREQ1, F_SENSOR1_CONFIG_RP1,
|
||||
F_SENSOR2_CONFIG_SENCYC2, F_SENSOR2_CONFIG_FREQ2, F_SENSOR2_CONFIG_RP2,
|
||||
F_SENSOR3_CONFIG_SENCYC3, F_SENSOR3_CONFIG_FREQ3, F_SENSOR3_CONFIG_RP3,
|
||||
|
||||
/* Fast Tracking Factor */
|
||||
F_FTF0_FTF0, F_FTF1_2_FTF1, F_FTF1_2_FTF2, F_FTF3_FTF3,
|
||||
|
||||
/* sentinel */
|
||||
F_MAX_FIELDS
|
||||
};
|
||||
|
||||
struct ldc2114_cfg_data {
|
||||
uint8_t address, value;
|
||||
};
|
||||
|
||||
struct ldc2114_config {
|
||||
int size;
|
||||
struct ldc2114_cfg_data data[0];
|
||||
};
|
||||
|
||||
struct ldc2114_cfg_info {
|
||||
struct ldc2114_config *normal;
|
||||
struct ldc2114_config *lpm;
|
||||
struct ldc2114_config *active;
|
||||
int attempts;
|
||||
int delay_ms;
|
||||
bool toggled;
|
||||
bool reschedulable;
|
||||
struct completion done;
|
||||
};
|
||||
|
||||
struct ldc2114_16bit {
|
||||
uint8_t lsb;
|
||||
uint8_t msb;
|
||||
} __packed;
|
||||
|
||||
struct ldc2114_raw {
|
||||
uint8_t out;
|
||||
struct ldc2114_16bit values[MAX_KEYS];
|
||||
} __packed;
|
||||
|
||||
struct ldc2114_raw_ext {
|
||||
uint8_t status;
|
||||
struct ldc2114_raw data;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct ldc2114_data - Instance data for LDC2114
|
||||
* @dev: Device structure
|
||||
* @regmap - Register map of the device
|
||||
* @fields: Register fields of the device
|
||||
* @irq: INTB line interrupt number
|
||||
*/
|
||||
struct ldc2114_data {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct regmap_field *fields[F_MAX_FIELDS];
|
||||
atomic_t irq_work_running;
|
||||
atomic_t poll_work_running;
|
||||
struct semaphore semaphore;
|
||||
int intb_gpio;
|
||||
int lpwm_gpio;
|
||||
int signal_gpio;
|
||||
int intb_polarity;
|
||||
int irq;
|
||||
int failures;
|
||||
int instance;
|
||||
bool irq_enabled;
|
||||
bool btn_enabled;
|
||||
bool data_polling;
|
||||
bool not_connected;
|
||||
unsigned int poll_interval;
|
||||
unsigned int button_map[MAX_KEYS];
|
||||
struct delayed_work polling_work;
|
||||
struct delayed_work irq_work;
|
||||
struct delayed_work config_work;
|
||||
struct input_dev *input;
|
||||
struct notifier_block poll_nb;
|
||||
struct notifier_block reboot_nb;
|
||||
unsigned int verno;
|
||||
struct ldc2114_cfg_info config;
|
||||
struct workqueue_struct *wq;
|
||||
|
||||
int buttons[MAX_KEYS];
|
||||
int output_bits;
|
||||
};
|
||||
|
||||
typedef struct data {
|
||||
int type;
|
||||
struct ldc2114_raw_ext de;
|
||||
} item_t;
|
||||
|
||||
struct buffer {
|
||||
struct mutex mutex;
|
||||
int capacity;
|
||||
unsigned long opened;
|
||||
atomic_t start;
|
||||
atomic_t end;
|
||||
atomic_t active;
|
||||
item_t **data;
|
||||
wait_queue_head_t wait;
|
||||
};
|
||||
|
||||
struct ldc2114_drv {
|
||||
struct dentry *dentry;
|
||||
struct device *dev;
|
||||
char *name;
|
||||
struct buffer ds;
|
||||
struct blocking_notifier_head nhead;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_DEBUG_FS)
|
||||
int ldc2114_debugfs_init(struct ldc2114_data *ldc);
|
||||
void ldc2114_debugfs_remove(struct ldc2114_data *ldc);
|
||||
int ldc2114_buffer(struct ldc2114_data *ldc, int type, ...);
|
||||
int ldc2114_register_client(struct ldc2114_data *ldc, struct notifier_block *nb);
|
||||
#else
|
||||
static int ldc2114_debugfs_init(struct ldc2114_data *ldc)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
static void ldc2114_debugfs_remove(struct ldc2114_data *ldc)
|
||||
{
|
||||
}
|
||||
static int ldc2114_buffer(struct ldc2114_data *ldc, int type, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static int ldc2114_register_client(struct ldc2114_data *ldc, struct notifier_block *nb)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
Loading…
Reference in a new issue