From 4f16051c5974ca87d629c5ac529019ced185b2a3 Mon Sep 17 00:00:00 2001 From: Konstantin Makariev Date: Thu, 29 Nov 2018 16:27:02 -0600 Subject: [PATCH] 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 Reviewed-on: https://gerrit.mot.com/1277626 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Reviewed-by: Konstantin Makariev Submit-Approved: Jira Key --- drivers/input/misc/Kbuild | 13 - drivers/input/misc/ldc2114_cdev.h | 28 -- .../input/misc/{ => ldc2114_mmi}/Android.mk | 2 - drivers/input/misc/ldc2114_mmi/Kbuild | 12 + drivers/input/misc/ldc2114_mmi/Makefile | 10 + .../ldc2114-debugfs.c} | 220 ++++++++------- .../input/misc/{ => ldc2114_mmi}/ldc2114.c | 266 ++++-------------- drivers/input/misc/ldc2114_mmi/ldc2114.h | 224 +++++++++++++++ 8 files changed, 413 insertions(+), 362 deletions(-) delete mode 100644 drivers/input/misc/Kbuild delete mode 100644 drivers/input/misc/ldc2114_cdev.h rename drivers/input/misc/{ => ldc2114_mmi}/Android.mk (81%) create mode 100644 drivers/input/misc/ldc2114_mmi/Kbuild create mode 100644 drivers/input/misc/ldc2114_mmi/Makefile rename drivers/input/misc/{ldc2114-cdev.c => ldc2114_mmi/ldc2114-debugfs.c} (55%) rename drivers/input/misc/{ => ldc2114_mmi}/ldc2114.c (86%) create mode 100644 drivers/input/misc/ldc2114_mmi/ldc2114.h diff --git a/drivers/input/misc/Kbuild b/drivers/input/misc/Kbuild deleted file mode 100644 index 9a69ca4e0e99..000000000000 --- a/drivers/input/misc/Kbuild +++ /dev/null @@ -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 diff --git a/drivers/input/misc/ldc2114_cdev.h b/drivers/input/misc/ldc2114_cdev.h deleted file mode 100644 index 6f6c540fd0a2..000000000000 --- a/drivers/input/misc/ldc2114_cdev.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _LDC2114_CDEV_HDR_ -#define _LDC2114_CDEV_HDR_ - -#include - -#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 diff --git a/drivers/input/misc/Android.mk b/drivers/input/misc/ldc2114_mmi/Android.mk similarity index 81% rename from drivers/input/misc/Android.mk rename to drivers/input/misc/ldc2114_mmi/Android.mk index 7f979205721c..92f16292aa88 100644 --- a/drivers/input/misc/Android.mk +++ b/drivers/input/misc/ldc2114_mmi/Android.mk @@ -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)) diff --git a/drivers/input/misc/ldc2114_mmi/Kbuild b/drivers/input/misc/ldc2114_mmi/Kbuild new file mode 100644 index 000000000000..db4897bbff02 --- /dev/null +++ b/drivers/input/misc/ldc2114_mmi/Kbuild @@ -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 diff --git a/drivers/input/misc/ldc2114_mmi/Makefile b/drivers/input/misc/ldc2114_mmi/Makefile new file mode 100644 index 000000000000..4191dea22679 --- /dev/null +++ b/drivers/input/misc/ldc2114_mmi/Makefile @@ -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 diff --git a/drivers/input/misc/ldc2114-cdev.c b/drivers/input/misc/ldc2114_mmi/ldc2114-debugfs.c similarity index 55% rename from drivers/input/misc/ldc2114-cdev.c rename to drivers/input/misc/ldc2114_mmi/ldc2114-debugfs.c index 346b37f7e0a0..0205728612fa 100644 --- a/drivers/input/misc/ldc2114-cdev.c +++ b/drivers/input/misc/ldc2114_mmi/ldc2114-debugfs.c @@ -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 +#include #include -#include #include #include #include #include -#include -#include -#include -#include #include -#include #include +#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 diff --git a/drivers/input/misc/ldc2114.c b/drivers/input/misc/ldc2114_mmi/ldc2114.c similarity index 86% rename from drivers/input/misc/ldc2114.c rename to drivers/input/misc/ldc2114_mmi/ldc2114.c index 35f8e6ed293d..82b3f30876c7 100644 --- a/drivers/input/misc/ldc2114.c +++ b/drivers/input/misc/ldc2114_mmi/ldc2114.c @@ -14,13 +14,10 @@ * General Public License for more details. */ -#include #include #include #include #include -#include -#include #include #include #include @@ -28,10 +25,14 @@ #include #include -#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); diff --git a/drivers/input/misc/ldc2114_mmi/ldc2114.h b/drivers/input/misc/ldc2114_mmi/ldc2114.h new file mode 100644 index 000000000000..f6a3d47a3b15 --- /dev/null +++ b/drivers/input/misc/ldc2114_mmi/ldc2114.h @@ -0,0 +1,224 @@ +#ifndef _LDC2114_HDR_ +#define _LDC2114_HDR_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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