diff mbox series

Input: add switch event(SW_COVER_ATTACHED)

Message ID 20201030060204epcms1p48c0c3d0b82d0304c6e1b296cb6ebc778@epcms1p4
State New
Headers show
Series Input: add switch event(SW_COVER_ATTACHED) | expand

Commit Message

HyungJae Im Oct. 30, 2020, 6:02 a.m. UTC
We need support to various accessories on the device,
some requiring switch does not exist in switch list.
So added switch for the following purpose.

SW_COVER_ATTACHED is for the checking the cover
attached or not on the device. We also added driver
that uses such event.

Signed-off-by: Hyungjae Im <hj2.im@samsung.com>
---
 drivers/input/Kconfig                  |  12 ++
 drivers/input/Makefile                 |   2 +
 drivers/input/cover_detect.c           | 236 +++++++++++++++++++++++++
 include/linux/mod_devicetable.h        |   2 +-
 include/uapi/linux/input-event-codes.h |   3 +-
 5 files changed, 253 insertions(+), 2 deletions(-)
 create mode 100644 drivers/input/cover_detect.c

Comments

kernel test robot Nov. 1, 2020, 11:27 a.m. UTC | #1
Hi HyungJae,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on input/next]
[also build test ERROR on linus/master linux/master v5.10-rc1 next-20201030]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/HyungJae-Im/Input-add-switch-event-SW_COVER_ATTACHED/20201030-140340
base:   https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git next
config: s390-allmodconfig (attached as .config)
compiler: s390-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/0b49228f266d7c09d3a85cc94357ac0e11f4f2ef
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review HyungJae-Im/Input-add-switch-event-SW_COVER_ATTACHED/20201030-140340
        git checkout 0b49228f266d7c09d3a85cc94357ac0e11f4f2ef
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=s390 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

>> drivers/input/cover_detect.c:17:10: fatal error: linux/wakelock.h: No such file or directory
      17 | #include <linux/wakelock.h>
         |          ^~~~~~~~~~~~~~~~~~
   compilation terminated.

vim +17 drivers/input/cover_detect.c

  > 17	#include <linux/wakelock.h>
    18	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff mbox series

Patch

diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 1efd3154b68d..ba5e7444c547 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -185,6 +185,18 @@  config INPUT_APMPOWER
 	  To compile this driver as a module, choose M here: the
 	  module will be called apm-power.
 
+config INPUT_COVER_DETECT
+	tristate "Enable cover attach detection"
+	help
+	  Say Y here to enable cover attach detection
+	  and send a event when cover is attached/detached.
+	  Active gpio state is low and active event value is 0.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cover_detect.
+
 comment "Input Device Drivers"
 
 source "drivers/input/keyboard/Kconfig"
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index e35650930371..fc8dd9091821 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -29,3 +29,5 @@  obj-$(CONFIG_INPUT_MISC)	+= misc/
 obj-$(CONFIG_INPUT_APMPOWER)	+= apm-power.o
 
 obj-$(CONFIG_RMI4_CORE)		+= rmi4/
