[3/6] cap11xx: polling mode without irq
diff mbox series

Message ID 1577647277-8298-4-git-send-email-dev.kurt@vandijck-laurijssen.be
State New
Headers show
Series
  • [1/6] cap11xx: set device driver_data
Related show

Commit Message

Kurt Van Dijck Dec. 29, 2019, 7:21 p.m. UTC
Signed-off-by: Kurt Van Dijck <dev.kurt@vandijck-laurijssen.be>
---
 drivers/input/keyboard/cap11xx.c | 49 ++++++++++++++++++++++++++++++++++++----
 1 file changed, 45 insertions(+), 4 deletions(-)

Patch
diff mbox series

diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index 092dcd2..5a7eaed 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -9,6 +9,7 @@ 
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/input.h>
+#include <linux/kthread.h>
 #include <linux/leds.h>
 #include <linux/of_irq.h>
 #include <linux/regmap.h>
@@ -78,6 +79,7 @@  struct cap11xx_led {
 
 struct cap11xx_priv {
 	struct regmap *regmap;
+	struct task_struct *poll_thread;
 	struct input_dev *idev;
 
 	struct cap11xx_led *leds;
@@ -202,6 +204,24 @@  static irqreturn_t cap11xx_thread_func(int irq_num, void *data)
 	return IRQ_HANDLED;
 }
 
+static int poll_irq(void *data) {
+
+	struct cap11xx_priv *priv = data;
+	int ret;
+	unsigned int status;
+
+	/* until module unload */
+	while (!kthread_should_stop()) {
+		ret = regmap_read(priv->regmap, CAP11XX_REG_MAIN_CONTROL, &status);
+		if (ret >= 0 && (status & 1))
+			cap11xx_thread_func(-1, priv);
+		usleep_range(15000, 25000);
+	}
+
+	return 0;
+}
+
+
 static int cap11xx_set_sleep(struct cap11xx_priv *priv, bool sleep)
 {
 	/*
@@ -320,6 +340,17 @@  static int cap11xx_init_leds(struct device *dev,
 }
 #endif
 
+static int cap11xx_i2c_remove(struct i2c_client *i2c_client)
+{
+	struct cap11xx_priv *priv = i2c_get_clientdata(i2c_client);
+
+	if (priv->poll_thread) {
+		kthread_stop(priv->poll_thread);
+		mdelay(10);
+	}
+	return 0;
+}
+
 static int cap11xx_i2c_probe(struct i2c_client *i2c_client,
 			     const struct i2c_device_id *id)
 {
@@ -348,8 +379,6 @@  static int cap11xx_i2c_probe(struct i2c_client *i2c_client,
 	if (!priv)
 		return -ENOMEM;
 
-	i2c_set_clientdata(i2c_client, priv);
-
 	priv->regmap = devm_regmap_init_i2c(i2c_client, &cap11xx_regmap_config);
 	if (IS_ERR(priv->regmap))
 		return PTR_ERR(priv->regmap);
@@ -458,8 +487,19 @@  static int cap11xx_i2c_probe(struct i2c_client *i2c_client,
 
 	irq = irq_of_parse_and_map(node, 0);
 	if (!irq) {
-		dev_err(dev, "Unable to parse or map IRQ\n");
-		return -ENXIO;
+		if (!of_property_read_bool(node, "linux,irq-poll")) {
+			dev_err(dev, "Unable to parse or map IRQ\n");
+			return -ENXIO;
+		}
+		dev_info(dev, "IRQ failed or undefined, using poll_thread\n");
+		priv->poll_thread = kthread_create(poll_irq, priv, "%s-%s-poll",
+				id->name, dev_name(dev));
+		if (!priv->poll_thread) {
+			dev_err(dev, "Unable to start poll_thread\n");
+			return -ENXIO;
+		}
+		wake_up_process(priv->poll_thread);
+		return 0;
 	}
 
 	error = devm_request_threaded_irq(dev, irq, NULL, cap11xx_thread_func,
@@ -495,6 +535,7 @@  static int cap11xx_i2c_probe(struct i2c_client *i2c_client,
 	},
 	.id_table	= cap11xx_i2c_ids,
 	.probe		= cap11xx_i2c_probe,
+	.remove		= cap11xx_i2c_remove,
 };
 
 module_i2c_driver(cap11xx_i2c_driver);