diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index c8e8bfb78c19a4136e1e11665921e6a405a0aebd..c971b0fae4c420cb1642e736a4538207f66a1312 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -97,6 +97,8 @@ MODULE_LICENSE("GPL"); #define HCI_FAILURE 0x1000 #define HCI_NOT_SUPPORTED 0x8000 #define HCI_EMPTY 0x8c00 +#define HCI_DATA_NOT_AVAILABLE 0x8d20 +#define HCI_NOT_INITIALIZED 0x8d50 #define SCI_OPEN_CLOSE_OK 0x0044 #define SCI_ALREADY_OPEN 0x8100 #define SCI_NOT_OPENED 0x8200 @@ -111,13 +113,16 @@ MODULE_LICENSE("GPL"); #define HCI_HOTKEY_EVENT 0x001e #define HCI_LCD_BRIGHTNESS 0x002a #define HCI_WIRELESS 0x0056 +#define HCI_ACCELEROMETER 0x006d #define HCI_KBD_ILLUMINATION 0x0095 #define HCI_ECO_MODE 0x0097 +#define HCI_ACCELEROMETER2 0x00a6 #define SCI_ILLUMINATION 0x014e #define SCI_KBD_ILLUM_STATUS 0x015c #define SCI_TOUCHPAD 0x050e /* field definitions */ +#define HCI_ACCEL_MASK 0x7fff #define HCI_HOTKEY_DISABLE 0x0b #define HCI_HOTKEY_ENABLE 0x09 #define HCI_LCD_BRIGHTNESS_BITS 3 @@ -162,6 +167,7 @@ struct toshiba_acpi_dev { unsigned int kbd_led_registered:1; unsigned int touchpad_supported:1; unsigned int eco_supported:1; + unsigned int accelerometer_supported:1; unsigned int sysfs_created:1; struct mutex mutex; @@ -624,6 +630,52 @@ static void toshiba_eco_mode_set_status(struct led_classdev *cdev, return; } } + +/* Accelerometer support */ +static int toshiba_accelerometer_supported(struct toshiba_acpi_dev *dev) +{ + u32 in[HCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 }; + u32 out[HCI_WORDS]; + acpi_status status; + + /* Check if the accelerometer call exists, + * this call also serves as initialization + */ + status = hci_raw(dev, in, out); + if (ACPI_FAILURE(status) || out[0] == SCI_INPUT_DATA_ERROR) { + pr_err("ACPI call to query the accelerometer failed\n"); + return -EIO; + } else if (out[0] == HCI_DATA_NOT_AVAILABLE || + out[0] == HCI_NOT_INITIALIZED) { + pr_err("Accelerometer not initialized\n"); + return -EIO; + } else if (out[0] == HCI_NOT_SUPPORTED) { + pr_info("Accelerometer not supported\n"); + return -ENODEV; + } + + return 0; +} + +static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, + u32 *xy, u32 *z) +{ + u32 in[HCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 }; + u32 out[HCI_WORDS]; + acpi_status status; + + /* Check the Accelerometer status */ + status = hci_raw(dev, in, out); + if (ACPI_FAILURE(status) || out[0] == SCI_INPUT_DATA_ERROR) { + pr_err("ACPI call to query the accelerometer failed\n"); + return -EIO; + } + + *xy = out[2]; + *z = out[4]; + + return 0; +} /* Bluetooth rfkill handlers */ @@ -1257,6 +1309,27 @@ static ssize_t toshiba_touchpad_show(struct device *dev, return sprintf(buf, "%i\n", state); } + +static ssize_t toshiba_position_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); + u32 xyval, zval, tmp; + u16 x, y, z; + int ret; + + xyval = zval = 0; + ret = toshiba_accelerometer_get(toshiba, &xyval, &zval); + if (ret < 0) + return ret; + + x = xyval & HCI_ACCEL_MASK; + tmp = xyval >> HCI_MISC_SHIFT; + y = tmp & HCI_ACCEL_MASK; + z = zval & HCI_ACCEL_MASK; + + return sprintf(buf, "%d %d %d\n", x, y, z); +} static DEVICE_ATTR(kbd_backlight_mode, S_IRUGO | S_IWUSR, toshiba_kbd_bl_mode_show, toshiba_kbd_bl_mode_store); @@ -1264,11 +1337,13 @@ static DEVICE_ATTR(kbd_backlight_timeout, S_IRUGO | S_IWUSR, toshiba_kbd_bl_timeout_show, toshiba_kbd_bl_timeout_store); static DEVICE_ATTR(touchpad, S_IRUGO | S_IWUSR, toshiba_touchpad_show, toshiba_touchpad_store); +static DEVICE_ATTR(position, S_IRUGO, toshiba_position_show, NULL); static struct attribute *toshiba_attributes[] = { &dev_attr_kbd_backlight_mode.attr, &dev_attr_kbd_backlight_timeout.attr, &dev_attr_touchpad.attr, + &dev_attr_position.attr, NULL, }; @@ -1285,6 +1360,8 @@ static umode_t toshiba_sysfs_is_visible(struct kobject *kobj, exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false; else if (attr == &dev_attr_touchpad.attr) exists = (drv->touchpad_supported) ? true : false; + else if (attr == &dev_attr_position.attr) + exists = (drv->accelerometer_supported) ? true : false; return exists ? attr->mode : 0; } @@ -1643,6 +1720,9 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) ret = toshiba_touchpad_get(dev, &dummy); dev->touchpad_supported = !ret; + + ret = toshiba_accelerometer_supported(dev); + dev->accelerometer_supported = !ret; /* Determine whether or not BIOS supports fan and video interfaces */