From 8819de7f988289111cf4c44946f0d8c008b2d9a7 Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Fri, 14 Oct 2011 11:13:35 +0200 Subject: asus-laptop: Platform detection for Pegatron Lucid Recognize the Pegatron Lucid tablets by their method signatures. Signed-off-by: Andy Ross Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-laptop.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'drivers/platform/x86/asus-laptop.c') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index fa6d7ec68b26..c08f4c26b988 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -4,6 +4,7 @@ * * Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor * Copyright (C) 2006-2007 Corentin Chary + * Copyright (C) 2011 Wind River Systems * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -48,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -173,6 +175,12 @@ MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot " #define METHOD_KBD_LIGHT_SET "SLKB" #define METHOD_KBD_LIGHT_GET "GLKB" +/* For Pegatron Lucid tablet */ +#define DEVICE_NAME_PEGA "Lucid" +#define METHOD_PEGA_ENABLE "ENPR" +#define METHOD_PEGA_DISABLE "DAPR" +#define METHOD_PEGA_READ "RDLN" + /* * Define a specific led structure to keep the main structure clean */ @@ -209,6 +217,7 @@ struct asus_laptop { int wireless_status; bool have_rsts; + bool is_pega_lucid; struct rfkill *gps_rfkill; @@ -323,6 +332,14 @@ static int acpi_check_handle(acpi_handle handle, const char *method, return 0; } +static bool asus_check_pega_lucid(struct asus_laptop *asus) +{ + return !strcmp(asus->name, DEVICE_NAME_PEGA) && + !acpi_check_handle(asus->handle, METHOD_PEGA_ENABLE, NULL) && + !acpi_check_handle(asus->handle, METHOD_PEGA_DISABLE, NULL) && + !acpi_check_handle(asus->handle, METHOD_PEGA_READ, NULL); +} + /* Generic LED function */ static int asus_led_set(struct asus_laptop *asus, const char *method, int value) @@ -1203,7 +1220,6 @@ static mode_t asus_sysfs_is_visible(struct kobject *kobj, attr == &dev_attr_ls_level.attr) { supported = !acpi_check_handle(handle, METHOD_ALS_CONTROL, NULL) && !acpi_check_handle(handle, METHOD_ALS_LEVEL, NULL); - } else if (attr == &dev_attr_gps.attr) { supported = !acpi_check_handle(handle, METHOD_GPS_ON, NULL) && !acpi_check_handle(handle, METHOD_GPS_OFF, NULL) && @@ -1439,9 +1455,10 @@ static int __devinit asus_acpi_add(struct acpi_device *device) goto fail_platform; /* - * Register the platform device first. It is used as a parent for the - * sub-devices below. + * Need platform type detection first, then the platform + * device. It is used as a parent for the sub-devices below. */ + asus->is_pega_lucid = asus_check_pega_lucid(asus); result = asus_platform_init(asus); if (result) goto fail_platform; -- cgit v1.2.3 From 33989ba6f7feb3d03916e42d7775d802d2fdea1e Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Fri, 14 Oct 2011 11:13:36 +0200 Subject: asus-laptop: Pegatron Lucid ALS sensor Ambient light sensor for Pegatron Lucid. Supports pre-existing ls_switch sysfs interface to en/disable automatic control, and exports the brightness from the device as "ls_value". Signed-off-by: Andy Ross Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-laptop.c | 80 +++++++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 5 deletions(-) (limited to 'drivers/platform/x86/asus-laptop.c') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index c08f4c26b988..afed9ff33b86 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -177,9 +177,15 @@ MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot " /* For Pegatron Lucid tablet */ #define DEVICE_NAME_PEGA "Lucid" + #define METHOD_PEGA_ENABLE "ENPR" #define METHOD_PEGA_DISABLE "DAPR" +#define PEGA_ALS 0x04 +#define PEGA_ALS_POWER 0x05 + #define METHOD_PEGA_READ "RDLN" +#define PEGA_READ_ALS_H 0x02 +#define PEGA_READ_ALS_L 0x03 /* * Define a specific led structure to keep the main structure clean @@ -340,6 +346,12 @@ static bool asus_check_pega_lucid(struct asus_laptop *asus) !acpi_check_handle(asus->handle, METHOD_PEGA_READ, NULL); } +static int asus_pega_lucid_set(struct asus_laptop *asus, int unit, bool enable) +{ + char *method = enable ? METHOD_PEGA_ENABLE : METHOD_PEGA_DISABLE; + return write_acpi_int(asus->handle, method, unit); +} + /* Generic LED function */ static int asus_led_set(struct asus_laptop *asus, const char *method, int value) @@ -924,8 +936,18 @@ static ssize_t store_disp(struct device *dev, struct device_attribute *attr, */ static void asus_als_switch(struct asus_laptop *asus, int value) { - if (write_acpi_int(asus->handle, METHOD_ALS_CONTROL, value)) - pr_warn("Error setting light sensor switch\n"); + int ret; + + if (asus->is_pega_lucid) { + ret = asus_pega_lucid_set(asus, PEGA_ALS, value); + if (!ret) + ret = asus_pega_lucid_set(asus, PEGA_ALS_POWER, value); + } else { + ret = write_acpi_int(asus->handle, METHOD_ALS_CONTROL, value); + } + if (ret) + pr_warning("Error setting light sensor switch\n"); + asus->light_switch = value; } @@ -981,6 +1003,35 @@ static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr, return rv; } +static int pega_int_read(struct asus_laptop *asus, int arg, int *result) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + int err = write_acpi_int_ret(asus->handle, METHOD_PEGA_READ, arg, + &buffer); + if (!err) { + union acpi_object *obj = buffer.pointer; + if (obj && obj->type == ACPI_TYPE_INTEGER) + *result = obj->integer.value; + else + err = -EIO; + } + return err; +} + +static ssize_t show_lsvalue(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct asus_laptop *asus = dev_get_drvdata(dev); + int err, hi, lo; + + err = pega_int_read(asus, PEGA_READ_ALS_H, &hi); + if (!err) + err = pega_int_read(asus, PEGA_READ_ALS_L, &lo); + if (!err) + return sprintf(buf, "%d\n", 10 * hi + lo); + return err; +} + /* * GPS */ @@ -1169,6 +1220,7 @@ static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax); static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan); static DEVICE_ATTR(display, S_IWUSR, NULL, store_disp); static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd); +static DEVICE_ATTR(ls_value, S_IRUGO, show_lsvalue, NULL); static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl); static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw); static DEVICE_ATTR(gps, S_IRUGO | S_IWUSR, show_gps, store_gps); @@ -1181,6 +1233,7 @@ static struct attribute *asus_attributes[] = { &dev_attr_wwan.attr, &dev_attr_display.attr, &dev_attr_ledd.attr, + &dev_attr_ls_value.attr, &dev_attr_ls_level.attr, &dev_attr_ls_switch.attr, &dev_attr_gps.attr, @@ -1197,6 +1250,19 @@ static mode_t asus_sysfs_is_visible(struct kobject *kobj, acpi_handle handle = asus->handle; bool supported; + if (asus->is_pega_lucid) { + /* no ls_level interface on the Lucid */ + if (attr == &dev_attr_ls_switch.attr) + supported = true; + else if (attr == &dev_attr_ls_level.attr) + supported = false; + else + goto normal; + + return supported; + } + +normal: if (attr == &dev_attr_wlan.attr) { supported = !acpi_check_handle(handle, METHOD_WLAN, NULL); @@ -1219,7 +1285,9 @@ static mode_t asus_sysfs_is_visible(struct kobject *kobj, } else if (attr == &dev_attr_ls_switch.attr || attr == &dev_attr_ls_level.attr) { supported = !acpi_check_handle(handle, METHOD_ALS_CONTROL, NULL) && - !acpi_check_handle(handle, METHOD_ALS_LEVEL, NULL); + !acpi_check_handle(handle, METHOD_ALS_LEVEL, NULL); + } else if (attr == &dev_attr_ls_value.attr) { + supported = asus->is_pega_lucid; } else if (attr == &dev_attr_gps.attr) { supported = !acpi_check_handle(handle, METHOD_GPS_ON, NULL) && !acpi_check_handle(handle, METHOD_GPS_OFF, NULL) && @@ -1407,8 +1475,10 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) asus->light_switch = 0; /* Default to light sensor disabled */ asus->light_level = 5; /* level 5 for sensor sensitivity */ - if (!acpi_check_handle(asus->handle, METHOD_ALS_CONTROL, NULL) && - !acpi_check_handle(asus->handle, METHOD_ALS_LEVEL, NULL)) { + if (asus->is_pega_lucid) { + asus_als_switch(asus, asus->light_switch); + } else if (!acpi_check_handle(asus->handle, METHOD_ALS_CONTROL, NULL) && + !acpi_check_handle(asus->handle, METHOD_ALS_LEVEL, NULL)) { asus_als_switch(asus, asus->light_switch); asus_als_level(asus, asus->light_level); } -- cgit v1.2.3 From 8fcf71aa0032acbd30b3222f9cb238919ab3b984 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 8 Aug 2011 17:17:18 +0800 Subject: platform-drivers-x86: asus-laptop: fix wrong test for successful registered led_classdev device_create returns &struct device pointer on success, or ERR_PTR() on error. Thus if led_classdev_register fails, led_cdev->dev is always not NULL. Thus to unregister a successful registered led_classdev, we should check IS_ERR_OR_NULL macro for led_cdev->dev instead of checking if led_cdev->dev is NULL or not. we use IS_ERR_OR_NULL instead of IS_ERR because if we havn't call led_classdev_register, the led_cdev->dev is NULL. Signed-off-by: Axel Lin Acked-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-laptop.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/platform/x86/asus-laptop.c') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index afed9ff33b86..10b0a8663bb7 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -459,17 +459,17 @@ static enum led_brightness asus_kled_cdev_get(struct led_classdev *led_cdev) static void asus_led_exit(struct asus_laptop *asus) { - if (asus->mled.led.dev) + if (!IS_ERR_OR_NULL(asus->mled.led.dev)) led_classdev_unregister(&asus->mled.led); - if (asus->tled.led.dev) + if (!IS_ERR_OR_NULL(asus->tled.led.dev)) led_classdev_unregister(&asus->tled.led); - if (asus->pled.led.dev) + if (!IS_ERR_OR_NULL(asus->pled.led.dev)) led_classdev_unregister(&asus->pled.led); - if (asus->rled.led.dev) + if (!IS_ERR_OR_NULL(asus->rled.led.dev)) led_classdev_unregister(&asus->rled.led); - if (asus->gled.led.dev) + if (!IS_ERR_OR_NULL(asus->gled.led.dev)) led_classdev_unregister(&asus->gled.led); - if (asus->kled.led.dev) + if (!IS_ERR_OR_NULL(asus->kled.led.dev)) led_classdev_unregister(&asus->kled.led); if (asus->led_workqueue) { destroy_workqueue(asus->led_workqueue); -- cgit v1.2.3 From abec04dbc3dbe7577ccd9d5d6e188aa153d464eb Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Fri, 14 Oct 2011 11:13:37 +0200 Subject: asus-laptop: allow boot time control of Pegatron ALS sensor Signed-off-by: Andy Ross Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-laptop.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/platform/x86/asus-laptop.c') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 10b0a8663bb7..8327d06b6e8a 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -85,6 +85,7 @@ static int wlan_status = 1; static int bluetooth_status = 1; static int wimax_status = -1; static int wwan_status = -1; +static int als_status; module_param(wlan_status, int, 0444); MODULE_PARM_DESC(wlan_status, "Set the wireless status on boot " @@ -106,6 +107,11 @@ MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot " "(0 = disabled, 1 = enabled, -1 = don't do anything). " "default is 1"); +module_param(als_status, int, 0444); +MODULE_PARM_DESC(als_status, "Set the ALS status on boot " + "(0 = disabled, 1 = enabled). " + "default is 0"); + /* * Some events we use, same for all Asus */ @@ -1472,7 +1478,7 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus) asus->ledd_status = 0xFFF; /* Set initial values of light sensor and level */ - asus->light_switch = 0; /* Default to light sensor disabled */ + asus->light_switch = !!als_status; asus->light_level = 5; /* level 5 for sensor sensitivity */ if (asus->is_pega_lucid) { -- cgit v1.2.3 From b23910c2194e0e0ee43e585788085f8e6dd4877e Mon Sep 17 00:00:00 2001 From: Andy Ross Date: Fri, 14 Oct 2011 11:13:38 +0200 Subject: asus-laptop: Pegatron Lucid accelerometer Support the built-in accelerometer on the Lucid tablets as a standard 3-axis input device. Signed-off-by: Andy Ross Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 9 +-- drivers/platform/x86/asus-laptop.c | 129 ++++++++++++++++++++++++++++++++++++- 2 files changed, 133 insertions(+), 5 deletions(-) (limited to 'drivers/platform/x86/asus-laptop.c') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 4e5623e4fa0b..0d4146ca011f 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -69,10 +69,11 @@ config ASUS_LAPTOP This is a driver for Asus laptops, Lenovo SL 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 see . diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 8327d06b6e8a..613762d825f9 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -193,6 +193,14 @@ MODULE_PARM_DESC(als_status, "Set the ALS status on boot " #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 */ @@ -218,6 +226,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; @@ -230,6 +239,10 @@ struct asus_laptop { int wireless_status; bool have_rsts; bool is_pega_lucid; + bool pega_acc_live; + int pega_acc_x; + int pega_acc_y; + int pega_acc_z; struct rfkill *gps_rfkill; @@ -358,6 +371,113 @@ 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. 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_exit(struct asus_laptop *asus) +{ + 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; +} + +static int pega_accel_init(struct asus_laptop *asus) +{ + int err; + struct input_polled_dev *ipd; + + if (!asus->is_pega_lucid) + return -ENODEV; + + if (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 -ENODEV; + + ipd = input_allocate_polled_device(); + if (!ipd) + return -ENOMEM; + + 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) + goto exit; + + asus->pega_accel_poll = ipd; + return 0; + +exit: + input_free_polled_device(ipd); + return err; +} + /* Generic LED function */ static int asus_led_set(struct asus_laptop *asus, const char *method, int value) @@ -1348,7 +1468,7 @@ static struct platform_driver platform_driver = { .driver = { .name = ASUS_LAPTOP_FILE, .owner = THIS_MODULE, - } + }, }; /* @@ -1558,9 +1678,15 @@ static int __devinit asus_acpi_add(struct acpi_device *device) if (result) goto fail_rfkill; + result = pega_accel_init(asus); + if (result && result != -ENODEV) + goto fail_pega_accel; + asus_device_present = true; return 0; +fail_pega_accel: + asus_rfkill_exit(asus); fail_rfkill: asus_led_exit(asus); fail_led: @@ -1584,6 +1710,7 @@ static int asus_acpi_remove(struct acpi_device *device, int type) asus_rfkill_exit(asus); asus_led_exit(asus); asus_input_exit(asus); + pega_accel_exit(asus); asus_platform_exit(asus); kfree(asus->name); -- cgit v1.2.3 From 8d38e42c61c53ab63abbb15380b39df4eae8d44e Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 14 Oct 2011 11:13:39 +0200 Subject: asus-laptop: hide leds on Pegatron Lucid Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-laptop.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/platform/x86/asus-laptop.c') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 613762d825f9..1fb8e699baf4 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -628,6 +628,13 @@ static int asus_led_init(struct asus_laptop *asus) { int r; + /* + * The Pegatron Lucid has no physical leds, but all methods are + * available in the DSDT... + */ + if (asus->is_pega_lucid) + return 0; + /* * Functions that actually update the LED's are called from a * workqueue. By doing this as separate work rather than when the LED -- cgit v1.2.3 From 16cbf93369a8d148316a75c333bb81bbb64a46c4 Mon Sep 17 00:00:00 2001 From: Corentin Chary Date: Fri, 14 Oct 2011 11:13:40 +0200 Subject: asus-laptop: fix module description Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-laptop.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/platform/x86/asus-laptop.c') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 1fb8e699baf4..012c44d38d48 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -90,22 +90,22 @@ static int als_status; module_param(wlan_status, int, 0444); MODULE_PARM_DESC(wlan_status, "Set the wireless status on boot " "(0 = disabled, 1 = enabled, -1 = don't do anything). " - "default is 1"); + "default is -1"); module_param(bluetooth_status, int, 0444); MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " "(0 = disabled, 1 = enabled, -1 = don't do anything). " - "default is 1"); + "default is -1"); module_param(wimax_status, int, 0444); MODULE_PARM_DESC(wimax_status, "Set the wireless status on boot " "(0 = disabled, 1 = enabled, -1 = don't do anything). " - "default is 1"); + "default is -1"); module_param(wwan_status, int, 0444); MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot " "(0 = disabled, 1 = enabled, -1 = don't do anything). " - "default is 1"); + "default is -1"); module_param(als_status, int, 0444); MODULE_PARM_DESC(als_status, "Set the ALS status on boot " -- cgit v1.2.3 From b93f82816c9ee4868c5aa1c8e06259233916d988 Mon Sep 17 00:00:00 2001 From: Anisse Astier Date: Fri, 14 Oct 2011 11:13:41 +0200 Subject: asus-laptop: pega_accel - Report accelerometer orientation change through udev Signed-off-by: Anisse Astier Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-laptop.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/platform/x86/asus-laptop.c') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 012c44d38d48..05c0e594c036 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -1342,6 +1342,14 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event) } return ; } + + /* Accelerometer "coarse orientation change" event */ + if (asus->pega_accel_poll && event == 0xEA) { + kobject_uevent(&asus->pega_accel_poll->input->dev.kobj, + KOBJ_CHANGE); + return ; + } + asus_input_notify(asus, event); } -- cgit v1.2.3 From 149083996e52c640fdfd73ad92550be4b803f349 Mon Sep 17 00:00:00 2001 From: Anisse Astier Date: Fri, 14 Oct 2011 11:13:42 +0200 Subject: asus-laptop: Add rfkill support for Pegatron Lucid tablet Add three new rfkill switches in this driver that are specific to Pegatron Lucid tablet. Please note that you might not need all three switches. For example if you don't have a 3G module inside your tablet. Also, on my device, the gpio for the wifi/bt module is connected to the bluetooth line. Therefore to activate your wireless lan interface, you need to use the "pega-bt" rfkill switch. Finally, the rfkill switch only works before the wireless module is loaded the first time. Unloading ath9k doesn't help, a reboot is necessary. Signed-off-by: Anisse Astier Signed-off-by: Corentin Chary Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-laptop.c | 103 +++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) (limited to 'drivers/platform/x86/asus-laptop.c') diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 05c0e594c036..edaccad9b5bf 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -186,6 +186,9 @@ MODULE_PARM_DESC(als_status, "Set the ALS status on boot " #define METHOD_PEGA_ENABLE "ENPR" #define METHOD_PEGA_DISABLE "DAPR" +#define PEGA_WLAN 0x00 +#define PEGA_BLUETOOTH 0x01 +#define PEGA_WWAN 0x02 #define PEGA_ALS 0x04 #define PEGA_ALS_POWER 0x05 @@ -212,6 +215,15 @@ struct asus_led { const char *method; }; +/* + * Same thing for rfkill + */ +struct asus_pega_rfkill { + int control_id; /* type of control. Maps to PEGA_* values */ + struct rfkill *rfkill; + struct asus_laptop *asus; +}; + /* * This is the main structure, we can use it to store anything interesting * about the hotk device @@ -246,6 +258,10 @@ struct asus_laptop { struct rfkill *gps_rfkill; + struct asus_pega_rfkill wlanrfk; + struct asus_pega_rfkill btrfk; + struct asus_pega_rfkill wwanrfk; + acpi_handle handle; /* the handle of the hotk device */ u32 ledd_status; /* status of the LED display */ u8 light_level; /* light sensor level */ @@ -1263,6 +1279,86 @@ static int asus_rfkill_init(struct asus_laptop *asus) return result; } +static int pega_rfkill_set(void *data, bool blocked) +{ + struct asus_pega_rfkill *pega_rfk = data; + + int ret = asus_pega_lucid_set(pega_rfk->asus, pega_rfk->control_id, !blocked); + pr_warn("Setting rfkill %d, to %d; returned %d\n", pega_rfk->control_id, !blocked, ret); + + return ret; +} + +static const struct rfkill_ops pega_rfkill_ops = { + .set_block = pega_rfkill_set, +}; + +static void pega_rfkill_terminate(struct asus_pega_rfkill *pega_rfk) +{ + pr_warn("Terminating %d\n", pega_rfk->control_id); + if (pega_rfk->rfkill) { + rfkill_unregister(pega_rfk->rfkill); + rfkill_destroy(pega_rfk->rfkill); + pega_rfk->rfkill = NULL; + } +} + +static void pega_rfkill_exit(struct asus_laptop *asus) +{ + pega_rfkill_terminate(&asus->wwanrfk); + pega_rfkill_terminate(&asus->btrfk); + pega_rfkill_terminate(&asus->wlanrfk); +} + +static int pega_rfkill_setup(struct asus_laptop *asus, struct asus_pega_rfkill *pega_rfk, + const char *name, int controlid, int rfkill_type) +{ + int result; + + pr_warn("Setting up rfk %s, control %d, type %d\n", name, controlid, rfkill_type); + pega_rfk->control_id = controlid; + pega_rfk->asus = asus; + pega_rfk->rfkill = rfkill_alloc(name, &asus->platform_device->dev, + rfkill_type, &pega_rfkill_ops, pega_rfk); + if (!pega_rfk->rfkill) + return -EINVAL; + + result = rfkill_register(pega_rfk->rfkill); + if (result) { + rfkill_destroy(pega_rfk->rfkill); + pega_rfk->rfkill = NULL; + } + + return result; +} + +static int pega_rfkill_init(struct asus_laptop *asus) +{ + int ret = 0; + + if(!asus->is_pega_lucid) + return -ENODEV; + + ret = pega_rfkill_setup(asus, &asus->wlanrfk, "pega-wlan", PEGA_WLAN, RFKILL_TYPE_WLAN); + if(ret) + return ret; + ret = pega_rfkill_setup(asus, &asus->btrfk, "pega-bt", PEGA_BLUETOOTH, RFKILL_TYPE_BLUETOOTH); + if(ret) + goto err_btrfk; + ret = pega_rfkill_setup(asus, &asus->wwanrfk, "pega-wwan", PEGA_WWAN, RFKILL_TYPE_WWAN); + if(ret) + goto err_wwanrfk; + + pr_warn("Pega rfkill init succeeded\n"); + return 0; +err_wwanrfk: + pega_rfkill_terminate(&asus->btrfk); +err_btrfk: + pega_rfkill_terminate(&asus->wlanrfk); + + return ret; +} + /* * Input device (i.e. hotkeys) */ @@ -1697,9 +1793,15 @@ static int __devinit asus_acpi_add(struct acpi_device *device) if (result && result != -ENODEV) goto fail_pega_accel; + result = pega_rfkill_init(asus); + if (result && result != -ENODEV) + goto fail_pega_rfkill; + asus_device_present = true; return 0; +fail_pega_rfkill: + pega_accel_exit(asus); fail_pega_accel: asus_rfkill_exit(asus); fail_rfkill: @@ -1726,6 +1828,7 @@ static int asus_acpi_remove(struct acpi_device *device, int type) asus_led_exit(asus); asus_input_exit(asus); pega_accel_exit(asus); + pega_rfkill_exit(asus); asus_platform_exit(asus); kfree(asus->name); -- cgit v1.2.3