+
+obj-$(CONFIG_INPUT_COVER_DETECT)+= cover_detect.o
diff --git a/drivers/input/cover_detect.c b/drivers/input/cover_detect.c
new file mode 100644
index 000000000000..4a5947356d50
--- /dev/null
+++ b/drivers/input/cover_detect.c
@@ -0,0 +1,236 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Support detection for cover attachment
+ *
+ * Copyright (C) 2020 Samsung Electronics Co. Ltd. All Rights Reserved.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/wakelock.h>
+
+struct cover_detect_drvdata {
+	struct input_dev *input;
+	struct delayed_work cover_detect_dwork;
+	struct wakeup_source *ws;
+	int gpio_cover_detect;
+	int irq_cover_detect;
+};
+
+static void cover_detect_work(struct work_struct *work)
+{
+	struct cover_detect_drvdata *ddata =
+		container_of(work, struct cover_detect_drvdata,
+				cover_detect_dwork.work);
+	bool cover_status;
+
+	cover_status = gpio_get_value(ddata->gpio_cover_detect);
+
+	input_report_switch(ddata->input,
+			SW_COVER_ATTACHED, cover_status);
+	input_sync(ddata->input);
+}
+
+static void __cover_detect(struct cover_detect_drvdata *ddata,
+				 bool cover_status)
+{
+	cancel_delayed_work_sync(&ddata->cover_detect_dwork);
+	if (cover_status) {
+		__pm_wakeup_event(ddata->ws, jiffies_to_msecs(HZ / 20));
+		schedule_delayed_work(&ddata->cover_detect_dwork, HZ * 1 / 100);
+	} else {
+		__pm_relax(ddata->ws);
+		schedule_delayed_work(&ddata->cover_detect_dwork, 0);
+	}
+}
+
+static irqreturn_t cover_detect_irq(int irq, void *dev_id)
+{
+	bool cover_status;
+	struct cover_detect_drvdata *ddata = dev_id;
+
+	cover_status = gpio_get_value(ddata->gpio_cover_detect);
+
+	__cover_detect(ddata, cover_status);
+
+	return IRQ_HANDLED;
+}
+
+static int cover_detect_open(struct input_dev *input)
+{
+	struct cover_detect_drvdata *ddata = input_get_drvdata(input);
+	/* update the current status */
+	schedule_delayed_work(&ddata->cover_detect_dwork, HZ / 2);
+	/* Report current state of buttons that are connected to GPIOs */
+	input_sync(input);
+
+	return 0;
+}
+
+static void cover_detect_close(struct input_dev *input)
+{
+}
+
+static void init_cover_detect_irq(struct input_dev *input)
+{
+	struct cover_detect_drvdata *ddata = input_get_drvdata(input);
+
+	int ret = 0;
+	int irq = ddata->irq_cover_detect;
+
+	ret =	request_threaded_irq(
+		irq, NULL,
+		cover_detect_irq,
+		IRQF_TRIGGER_RISING |
+		IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+		"cover_detect", ddata);
+	if (ret < 0)
+		pr_err("keys: failed to request cover detect irq %d gpio %d\n",
+			irq, ddata->gpio_cover_detect);
+}
+
+#ifdef CONFIG_OF
+static int of_cover_detect_data_parsing_dt(struct device *dev,
+					struct cover_detect_drvdata *ddata)
+{
+	struct device_node *np = dev->of_node;
+	int gpio;
+	enum of_gpio_flags flags;
+
+	gpio = of_get_named_gpio_flags(np, "gpio_cover_detect", 0, &flags);
+	ddata->gpio_cover_detect = gpio;
+
+	ddata->irq_cover_detect = gpio_to_irq(gpio);
+
+	return 0;
+}
+#endif
+
+static int cover_detect_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct cover_detect_drvdata *ddata;
+	struct input_dev *input;
+	int error;
+	int wakeup = 0;
+
+	ddata = kzalloc(sizeof(struct cover_detect_drvdata), GFP_KERNEL);
+	if (!ddata)
+		return -ENOMEM;
+
+#ifdef CONFIG_OF
+	if (dev->of_node) {
+		error = of_cover_detect_data_parsing_dt(dev, ddata);
+		if (error < 0) {
+			dev_err(dev, "fail to get the devicetree, error: %d\n",
+					error);
+			goto fail1;
+		}
+	}
+#endif
+
+	input = input_allocate_device();
+	if (!input) {
+		dev_err(dev, "failed to allocate state\n");
+		error = -ENOMEM;
+		goto fail1;
+	}
+
+	ddata->input = input;
+
+	ddata->ws = wakeup_source_register(NULL, "cover_detect");
+
+	platform_set_drvdata(pdev, ddata);
+	input_set_drvdata(input, ddata);
+
+	input->name = "cover_detect";
+	input->phys = "cover_detect";
+	input->dev.parent = &pdev->dev;
+
+	input->evbit[0] |= BIT_MASK(EV_SW);
+	input_set_capability(input, EV_SW, SW_COVER_ATTACHED);
+
+	input->open = cover_detect_open;
+	input->close = cover_detect_close;
+
+	/* Enable auto repeat feature of Linux input subsystem */
+	__set_bit(EV_REP, input->evbit);
+
+	INIT_DELAYED_WORK(&ddata->cover_detect_dwork, cover_detect_work);
+
+	init_cover_detect_irq(input);
+
+	if (ddata->gpio_cover_detect != 0) {
+		error = input_register_device(input);
+		if (error) {
+			dev_err(dev, "Unable to register input device, error: %d\n",
+				error);
+			goto fail1;
+		}
+	}
+
+	device_init_wakeup(&pdev->dev, wakeup);
+
+	return 0;
+
+ fail1:
+	kfree(ddata);
+
+	return error;
+}
+
+static int cover_detect_remove(struct platform_device *pdev)
+{
+	struct cover_detect_drvdata *ddata = platform_get_drvdata(pdev);
+	struct input_dev *input = ddata->input;
+
+	device_init_wakeup(&pdev->dev, 0);
+
+	input_unregister_device(input);
+
+	wakeup_source_unregister(ddata->ws);
+
+	kfree(ddata);
+
+	return 0;
+}
+
+#if defined(CONFIG_OF)
+static const struct of_device_id cover_detect_dt_ids[] = {
+	{ .compatible = "cover_detect" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, cover_detect_dt_ids);
+#endif /* CONFIG_OF */
+
+static struct platform_driver cover_detect_device_driver = {
+	.probe		= cover_detect_probe,
+	.remove		= cover_detect_remove,
+	.driver		= {
+		.name	= "cover_detect",
+		.owner	= THIS_MODULE,
+#if defined(CONFIG_OF)
+		.of_match_table	= cover_detect_dt_ids,
+#endif /* CONFIG_OF */
+	}
+};
+
+static int __init cover_detect_init(void)
+{
+	return platform_driver_register(&cover_detect_device_driver);
+}
+
+static void __exit cover_detect_exit(void)
+{
+	platform_driver_unregister(&cover_detect_device_driver);
+}
+
+module_init(cover_detect_init);
+module_exit(cover_detect_exit);
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 5b08a473cdba..2e6ae686555b 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -320,7 +320,7 @@  struct pcmcia_device_id {
 #define INPUT_DEVICE_ID_LED_MAX		0x0f
 #define INPUT_DEVICE_ID_SND_MAX		0x07
 #define INPUT_DEVICE_ID_FF_MAX		0x7f
-#define INPUT_DEVICE_ID_SW_MAX		0x10
+#define INPUT_DEVICE_ID_SW_MAX		0x11
 #define INPUT_DEVICE_ID_PROP_MAX	0x1f
 
 #define INPUT_DEVICE_ID_MATCH_BUS	1
diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h
index 0c2e27d28e0a..32e27732161c 100644
--- a/include/uapi/linux/input-event-codes.h
+++ b/include/uapi/linux/input-event-codes.h
@@ -889,7 +889,8 @@ 
 #define SW_MUTE_DEVICE		0x0e  /* set = device disabled */
 #define SW_PEN_INSERTED		0x0f  /* set = pen inserted */
 #define SW_MACHINE_COVER	0x10  /* set = cover closed */
-#define SW_MAX			0x10
+#define SW_COVER_ATTACHED	0x11  /* set = cover attached */
+#define SW_MAX			0x11
 #define SW_CNT			(SW_MAX+1)
 
 /*