Signed-off-by: Kurt Van Dijck <dev.kurt@xxxxxxxxxxxxxxxxxxxxxx> --- drivers/input/keyboard/cap11xx.c | 49 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) 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); -- 1.8.5.rc3