From: Alan Cox <alan@lxorguk.ukuu.org.uk>
To: dmitry.torokhov@gmail.com, linux-input@vger.kernel.org
Subject: [PATCH 1/3] input: mpu3050: Support for polled input device
Date: Thu, 15 Dec 2011 22:18:34 +0000 [thread overview]
Message-ID: <20111215221829.8657.37926.stgit@bob.linux.org.uk> (raw)
In-Reply-To: <20111215221732.8657.63987.stgit@bob.linux.org.uk>
From: Heikki Krogerus <heikki.krogerus@linux.intel.com>
The driver does not need to depend on interrupts.
Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Alan Cox <alan@linux.intel.com>
---
drivers/input/misc/mpu3050.c | 189 +++++++++++++++++++++++++++++++-----------
1 files changed, 141 insertions(+), 48 deletions(-)
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index f71dc72..da47b10 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -37,6 +37,7 @@
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/input.h>
+#include <linux/input-polldev.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
@@ -53,6 +54,8 @@
#define MPU3050_MIN_VALUE -32768
#define MPU3050_MAX_VALUE 32767
+#define MPU3050_DEFAULT_POLL_INTERVAL 200
+
struct axis_data {
s16 x;
s16 y;
@@ -63,6 +66,7 @@ struct mpu3050_sensor {
struct i2c_client *client;
struct device *dev;
struct input_dev *idev;
+ struct input_polled_dev *input_polled;
};
/**
@@ -168,6 +172,38 @@ static void mpu3050_input_close(struct input_dev *input)
pm_runtime_put(sensor->dev);
}
+static void mpu3050_poll_open(struct input_polled_dev *ipoll_dev)
+{
+ struct mpu3050_sensor *sensor = ipoll_dev->private;
+
+ mpu3050_set_power_mode(sensor->client, 1);
+ msleep(100); /* wait for gyro chip resume */
+}
+
+static void mpu3050_poll_close(struct input_polled_dev *ipoll_dev)
+{
+ struct mpu3050_sensor *sensor = ipoll_dev->private;
+
+ mpu3050_set_power_mode(sensor->client, 1);
+}
+
+static void mpu3050_report_xyz(struct mpu3050_sensor *sensor)
+{
+ struct axis_data axis;
+
+ mpu3050_read_xyz(sensor->client, &axis);
+
+ input_report_abs(sensor->idev, ABS_X, axis.x);
+ input_report_abs(sensor->idev, ABS_Y, axis.y);
+ input_report_abs(sensor->idev, ABS_Z, axis.z);
+ input_sync(sensor->idev);
+}
+
+static void mpu3050_poll(struct input_polled_dev *dev)
+{
+ mpu3050_report_xyz(dev->private);
+}
+
/**
* mpu3050_interrupt_thread - handle an IRQ
* @irq: interrupt numner
@@ -178,17 +214,82 @@ static void mpu3050_input_close(struct input_dev *input)
*/
static irqreturn_t mpu3050_interrupt_thread(int irq, void *data)
{
- struct mpu3050_sensor *sensor = data;
- struct axis_data axis;
+ mpu3050_report_xyz(data);
- mpu3050_read_xyz(sensor->client, &axis);
+ return IRQ_HANDLED;
+}
- input_report_abs(sensor->idev, ABS_X, axis.x);
- input_report_abs(sensor->idev, ABS_Y, axis.y);
- input_report_abs(sensor->idev, ABS_Z, axis.z);
- input_sync(sensor->idev);
+static void __devinit mpu3050_init_idev(struct mpu3050_sensor *sensor,
+ struct input_dev *idev)
+{
+ idev->name = "MPU3050";
+ idev->id.bustype = BUS_I2C;
+ idev->dev.parent = &sensor->client->dev;
- return IRQ_HANDLED;
+ __set_bit(EV_ABS, idev->evbit);
+ input_set_abs_params(idev, ABS_X,
+ MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
+ input_set_abs_params(idev, ABS_Y,
+ MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
+ input_set_abs_params(idev, ABS_Z,
+ MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
+}
+
+static int __devinit mpu3050_create_idev(struct mpu3050_sensor *sensor)
+{
+ struct input_dev *idev;
+ int err;
+
+ idev = input_allocate_device();
+ if (!idev)
+ return -ENODEV;
+
+ mpu3050_init_idev(sensor, idev);
+
+ idev->open = mpu3050_input_open;
+ idev->close = mpu3050_input_close;
+ input_set_drvdata(idev, sensor);
+
+ err = input_register_device(idev);
+ if (err) {
+ input_free_device(idev);
+ return err;
+ }
+
+ sensor->idev = idev;
+
+ return 0;
+}
+
+static int __devinit mpu3050_create_polled_idev(struct mpu3050_sensor *sensor)
+{
+ struct input_polled_dev *ipoll_dev;
+ int err;
+
+ ipoll_dev = input_allocate_polled_device();
+ if (!ipoll_dev)
+ return -ENOMEM;
+
+ ipoll_dev->private = sensor;
+ ipoll_dev->open = mpu3050_poll_open;
+ ipoll_dev->close = mpu3050_poll_close;
+ ipoll_dev->poll = mpu3050_poll;
+ ipoll_dev->poll_interval = MPU3050_DEFAULT_POLL_INTERVAL;
+ ipoll_dev->poll_interval_min = 10;
+ ipoll_dev->poll_interval_max = MPU3050_DEFAULT_POLL_INTERVAL;
+
+ mpu3050_init_idev(sensor, ipoll_dev->input);
+
+ err = input_register_polled_device(ipoll_dev);
+ if (err) {
+ input_free_polled_device(ipoll_dev);
+ return err;
+ }
+
+ sensor->input_polled = ipoll_dev;
+ sensor->idev = ipoll_dev->input;
+
+ return 0;
}
/**
@@ -205,21 +306,17 @@ static int __devinit mpu3050_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct mpu3050_sensor *sensor;
- struct input_dev *idev;
int ret;
int error;
sensor = kzalloc(sizeof(struct mpu3050_sensor), GFP_KERNEL);
- idev = input_allocate_device();
- if (!sensor || !idev) {
+ if (!sensor) {
dev_err(&client->dev, "failed to allocate driver data\n");
- error = -ENOMEM;
- goto err_free_mem;
+ return -ENOMEM;
}
sensor->client = client;
sensor->dev = &client->dev;
- sensor->idev = idev;
mpu3050_set_power_mode(client, 1);
msleep(10);
@@ -237,39 +334,31 @@ static int __devinit mpu3050_probe(struct i2c_client *client,
goto err_free_mem;
}
- idev->name = "MPU3050";
- idev->id.bustype = BUS_I2C;
- idev->dev.parent = &client->dev;
-
- idev->open = mpu3050_input_open;
- idev->close = mpu3050_input_close;
-
- __set_bit(EV_ABS, idev->evbit);
- input_set_abs_params(idev, ABS_X,
- MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
- input_set_abs_params(idev, ABS_Y,
- MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
- input_set_abs_params(idev, ABS_Z,
- MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0);
-
- input_set_drvdata(idev, sensor);
-
pm_runtime_set_active(&client->dev);
- error = request_threaded_irq(client->irq,
- NULL, mpu3050_interrupt_thread,
- IRQF_TRIGGER_RISING,
- "mpu_int", sensor);
- if (error) {
- dev_err(&client->dev,
- "can't get IRQ %d, error %d\n", client->irq, error);
- goto err_pm_set_suspended;
- }
-
- error = input_register_device(idev);
- if (error) {
- dev_err(&client->dev, "failed to register input device\n");
- goto err_free_irq;
+ if (client->irq > 0) {
+ error = mpu3050_create_idev(sensor);
+ if (error) {
+ dev_err(&client->dev, "failed to register input device\n");
+ goto err_free_irq;
+ }
+
+ error = request_threaded_irq(client->irq,
+ NULL, mpu3050_interrupt_thread,
+ IRQF_TRIGGER_RISING,
+ "mpu_int", sensor);
+ if (error) {
+ dev_err(&client->dev, "can't get IRQ %d, error %d\n",
+ client->irq, error);
+ goto err_pm_set_suspended;
+ }
+ } else {
+ error = mpu3050_create_polled_idev(sensor);
+ if (error) {
+ dev_err(&client->dev,
+ "failed to register polled input device");
+ goto err_pm_set_suspended;
+ }
}
pm_runtime_enable(&client->dev);
@@ -282,7 +371,6 @@ err_free_irq:
err_pm_set_suspended:
pm_runtime_set_suspended(&client->dev);
err_free_mem:
- input_free_device(idev);
kfree(sensor);
return error;
}
@@ -300,8 +388,13 @@ static int __devexit mpu3050_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
- free_irq(client->irq, sensor);
- input_unregister_device(sensor->idev);
+ if (client->irq > 0) {
+ free_irq(client->irq, sensor);
+ input_unregister_device(sensor->idev);
+ } else {
+ input_unregister_polled_device(sensor->input_polled);
+ input_free_polled_device(sensor->input_polled);
+ }
kfree(sensor);
return 0;
next prev parent reply other threads:[~2011-12-15 22:22 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-12-15 22:18 [PATCH 0/3] mpu3050 updates Alan Cox
2011-12-15 22:18 ` Alan Cox [this message]
2011-12-16 10:52 ` [PATCH 1/3] input: mpu3050: Support for polled input device Shubhrajyoti
2011-12-28 5:07 ` Dmitry Torokhov
2011-12-15 22:18 ` [PATCH 2/3] input: mpu3050: Configure the sampling method Alan Cox
2011-12-24 8:07 ` Dmitry Torokhov
2011-12-15 22:18 ` [PATCH 3/3] input: mpu3050: Ensure we enable interrupts Alan Cox
2011-12-24 8:09 ` Dmitry Torokhov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20111215221829.8657.37926.stgit@bob.linux.org.uk \
--to=alan@lxorguk.ukuu.org.uk \
--cc=dmitry.torokhov@gmail.com \
--cc=linux-input@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.