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(+) diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 05c0e594c03..edaccad9b5b 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