From: Andy Ross <andy.ross@windriver.com>
To: Corentin Chary <corentin.chary@gmail.com>
Cc: acpi4asus-user@lists.sourceforge.net,
platform-driver-x86@vger.kernel.org
Subject: [PATCH 3/4] asus-laptop: Pegatron Lucid accelerometer
Date: Thu, 24 Mar 2011 15:02:09 -0700 [thread overview]
Message-ID: <1301004130-3294-4-git-send-email-andy.ross@windriver.com> (raw)
In-Reply-To: <1301004130-3294-1-git-send-email-andy.ross@windriver.com>
Support the built-in accelerometer on the Lucid tablets as a standard
3-axis input device.
Signed-off-by: Andy Ross <andy.ross@windriver.com>
---
drivers/platform/x86/Kconfig | 9 ++-
drivers/platform/x86/asus-laptop.c | 137 +++++++++++++++++++++++++++++++++++-
2 files changed, 141 insertions(+), 5 deletions(-)
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index b6f983e..43906f5 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -67,10 +67,11 @@ config ASUS_LAPTOP
This is a driver for Asus laptops and the Pegatron Lucid
tablet. It may also support some MEDION, JVC or VICTOR
laptops. It makes all the extra buttons generate standard
- ACPI events and input events. It also adds support for video
- output switching, LCD backlight control, Bluetooth and Wlan
- control, and most importantly, allows you to blink those
- fancy LEDs.
+ ACPI events and input events, and on the Lucid the built-in
+ accelerometer appears as an input device. It also adds
+ support for video output switching, LCD backlight control,
+ Bluetooth and Wlan control, and most importantly, allows you
+ to blink those fancy LEDs.
For more information and a userspace daemon for handling the extra
buttons see <http://acpi4asus.sf.net>.
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index 6651d8c..9b07368 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -224,6 +224,14 @@ static char *display_get_paths[] = {
#define PEGA_READ_ALS_H 0x02
#define PEGA_READ_ALS_L 0x03
+#define PEGA_ACCEL_NAME "pega_accel"
+#define PEGA_ACCEL_DESC "Pegatron Lucid Tablet Accelerometer"
+#define METHOD_XLRX "XLRX"
+#define METHOD_XLRY "XLRY"
+#define METHOD_XLRZ "XLRZ"
+#define PEGA_ACC_CLAMP 512 /* 1G accel is reported as ~256, so clamp to 2G */
+#define PEGA_ACC_RETRIES 3
+
/*
* Define a specific led structure to keep the main structure clean
*/
@@ -249,6 +257,7 @@ struct asus_laptop {
struct input_dev *inputdev;
struct key_entry *keymap;
+ struct input_polled_dev *pega_accel_poll;
struct asus_led mled;
struct asus_led tled;
@@ -262,6 +271,10 @@ struct asus_laptop {
bool have_rsts;
bool have_pega_lucid;
int lcd_state;
+ bool pega_acc_live;
+ int pega_acc_x;
+ int pega_acc_y;
+ int pega_acc_z;
struct rfkill *gps_rfkill;
@@ -390,6 +403,99 @@ static int asus_pega_lucid_set(struct asus_laptop *asus, int unit, bool enable)
return write_acpi_int(asus->handle, method, unit);
}
+static int pega_acc_axis(struct asus_laptop *asus, int curr, char *method)
+{
+ int i, delta;
+ unsigned long long val;
+ for (i = 0; i < PEGA_ACC_RETRIES; i++) {
+ acpi_evaluate_integer(asus->handle, method, NULL, &val);
+
+ /* The output is noisy. From reading the ASL
+ * dissassembly, timeout errors are returned with 1's
+ * in the high word, and the lack of locking around
+ * thei hi/lo byte reads means that a transition
+ * between (for example) -1 and 0 could be read as
+ * 0xff00 or 0x00ff. */
+ delta = abs(curr - (short)val);
+ if (delta < 128 && !(val & ~0xffff))
+ break;
+ }
+ return clamp_val((short)val, -PEGA_ACC_CLAMP, PEGA_ACC_CLAMP);
+}
+
+static void pega_accel_poll(struct input_polled_dev *ipd)
+{
+ struct device *parent = ipd->input->dev.parent;
+ struct asus_laptop *asus = dev_get_drvdata(parent);
+
+ /* In some cases, the very first call to poll causes a
+ * recursive fault under the polldev worker. This is
+ * apparently related to very early userspace access to the
+ * device, and perhaps a firmware bug. See related comments
+ * in asus_platform_probe regarding the fragility of these
+ * methods early in the boot. Fake the first report. */
+ if (!asus->pega_acc_live) {
+ asus->pega_acc_live = true;
+ input_report_abs(ipd->input, ABS_X, 0);
+ input_report_abs(ipd->input, ABS_Y, 0);
+ input_report_abs(ipd->input, ABS_Z, 0);
+ input_sync(ipd->input);
+ return;
+ }
+
+ asus->pega_acc_x = pega_acc_axis(asus, asus->pega_acc_x, METHOD_XLRX);
+ asus->pega_acc_y = pega_acc_axis(asus, asus->pega_acc_y, METHOD_XLRY);
+ asus->pega_acc_z = pega_acc_axis(asus, asus->pega_acc_z, METHOD_XLRZ);
+
+ /* Note transform, convert to "right/up/out" in the native
+ * landscape orientation (i.e. the vector is the direction of
+ * "real up" in the device's cartiesian coordinates). */
+ input_report_abs(ipd->input, ABS_X, -asus->pega_acc_x);
+ input_report_abs(ipd->input, ABS_Y, -asus->pega_acc_y);
+ input_report_abs(ipd->input, ABS_Z, asus->pega_acc_z);
+ input_sync(ipd->input);
+}
+
+static void pega_accel_probe(struct asus_laptop *asus)
+{
+ int err;
+ struct input_polled_dev *ipd;
+
+ if (!asus->have_pega_lucid ||
+ acpi_check_handle(asus->handle, METHOD_XLRX, NULL) ||
+ acpi_check_handle(asus->handle, METHOD_XLRY, NULL) ||
+ acpi_check_handle(asus->handle, METHOD_XLRZ, NULL))
+ return;
+
+ ipd = input_allocate_polled_device();
+ if (!ipd)
+ return;
+
+ ipd->poll = pega_accel_poll;
+ ipd->poll_interval = 125;
+ ipd->poll_interval_min = 50;
+ ipd->poll_interval_max = 2000;
+
+ ipd->input->name = PEGA_ACCEL_DESC;
+ ipd->input->phys = PEGA_ACCEL_NAME "/input0";
+ ipd->input->dev.parent = &asus->platform_device->dev;
+ ipd->input->id.bustype = BUS_HOST;
+
+ set_bit(EV_ABS, ipd->input->evbit);
+ input_set_abs_params(ipd->input, ABS_X,
+ -PEGA_ACC_CLAMP, PEGA_ACC_CLAMP, 0, 0);
+ input_set_abs_params(ipd->input, ABS_Y,
+ -PEGA_ACC_CLAMP, PEGA_ACC_CLAMP, 0, 0);
+ input_set_abs_params(ipd->input, ABS_Z,
+ -PEGA_ACC_CLAMP, PEGA_ACC_CLAMP, 0, 0);
+
+ err = input_register_polled_device(ipd);
+ if (err)
+ input_free_polled_device(ipd);
+ else
+ asus->pega_accel_poll = ipd;
+}
+
/* Generic LED function */
static int asus_led_set(struct asus_laptop *asus, const char *method,
int value)
@@ -1459,11 +1565,40 @@ static void asus_platform_exit(struct asus_laptop *asus)
platform_device_unregister(asus->platform_device);
}
+static int asus_platform_probe(struct platform_device *pd)
+{
+ struct asus_laptop *asus = dev_get_drvdata(&pd->dev);
+
+ /* This is instantiated during platform driver initialization
+ * becuase if it's done from underneath asus_acpi_add(), the
+ * resulting input device can be grabbed by an early userspace
+ * reader before ACPI initialization is finished and something
+ * oopses underneath the acpi_evaluate_integer() call out of
+ * pega_accel_poll(). Firmware bug? */
+ pega_accel_probe(asus);
+
+ return 0;
+}
+
+static int __devexit asus_platform_remove(struct platform_device *pd)
+{
+ struct asus_laptop *asus = dev_get_drvdata(&pd->dev);
+ if (asus->pega_accel_poll) {
+ input_unregister_polled_device(asus->pega_accel_poll);
+ input_free_polled_device(asus->pega_accel_poll);
+ }
+ asus->pega_accel_poll = NULL;
+ return 0;
+}
+
+
static struct platform_driver platform_driver = {
.driver = {
.name = ASUS_LAPTOP_FILE,
.owner = THIS_MODULE,
- }
+ },
+ .probe = asus_platform_probe,
+ .remove = asus_platform_remove,
};
static int asus_handle_init(char *name, acpi_handle * handle,
--
1.7.1
next prev parent reply other threads:[~2011-03-24 22:08 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-03-24 22:02 [PATCH 0/4] asus-laptop: Pegatron Lucid (WeTab/ExoPC) support Andy Ross
2011-03-24 22:02 ` [PATCH 1/4] asus-laptop: Platform detection for Pegatron Lucid Andy Ross
2011-03-24 22:02 ` [PATCH 2/4] asus-laptop: Pegatron Lucid ALS sensor Andy Ross
2011-03-25 7:48 ` Corentin Chary
2011-03-24 22:02 ` Andy Ross [this message]
2011-03-25 11:21 ` [PATCH 3/4] asus-laptop: Pegatron Lucid accelerometer Corentin Chary
2011-03-28 5:43 ` Dmitry Torokhov
2011-03-28 15:36 ` Andy Ross
2011-03-31 7:23 ` Corentin Chary
2011-04-04 17:16 ` Corentin Chary
2011-04-07 15:56 ` Anisse Astier
2011-04-07 16:09 ` Corentin Chary
2011-03-28 6:41 ` Corentin Chary
2011-03-24 22:02 ` [PATCH 4/4] asus-laptop: allow boot time control of Pegatron ALS sensor Andy Ross
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=1301004130-3294-4-git-send-email-andy.ross@windriver.com \
--to=andy.ross@windriver.com \
--cc=acpi4asus-user@lists.sourceforge.net \
--cc=corentin.chary@gmail.com \
--cc=platform-driver-x86@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox