diff options
author | Marek Vasut <marex@denx.de> | 2012-06-01 13:11:22 -0400 |
---|---|---|
committer | Matthew Garrett <mjg@redhat.com> | 2012-07-28 00:06:02 -0400 |
commit | 1eb3fe1d3b6b9bf6045eb12f0c3ac12569169870 (patch) | |
tree | b2e6212f64174dee7c57c10d971e70914ba30de9 /drivers/platform | |
parent | 63a78bb1051b240417daad3a3fa9c1bb10646dca (diff) |
ACER: Add support for accelerometer sensor
This device is present on Iconia Tab W500.
Signed-off-by: Marek Vasut <marex@denx.de>
Cc: joeyli <jlee@suse.com>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/x86/acer-wmi.c | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index c8f40c9c0428..175809dd5587 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c | |||
@@ -95,6 +95,7 @@ MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026"); | |||
95 | 95 | ||
96 | enum acer_wmi_event_ids { | 96 | enum acer_wmi_event_ids { |
97 | WMID_HOTKEY_EVENT = 0x1, | 97 | WMID_HOTKEY_EVENT = 0x1, |
98 | WMID_ACCEL_EVENT = 0x5, | ||
98 | }; | 99 | }; |
99 | 100 | ||
100 | static const struct key_entry acer_wmi_keymap[] = { | 101 | static const struct key_entry acer_wmi_keymap[] = { |
@@ -130,6 +131,7 @@ static const struct key_entry acer_wmi_keymap[] = { | |||
130 | }; | 131 | }; |
131 | 132 | ||
132 | static struct input_dev *acer_wmi_input_dev; | 133 | static struct input_dev *acer_wmi_input_dev; |
134 | static struct input_dev *acer_wmi_accel_dev; | ||
133 | 135 | ||
134 | struct event_return_value { | 136 | struct event_return_value { |
135 | u8 function; | 137 | u8 function; |
@@ -200,6 +202,7 @@ struct hotkey_function_type_aa { | |||
200 | #define ACER_CAP_BLUETOOTH (1<<2) | 202 | #define ACER_CAP_BLUETOOTH (1<<2) |
201 | #define ACER_CAP_BRIGHTNESS (1<<3) | 203 | #define ACER_CAP_BRIGHTNESS (1<<3) |
202 | #define ACER_CAP_THREEG (1<<4) | 204 | #define ACER_CAP_THREEG (1<<4) |
205 | #define ACER_CAP_ACCEL (1<<5) | ||
203 | #define ACER_CAP_ANY (0xFFFFFFFF) | 206 | #define ACER_CAP_ANY (0xFFFFFFFF) |
204 | 207 | ||
205 | /* | 208 | /* |
@@ -1399,6 +1402,60 @@ static void acer_backlight_exit(void) | |||
1399 | } | 1402 | } |
1400 | 1403 | ||
1401 | /* | 1404 | /* |
1405 | * Accelerometer device | ||
1406 | */ | ||
1407 | static acpi_handle gsensor_handle; | ||
1408 | |||
1409 | static int acer_gsensor_init(void) | ||
1410 | { | ||
1411 | acpi_status status; | ||
1412 | struct acpi_buffer output; | ||
1413 | union acpi_object out_obj; | ||
1414 | |||
1415 | output.length = sizeof(out_obj); | ||
1416 | output.pointer = &out_obj; | ||
1417 | status = acpi_evaluate_object(gsensor_handle, "_INI", NULL, &output); | ||
1418 | if (ACPI_FAILURE(status)) | ||
1419 | return -1; | ||
1420 | |||
1421 | return 0; | ||
1422 | } | ||
1423 | |||
1424 | static int acer_gsensor_open(struct input_dev *input) | ||
1425 | { | ||
1426 | return acer_gsensor_init(); | ||
1427 | } | ||
1428 | |||
1429 | static int acer_gsensor_event(void) | ||
1430 | { | ||
1431 | acpi_status status; | ||
1432 | struct acpi_buffer output; | ||
1433 | union acpi_object out_obj[5]; | ||
1434 | |||
1435 | if (!has_cap(ACER_CAP_ACCEL)) | ||
1436 | return -1; | ||
1437 | |||
1438 | output.length = sizeof(out_obj); | ||
1439 | output.pointer = out_obj; | ||
1440 | |||
1441 | status = acpi_evaluate_object(gsensor_handle, "RDVL", NULL, &output); | ||
1442 | if (ACPI_FAILURE(status)) | ||
1443 | return -1; | ||
1444 | |||
1445 | if (out_obj->package.count != 4) | ||
1446 | return -1; | ||
1447 | |||
1448 | input_report_abs(acer_wmi_accel_dev, ABS_X, | ||
1449 | (s16)out_obj->package.elements[0].integer.value); | ||
1450 | input_report_abs(acer_wmi_accel_dev, ABS_Y, | ||
1451 | (s16)out_obj->package.elements[1].integer.value); | ||
1452 | input_report_abs(acer_wmi_accel_dev, ABS_Z, | ||
1453 | (s16)out_obj->package.elements[2].integer.value); | ||
1454 | input_sync(acer_wmi_accel_dev); | ||
1455 | return 0; | ||
1456 | } | ||
1457 | |||
1458 | /* | ||
1402 | * Rfkill devices | 1459 | * Rfkill devices |
1403 | */ | 1460 | */ |
1404 | static void acer_rfkill_update(struct work_struct *ignored); | 1461 | static void acer_rfkill_update(struct work_struct *ignored); |
@@ -1673,6 +1730,9 @@ static void acer_wmi_notify(u32 value, void *context) | |||
1673 | 1, true); | 1730 | 1, true); |
1674 | } | 1731 | } |
1675 | break; | 1732 | break; |
1733 | case WMID_ACCEL_EVENT: | ||
1734 | acer_gsensor_event(); | ||
1735 | break; | ||
1676 | default: | 1736 | default: |
1677 | pr_warn("Unknown function number - %d - %d\n", | 1737 | pr_warn("Unknown function number - %d - %d\n", |
1678 | return_value.function, return_value.key_num); | 1738 | return_value.function, return_value.key_num); |
@@ -1758,6 +1818,74 @@ static int acer_wmi_enable_lm(void) | |||
1758 | return status; | 1818 | return status; |
1759 | } | 1819 | } |
1760 | 1820 | ||
1821 | static acpi_status __init acer_wmi_get_handle_cb(acpi_handle ah, u32 level, | ||
1822 | void *ctx, void **retval) | ||
1823 | { | ||
1824 | *(acpi_handle *)retval = ah; | ||
1825 | return AE_OK; | ||
1826 | } | ||
1827 | |||
1828 | static int __init acer_wmi_get_handle(const char *name, const char *prop, | ||
1829 | acpi_handle *ah) | ||
1830 | { | ||
1831 | acpi_status status; | ||
1832 | acpi_handle handle; | ||
1833 | |||
1834 | BUG_ON(!name || !ah); | ||
1835 | |||
1836 | handle = 0; | ||
1837 | status = acpi_get_devices(prop, acer_wmi_get_handle_cb, | ||
1838 | (void *)name, &handle); | ||
1839 | |||
1840 | if (ACPI_SUCCESS(status)) { | ||
1841 | *ah = handle; | ||
1842 | return 0; | ||
1843 | } else { | ||
1844 | return -ENODEV; | ||
1845 | } | ||
1846 | } | ||
1847 | |||
1848 | static int __init acer_wmi_accel_setup(void) | ||
1849 | { | ||
1850 | int err; | ||
1851 | |||
1852 | err = acer_wmi_get_handle("SENR", "BST0001", &gsensor_handle); | ||
1853 | if (err) | ||
1854 | return err; | ||
1855 | |||
1856 | interface->capability |= ACER_CAP_ACCEL; | ||
1857 | |||
1858 | acer_wmi_accel_dev = input_allocate_device(); | ||
1859 | if (!acer_wmi_accel_dev) | ||
1860 | return -ENOMEM; | ||
1861 | |||
1862 | acer_wmi_accel_dev->open = acer_gsensor_open; | ||
1863 | |||
1864 | acer_wmi_accel_dev->name = "Acer BMA150 accelerometer"; | ||
1865 | acer_wmi_accel_dev->phys = "wmi/input1"; | ||
1866 | acer_wmi_accel_dev->id.bustype = BUS_HOST; | ||
1867 | acer_wmi_accel_dev->evbit[0] = BIT_MASK(EV_ABS); | ||
1868 | input_set_abs_params(acer_wmi_accel_dev, ABS_X, -16384, 16384, 0, 0); | ||
1869 | input_set_abs_params(acer_wmi_accel_dev, ABS_Y, -16384, 16384, 0, 0); | ||
1870 | input_set_abs_params(acer_wmi_accel_dev, ABS_Z, -16384, 16384, 0, 0); | ||
1871 | |||
1872 | err = input_register_device(acer_wmi_accel_dev); | ||
1873 | if (err) | ||
1874 | goto err_free_dev; | ||
1875 | |||
1876 | return 0; | ||
1877 | |||
1878 | err_free_dev: | ||
1879 | input_free_device(acer_wmi_accel_dev); | ||
1880 | return err; | ||
1881 | } | ||
1882 | |||
1883 | static void acer_wmi_accel_destroy(void) | ||
1884 | { | ||
1885 | input_unregister_device(acer_wmi_accel_dev); | ||
1886 | input_free_device(acer_wmi_accel_dev); | ||
1887 | } | ||
1888 | |||
1761 | static int __init acer_wmi_input_setup(void) | 1889 | static int __init acer_wmi_input_setup(void) |
1762 | { | 1890 | { |
1763 | acpi_status status; | 1891 | acpi_status status; |
@@ -1912,6 +2040,9 @@ static int acer_resume(struct device *dev) | |||
1912 | if (has_cap(ACER_CAP_BRIGHTNESS)) | 2040 | if (has_cap(ACER_CAP_BRIGHTNESS)) |
1913 | set_u32(data->brightness, ACER_CAP_BRIGHTNESS); | 2041 | set_u32(data->brightness, ACER_CAP_BRIGHTNESS); |
1914 | 2042 | ||
2043 | if (has_cap(ACER_CAP_ACCEL)) | ||
2044 | acer_gsensor_init(); | ||
2045 | |||
1915 | return 0; | 2046 | return 0; |
1916 | } | 2047 | } |
1917 | 2048 | ||
@@ -2090,6 +2221,8 @@ static int __init acer_wmi_init(void) | |||
2090 | return err; | 2221 | return err; |
2091 | } | 2222 | } |
2092 | 2223 | ||
2224 | acer_wmi_accel_setup(); | ||
2225 | |||
2093 | err = platform_driver_register(&acer_platform_driver); | 2226 | err = platform_driver_register(&acer_platform_driver); |
2094 | if (err) { | 2227 | if (err) { |
2095 | pr_err("Unable to register platform driver\n"); | 2228 | pr_err("Unable to register platform driver\n"); |
@@ -2133,6 +2266,8 @@ error_device_alloc: | |||
2133 | error_platform_register: | 2266 | error_platform_register: |
2134 | if (wmi_has_guid(ACERWMID_EVENT_GUID)) | 2267 | if (wmi_has_guid(ACERWMID_EVENT_GUID)) |
2135 | acer_wmi_input_destroy(); | 2268 | acer_wmi_input_destroy(); |
2269 | if (has_cap(ACER_CAP_ACCEL)) | ||
2270 | acer_wmi_accel_destroy(); | ||
2136 | 2271 | ||
2137 | return err; | 2272 | return err; |
2138 | } | 2273 | } |
@@ -2142,6 +2277,9 @@ static void __exit acer_wmi_exit(void) | |||
2142 | if (wmi_has_guid(ACERWMID_EVENT_GUID)) | 2277 | if (wmi_has_guid(ACERWMID_EVENT_GUID)) |
2143 | acer_wmi_input_destroy(); | 2278 | acer_wmi_input_destroy(); |
2144 | 2279 | ||
2280 | if (has_cap(ACER_CAP_ACCEL)) | ||
2281 | acer_wmi_accel_destroy(); | ||
2282 | |||
2145 | remove_sysfs(acer_platform_device); | 2283 | remove_sysfs(acer_platform_device); |
2146 | remove_debugfs(); | 2284 | remove_debugfs(); |
2147 | platform_device_unregister(acer_platform_device); | 2285 | platform_device_unregister(acer_platform_device); |