1b4f9fe12SLen Brown /* 2b4f9fe12SLen Brown * toshiba_acpi.c - Toshiba Laptop ACPI Extras 3b4f9fe12SLen Brown * 4b4f9fe12SLen Brown * Copyright (C) 2002-2004 John Belmonte 5b4f9fe12SLen Brown * Copyright (C) 2008 Philip Langdale 66c3f6e6cSPierre Ducroquet * Copyright (C) 2010 Pierre Ducroquet 77216d702SAzael Avalos * Copyright (C) 2014-2015 Azael Avalos 8b4f9fe12SLen Brown * 9b4f9fe12SLen Brown * This program is free software; you can redistribute it and/or modify 10b4f9fe12SLen Brown * it under the terms of the GNU General Public License as published by 11b4f9fe12SLen Brown * the Free Software Foundation; either version 2 of the License, or 12b4f9fe12SLen Brown * (at your option) any later version. 13b4f9fe12SLen Brown * 14b4f9fe12SLen Brown * This program is distributed in the hope that it will be useful, 15b4f9fe12SLen Brown * but WITHOUT ANY WARRANTY; without even the implied warranty of 16b4f9fe12SLen Brown * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17b4f9fe12SLen Brown * GNU General Public License for more details. 18b4f9fe12SLen Brown * 19c57c0fa4SDarren Hart * The full GNU General Public License is included in this distribution in 20c57c0fa4SDarren Hart * the file called "COPYING". 21b4f9fe12SLen Brown * 22b4f9fe12SLen Brown * The devolpment page for this driver is located at 23b4f9fe12SLen Brown * http://memebeam.org/toys/ToshibaAcpiDriver. 24b4f9fe12SLen Brown * 25b4f9fe12SLen Brown * Credits: 26b4f9fe12SLen Brown * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse 27b4f9fe12SLen Brown * engineering the Windows drivers 28b4f9fe12SLen Brown * Yasushi Nagato - changes for linux kernel 2.4 -> 2.5 29b4f9fe12SLen Brown * Rob Miller - TV out and hotkeys help 30b4f9fe12SLen Brown */ 31b4f9fe12SLen Brown 327e33460dSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 337e33460dSJoe Perches 3463ba3e28SAzael Avalos #define TOSHIBA_ACPI_VERSION "0.22" 35b4f9fe12SLen Brown #define PROC_INTERFACE_VERSION 1 36b4f9fe12SLen Brown 37b4f9fe12SLen Brown #include <linux/kernel.h> 38b4f9fe12SLen Brown #include <linux/module.h> 39b4f9fe12SLen Brown #include <linux/init.h> 40b4f9fe12SLen Brown #include <linux/types.h> 41b4f9fe12SLen Brown #include <linux/proc_fs.h> 42936c8bcdSAlexey Dobriyan #include <linux/seq_file.h> 43b4f9fe12SLen Brown #include <linux/backlight.h> 446335e4d5SMatthew Garrett #include <linux/input.h> 45384a7cd9SDmitry Torokhov #include <linux/input/sparse-keymap.h> 466c3f6e6cSPierre Ducroquet #include <linux/leds.h> 475a0e3ad6STejun Heo #include <linux/slab.h> 4829cd293fSSeth Forshee #include <linux/workqueue.h> 4929cd293fSSeth Forshee #include <linux/i8042.h> 508b48463fSLv Zheng #include <linux/acpi.h> 51358d6a2cSHans de Goede #include <linux/dmi.h> 52b5163992SAzael Avalos #include <linux/uaccess.h> 53fc5462f8SAzael Avalos #include <linux/miscdevice.h> 54fc5462f8SAzael Avalos #include <linux/toshiba.h> 55358d6a2cSHans de Goede #include <acpi/video.h> 56b4f9fe12SLen Brown 57b4f9fe12SLen Brown MODULE_AUTHOR("John Belmonte"); 58b4f9fe12SLen Brown MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); 59b4f9fe12SLen Brown MODULE_LICENSE("GPL"); 60b4f9fe12SLen Brown 61f11f999eSSeth Forshee #define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100" 62f11f999eSSeth Forshee 6329cd293fSSeth Forshee /* Scan code for Fn key on TOS1900 models */ 6429cd293fSSeth Forshee #define TOS1900_FN_SCAN 0x6e 6529cd293fSSeth Forshee 66b4f9fe12SLen Brown /* Toshiba ACPI method paths */ 67b4f9fe12SLen Brown #define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX" 68b4f9fe12SLen Brown 69e0769fe6SDarren Hart /* 70e0769fe6SDarren Hart * The Toshiba configuration interface is composed of the HCI and the SCI, 71258c5903SAzael Avalos * which are defined as follows: 72b4f9fe12SLen Brown * 73b4f9fe12SLen Brown * HCI is Toshiba's "Hardware Control Interface" which is supposed to 74b4f9fe12SLen Brown * be uniform across all their models. Ideally we would just call 75b4f9fe12SLen Brown * dedicated ACPI methods instead of using this primitive interface. 76b4f9fe12SLen Brown * However the ACPI methods seem to be incomplete in some areas (for 77b4f9fe12SLen Brown * example they allow setting, but not reading, the LCD brightness value), 78b4f9fe12SLen Brown * so this is still useful. 7984a6273fSAzael Avalos * 8084a6273fSAzael Avalos * SCI stands for "System Configuration Interface" which aim is to 8184a6273fSAzael Avalos * conceal differences in hardware between different models. 82b4f9fe12SLen Brown */ 83b4f9fe12SLen Brown 84258c5903SAzael Avalos #define TCI_WORDS 6 85b4f9fe12SLen Brown 863f75bbe9SAzael Avalos /* Operations */ 87b4f9fe12SLen Brown #define HCI_SET 0xff00 88b4f9fe12SLen Brown #define HCI_GET 0xfe00 8984a6273fSAzael Avalos #define SCI_OPEN 0xf100 9084a6273fSAzael Avalos #define SCI_CLOSE 0xf200 9184a6273fSAzael Avalos #define SCI_GET 0xf300 9284a6273fSAzael Avalos #define SCI_SET 0xf400 93b4f9fe12SLen Brown 943f75bbe9SAzael Avalos /* Return codes */ 951864bbc2SAzael Avalos #define TOS_SUCCESS 0x0000 96*e1a949c1SAzael Avalos #define TOS_SUCCESS2 0x0001 971864bbc2SAzael Avalos #define TOS_OPEN_CLOSE_OK 0x0044 981864bbc2SAzael Avalos #define TOS_FAILURE 0x1000 991864bbc2SAzael Avalos #define TOS_NOT_SUPPORTED 0x8000 1001864bbc2SAzael Avalos #define TOS_ALREADY_OPEN 0x8100 1011864bbc2SAzael Avalos #define TOS_NOT_OPENED 0x8200 1021864bbc2SAzael Avalos #define TOS_INPUT_DATA_ERROR 0x8300 1031864bbc2SAzael Avalos #define TOS_WRITE_PROTECTED 0x8400 1041864bbc2SAzael Avalos #define TOS_NOT_PRESENT 0x8600 1051864bbc2SAzael Avalos #define TOS_FIFO_EMPTY 0x8c00 1061864bbc2SAzael Avalos #define TOS_DATA_NOT_AVAILABLE 0x8d20 1071864bbc2SAzael Avalos #define TOS_NOT_INITIALIZED 0x8d50 10898fc4ec6SAzael Avalos #define TOS_NOT_INSTALLED 0x8e00 109b4f9fe12SLen Brown 1103f75bbe9SAzael Avalos /* Registers */ 111b4f9fe12SLen Brown #define HCI_FAN 0x0004 112121b7b0dSAkio Idehara #define HCI_TR_BACKLIGHT 0x0005 113b4f9fe12SLen Brown #define HCI_SYSTEM_EVENT 0x0016 114b4f9fe12SLen Brown #define HCI_VIDEO_OUT 0x001c 115b4f9fe12SLen Brown #define HCI_HOTKEY_EVENT 0x001e 116b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS 0x002a 1175a2813e9SAzael Avalos #define HCI_ACCELEROMETER 0x006d 118360f0f39SAzael Avalos #define HCI_KBD_ILLUMINATION 0x0095 119def6c4e2SAzael Avalos #define HCI_ECO_MODE 0x0097 1205a2813e9SAzael Avalos #define HCI_ACCELEROMETER2 0x00a6 12156e6b353SAzael Avalos #define HCI_SYSTEM_INFO 0xc000 12235d53ceaSAzael Avalos #define SCI_PANEL_POWER_ON 0x010d 123fdb79081SAzael Avalos #define SCI_ILLUMINATION 0x014e 124e26ffe51SAzael Avalos #define SCI_USB_SLEEP_CHARGE 0x0150 125360f0f39SAzael Avalos #define SCI_KBD_ILLUM_STATUS 0x015c 126172ce0a9SAzael Avalos #define SCI_USB_SLEEP_MUSIC 0x015e 12717fe4b3dSAzael Avalos #define SCI_USB_THREE 0x0169 1289d8658acSAzael Avalos #define SCI_TOUCHPAD 0x050e 129bae84195SAzael Avalos #define SCI_KBD_FUNCTION_KEYS 0x0522 130b4f9fe12SLen Brown 1313f75bbe9SAzael Avalos /* Field definitions */ 1325a2813e9SAzael Avalos #define HCI_ACCEL_MASK 0x7fff 13329cd293fSSeth Forshee #define HCI_HOTKEY_DISABLE 0x0b 13429cd293fSSeth Forshee #define HCI_HOTKEY_ENABLE 0x09 135fb42d1f4SAzael Avalos #define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10 136b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_BITS 3 137b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) 138b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS) 139360f0f39SAzael Avalos #define HCI_MISC_SHIFT 0x10 14056e6b353SAzael Avalos #define HCI_SYSTEM_TYPE1 0x10 14156e6b353SAzael Avalos #define HCI_SYSTEM_TYPE2 0x11 142b4f9fe12SLen Brown #define HCI_VIDEO_OUT_LCD 0x1 143b4f9fe12SLen Brown #define HCI_VIDEO_OUT_CRT 0x2 144b4f9fe12SLen Brown #define HCI_VIDEO_OUT_TV 0x4 14593f8c16dSAzael Avalos #define SCI_KBD_MODE_MASK 0x1f 146360f0f39SAzael Avalos #define SCI_KBD_MODE_FNZ 0x1 147360f0f39SAzael Avalos #define SCI_KBD_MODE_AUTO 0x2 14893f8c16dSAzael Avalos #define SCI_KBD_MODE_ON 0x8 14993f8c16dSAzael Avalos #define SCI_KBD_MODE_OFF 0x10 15093f8c16dSAzael Avalos #define SCI_KBD_TIME_MAX 0x3c001a 151e26ffe51SAzael Avalos #define SCI_USB_CHARGE_MODE_MASK 0xff 152c8c91842SAzael Avalos #define SCI_USB_CHARGE_DISABLED 0x00 153c8c91842SAzael Avalos #define SCI_USB_CHARGE_ALTERNATE 0x09 154c8c91842SAzael Avalos #define SCI_USB_CHARGE_TYPICAL 0x11 155c8c91842SAzael Avalos #define SCI_USB_CHARGE_AUTO 0x21 156182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_MASK 0x7 157182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_OFF 0x1 158182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_ON 0x4 159182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL 0x0200 160bb3fe01fSAzael Avalos #define SCI_USB_CHARGE_RAPID_DSP 0x0300 161b4f9fe12SLen Brown 162135740deSSeth Forshee struct toshiba_acpi_dev { 163135740deSSeth Forshee struct acpi_device *acpi_dev; 164135740deSSeth Forshee const char *method_hci; 165135740deSSeth Forshee struct input_dev *hotkey_dev; 16629cd293fSSeth Forshee struct work_struct hotkey_work; 167135740deSSeth Forshee struct backlight_device *backlight_dev; 168135740deSSeth Forshee struct led_classdev led_dev; 169360f0f39SAzael Avalos struct led_classdev kbd_led; 170def6c4e2SAzael Avalos struct led_classdev eco_led; 171fc5462f8SAzael Avalos struct miscdevice miscdev; 17236d03f93SSeth Forshee 173135740deSSeth Forshee int force_fan; 174135740deSSeth Forshee int last_key_event; 175135740deSSeth Forshee int key_event_valid; 17693f8c16dSAzael Avalos int kbd_type; 177360f0f39SAzael Avalos int kbd_mode; 178360f0f39SAzael Avalos int kbd_time; 179182bcaa5SAzael Avalos int usbsc_bat_level; 180c8c91842SAzael Avalos int usbsc_mode_base; 181a2b3471bSAzael Avalos int hotkey_event_type; 182135740deSSeth Forshee 183592b746cSDan Carpenter unsigned int illumination_supported:1; 184592b746cSDan Carpenter unsigned int video_supported:1; 185592b746cSDan Carpenter unsigned int fan_supported:1; 186592b746cSDan Carpenter unsigned int system_event_supported:1; 18729cd293fSSeth Forshee unsigned int ntfy_supported:1; 18829cd293fSSeth Forshee unsigned int info_supported:1; 189121b7b0dSAkio Idehara unsigned int tr_backlight_supported:1; 190360f0f39SAzael Avalos unsigned int kbd_illum_supported:1; 1919d8658acSAzael Avalos unsigned int touchpad_supported:1; 192def6c4e2SAzael Avalos unsigned int eco_supported:1; 1935a2813e9SAzael Avalos unsigned int accelerometer_supported:1; 194e26ffe51SAzael Avalos unsigned int usb_sleep_charge_supported:1; 195bb3fe01fSAzael Avalos unsigned int usb_rapid_charge_supported:1; 196172ce0a9SAzael Avalos unsigned int usb_sleep_music_supported:1; 197bae84195SAzael Avalos unsigned int kbd_function_keys_supported:1; 19835d53ceaSAzael Avalos unsigned int panel_power_on_supported:1; 19917fe4b3dSAzael Avalos unsigned int usb_three_supported:1; 200360f0f39SAzael Avalos unsigned int sysfs_created:1; 201ea215a3fSAzael Avalos 202ea215a3fSAzael Avalos bool kbd_led_registered; 203ea215a3fSAzael Avalos bool illumination_led_registered; 204ea215a3fSAzael Avalos bool eco_led_registered; 205135740deSSeth Forshee }; 206135740deSSeth Forshee 20729cd293fSSeth Forshee static struct toshiba_acpi_dev *toshiba_acpi; 20829cd293fSSeth Forshee 209b4f9fe12SLen Brown static const struct acpi_device_id toshiba_device_ids[] = { 210b4f9fe12SLen Brown {"TOS6200", 0}, 21163a9e016SOndrej Zary {"TOS6207", 0}, 212b4f9fe12SLen Brown {"TOS6208", 0}, 213b4f9fe12SLen Brown {"TOS1900", 0}, 214b4f9fe12SLen Brown {"", 0}, 215b4f9fe12SLen Brown }; 216b4f9fe12SLen Brown MODULE_DEVICE_TABLE(acpi, toshiba_device_ids); 217b4f9fe12SLen Brown 218b859f159SGreg Kroah-Hartman static const struct key_entry toshiba_acpi_keymap[] = { 219fec278a1SUnai Uribarri { KE_KEY, 0x9e, { KEY_RFKILL } }, 220384a7cd9SDmitry Torokhov { KE_KEY, 0x101, { KEY_MUTE } }, 221384a7cd9SDmitry Torokhov { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 222384a7cd9SDmitry Torokhov { KE_KEY, 0x103, { KEY_ZOOMIN } }, 223408a5d13SAzael Avalos { KE_KEY, 0x10f, { KEY_TAB } }, 224af502837SAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 225af502837SAzael Avalos { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 226384a7cd9SDmitry Torokhov { KE_KEY, 0x13b, { KEY_COFFEE } }, 227384a7cd9SDmitry Torokhov { KE_KEY, 0x13c, { KEY_BATTERY } }, 228384a7cd9SDmitry Torokhov { KE_KEY, 0x13d, { KEY_SLEEP } }, 229384a7cd9SDmitry Torokhov { KE_KEY, 0x13e, { KEY_SUSPEND } }, 230384a7cd9SDmitry Torokhov { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } }, 231384a7cd9SDmitry Torokhov { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } }, 232384a7cd9SDmitry Torokhov { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } }, 233384a7cd9SDmitry Torokhov { KE_KEY, 0x142, { KEY_WLAN } }, 234af502837SAzael Avalos { KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } }, 235a49010f5SJon Dowland { KE_KEY, 0x17f, { KEY_FN } }, 236384a7cd9SDmitry Torokhov { KE_KEY, 0xb05, { KEY_PROG2 } }, 237384a7cd9SDmitry Torokhov { KE_KEY, 0xb06, { KEY_WWW } }, 238384a7cd9SDmitry Torokhov { KE_KEY, 0xb07, { KEY_MAIL } }, 239384a7cd9SDmitry Torokhov { KE_KEY, 0xb30, { KEY_STOP } }, 240384a7cd9SDmitry Torokhov { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } }, 241384a7cd9SDmitry Torokhov { KE_KEY, 0xb32, { KEY_NEXTSONG } }, 242384a7cd9SDmitry Torokhov { KE_KEY, 0xb33, { KEY_PLAYPAUSE } }, 243384a7cd9SDmitry Torokhov { KE_KEY, 0xb5a, { KEY_MEDIA } }, 244408a5d13SAzael Avalos { KE_IGNORE, 0x1430, { KEY_RESERVED } }, /* Wake from sleep */ 245408a5d13SAzael Avalos { KE_IGNORE, 0x1501, { KEY_RESERVED } }, /* Output changed */ 246408a5d13SAzael Avalos { KE_IGNORE, 0x1502, { KEY_RESERVED } }, /* HDMI plugged/unplugged */ 247408a5d13SAzael Avalos { KE_IGNORE, 0x1ABE, { KEY_RESERVED } }, /* Protection level set */ 248408a5d13SAzael Avalos { KE_IGNORE, 0x1ABF, { KEY_RESERVED } }, /* Protection level off */ 249384a7cd9SDmitry Torokhov { KE_END, 0 }, 2506335e4d5SMatthew Garrett }; 2516335e4d5SMatthew Garrett 252fe808bfbSTakashi Iwai static const struct key_entry toshiba_acpi_alt_keymap[] = { 253fe808bfbSTakashi Iwai { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 254fe808bfbSTakashi Iwai { KE_KEY, 0x103, { KEY_ZOOMIN } }, 255e6efad7fSAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 256fe808bfbSTakashi Iwai { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 257fe808bfbSTakashi Iwai { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } }, 258fe808bfbSTakashi Iwai { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } }, 259d50c9005SAzael Avalos { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } }, 260fe808bfbSTakashi Iwai { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } }, 261d50c9005SAzael Avalos { KE_KEY, 0x157, { KEY_MUTE } }, 262d50c9005SAzael Avalos { KE_KEY, 0x158, { KEY_WLAN } }, 263fe808bfbSTakashi Iwai { KE_END, 0 }, 264fe808bfbSTakashi Iwai }; 265fe808bfbSTakashi Iwai 266e0769fe6SDarren Hart /* 267358d6a2cSHans de Goede * List of models which have a broken acpi-video backlight interface and thus 268358d6a2cSHans de Goede * need to use the toshiba (vendor) interface instead. 269358d6a2cSHans de Goede */ 270358d6a2cSHans de Goede static const struct dmi_system_id toshiba_vendor_backlight_dmi[] = { 271358d6a2cSHans de Goede {} 272358d6a2cSHans de Goede }; 273358d6a2cSHans de Goede 274358d6a2cSHans de Goede /* 275e0769fe6SDarren Hart * Utility 276b4f9fe12SLen Brown */ 277b4f9fe12SLen Brown 278b5163992SAzael Avalos static inline void _set_bit(u32 *word, u32 mask, int value) 279b4f9fe12SLen Brown { 280b4f9fe12SLen Brown *word = (*word & ~mask) | (mask * value); 281b4f9fe12SLen Brown } 282b4f9fe12SLen Brown 283e0769fe6SDarren Hart /* 284e0769fe6SDarren Hart * ACPI interface wrappers 285b4f9fe12SLen Brown */ 286b4f9fe12SLen Brown 287b4f9fe12SLen Brown static int write_acpi_int(const char *methodName, int val) 288b4f9fe12SLen Brown { 289b4f9fe12SLen Brown acpi_status status; 290b4f9fe12SLen Brown 291619400daSZhang Rui status = acpi_execute_simple_method(NULL, (char *)methodName, val); 29232bcd5cbSSeth Forshee return (status == AE_OK) ? 0 : -EIO; 293b4f9fe12SLen Brown } 294b4f9fe12SLen Brown 295e0769fe6SDarren Hart /* 296e0769fe6SDarren Hart * Perform a raw configuration call. Here we don't care about input or output 297258c5903SAzael Avalos * buffer format. 298b4f9fe12SLen Brown */ 299258c5903SAzael Avalos static acpi_status tci_raw(struct toshiba_acpi_dev *dev, 300258c5903SAzael Avalos const u32 in[TCI_WORDS], u32 out[TCI_WORDS]) 301b4f9fe12SLen Brown { 302b4f9fe12SLen Brown struct acpi_object_list params; 303258c5903SAzael Avalos union acpi_object in_objs[TCI_WORDS]; 304b4f9fe12SLen Brown struct acpi_buffer results; 305258c5903SAzael Avalos union acpi_object out_objs[TCI_WORDS + 1]; 306b4f9fe12SLen Brown acpi_status status; 307b4f9fe12SLen Brown int i; 308b4f9fe12SLen Brown 309258c5903SAzael Avalos params.count = TCI_WORDS; 310b4f9fe12SLen Brown params.pointer = in_objs; 311258c5903SAzael Avalos for (i = 0; i < TCI_WORDS; ++i) { 312b4f9fe12SLen Brown in_objs[i].type = ACPI_TYPE_INTEGER; 313b4f9fe12SLen Brown in_objs[i].integer.value = in[i]; 314b4f9fe12SLen Brown } 315b4f9fe12SLen Brown 316b4f9fe12SLen Brown results.length = sizeof(out_objs); 317b4f9fe12SLen Brown results.pointer = out_objs; 318b4f9fe12SLen Brown 3196e02cc7eSSeth Forshee status = acpi_evaluate_object(dev->acpi_dev->handle, 3206e02cc7eSSeth Forshee (char *)dev->method_hci, ¶ms, 321b4f9fe12SLen Brown &results); 322258c5903SAzael Avalos if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) { 323b5163992SAzael Avalos for (i = 0; i < out_objs->package.count; ++i) 324b4f9fe12SLen Brown out[i] = out_objs->package.elements[i].integer.value; 325b4f9fe12SLen Brown } 326b4f9fe12SLen Brown 327b4f9fe12SLen Brown return status; 328b4f9fe12SLen Brown } 329b4f9fe12SLen Brown 330e0769fe6SDarren Hart /* 331d37782bdSAzael Avalos * Common hci tasks 332b4f9fe12SLen Brown * 333b4f9fe12SLen Brown * In addition to the ACPI status, the HCI system returns a result which 334b4f9fe12SLen Brown * may be useful (such as "not supported"). 335b4f9fe12SLen Brown */ 336b4f9fe12SLen Brown 337d37782bdSAzael Avalos static u32 hci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 338b4f9fe12SLen Brown { 339258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 }; 340258c5903SAzael Avalos u32 out[TCI_WORDS]; 341258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 342893f3f62SAzael Avalos 343893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 344b4f9fe12SLen Brown } 345b4f9fe12SLen Brown 346d37782bdSAzael Avalos static u32 hci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 347b4f9fe12SLen Brown { 348258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 }; 349258c5903SAzael Avalos u32 out[TCI_WORDS]; 350258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 351b5163992SAzael Avalos 352893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 353893f3f62SAzael Avalos return TOS_FAILURE; 354893f3f62SAzael Avalos 355b4f9fe12SLen Brown *out1 = out[2]; 356893f3f62SAzael Avalos 357893f3f62SAzael Avalos return out[0]; 358b4f9fe12SLen Brown } 359b4f9fe12SLen Brown 360e0769fe6SDarren Hart /* 361e0769fe6SDarren Hart * Common sci tasks 36284a6273fSAzael Avalos */ 36384a6273fSAzael Avalos 36484a6273fSAzael Avalos static int sci_open(struct toshiba_acpi_dev *dev) 36584a6273fSAzael Avalos { 366258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 }; 367258c5903SAzael Avalos u32 out[TCI_WORDS]; 36884a6273fSAzael Avalos acpi_status status; 36984a6273fSAzael Avalos 370258c5903SAzael Avalos status = tci_raw(dev, in, out); 3718baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 37284a6273fSAzael Avalos pr_err("ACPI call to open SCI failed\n"); 37384a6273fSAzael Avalos return 0; 37484a6273fSAzael Avalos } 37584a6273fSAzael Avalos 3761864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) { 37784a6273fSAzael Avalos return 1; 3781864bbc2SAzael Avalos } else if (out[0] == TOS_ALREADY_OPEN) { 37984a6273fSAzael Avalos pr_info("Toshiba SCI already opened\n"); 38084a6273fSAzael Avalos return 1; 381fa465739SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 382e0769fe6SDarren Hart /* 383e0769fe6SDarren Hart * Some BIOSes do not have the SCI open/close functions 384fa465739SAzael Avalos * implemented and return 0x8000 (Not Supported), failing to 385fa465739SAzael Avalos * register some supported features. 386fa465739SAzael Avalos * 387fa465739SAzael Avalos * Simply return 1 if we hit those affected laptops to make the 388fa465739SAzael Avalos * supported features work. 389fa465739SAzael Avalos * 390fa465739SAzael Avalos * In the case that some laptops really do not support the SCI, 391fa465739SAzael Avalos * all the SCI dependent functions check for TOS_NOT_SUPPORTED, 392fa465739SAzael Avalos * and thus, not registering support for the queried feature. 393fa465739SAzael Avalos */ 394fa465739SAzael Avalos return 1; 3951864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_PRESENT) { 39684a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 39784a6273fSAzael Avalos } 39884a6273fSAzael Avalos 39984a6273fSAzael Avalos return 0; 40084a6273fSAzael Avalos } 40184a6273fSAzael Avalos 40284a6273fSAzael Avalos static void sci_close(struct toshiba_acpi_dev *dev) 40384a6273fSAzael Avalos { 404258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 }; 405258c5903SAzael Avalos u32 out[TCI_WORDS]; 40684a6273fSAzael Avalos acpi_status status; 40784a6273fSAzael Avalos 408258c5903SAzael Avalos status = tci_raw(dev, in, out); 4098baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 41084a6273fSAzael Avalos pr_err("ACPI call to close SCI failed\n"); 41184a6273fSAzael Avalos return; 41284a6273fSAzael Avalos } 41384a6273fSAzael Avalos 4141864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) 41584a6273fSAzael Avalos return; 4161864bbc2SAzael Avalos else if (out[0] == TOS_NOT_OPENED) 41784a6273fSAzael Avalos pr_info("Toshiba SCI not opened\n"); 4181864bbc2SAzael Avalos else if (out[0] == TOS_NOT_PRESENT) 41984a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 42084a6273fSAzael Avalos } 42184a6273fSAzael Avalos 422893f3f62SAzael Avalos static u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 42384a6273fSAzael Avalos { 424258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 }; 425258c5903SAzael Avalos u32 out[TCI_WORDS]; 426258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 427b5163992SAzael Avalos 428893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 429893f3f62SAzael Avalos return TOS_FAILURE; 430893f3f62SAzael Avalos 43184a6273fSAzael Avalos *out1 = out[2]; 432893f3f62SAzael Avalos 433893f3f62SAzael Avalos return out[0]; 43484a6273fSAzael Avalos } 43584a6273fSAzael Avalos 436893f3f62SAzael Avalos static u32 sci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 43784a6273fSAzael Avalos { 438258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 }; 439258c5903SAzael Avalos u32 out[TCI_WORDS]; 440258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 441893f3f62SAzael Avalos 442893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 44384a6273fSAzael Avalos } 44484a6273fSAzael Avalos 4456c3f6e6cSPierre Ducroquet /* Illumination support */ 446ea215a3fSAzael Avalos static void toshiba_illumination_available(struct toshiba_acpi_dev *dev) 4476c3f6e6cSPierre Ducroquet { 448258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 }; 449258c5903SAzael Avalos u32 out[TCI_WORDS]; 4506c3f6e6cSPierre Ducroquet acpi_status status; 4516c3f6e6cSPierre Ducroquet 452ea215a3fSAzael Avalos dev->illumination_supported = 0; 453ea215a3fSAzael Avalos dev->illumination_led_registered = false; 454ea215a3fSAzael Avalos 455fdb79081SAzael Avalos if (!sci_open(dev)) 456ea215a3fSAzael Avalos return; 457fdb79081SAzael Avalos 458258c5903SAzael Avalos status = tci_raw(dev, in, out); 459fdb79081SAzael Avalos sci_close(dev); 460ea215a3fSAzael Avalos if (ACPI_FAILURE(status)) 461fdb79081SAzael Avalos pr_err("ACPI call to query Illumination support failed\n"); 462ea215a3fSAzael Avalos else if (out[0] == TOS_NOT_SUPPORTED) 4630409cbceSAzael Avalos return; 464ea215a3fSAzael Avalos else if (out[0] == TOS_SUCCESS) 465ea215a3fSAzael Avalos dev->illumination_supported = 1; 4666c3f6e6cSPierre Ducroquet } 4676c3f6e6cSPierre Ducroquet 4686c3f6e6cSPierre Ducroquet static void toshiba_illumination_set(struct led_classdev *cdev, 4696c3f6e6cSPierre Ducroquet enum led_brightness brightness) 4706c3f6e6cSPierre Ducroquet { 471135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 472135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 473*e1a949c1SAzael Avalos u32 result; 474*e1a949c1SAzael Avalos u32 state; 4756c3f6e6cSPierre Ducroquet 4766c3f6e6cSPierre Ducroquet /* First request : initialize communication. */ 477fdb79081SAzael Avalos if (!sci_open(dev)) 4786c3f6e6cSPierre Ducroquet return; 4796c3f6e6cSPierre Ducroquet 480fdb79081SAzael Avalos /* Switch the illumination on/off */ 481fdb79081SAzael Avalos state = brightness ? 1 : 0; 482893f3f62SAzael Avalos result = sci_write(dev, SCI_ILLUMINATION, state); 483fdb79081SAzael Avalos sci_close(dev); 484893f3f62SAzael Avalos if (result == TOS_FAILURE) { 485fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 486fdb79081SAzael Avalos return; 4871864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 4886c3f6e6cSPierre Ducroquet return; 4896c3f6e6cSPierre Ducroquet } 4906c3f6e6cSPierre Ducroquet } 4916c3f6e6cSPierre Ducroquet 4926c3f6e6cSPierre Ducroquet static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) 4936c3f6e6cSPierre Ducroquet { 494135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 495135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 496fdb79081SAzael Avalos u32 state, result; 4976c3f6e6cSPierre Ducroquet 4983f75bbe9SAzael Avalos /* First request : initialize communication. */ 499fdb79081SAzael Avalos if (!sci_open(dev)) 5006c3f6e6cSPierre Ducroquet return LED_OFF; 5016c3f6e6cSPierre Ducroquet 5026c3f6e6cSPierre Ducroquet /* Check the illumination */ 503893f3f62SAzael Avalos result = sci_read(dev, SCI_ILLUMINATION, &state); 504fdb79081SAzael Avalos sci_close(dev); 505893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 506fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 507fdb79081SAzael Avalos return LED_OFF; 508*e1a949c1SAzael Avalos } else if (result != TOS_SUCCESS) { 5096c3f6e6cSPierre Ducroquet return LED_OFF; 5106c3f6e6cSPierre Ducroquet } 5116c3f6e6cSPierre Ducroquet 512fdb79081SAzael Avalos return state ? LED_FULL : LED_OFF; 5136c3f6e6cSPierre Ducroquet } 5146c3f6e6cSPierre Ducroquet 515360f0f39SAzael Avalos /* KBD Illumination */ 516ea215a3fSAzael Avalos static void toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev) 51793f8c16dSAzael Avalos { 518258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 }; 519258c5903SAzael Avalos u32 out[TCI_WORDS]; 52093f8c16dSAzael Avalos acpi_status status; 52193f8c16dSAzael Avalos 522ea215a3fSAzael Avalos dev->kbd_illum_supported = 0; 523ea215a3fSAzael Avalos dev->kbd_led_registered = false; 524ea215a3fSAzael Avalos 52593f8c16dSAzael Avalos if (!sci_open(dev)) 526ea215a3fSAzael Avalos return; 52793f8c16dSAzael Avalos 528258c5903SAzael Avalos status = tci_raw(dev, in, out); 52993f8c16dSAzael Avalos sci_close(dev); 5301864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 53193f8c16dSAzael Avalos pr_err("ACPI call to query kbd illumination support failed\n"); 5321864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 5330409cbceSAzael Avalos return; 534ea215a3fSAzael Avalos } else if (out[0] == TOS_SUCCESS) { 535e0769fe6SDarren Hart /* 536e0769fe6SDarren Hart * Check for keyboard backlight timeout max value, 53793f8c16dSAzael Avalos * previous kbd backlight implementation set this to 53893f8c16dSAzael Avalos * 0x3c0003, and now the new implementation set this 539e0769fe6SDarren Hart * to 0x3c001a, use this to distinguish between them. 54093f8c16dSAzael Avalos */ 54193f8c16dSAzael Avalos if (out[3] == SCI_KBD_TIME_MAX) 54293f8c16dSAzael Avalos dev->kbd_type = 2; 54393f8c16dSAzael Avalos else 54493f8c16dSAzael Avalos dev->kbd_type = 1; 54593f8c16dSAzael Avalos /* Get the current keyboard backlight mode */ 54693f8c16dSAzael Avalos dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK; 54793f8c16dSAzael Avalos /* Get the current time (1-60 seconds) */ 54893f8c16dSAzael Avalos dev->kbd_time = out[2] >> HCI_MISC_SHIFT; 549ea215a3fSAzael Avalos /* Flag as supported */ 550ea215a3fSAzael Avalos dev->kbd_illum_supported = 1; 551ea215a3fSAzael Avalos } 55293f8c16dSAzael Avalos } 55393f8c16dSAzael Avalos 554360f0f39SAzael Avalos static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time) 555360f0f39SAzael Avalos { 556360f0f39SAzael Avalos u32 result; 557360f0f39SAzael Avalos 558360f0f39SAzael Avalos if (!sci_open(dev)) 559360f0f39SAzael Avalos return -EIO; 560360f0f39SAzael Avalos 561893f3f62SAzael Avalos result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time); 562360f0f39SAzael Avalos sci_close(dev); 563893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 564360f0f39SAzael Avalos pr_err("ACPI call to set KBD backlight status failed\n"); 565360f0f39SAzael Avalos return -EIO; 5661864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 567360f0f39SAzael Avalos return -ENODEV; 568360f0f39SAzael Avalos } 569360f0f39SAzael Avalos 570*e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 571360f0f39SAzael Avalos } 572360f0f39SAzael Avalos 573360f0f39SAzael Avalos static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time) 574360f0f39SAzael Avalos { 575360f0f39SAzael Avalos u32 result; 576360f0f39SAzael Avalos 577360f0f39SAzael Avalos if (!sci_open(dev)) 578360f0f39SAzael Avalos return -EIO; 579360f0f39SAzael Avalos 580893f3f62SAzael Avalos result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time); 581360f0f39SAzael Avalos sci_close(dev); 582893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 583360f0f39SAzael Avalos pr_err("ACPI call to get KBD backlight status failed\n"); 584360f0f39SAzael Avalos return -EIO; 5851864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 586360f0f39SAzael Avalos return -ENODEV; 587360f0f39SAzael Avalos } 588360f0f39SAzael Avalos 589*e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 590360f0f39SAzael Avalos } 591360f0f39SAzael Avalos 592360f0f39SAzael Avalos static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev) 593360f0f39SAzael Avalos { 594360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 595360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 596*e1a949c1SAzael Avalos u32 result; 597*e1a949c1SAzael Avalos u32 state; 598360f0f39SAzael Avalos 599360f0f39SAzael Avalos /* Check the keyboard backlight state */ 600d37782bdSAzael Avalos result = hci_read(dev, HCI_KBD_ILLUMINATION, &state); 601893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 602360f0f39SAzael Avalos pr_err("ACPI call to get the keyboard backlight failed\n"); 603360f0f39SAzael Avalos return LED_OFF; 604*e1a949c1SAzael Avalos } else if (result != TOS_SUCCESS) { 605360f0f39SAzael Avalos return LED_OFF; 606360f0f39SAzael Avalos } 607360f0f39SAzael Avalos 608360f0f39SAzael Avalos return state ? LED_FULL : LED_OFF; 609360f0f39SAzael Avalos } 610360f0f39SAzael Avalos 611360f0f39SAzael Avalos static void toshiba_kbd_backlight_set(struct led_classdev *cdev, 612360f0f39SAzael Avalos enum led_brightness brightness) 613360f0f39SAzael Avalos { 614360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 615360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 616*e1a949c1SAzael Avalos u32 result; 617*e1a949c1SAzael Avalos u32 state; 618360f0f39SAzael Avalos 619360f0f39SAzael Avalos /* Set the keyboard backlight state */ 620360f0f39SAzael Avalos state = brightness ? 1 : 0; 621d37782bdSAzael Avalos result = hci_write(dev, HCI_KBD_ILLUMINATION, state); 622893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 623360f0f39SAzael Avalos pr_err("ACPI call to set KBD Illumination mode failed\n"); 624360f0f39SAzael Avalos return; 6251864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 626360f0f39SAzael Avalos return; 627360f0f39SAzael Avalos } 628360f0f39SAzael Avalos } 629360f0f39SAzael Avalos 6309d8658acSAzael Avalos /* TouchPad support */ 6319d8658acSAzael Avalos static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state) 6329d8658acSAzael Avalos { 6339d8658acSAzael Avalos u32 result; 6349d8658acSAzael Avalos 6359d8658acSAzael Avalos if (!sci_open(dev)) 6369d8658acSAzael Avalos return -EIO; 6379d8658acSAzael Avalos 638893f3f62SAzael Avalos result = sci_write(dev, SCI_TOUCHPAD, state); 6399d8658acSAzael Avalos sci_close(dev); 640893f3f62SAzael Avalos if (result == TOS_FAILURE) { 6419d8658acSAzael Avalos pr_err("ACPI call to set the touchpad failed\n"); 6429d8658acSAzael Avalos return -EIO; 6431864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 6449d8658acSAzael Avalos return -ENODEV; 6459d8658acSAzael Avalos } 6469d8658acSAzael Avalos 647*e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 6489d8658acSAzael Avalos } 6499d8658acSAzael Avalos 6509d8658acSAzael Avalos static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) 6519d8658acSAzael Avalos { 6529d8658acSAzael Avalos u32 result; 6539d8658acSAzael Avalos 6549d8658acSAzael Avalos if (!sci_open(dev)) 6559d8658acSAzael Avalos return -EIO; 6569d8658acSAzael Avalos 657893f3f62SAzael Avalos result = sci_read(dev, SCI_TOUCHPAD, state); 6589d8658acSAzael Avalos sci_close(dev); 659893f3f62SAzael Avalos if (result == TOS_FAILURE) { 6609d8658acSAzael Avalos pr_err("ACPI call to query the touchpad failed\n"); 6619d8658acSAzael Avalos return -EIO; 6621864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 6639d8658acSAzael Avalos return -ENODEV; 6649d8658acSAzael Avalos } 6659d8658acSAzael Avalos 666*e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 6679d8658acSAzael Avalos } 6689d8658acSAzael Avalos 669def6c4e2SAzael Avalos /* Eco Mode support */ 670ea215a3fSAzael Avalos static void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) 671def6c4e2SAzael Avalos { 672def6c4e2SAzael Avalos acpi_status status; 67398fc4ec6SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 }; 674258c5903SAzael Avalos u32 out[TCI_WORDS]; 675def6c4e2SAzael Avalos 676ea215a3fSAzael Avalos dev->eco_supported = 0; 677ea215a3fSAzael Avalos dev->eco_led_registered = false; 678ea215a3fSAzael Avalos 679258c5903SAzael Avalos status = tci_raw(dev, in, out); 6808baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 68198fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 68298fc4ec6SAzael Avalos } else if (out[0] == TOS_NOT_INSTALLED) { 68398fc4ec6SAzael Avalos pr_info("ECO led not installed"); 68498fc4ec6SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 685e0769fe6SDarren Hart /* 686e0769fe6SDarren Hart * If we receive 0x8300 (Input Data Error), it means that the 68798fc4ec6SAzael Avalos * LED device is present, but that we just screwed the input 68898fc4ec6SAzael Avalos * parameters. 68998fc4ec6SAzael Avalos * 69098fc4ec6SAzael Avalos * Let's query the status of the LED to see if we really have a 69198fc4ec6SAzael Avalos * success response, indicating the actual presense of the LED, 69298fc4ec6SAzael Avalos * bail out otherwise. 69398fc4ec6SAzael Avalos */ 69498fc4ec6SAzael Avalos in[3] = 1; 69598fc4ec6SAzael Avalos status = tci_raw(dev, in, out); 69698fc4ec6SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) 69798fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 69898fc4ec6SAzael Avalos else if (out[0] == TOS_SUCCESS) 699ea215a3fSAzael Avalos dev->eco_supported = 1; 700def6c4e2SAzael Avalos } 701def6c4e2SAzael Avalos } 702def6c4e2SAzael Avalos 703b5163992SAzael Avalos static enum led_brightness 704b5163992SAzael Avalos toshiba_eco_mode_get_status(struct led_classdev *cdev) 705def6c4e2SAzael Avalos { 706def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 707def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 708258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 }; 709258c5903SAzael Avalos u32 out[TCI_WORDS]; 710def6c4e2SAzael Avalos acpi_status status; 711def6c4e2SAzael Avalos 712258c5903SAzael Avalos status = tci_raw(dev, in, out); 7131864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 714def6c4e2SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 715def6c4e2SAzael Avalos return LED_OFF; 716*e1a949c1SAzael Avalos } else if (out[0] != TOS_SUCCESS) { 717*e1a949c1SAzael Avalos return LED_OFF; 718def6c4e2SAzael Avalos } 719def6c4e2SAzael Avalos 720def6c4e2SAzael Avalos return out[2] ? LED_FULL : LED_OFF; 721def6c4e2SAzael Avalos } 722def6c4e2SAzael Avalos 723def6c4e2SAzael Avalos static void toshiba_eco_mode_set_status(struct led_classdev *cdev, 724def6c4e2SAzael Avalos enum led_brightness brightness) 725def6c4e2SAzael Avalos { 726def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 727def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 728258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 }; 729258c5903SAzael Avalos u32 out[TCI_WORDS]; 730def6c4e2SAzael Avalos acpi_status status; 731def6c4e2SAzael Avalos 732def6c4e2SAzael Avalos /* Switch the Eco Mode led on/off */ 733def6c4e2SAzael Avalos in[2] = (brightness) ? 1 : 0; 734258c5903SAzael Avalos status = tci_raw(dev, in, out); 7351864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 736def6c4e2SAzael Avalos pr_err("ACPI call to set ECO led failed\n"); 737def6c4e2SAzael Avalos return; 738def6c4e2SAzael Avalos } 739def6c4e2SAzael Avalos } 740def6c4e2SAzael Avalos 7415a2813e9SAzael Avalos /* Accelerometer support */ 742ea215a3fSAzael Avalos static void toshiba_accelerometer_available(struct toshiba_acpi_dev *dev) 7435a2813e9SAzael Avalos { 744258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 }; 745258c5903SAzael Avalos u32 out[TCI_WORDS]; 7465a2813e9SAzael Avalos acpi_status status; 7475a2813e9SAzael Avalos 748ea215a3fSAzael Avalos dev->accelerometer_supported = 0; 749ea215a3fSAzael Avalos 750e0769fe6SDarren Hart /* 751e0769fe6SDarren Hart * Check if the accelerometer call exists, 7525a2813e9SAzael Avalos * this call also serves as initialization 7535a2813e9SAzael Avalos */ 754258c5903SAzael Avalos status = tci_raw(dev, in, out); 755ea215a3fSAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) 7565a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 757ea215a3fSAzael Avalos else if (out[0] == TOS_DATA_NOT_AVAILABLE || 758ea215a3fSAzael Avalos out[0] == TOS_NOT_INITIALIZED) 7595a2813e9SAzael Avalos pr_err("Accelerometer not initialized\n"); 760ea215a3fSAzael Avalos else if (out[0] == TOS_NOT_SUPPORTED) 7610409cbceSAzael Avalos return; 762ea215a3fSAzael Avalos else if (out[0] == TOS_SUCCESS) 763ea215a3fSAzael Avalos dev->accelerometer_supported = 1; 7645a2813e9SAzael Avalos } 7655a2813e9SAzael Avalos 7665a2813e9SAzael Avalos static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, 7675a2813e9SAzael Avalos u32 *xy, u32 *z) 7685a2813e9SAzael Avalos { 769258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 }; 770258c5903SAzael Avalos u32 out[TCI_WORDS]; 7715a2813e9SAzael Avalos acpi_status status; 7725a2813e9SAzael Avalos 7735a2813e9SAzael Avalos /* Check the Accelerometer status */ 774258c5903SAzael Avalos status = tci_raw(dev, in, out); 7751864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 7765a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 7775a2813e9SAzael Avalos return -EIO; 778*e1a949c1SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 779*e1a949c1SAzael Avalos return -ENODEV; 780*e1a949c1SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 7815a2813e9SAzael Avalos *xy = out[2]; 7825a2813e9SAzael Avalos *z = out[4]; 7835a2813e9SAzael Avalos return 0; 7845a2813e9SAzael Avalos } 7855a2813e9SAzael Avalos 786*e1a949c1SAzael Avalos return -EIO; 787*e1a949c1SAzael Avalos } 788*e1a949c1SAzael Avalos 789e26ffe51SAzael Avalos /* Sleep (Charge and Music) utilities support */ 790c8c91842SAzael Avalos static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev) 791c8c91842SAzael Avalos { 792c8c91842SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 793c8c91842SAzael Avalos u32 out[TCI_WORDS]; 794c8c91842SAzael Avalos acpi_status status; 795c8c91842SAzael Avalos 796c8c91842SAzael Avalos dev->usb_sleep_charge_supported = 0; 797c8c91842SAzael Avalos 798c8c91842SAzael Avalos if (!sci_open(dev)) 799c8c91842SAzael Avalos return; 800c8c91842SAzael Avalos 801c8c91842SAzael Avalos status = tci_raw(dev, in, out); 8028baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 803c8c91842SAzael Avalos pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); 804c8c91842SAzael Avalos sci_close(dev); 805c8c91842SAzael Avalos return; 806c8c91842SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 807c8c91842SAzael Avalos sci_close(dev); 808c8c91842SAzael Avalos return; 809c8c91842SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 810c8c91842SAzael Avalos dev->usbsc_mode_base = out[4]; 811c8c91842SAzael Avalos } 812c8c91842SAzael Avalos 813c8c91842SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 814c8c91842SAzael Avalos status = tci_raw(dev, in, out); 815ea215a3fSAzael Avalos sci_close(dev); 8168baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 817c8c91842SAzael Avalos pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); 818c8c91842SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 8190409cbceSAzael Avalos return; 820c8c91842SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 821c8c91842SAzael Avalos dev->usbsc_bat_level = out[2]; 822ea215a3fSAzael Avalos /* Flag as supported */ 823c8c91842SAzael Avalos dev->usb_sleep_charge_supported = 1; 824c8c91842SAzael Avalos } 825c8c91842SAzael Avalos 826c8c91842SAzael Avalos } 827c8c91842SAzael Avalos 828e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, 829e26ffe51SAzael Avalos u32 *mode) 830e26ffe51SAzael Avalos { 831e26ffe51SAzael Avalos u32 result; 832e26ffe51SAzael Avalos 833e26ffe51SAzael Avalos if (!sci_open(dev)) 834e26ffe51SAzael Avalos return -EIO; 835e26ffe51SAzael Avalos 836e26ffe51SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode); 837e26ffe51SAzael Avalos sci_close(dev); 838e26ffe51SAzael Avalos if (result == TOS_FAILURE) { 839e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 840e26ffe51SAzael Avalos return -EIO; 841e26ffe51SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 842e26ffe51SAzael Avalos return -ENODEV; 843e26ffe51SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 844e26ffe51SAzael Avalos return -EIO; 845e26ffe51SAzael Avalos } 846e26ffe51SAzael Avalos 847*e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 848e26ffe51SAzael Avalos } 849e26ffe51SAzael Avalos 850e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev, 851e26ffe51SAzael Avalos u32 mode) 852e26ffe51SAzael Avalos { 853e26ffe51SAzael Avalos u32 result; 854e26ffe51SAzael Avalos 855e26ffe51SAzael Avalos if (!sci_open(dev)) 856e26ffe51SAzael Avalos return -EIO; 857e26ffe51SAzael Avalos 858e26ffe51SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode); 859e26ffe51SAzael Avalos sci_close(dev); 860e26ffe51SAzael Avalos if (result == TOS_FAILURE) { 861e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 862e26ffe51SAzael Avalos return -EIO; 863e26ffe51SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 864e26ffe51SAzael Avalos return -ENODEV; 865e26ffe51SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 866e26ffe51SAzael Avalos return -EIO; 867e26ffe51SAzael Avalos } 868e26ffe51SAzael Avalos 869*e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 870e26ffe51SAzael Avalos } 871e26ffe51SAzael Avalos 872182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev, 873182bcaa5SAzael Avalos u32 *mode) 874182bcaa5SAzael Avalos { 875182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 876182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 877182bcaa5SAzael Avalos acpi_status status; 878182bcaa5SAzael Avalos 879182bcaa5SAzael Avalos if (!sci_open(dev)) 880182bcaa5SAzael Avalos return -EIO; 881182bcaa5SAzael Avalos 882182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 883182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 884182bcaa5SAzael Avalos sci_close(dev); 8858baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 886182bcaa5SAzael Avalos pr_err("ACPI call to get USB S&C battery level failed\n"); 887182bcaa5SAzael Avalos return -EIO; 888182bcaa5SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 889182bcaa5SAzael Avalos return -ENODEV; 890182bcaa5SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 891182bcaa5SAzael Avalos return -EIO; 892*e1a949c1SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 893*e1a949c1SAzael Avalos *mode = out[2]; 894*e1a949c1SAzael Avalos return 0; 895182bcaa5SAzael Avalos } 896182bcaa5SAzael Avalos 897*e1a949c1SAzael Avalos return -EIO; 898182bcaa5SAzael Avalos } 899182bcaa5SAzael Avalos 900182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, 901182bcaa5SAzael Avalos u32 mode) 902182bcaa5SAzael Avalos { 903182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 904182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 905182bcaa5SAzael Avalos acpi_status status; 906182bcaa5SAzael Avalos 907182bcaa5SAzael Avalos if (!sci_open(dev)) 908182bcaa5SAzael Avalos return -EIO; 909182bcaa5SAzael Avalos 910182bcaa5SAzael Avalos in[2] = mode; 911182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 912182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 913182bcaa5SAzael Avalos sci_close(dev); 9148baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 915182bcaa5SAzael Avalos pr_err("ACPI call to set USB S&C battery level failed\n"); 916182bcaa5SAzael Avalos return -EIO; 917182bcaa5SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 918182bcaa5SAzael Avalos return -ENODEV; 919182bcaa5SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 920182bcaa5SAzael Avalos return -EIO; 921182bcaa5SAzael Avalos } 922182bcaa5SAzael Avalos 923*e1a949c1SAzael Avalos return out[0] == TOS_SUCCESS ? 0 : -EIO; 924182bcaa5SAzael Avalos } 925182bcaa5SAzael Avalos 926bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, 927bb3fe01fSAzael Avalos u32 *state) 928bb3fe01fSAzael Avalos { 929bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 930bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 931bb3fe01fSAzael Avalos acpi_status status; 932bb3fe01fSAzael Avalos 933bb3fe01fSAzael Avalos if (!sci_open(dev)) 934bb3fe01fSAzael Avalos return -EIO; 935bb3fe01fSAzael Avalos 936bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 937bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 938bb3fe01fSAzael Avalos sci_close(dev); 9398baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 940bb26f189SAzael Avalos pr_err("ACPI call to get USB Rapid Charge failed\n"); 941bb3fe01fSAzael Avalos return -EIO; 942bb3fe01fSAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED || 943bb3fe01fSAzael Avalos out[0] == TOS_INPUT_DATA_ERROR) { 944bb3fe01fSAzael Avalos return -ENODEV; 945*e1a949c1SAzael Avalos } else if (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) { 946*e1a949c1SAzael Avalos *state = out[2]; 947*e1a949c1SAzael Avalos return 0; 948bb3fe01fSAzael Avalos } 949bb3fe01fSAzael Avalos 950*e1a949c1SAzael Avalos return -EIO; 951bb3fe01fSAzael Avalos } 952bb3fe01fSAzael Avalos 953bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, 954bb3fe01fSAzael Avalos u32 state) 955bb3fe01fSAzael Avalos { 956bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 957bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 958bb3fe01fSAzael Avalos acpi_status status; 959bb3fe01fSAzael Avalos 960bb3fe01fSAzael Avalos if (!sci_open(dev)) 961bb3fe01fSAzael Avalos return -EIO; 962bb3fe01fSAzael Avalos 963bb3fe01fSAzael Avalos in[2] = state; 964bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 965bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 966bb3fe01fSAzael Avalos sci_close(dev); 9678baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 968bb26f189SAzael Avalos pr_err("ACPI call to set USB Rapid Charge failed\n"); 969bb3fe01fSAzael Avalos return -EIO; 970bb3fe01fSAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 971bb3fe01fSAzael Avalos return -ENODEV; 972bb3fe01fSAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 973bb3fe01fSAzael Avalos return -EIO; 974bb3fe01fSAzael Avalos } 975bb3fe01fSAzael Avalos 976*e1a949c1SAzael Avalos return (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) ? 0 : -EIO; 977bb3fe01fSAzael Avalos } 978bb3fe01fSAzael Avalos 979172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state) 980172ce0a9SAzael Avalos { 981172ce0a9SAzael Avalos u32 result; 982172ce0a9SAzael Avalos 983172ce0a9SAzael Avalos if (!sci_open(dev)) 984172ce0a9SAzael Avalos return -EIO; 985172ce0a9SAzael Avalos 986172ce0a9SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state); 987172ce0a9SAzael Avalos sci_close(dev); 988172ce0a9SAzael Avalos if (result == TOS_FAILURE) { 989bb26f189SAzael Avalos pr_err("ACPI call to get Sleep and Music failed\n"); 990172ce0a9SAzael Avalos return -EIO; 991172ce0a9SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 992172ce0a9SAzael Avalos return -ENODEV; 993172ce0a9SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 994172ce0a9SAzael Avalos return -EIO; 995172ce0a9SAzael Avalos } 996172ce0a9SAzael Avalos 997*e1a949c1SAzael Avalos return result = TOS_SUCCESS ? 0 : -EIO; 998172ce0a9SAzael Avalos } 999172ce0a9SAzael Avalos 1000172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state) 1001172ce0a9SAzael Avalos { 1002172ce0a9SAzael Avalos u32 result; 1003172ce0a9SAzael Avalos 1004172ce0a9SAzael Avalos if (!sci_open(dev)) 1005172ce0a9SAzael Avalos return -EIO; 1006172ce0a9SAzael Avalos 1007172ce0a9SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state); 1008172ce0a9SAzael Avalos sci_close(dev); 1009172ce0a9SAzael Avalos if (result == TOS_FAILURE) { 1010bb26f189SAzael Avalos pr_err("ACPI call to set Sleep and Music failed\n"); 1011172ce0a9SAzael Avalos return -EIO; 1012172ce0a9SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1013172ce0a9SAzael Avalos return -ENODEV; 1014172ce0a9SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 1015172ce0a9SAzael Avalos return -EIO; 1016172ce0a9SAzael Avalos } 1017172ce0a9SAzael Avalos 1018*e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1019172ce0a9SAzael Avalos } 1020172ce0a9SAzael Avalos 1021bae84195SAzael Avalos /* Keyboard function keys */ 1022bae84195SAzael Avalos static int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode) 1023bae84195SAzael Avalos { 1024bae84195SAzael Avalos u32 result; 1025bae84195SAzael Avalos 1026bae84195SAzael Avalos if (!sci_open(dev)) 1027bae84195SAzael Avalos return -EIO; 1028bae84195SAzael Avalos 1029bae84195SAzael Avalos result = sci_read(dev, SCI_KBD_FUNCTION_KEYS, mode); 1030bae84195SAzael Avalos sci_close(dev); 1031bae84195SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 1032bae84195SAzael Avalos pr_err("ACPI call to get KBD function keys failed\n"); 1033bae84195SAzael Avalos return -EIO; 1034bae84195SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1035bae84195SAzael Avalos return -ENODEV; 1036bae84195SAzael Avalos } 1037bae84195SAzael Avalos 1038*e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 1039bae84195SAzael Avalos } 1040bae84195SAzael Avalos 1041bae84195SAzael Avalos static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode) 1042bae84195SAzael Avalos { 1043bae84195SAzael Avalos u32 result; 1044bae84195SAzael Avalos 1045bae84195SAzael Avalos if (!sci_open(dev)) 1046bae84195SAzael Avalos return -EIO; 1047bae84195SAzael Avalos 1048bae84195SAzael Avalos result = sci_write(dev, SCI_KBD_FUNCTION_KEYS, mode); 1049bae84195SAzael Avalos sci_close(dev); 1050bae84195SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 1051bae84195SAzael Avalos pr_err("ACPI call to set KBD function keys failed\n"); 1052bae84195SAzael Avalos return -EIO; 1053bae84195SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1054bae84195SAzael Avalos return -ENODEV; 1055bae84195SAzael Avalos } 1056bae84195SAzael Avalos 1057*e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 1058bae84195SAzael Avalos } 1059bae84195SAzael Avalos 106035d53ceaSAzael Avalos /* Panel Power ON */ 106135d53ceaSAzael Avalos static int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state) 106235d53ceaSAzael Avalos { 106335d53ceaSAzael Avalos u32 result; 106435d53ceaSAzael Avalos 106535d53ceaSAzael Avalos if (!sci_open(dev)) 106635d53ceaSAzael Avalos return -EIO; 106735d53ceaSAzael Avalos 106835d53ceaSAzael Avalos result = sci_read(dev, SCI_PANEL_POWER_ON, state); 106935d53ceaSAzael Avalos sci_close(dev); 107035d53ceaSAzael Avalos if (result == TOS_FAILURE) { 107135d53ceaSAzael Avalos pr_err("ACPI call to get Panel Power ON failed\n"); 107235d53ceaSAzael Avalos return -EIO; 107335d53ceaSAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 107435d53ceaSAzael Avalos return -ENODEV; 107535d53ceaSAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 107635d53ceaSAzael Avalos return -EIO; 107735d53ceaSAzael Avalos } 107835d53ceaSAzael Avalos 1079*e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 108035d53ceaSAzael Avalos } 108135d53ceaSAzael Avalos 108235d53ceaSAzael Avalos static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state) 108335d53ceaSAzael Avalos { 108435d53ceaSAzael Avalos u32 result; 108535d53ceaSAzael Avalos 108635d53ceaSAzael Avalos if (!sci_open(dev)) 108735d53ceaSAzael Avalos return -EIO; 108835d53ceaSAzael Avalos 108935d53ceaSAzael Avalos result = sci_write(dev, SCI_PANEL_POWER_ON, state); 109035d53ceaSAzael Avalos sci_close(dev); 109135d53ceaSAzael Avalos if (result == TOS_FAILURE) { 109235d53ceaSAzael Avalos pr_err("ACPI call to set Panel Power ON failed\n"); 109335d53ceaSAzael Avalos return -EIO; 109435d53ceaSAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 109535d53ceaSAzael Avalos return -ENODEV; 109635d53ceaSAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 109735d53ceaSAzael Avalos return -EIO; 109835d53ceaSAzael Avalos } 109935d53ceaSAzael Avalos 1100*e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 110135d53ceaSAzael Avalos } 110235d53ceaSAzael Avalos 110317fe4b3dSAzael Avalos /* USB Three */ 110417fe4b3dSAzael Avalos static int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state) 110517fe4b3dSAzael Avalos { 110617fe4b3dSAzael Avalos u32 result; 110717fe4b3dSAzael Avalos 110817fe4b3dSAzael Avalos if (!sci_open(dev)) 110917fe4b3dSAzael Avalos return -EIO; 111017fe4b3dSAzael Avalos 111117fe4b3dSAzael Avalos result = sci_read(dev, SCI_USB_THREE, state); 111217fe4b3dSAzael Avalos sci_close(dev); 111317fe4b3dSAzael Avalos if (result == TOS_FAILURE) { 111417fe4b3dSAzael Avalos pr_err("ACPI call to get USB 3 failed\n"); 111517fe4b3dSAzael Avalos return -EIO; 111617fe4b3dSAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 111717fe4b3dSAzael Avalos return -ENODEV; 111817fe4b3dSAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 111917fe4b3dSAzael Avalos return -EIO; 112017fe4b3dSAzael Avalos } 112117fe4b3dSAzael Avalos 1122*e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 112317fe4b3dSAzael Avalos } 112417fe4b3dSAzael Avalos 112517fe4b3dSAzael Avalos static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state) 112617fe4b3dSAzael Avalos { 112717fe4b3dSAzael Avalos u32 result; 112817fe4b3dSAzael Avalos 112917fe4b3dSAzael Avalos if (!sci_open(dev)) 113017fe4b3dSAzael Avalos return -EIO; 113117fe4b3dSAzael Avalos 113217fe4b3dSAzael Avalos result = sci_write(dev, SCI_USB_THREE, state); 113317fe4b3dSAzael Avalos sci_close(dev); 113417fe4b3dSAzael Avalos if (result == TOS_FAILURE) { 113517fe4b3dSAzael Avalos pr_err("ACPI call to set USB 3 failed\n"); 113617fe4b3dSAzael Avalos return -EIO; 113717fe4b3dSAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 113817fe4b3dSAzael Avalos return -ENODEV; 113917fe4b3dSAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 114017fe4b3dSAzael Avalos return -EIO; 114117fe4b3dSAzael Avalos } 114217fe4b3dSAzael Avalos 1143*e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 114417fe4b3dSAzael Avalos } 114517fe4b3dSAzael Avalos 114656e6b353SAzael Avalos /* Hotkey Event type */ 114756e6b353SAzael Avalos static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev, 114856e6b353SAzael Avalos u32 *type) 114956e6b353SAzael Avalos { 11503b876000SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_SYSTEM_INFO, 0x03, 0, 0, 0 }; 11513b876000SAzael Avalos u32 out[TCI_WORDS]; 11523b876000SAzael Avalos acpi_status status; 115356e6b353SAzael Avalos 11543b876000SAzael Avalos status = tci_raw(dev, in, out); 11553b876000SAzael Avalos if (ACPI_FAILURE(status)) { 115656e6b353SAzael Avalos pr_err("ACPI call to get System type failed\n"); 115756e6b353SAzael Avalos return -EIO; 11583b876000SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 115956e6b353SAzael Avalos return -ENODEV; 1160*e1a949c1SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 1161*e1a949c1SAzael Avalos *type = out[3]; 1162*e1a949c1SAzael Avalos return 0; 116356e6b353SAzael Avalos } 116456e6b353SAzael Avalos 1165*e1a949c1SAzael Avalos return -EIO; 116656e6b353SAzael Avalos } 116756e6b353SAzael Avalos 11683f75bbe9SAzael Avalos /* Transflective Backlight */ 1169695f6060SAzael Avalos static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status) 1170121b7b0dSAkio Idehara { 1171*e1a949c1SAzael Avalos u32 result = hci_read(dev, HCI_TR_BACKLIGHT, status); 1172121b7b0dSAkio Idehara 1173*e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1174*e1a949c1SAzael Avalos pr_err("ACPI call to get Transflective Backlight failed\n"); 1175*e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1176*e1a949c1SAzael Avalos return -ENODEV; 1177*e1a949c1SAzael Avalos 1178*e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1179121b7b0dSAkio Idehara } 1180121b7b0dSAkio Idehara 1181695f6060SAzael Avalos static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 status) 1182121b7b0dSAkio Idehara { 1183*e1a949c1SAzael Avalos u32 result = hci_write(dev, HCI_TR_BACKLIGHT, !status); 1184121b7b0dSAkio Idehara 1185*e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1186*e1a949c1SAzael Avalos pr_err("ACPI call to set Transflective Backlight failed\n"); 1187*e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1188*e1a949c1SAzael Avalos return -ENODEV; 1189*e1a949c1SAzael Avalos 1190*e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1191121b7b0dSAkio Idehara } 1192121b7b0dSAkio Idehara 11933f75bbe9SAzael Avalos static struct proc_dir_entry *toshiba_proc_dir; 1194b4f9fe12SLen Brown 11953f75bbe9SAzael Avalos /* LCD Brightness */ 119662cce752SSeth Forshee static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) 1197b4f9fe12SLen Brown { 1198*e1a949c1SAzael Avalos u32 result; 1199b4f9fe12SLen Brown u32 value; 1200121b7b0dSAkio Idehara int brightness = 0; 1201121b7b0dSAkio Idehara 1202121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1203695f6060SAzael Avalos int ret = get_tr_backlight_status(dev, &value); 1204b5163992SAzael Avalos 1205121b7b0dSAkio Idehara if (ret) 1206121b7b0dSAkio Idehara return ret; 1207695f6060SAzael Avalos if (value) 1208121b7b0dSAkio Idehara return 0; 1209121b7b0dSAkio Idehara brightness++; 1210121b7b0dSAkio Idehara } 1211b4f9fe12SLen Brown 1212*e1a949c1SAzael Avalos result = hci_read(dev, HCI_LCD_BRIGHTNESS, &value); 1213*e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1214*e1a949c1SAzael Avalos pr_err("ACPI call to get LCD Brightness failed\n"); 1215*e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1216*e1a949c1SAzael Avalos return -ENODEV; 1217*e1a949c1SAzael Avalos if (result == TOS_SUCCESS) 1218121b7b0dSAkio Idehara return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT); 121932bcd5cbSSeth Forshee 122032bcd5cbSSeth Forshee return -EIO; 1221b4f9fe12SLen Brown } 1222b4f9fe12SLen Brown 122362cce752SSeth Forshee static int get_lcd_brightness(struct backlight_device *bd) 122462cce752SSeth Forshee { 122562cce752SSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 1226b5163992SAzael Avalos 122762cce752SSeth Forshee return __get_lcd_brightness(dev); 122862cce752SSeth Forshee } 122962cce752SSeth Forshee 1230936c8bcdSAlexey Dobriyan static int lcd_proc_show(struct seq_file *m, void *v) 1231b4f9fe12SLen Brown { 1232135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1233121b7b0dSAkio Idehara int levels; 1234*e1a949c1SAzael Avalos int value; 1235b4f9fe12SLen Brown 1236135740deSSeth Forshee if (!dev->backlight_dev) 1237135740deSSeth Forshee return -ENODEV; 1238135740deSSeth Forshee 1239121b7b0dSAkio Idehara levels = dev->backlight_dev->props.max_brightness + 1; 124062cce752SSeth Forshee value = get_lcd_brightness(dev->backlight_dev); 1241b4f9fe12SLen Brown if (value >= 0) { 1242936c8bcdSAlexey Dobriyan seq_printf(m, "brightness: %d\n", value); 1243121b7b0dSAkio Idehara seq_printf(m, "brightness_levels: %d\n", levels); 124432bcd5cbSSeth Forshee return 0; 1245b4f9fe12SLen Brown } 1246b4f9fe12SLen Brown 124732bcd5cbSSeth Forshee pr_err("Error reading LCD brightness\n"); 1248*e1a949c1SAzael Avalos 124932bcd5cbSSeth Forshee return -EIO; 1250936c8bcdSAlexey Dobriyan } 1251936c8bcdSAlexey Dobriyan 1252936c8bcdSAlexey Dobriyan static int lcd_proc_open(struct inode *inode, struct file *file) 1253936c8bcdSAlexey Dobriyan { 1254d9dda78bSAl Viro return single_open(file, lcd_proc_show, PDE_DATA(inode)); 1255b4f9fe12SLen Brown } 1256b4f9fe12SLen Brown 125762cce752SSeth Forshee static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) 1258b4f9fe12SLen Brown { 1259*e1a949c1SAzael Avalos u32 result; 1260b4f9fe12SLen Brown 1261121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1262695f6060SAzael Avalos int ret = set_tr_backlight_status(dev, !value); 1263b5163992SAzael Avalos 1264121b7b0dSAkio Idehara if (ret) 1265121b7b0dSAkio Idehara return ret; 1266121b7b0dSAkio Idehara if (value) 1267121b7b0dSAkio Idehara value--; 1268121b7b0dSAkio Idehara } 1269121b7b0dSAkio Idehara 1270a39f46dfSAzael Avalos value = value << HCI_LCD_BRIGHTNESS_SHIFT; 1271*e1a949c1SAzael Avalos result = hci_write(dev, HCI_LCD_BRIGHTNESS, value); 1272*e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1273*e1a949c1SAzael Avalos pr_err("ACPI call to set LCD Brightness failed\n"); 1274*e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1275*e1a949c1SAzael Avalos return -ENODEV; 1276*e1a949c1SAzael Avalos 1277*e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1278b4f9fe12SLen Brown } 1279b4f9fe12SLen Brown 1280b4f9fe12SLen Brown static int set_lcd_status(struct backlight_device *bd) 1281b4f9fe12SLen Brown { 1282135740deSSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 1283b5163992SAzael Avalos 128462cce752SSeth Forshee return set_lcd_brightness(dev, bd->props.brightness); 1285b4f9fe12SLen Brown } 1286b4f9fe12SLen Brown 1287936c8bcdSAlexey Dobriyan static ssize_t lcd_proc_write(struct file *file, const char __user *buf, 1288936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1289b4f9fe12SLen Brown { 1290d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1291936c8bcdSAlexey Dobriyan char cmd[42]; 1292936c8bcdSAlexey Dobriyan size_t len; 1293121b7b0dSAkio Idehara int levels = dev->backlight_dev->props.max_brightness + 1; 1294*e1a949c1SAzael Avalos int value; 1295b4f9fe12SLen Brown 1296936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1297936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1298936c8bcdSAlexey Dobriyan return -EFAULT; 1299936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1300936c8bcdSAlexey Dobriyan 1301*e1a949c1SAzael Avalos if (sscanf(cmd, " brightness : %i", &value) != 1 && 1302*e1a949c1SAzael Avalos value < 0 && value > levels) 1303*e1a949c1SAzael Avalos return -EINVAL; 1304*e1a949c1SAzael Avalos 1305*e1a949c1SAzael Avalos if (set_lcd_brightness(dev, value)) 1306*e1a949c1SAzael Avalos return -EIO; 1307*e1a949c1SAzael Avalos 1308*e1a949c1SAzael Avalos return count; 1309b4f9fe12SLen Brown } 1310b4f9fe12SLen Brown 1311936c8bcdSAlexey Dobriyan static const struct file_operations lcd_proc_fops = { 1312936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1313936c8bcdSAlexey Dobriyan .open = lcd_proc_open, 1314936c8bcdSAlexey Dobriyan .read = seq_read, 1315936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1316936c8bcdSAlexey Dobriyan .release = single_release, 1317936c8bcdSAlexey Dobriyan .write = lcd_proc_write, 1318936c8bcdSAlexey Dobriyan }; 1319936c8bcdSAlexey Dobriyan 1320*e1a949c1SAzael Avalos /* Video-Out */ 132136d03f93SSeth Forshee static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status) 132236d03f93SSeth Forshee { 1323*e1a949c1SAzael Avalos u32 result = hci_read(dev, HCI_VIDEO_OUT, status); 132436d03f93SSeth Forshee 1325*e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1326*e1a949c1SAzael Avalos pr_err("ACPI call to get Video-Out failed\n"); 1327*e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1328*e1a949c1SAzael Avalos return -ENODEV; 1329*e1a949c1SAzael Avalos 1330*e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 133136d03f93SSeth Forshee } 133236d03f93SSeth Forshee 1333936c8bcdSAlexey Dobriyan static int video_proc_show(struct seq_file *m, void *v) 1334b4f9fe12SLen Brown { 1335135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1336b4f9fe12SLen Brown u32 value; 1337b4f9fe12SLen Brown 1338*e1a949c1SAzael Avalos if (!get_video_status(dev, &value)) { 1339b4f9fe12SLen Brown int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; 1340b4f9fe12SLen Brown int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; 1341b4f9fe12SLen Brown int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; 1342b5163992SAzael Avalos 1343936c8bcdSAlexey Dobriyan seq_printf(m, "lcd_out: %d\n", is_lcd); 1344936c8bcdSAlexey Dobriyan seq_printf(m, "crt_out: %d\n", is_crt); 1345936c8bcdSAlexey Dobriyan seq_printf(m, "tv_out: %d\n", is_tv); 1346*e1a949c1SAzael Avalos return 0; 1347b4f9fe12SLen Brown } 1348b4f9fe12SLen Brown 1349*e1a949c1SAzael Avalos return -EIO; 1350b4f9fe12SLen Brown } 1351b4f9fe12SLen Brown 1352936c8bcdSAlexey Dobriyan static int video_proc_open(struct inode *inode, struct file *file) 1353b4f9fe12SLen Brown { 1354d9dda78bSAl Viro return single_open(file, video_proc_show, PDE_DATA(inode)); 1355936c8bcdSAlexey Dobriyan } 1356936c8bcdSAlexey Dobriyan 1357936c8bcdSAlexey Dobriyan static ssize_t video_proc_write(struct file *file, const char __user *buf, 1358936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1359936c8bcdSAlexey Dobriyan { 1360d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1361*e1a949c1SAzael Avalos char *buffer; 1362*e1a949c1SAzael Avalos char *cmd; 1363b4f9fe12SLen Brown int remain = count; 1364b4f9fe12SLen Brown int lcd_out = -1; 1365b4f9fe12SLen Brown int crt_out = -1; 1366b4f9fe12SLen Brown int tv_out = -1; 1367*e1a949c1SAzael Avalos int value; 1368*e1a949c1SAzael Avalos int ret; 1369b4f9fe12SLen Brown u32 video_out; 1370b4f9fe12SLen Brown 1371936c8bcdSAlexey Dobriyan cmd = kmalloc(count + 1, GFP_KERNEL); 1372936c8bcdSAlexey Dobriyan if (!cmd) 1373936c8bcdSAlexey Dobriyan return -ENOMEM; 1374936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, count)) { 1375936c8bcdSAlexey Dobriyan kfree(cmd); 1376936c8bcdSAlexey Dobriyan return -EFAULT; 1377936c8bcdSAlexey Dobriyan } 1378936c8bcdSAlexey Dobriyan cmd[count] = '\0'; 1379936c8bcdSAlexey Dobriyan 1380936c8bcdSAlexey Dobriyan buffer = cmd; 1381936c8bcdSAlexey Dobriyan 1382e0769fe6SDarren Hart /* 1383e0769fe6SDarren Hart * Scan expression. Multiple expressions may be delimited with ; 1384e0769fe6SDarren Hart * NOTE: To keep scanning simple, invalid fields are ignored. 1385b4f9fe12SLen Brown */ 1386b4f9fe12SLen Brown while (remain) { 1387b4f9fe12SLen Brown if (sscanf(buffer, " lcd_out : %i", &value) == 1) 1388b4f9fe12SLen Brown lcd_out = value & 1; 1389b4f9fe12SLen Brown else if (sscanf(buffer, " crt_out : %i", &value) == 1) 1390b4f9fe12SLen Brown crt_out = value & 1; 1391b4f9fe12SLen Brown else if (sscanf(buffer, " tv_out : %i", &value) == 1) 1392b4f9fe12SLen Brown tv_out = value & 1; 1393e0769fe6SDarren Hart /* Advance to one character past the next ; */ 1394b4f9fe12SLen Brown do { 1395b4f9fe12SLen Brown ++buffer; 1396b4f9fe12SLen Brown --remain; 1397b5163992SAzael Avalos } while (remain && *(buffer - 1) != ';'); 1398b4f9fe12SLen Brown } 1399b4f9fe12SLen Brown 1400936c8bcdSAlexey Dobriyan kfree(cmd); 1401936c8bcdSAlexey Dobriyan 140236d03f93SSeth Forshee ret = get_video_status(dev, &video_out); 140336d03f93SSeth Forshee if (!ret) { 1404b4f9fe12SLen Brown unsigned int new_video_out = video_out; 1405b5163992SAzael Avalos 1406b4f9fe12SLen Brown if (lcd_out != -1) 1407b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out); 1408b4f9fe12SLen Brown if (crt_out != -1) 1409b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out); 1410b4f9fe12SLen Brown if (tv_out != -1) 1411b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out); 1412e0769fe6SDarren Hart /* 1413e0769fe6SDarren Hart * To avoid unnecessary video disruption, only write the new 14143f75bbe9SAzael Avalos * video setting if something changed. 14153f75bbe9SAzael Avalos */ 1416b4f9fe12SLen Brown if (new_video_out != video_out) 141732bcd5cbSSeth Forshee ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out); 1418b4f9fe12SLen Brown } 1419b4f9fe12SLen Brown 1420*e1a949c1SAzael Avalos return ret ? -EIO : count; 1421b4f9fe12SLen Brown } 1422b4f9fe12SLen Brown 1423936c8bcdSAlexey Dobriyan static const struct file_operations video_proc_fops = { 1424936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1425936c8bcdSAlexey Dobriyan .open = video_proc_open, 1426936c8bcdSAlexey Dobriyan .read = seq_read, 1427936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1428936c8bcdSAlexey Dobriyan .release = single_release, 1429936c8bcdSAlexey Dobriyan .write = video_proc_write, 1430936c8bcdSAlexey Dobriyan }; 1431936c8bcdSAlexey Dobriyan 14323e07e5baSAzael Avalos /* Fan status */ 143336d03f93SSeth Forshee static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status) 143436d03f93SSeth Forshee { 14353e07e5baSAzael Avalos u32 result = hci_read(dev, HCI_FAN, status); 143636d03f93SSeth Forshee 14373e07e5baSAzael Avalos if (result == TOS_FAILURE) 14383e07e5baSAzael Avalos pr_err("ACPI call to get Fan status failed\n"); 14393e07e5baSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 14403e07e5baSAzael Avalos return -ENODEV; 14413e07e5baSAzael Avalos 1442*e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 14433e07e5baSAzael Avalos } 14443e07e5baSAzael Avalos 14453e07e5baSAzael Avalos static int set_fan_status(struct toshiba_acpi_dev *dev, u32 status) 14463e07e5baSAzael Avalos { 14473e07e5baSAzael Avalos u32 result = hci_write(dev, HCI_FAN, status); 14483e07e5baSAzael Avalos 14493e07e5baSAzael Avalos if (result == TOS_FAILURE) 14503e07e5baSAzael Avalos pr_err("ACPI call to set Fan status failed\n"); 14513e07e5baSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 14523e07e5baSAzael Avalos return -ENODEV; 14533e07e5baSAzael Avalos 1454*e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 145536d03f93SSeth Forshee } 145636d03f93SSeth Forshee 1457936c8bcdSAlexey Dobriyan static int fan_proc_show(struct seq_file *m, void *v) 1458b4f9fe12SLen Brown { 1459135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1460b4f9fe12SLen Brown u32 value; 1461b4f9fe12SLen Brown 14623e07e5baSAzael Avalos if (get_fan_status(dev, &value)) 14633e07e5baSAzael Avalos return -EIO; 14643e07e5baSAzael Avalos 1465936c8bcdSAlexey Dobriyan seq_printf(m, "running: %d\n", (value > 0)); 1466135740deSSeth Forshee seq_printf(m, "force_on: %d\n", dev->force_fan); 1467b4f9fe12SLen Brown 14683e07e5baSAzael Avalos return 0; 1469b4f9fe12SLen Brown } 1470b4f9fe12SLen Brown 1471936c8bcdSAlexey Dobriyan static int fan_proc_open(struct inode *inode, struct file *file) 1472b4f9fe12SLen Brown { 1473d9dda78bSAl Viro return single_open(file, fan_proc_show, PDE_DATA(inode)); 1474936c8bcdSAlexey Dobriyan } 1475936c8bcdSAlexey Dobriyan 1476936c8bcdSAlexey Dobriyan static ssize_t fan_proc_write(struct file *file, const char __user *buf, 1477936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1478936c8bcdSAlexey Dobriyan { 1479d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1480936c8bcdSAlexey Dobriyan char cmd[42]; 1481936c8bcdSAlexey Dobriyan size_t len; 1482b4f9fe12SLen Brown int value; 1483b4f9fe12SLen Brown 1484936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1485936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1486936c8bcdSAlexey Dobriyan return -EFAULT; 1487936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1488936c8bcdSAlexey Dobriyan 14893e07e5baSAzael Avalos if (sscanf(cmd, " force_on : %i", &value) != 1 && 14903e07e5baSAzael Avalos value != 0 && value != 1) 1491b4f9fe12SLen Brown return -EINVAL; 14923e07e5baSAzael Avalos 14933e07e5baSAzael Avalos if (set_fan_status(dev, value)) 14943e07e5baSAzael Avalos return -EIO; 14953e07e5baSAzael Avalos 14963e07e5baSAzael Avalos dev->force_fan = value; 1497b4f9fe12SLen Brown 1498b4f9fe12SLen Brown return count; 1499b4f9fe12SLen Brown } 1500b4f9fe12SLen Brown 1501936c8bcdSAlexey Dobriyan static const struct file_operations fan_proc_fops = { 1502936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1503936c8bcdSAlexey Dobriyan .open = fan_proc_open, 1504936c8bcdSAlexey Dobriyan .read = seq_read, 1505936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1506936c8bcdSAlexey Dobriyan .release = single_release, 1507936c8bcdSAlexey Dobriyan .write = fan_proc_write, 1508936c8bcdSAlexey Dobriyan }; 1509936c8bcdSAlexey Dobriyan 1510936c8bcdSAlexey Dobriyan static int keys_proc_show(struct seq_file *m, void *v) 1511b4f9fe12SLen Brown { 1512135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1513b4f9fe12SLen Brown 1514135740deSSeth Forshee seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid); 1515135740deSSeth Forshee seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event); 15167deef550SAzael Avalos 1517936c8bcdSAlexey Dobriyan return 0; 1518b4f9fe12SLen Brown } 1519b4f9fe12SLen Brown 1520936c8bcdSAlexey Dobriyan static int keys_proc_open(struct inode *inode, struct file *file) 1521b4f9fe12SLen Brown { 1522d9dda78bSAl Viro return single_open(file, keys_proc_show, PDE_DATA(inode)); 1523936c8bcdSAlexey Dobriyan } 1524936c8bcdSAlexey Dobriyan 1525936c8bcdSAlexey Dobriyan static ssize_t keys_proc_write(struct file *file, const char __user *buf, 1526936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1527936c8bcdSAlexey Dobriyan { 1528d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1529936c8bcdSAlexey Dobriyan char cmd[42]; 1530936c8bcdSAlexey Dobriyan size_t len; 1531b4f9fe12SLen Brown int value; 1532b4f9fe12SLen Brown 1533936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1534936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1535936c8bcdSAlexey Dobriyan return -EFAULT; 1536936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1537936c8bcdSAlexey Dobriyan 1538b5163992SAzael Avalos if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) 1539135740deSSeth Forshee dev->key_event_valid = 0; 1540b5163992SAzael Avalos else 1541b4f9fe12SLen Brown return -EINVAL; 1542b4f9fe12SLen Brown 1543b4f9fe12SLen Brown return count; 1544b4f9fe12SLen Brown } 1545b4f9fe12SLen Brown 1546936c8bcdSAlexey Dobriyan static const struct file_operations keys_proc_fops = { 1547936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1548936c8bcdSAlexey Dobriyan .open = keys_proc_open, 1549936c8bcdSAlexey Dobriyan .read = seq_read, 1550936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1551936c8bcdSAlexey Dobriyan .release = single_release, 1552936c8bcdSAlexey Dobriyan .write = keys_proc_write, 1553936c8bcdSAlexey Dobriyan }; 1554936c8bcdSAlexey Dobriyan 1555936c8bcdSAlexey Dobriyan static int version_proc_show(struct seq_file *m, void *v) 1556b4f9fe12SLen Brown { 1557936c8bcdSAlexey Dobriyan seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION); 1558936c8bcdSAlexey Dobriyan seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION); 1559936c8bcdSAlexey Dobriyan return 0; 1560b4f9fe12SLen Brown } 1561b4f9fe12SLen Brown 1562936c8bcdSAlexey Dobriyan static int version_proc_open(struct inode *inode, struct file *file) 1563936c8bcdSAlexey Dobriyan { 1564d9dda78bSAl Viro return single_open(file, version_proc_show, PDE_DATA(inode)); 1565936c8bcdSAlexey Dobriyan } 1566936c8bcdSAlexey Dobriyan 1567936c8bcdSAlexey Dobriyan static const struct file_operations version_proc_fops = { 1568936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1569936c8bcdSAlexey Dobriyan .open = version_proc_open, 1570936c8bcdSAlexey Dobriyan .read = seq_read, 1571936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1572936c8bcdSAlexey Dobriyan .release = single_release, 1573936c8bcdSAlexey Dobriyan }; 1574936c8bcdSAlexey Dobriyan 1575e0769fe6SDarren Hart /* 1576e0769fe6SDarren Hart * Proc and module init 1577b4f9fe12SLen Brown */ 1578b4f9fe12SLen Brown 1579b4f9fe12SLen Brown #define PROC_TOSHIBA "toshiba" 1580b4f9fe12SLen Brown 1581b859f159SGreg Kroah-Hartman static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1582b4f9fe12SLen Brown { 158336d03f93SSeth Forshee if (dev->backlight_dev) 1584135740deSSeth Forshee proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1585135740deSSeth Forshee &lcd_proc_fops, dev); 158636d03f93SSeth Forshee if (dev->video_supported) 1587135740deSSeth Forshee proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1588135740deSSeth Forshee &video_proc_fops, dev); 158936d03f93SSeth Forshee if (dev->fan_supported) 1590135740deSSeth Forshee proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1591135740deSSeth Forshee &fan_proc_fops, dev); 159236d03f93SSeth Forshee if (dev->hotkey_dev) 1593135740deSSeth Forshee proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1594135740deSSeth Forshee &keys_proc_fops, dev); 1595135740deSSeth Forshee proc_create_data("version", S_IRUGO, toshiba_proc_dir, 1596135740deSSeth Forshee &version_proc_fops, dev); 1597b4f9fe12SLen Brown } 1598b4f9fe12SLen Brown 159936d03f93SSeth Forshee static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1600b4f9fe12SLen Brown { 160136d03f93SSeth Forshee if (dev->backlight_dev) 1602936c8bcdSAlexey Dobriyan remove_proc_entry("lcd", toshiba_proc_dir); 160336d03f93SSeth Forshee if (dev->video_supported) 1604936c8bcdSAlexey Dobriyan remove_proc_entry("video", toshiba_proc_dir); 160536d03f93SSeth Forshee if (dev->fan_supported) 1606936c8bcdSAlexey Dobriyan remove_proc_entry("fan", toshiba_proc_dir); 160736d03f93SSeth Forshee if (dev->hotkey_dev) 1608936c8bcdSAlexey Dobriyan remove_proc_entry("keys", toshiba_proc_dir); 1609936c8bcdSAlexey Dobriyan remove_proc_entry("version", toshiba_proc_dir); 1610b4f9fe12SLen Brown } 1611b4f9fe12SLen Brown 1612acc2472eSLionel Debroux static const struct backlight_ops toshiba_backlight_data = { 1613121b7b0dSAkio Idehara .options = BL_CORE_SUSPENDRESUME, 161462cce752SSeth Forshee .get_brightness = get_lcd_brightness, 1615b4f9fe12SLen Brown .update_status = set_lcd_status, 1616b4f9fe12SLen Brown }; 1617b4f9fe12SLen Brown 1618360f0f39SAzael Avalos /* 1619360f0f39SAzael Avalos * Sysfs files 1620360f0f39SAzael Avalos */ 16219d309848SAzael Avalos static ssize_t version_show(struct device *dev, 1622c6c68ff8SAzael Avalos struct device_attribute *attr, char *buf) 1623c6c68ff8SAzael Avalos { 1624c6c68ff8SAzael Avalos return sprintf(buf, "%s\n", TOSHIBA_ACPI_VERSION); 1625c6c68ff8SAzael Avalos } 16260c3c0f10SAzael Avalos static DEVICE_ATTR_RO(version); 1627c6c68ff8SAzael Avalos 16289d309848SAzael Avalos static ssize_t fan_store(struct device *dev, 162994477d4cSAzael Avalos struct device_attribute *attr, 163094477d4cSAzael Avalos const char *buf, size_t count) 163194477d4cSAzael Avalos { 163294477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 163394477d4cSAzael Avalos int state; 163494477d4cSAzael Avalos int ret; 163594477d4cSAzael Avalos 163694477d4cSAzael Avalos ret = kstrtoint(buf, 0, &state); 163794477d4cSAzael Avalos if (ret) 163894477d4cSAzael Avalos return ret; 163994477d4cSAzael Avalos 164094477d4cSAzael Avalos if (state != 0 && state != 1) 164194477d4cSAzael Avalos return -EINVAL; 164294477d4cSAzael Avalos 16433e07e5baSAzael Avalos ret = set_fan_status(toshiba, state); 16443e07e5baSAzael Avalos if (ret) 16453e07e5baSAzael Avalos return ret; 164694477d4cSAzael Avalos 164794477d4cSAzael Avalos return count; 164894477d4cSAzael Avalos } 164994477d4cSAzael Avalos 16509d309848SAzael Avalos static ssize_t fan_show(struct device *dev, 165194477d4cSAzael Avalos struct device_attribute *attr, char *buf) 165294477d4cSAzael Avalos { 165394477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 165494477d4cSAzael Avalos u32 value; 165594477d4cSAzael Avalos int ret; 165694477d4cSAzael Avalos 165794477d4cSAzael Avalos ret = get_fan_status(toshiba, &value); 165894477d4cSAzael Avalos if (ret) 165994477d4cSAzael Avalos return ret; 166094477d4cSAzael Avalos 166194477d4cSAzael Avalos return sprintf(buf, "%d\n", value); 166294477d4cSAzael Avalos } 16630c3c0f10SAzael Avalos static DEVICE_ATTR_RW(fan); 166494477d4cSAzael Avalos 16659d309848SAzael Avalos static ssize_t kbd_backlight_mode_store(struct device *dev, 1666360f0f39SAzael Avalos struct device_attribute *attr, 1667360f0f39SAzael Avalos const char *buf, size_t count) 1668360f0f39SAzael Avalos { 1669360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1670aeaac098SDan Carpenter int mode; 1671aeaac098SDan Carpenter int ret; 1672360f0f39SAzael Avalos 1673aeaac098SDan Carpenter 1674aeaac098SDan Carpenter ret = kstrtoint(buf, 0, &mode); 1675aeaac098SDan Carpenter if (ret) 1676aeaac098SDan Carpenter return ret; 167793f8c16dSAzael Avalos 167893f8c16dSAzael Avalos /* Check for supported modes depending on keyboard backlight type */ 167993f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 168093f8c16dSAzael Avalos /* Type 1 supports SCI_KBD_MODE_FNZ and SCI_KBD_MODE_AUTO */ 1681aeaac098SDan Carpenter if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO) 1682360f0f39SAzael Avalos return -EINVAL; 168393f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 168493f8c16dSAzael Avalos /* Type 2 doesn't support SCI_KBD_MODE_FNZ */ 168593f8c16dSAzael Avalos if (mode != SCI_KBD_MODE_AUTO && mode != SCI_KBD_MODE_ON && 168693f8c16dSAzael Avalos mode != SCI_KBD_MODE_OFF) 168793f8c16dSAzael Avalos return -EINVAL; 168893f8c16dSAzael Avalos } 1689360f0f39SAzael Avalos 1690e0769fe6SDarren Hart /* 1691e0769fe6SDarren Hart * Set the Keyboard Backlight Mode where: 1692360f0f39SAzael Avalos * Auto - KBD backlight turns off automatically in given time 1693360f0f39SAzael Avalos * FN-Z - KBD backlight "toggles" when hotkey pressed 169493f8c16dSAzael Avalos * ON - KBD backlight is always on 169593f8c16dSAzael Avalos * OFF - KBD backlight is always off 1696360f0f39SAzael Avalos */ 169793f8c16dSAzael Avalos 169893f8c16dSAzael Avalos /* Only make a change if the actual mode has changed */ 1699aeaac098SDan Carpenter if (toshiba->kbd_mode != mode) { 170093f8c16dSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 17011e574dbfSAzael Avalos int time = toshiba->kbd_time << HCI_MISC_SHIFT; 170293f8c16dSAzael Avalos 170393f8c16dSAzael Avalos /* OR the "base time" to the actual method format */ 170493f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 170593f8c16dSAzael Avalos /* Type 1 requires the current mode */ 170693f8c16dSAzael Avalos time |= toshiba->kbd_mode; 170793f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 170893f8c16dSAzael Avalos /* Type 2 requires the desired mode */ 170993f8c16dSAzael Avalos time |= mode; 171093f8c16dSAzael Avalos } 171193f8c16dSAzael Avalos 1712aeaac098SDan Carpenter ret = toshiba_kbd_illum_status_set(toshiba, time); 1713aeaac098SDan Carpenter if (ret) 1714aeaac098SDan Carpenter return ret; 171593f8c16dSAzael Avalos 1716360f0f39SAzael Avalos toshiba->kbd_mode = mode; 1717360f0f39SAzael Avalos } 1718360f0f39SAzael Avalos 1719360f0f39SAzael Avalos return count; 1720360f0f39SAzael Avalos } 1721360f0f39SAzael Avalos 17229d309848SAzael Avalos static ssize_t kbd_backlight_mode_show(struct device *dev, 1723360f0f39SAzael Avalos struct device_attribute *attr, 1724360f0f39SAzael Avalos char *buf) 1725360f0f39SAzael Avalos { 1726360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1727360f0f39SAzael Avalos u32 time; 1728360f0f39SAzael Avalos 1729360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1730360f0f39SAzael Avalos return -EIO; 1731360f0f39SAzael Avalos 173293f8c16dSAzael Avalos return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK); 173393f8c16dSAzael Avalos } 17340c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_mode); 173593f8c16dSAzael Avalos 17369d309848SAzael Avalos static ssize_t kbd_type_show(struct device *dev, 17379d309848SAzael Avalos struct device_attribute *attr, char *buf) 173893f8c16dSAzael Avalos { 173993f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 174093f8c16dSAzael Avalos 174193f8c16dSAzael Avalos return sprintf(buf, "%d\n", toshiba->kbd_type); 174293f8c16dSAzael Avalos } 17430c3c0f10SAzael Avalos static DEVICE_ATTR_RO(kbd_type); 174493f8c16dSAzael Avalos 17459d309848SAzael Avalos static ssize_t available_kbd_modes_show(struct device *dev, 174693f8c16dSAzael Avalos struct device_attribute *attr, 174793f8c16dSAzael Avalos char *buf) 174893f8c16dSAzael Avalos { 174993f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 175093f8c16dSAzael Avalos 175193f8c16dSAzael Avalos if (toshiba->kbd_type == 1) 175293f8c16dSAzael Avalos return sprintf(buf, "%x %x\n", 175393f8c16dSAzael Avalos SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO); 175493f8c16dSAzael Avalos 175593f8c16dSAzael Avalos return sprintf(buf, "%x %x %x\n", 175693f8c16dSAzael Avalos SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF); 1757360f0f39SAzael Avalos } 17580c3c0f10SAzael Avalos static DEVICE_ATTR_RO(available_kbd_modes); 1759360f0f39SAzael Avalos 17609d309848SAzael Avalos static ssize_t kbd_backlight_timeout_store(struct device *dev, 1761360f0f39SAzael Avalos struct device_attribute *attr, 1762360f0f39SAzael Avalos const char *buf, size_t count) 1763360f0f39SAzael Avalos { 1764360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1765eabde0faSAzael Avalos int time; 1766eabde0faSAzael Avalos int ret; 1767360f0f39SAzael Avalos 1768eabde0faSAzael Avalos ret = kstrtoint(buf, 0, &time); 1769eabde0faSAzael Avalos if (ret) 1770eabde0faSAzael Avalos return ret; 1771eabde0faSAzael Avalos 1772eabde0faSAzael Avalos /* Check for supported values depending on kbd_type */ 1773eabde0faSAzael Avalos if (toshiba->kbd_type == 1) { 1774eabde0faSAzael Avalos if (time < 0 || time > 60) 1775360f0f39SAzael Avalos return -EINVAL; 1776eabde0faSAzael Avalos } else if (toshiba->kbd_type == 2) { 1777eabde0faSAzael Avalos if (time < 1 || time > 60) 1778eabde0faSAzael Avalos return -EINVAL; 1779eabde0faSAzael Avalos } 1780360f0f39SAzael Avalos 1781eabde0faSAzael Avalos /* Set the Keyboard Backlight Timeout */ 1782eabde0faSAzael Avalos 1783eabde0faSAzael Avalos /* Only make a change if the actual timeout has changed */ 1784eabde0faSAzael Avalos if (toshiba->kbd_time != time) { 1785eabde0faSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 1786360f0f39SAzael Avalos time = time << HCI_MISC_SHIFT; 1787eabde0faSAzael Avalos /* OR the "base time" to the actual method format */ 1788eabde0faSAzael Avalos if (toshiba->kbd_type == 1) 1789eabde0faSAzael Avalos time |= SCI_KBD_MODE_FNZ; 1790eabde0faSAzael Avalos else if (toshiba->kbd_type == 2) 1791eabde0faSAzael Avalos time |= SCI_KBD_MODE_AUTO; 1792eabde0faSAzael Avalos 1793eabde0faSAzael Avalos ret = toshiba_kbd_illum_status_set(toshiba, time); 1794eabde0faSAzael Avalos if (ret) 1795eabde0faSAzael Avalos return ret; 1796eabde0faSAzael Avalos 1797360f0f39SAzael Avalos toshiba->kbd_time = time >> HCI_MISC_SHIFT; 1798360f0f39SAzael Avalos } 1799360f0f39SAzael Avalos 1800360f0f39SAzael Avalos return count; 1801360f0f39SAzael Avalos } 1802360f0f39SAzael Avalos 18039d309848SAzael Avalos static ssize_t kbd_backlight_timeout_show(struct device *dev, 1804360f0f39SAzael Avalos struct device_attribute *attr, 1805360f0f39SAzael Avalos char *buf) 1806360f0f39SAzael Avalos { 1807360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1808360f0f39SAzael Avalos u32 time; 1809360f0f39SAzael Avalos 1810360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1811360f0f39SAzael Avalos return -EIO; 1812360f0f39SAzael Avalos 1813360f0f39SAzael Avalos return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT); 1814360f0f39SAzael Avalos } 18150c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_timeout); 1816360f0f39SAzael Avalos 18179d309848SAzael Avalos static ssize_t touchpad_store(struct device *dev, 18189d8658acSAzael Avalos struct device_attribute *attr, 18199d8658acSAzael Avalos const char *buf, size_t count) 18209d8658acSAzael Avalos { 18219d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 18229d8658acSAzael Avalos int state; 1823c8a41669SAzael Avalos int ret; 18249d8658acSAzael Avalos 18259d8658acSAzael Avalos /* Set the TouchPad on/off, 0 - Disable | 1 - Enable */ 1826c8a41669SAzael Avalos ret = kstrtoint(buf, 0, &state); 1827c8a41669SAzael Avalos if (ret) 1828c8a41669SAzael Avalos return ret; 1829c8a41669SAzael Avalos if (state != 0 && state != 1) 1830c8a41669SAzael Avalos return -EINVAL; 1831c8a41669SAzael Avalos 1832c8a41669SAzael Avalos ret = toshiba_touchpad_set(toshiba, state); 1833c8a41669SAzael Avalos if (ret) 1834c8a41669SAzael Avalos return ret; 18359d8658acSAzael Avalos 18369d8658acSAzael Avalos return count; 18379d8658acSAzael Avalos } 18389d8658acSAzael Avalos 18399d309848SAzael Avalos static ssize_t touchpad_show(struct device *dev, 18409d8658acSAzael Avalos struct device_attribute *attr, char *buf) 18419d8658acSAzael Avalos { 18429d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 18439d8658acSAzael Avalos u32 state; 18449d8658acSAzael Avalos int ret; 18459d8658acSAzael Avalos 18469d8658acSAzael Avalos ret = toshiba_touchpad_get(toshiba, &state); 18479d8658acSAzael Avalos if (ret < 0) 18489d8658acSAzael Avalos return ret; 18499d8658acSAzael Avalos 18509d8658acSAzael Avalos return sprintf(buf, "%i\n", state); 18519d8658acSAzael Avalos } 18520c3c0f10SAzael Avalos static DEVICE_ATTR_RW(touchpad); 18539d8658acSAzael Avalos 18549d309848SAzael Avalos static ssize_t position_show(struct device *dev, 18555a2813e9SAzael Avalos struct device_attribute *attr, char *buf) 18565a2813e9SAzael Avalos { 18575a2813e9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 18585a2813e9SAzael Avalos u32 xyval, zval, tmp; 18595a2813e9SAzael Avalos u16 x, y, z; 18605a2813e9SAzael Avalos int ret; 18615a2813e9SAzael Avalos 18625a2813e9SAzael Avalos xyval = zval = 0; 18635a2813e9SAzael Avalos ret = toshiba_accelerometer_get(toshiba, &xyval, &zval); 18645a2813e9SAzael Avalos if (ret < 0) 18655a2813e9SAzael Avalos return ret; 18665a2813e9SAzael Avalos 18675a2813e9SAzael Avalos x = xyval & HCI_ACCEL_MASK; 18685a2813e9SAzael Avalos tmp = xyval >> HCI_MISC_SHIFT; 18695a2813e9SAzael Avalos y = tmp & HCI_ACCEL_MASK; 18705a2813e9SAzael Avalos z = zval & HCI_ACCEL_MASK; 18715a2813e9SAzael Avalos 18725a2813e9SAzael Avalos return sprintf(buf, "%d %d %d\n", x, y, z); 18735a2813e9SAzael Avalos } 18740c3c0f10SAzael Avalos static DEVICE_ATTR_RO(position); 18755a2813e9SAzael Avalos 18769d309848SAzael Avalos static ssize_t usb_sleep_charge_show(struct device *dev, 18779d309848SAzael Avalos struct device_attribute *attr, char *buf) 1878e26ffe51SAzael Avalos { 1879e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1880e26ffe51SAzael Avalos u32 mode; 1881e26ffe51SAzael Avalos int ret; 1882e26ffe51SAzael Avalos 1883e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_get(toshiba, &mode); 1884e26ffe51SAzael Avalos if (ret < 0) 1885e26ffe51SAzael Avalos return ret; 1886e26ffe51SAzael Avalos 1887e26ffe51SAzael Avalos return sprintf(buf, "%x\n", mode & SCI_USB_CHARGE_MODE_MASK); 1888e26ffe51SAzael Avalos } 1889e26ffe51SAzael Avalos 18909d309848SAzael Avalos static ssize_t usb_sleep_charge_store(struct device *dev, 1891e26ffe51SAzael Avalos struct device_attribute *attr, 1892e26ffe51SAzael Avalos const char *buf, size_t count) 1893e26ffe51SAzael Avalos { 1894e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1895e26ffe51SAzael Avalos u32 mode; 1896e26ffe51SAzael Avalos int state; 1897e26ffe51SAzael Avalos int ret; 1898e26ffe51SAzael Avalos 1899e26ffe51SAzael Avalos ret = kstrtoint(buf, 0, &state); 1900e26ffe51SAzael Avalos if (ret) 1901e26ffe51SAzael Avalos return ret; 1902e0769fe6SDarren Hart /* 1903e0769fe6SDarren Hart * Check for supported values, where: 1904e26ffe51SAzael Avalos * 0 - Disabled 1905e26ffe51SAzael Avalos * 1 - Alternate (Non USB conformant devices that require more power) 1906e26ffe51SAzael Avalos * 2 - Auto (USB conformant devices) 1907c8c91842SAzael Avalos * 3 - Typical 1908e26ffe51SAzael Avalos */ 1909c8c91842SAzael Avalos if (state != 0 && state != 1 && state != 2 && state != 3) 1910e26ffe51SAzael Avalos return -EINVAL; 1911e26ffe51SAzael Avalos 1912e26ffe51SAzael Avalos /* Set the USB charging mode to internal value */ 1913c8c91842SAzael Avalos mode = toshiba->usbsc_mode_base; 1914e26ffe51SAzael Avalos if (state == 0) 1915c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_DISABLED; 1916e26ffe51SAzael Avalos else if (state == 1) 1917c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_ALTERNATE; 1918e26ffe51SAzael Avalos else if (state == 2) 1919c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_AUTO; 1920c8c91842SAzael Avalos else if (state == 3) 1921c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_TYPICAL; 1922e26ffe51SAzael Avalos 1923e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_set(toshiba, mode); 1924e26ffe51SAzael Avalos if (ret) 1925e26ffe51SAzael Avalos return ret; 1926e26ffe51SAzael Avalos 1927e26ffe51SAzael Avalos return count; 1928e26ffe51SAzael Avalos } 19290c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_charge); 1930e26ffe51SAzael Avalos 1931182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_show(struct device *dev, 1932182bcaa5SAzael Avalos struct device_attribute *attr, 1933182bcaa5SAzael Avalos char *buf) 1934182bcaa5SAzael Avalos { 1935182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1936182bcaa5SAzael Avalos u32 state; 1937182bcaa5SAzael Avalos int bat_lvl; 1938182bcaa5SAzael Avalos int status; 1939182bcaa5SAzael Avalos int ret; 1940182bcaa5SAzael Avalos int tmp; 1941182bcaa5SAzael Avalos 1942182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_get(toshiba, &state); 1943182bcaa5SAzael Avalos if (ret < 0) 1944182bcaa5SAzael Avalos return ret; 1945182bcaa5SAzael Avalos 1946182bcaa5SAzael Avalos /* Determine the status: 0x4 - Enabled | 0x1 - Disabled */ 1947182bcaa5SAzael Avalos tmp = state & SCI_USB_CHARGE_BAT_MASK; 1948182bcaa5SAzael Avalos status = (tmp == 0x4) ? 1 : 0; 1949182bcaa5SAzael Avalos /* Determine the battery level set */ 1950182bcaa5SAzael Avalos bat_lvl = state >> HCI_MISC_SHIFT; 1951182bcaa5SAzael Avalos 1952182bcaa5SAzael Avalos return sprintf(buf, "%d %d\n", status, bat_lvl); 1953182bcaa5SAzael Avalos } 1954182bcaa5SAzael Avalos 1955182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_store(struct device *dev, 1956182bcaa5SAzael Avalos struct device_attribute *attr, 1957182bcaa5SAzael Avalos const char *buf, size_t count) 1958182bcaa5SAzael Avalos { 1959182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1960182bcaa5SAzael Avalos u32 status; 1961182bcaa5SAzael Avalos int value; 1962182bcaa5SAzael Avalos int ret; 1963182bcaa5SAzael Avalos int tmp; 1964182bcaa5SAzael Avalos 1965182bcaa5SAzael Avalos ret = kstrtoint(buf, 0, &value); 1966182bcaa5SAzael Avalos if (ret) 1967182bcaa5SAzael Avalos return ret; 1968182bcaa5SAzael Avalos 1969e0769fe6SDarren Hart /* 1970e0769fe6SDarren Hart * Set the status of the function: 1971182bcaa5SAzael Avalos * 0 - Disabled 1972182bcaa5SAzael Avalos * 1-100 - Enabled 1973182bcaa5SAzael Avalos */ 1974182bcaa5SAzael Avalos if (value < 0 || value > 100) 1975182bcaa5SAzael Avalos return -EINVAL; 1976182bcaa5SAzael Avalos 1977182bcaa5SAzael Avalos if (value == 0) { 1978182bcaa5SAzael Avalos tmp = toshiba->usbsc_bat_level << HCI_MISC_SHIFT; 1979182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_OFF; 1980182bcaa5SAzael Avalos } else { 1981182bcaa5SAzael Avalos tmp = value << HCI_MISC_SHIFT; 1982182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_ON; 1983182bcaa5SAzael Avalos } 1984182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_set(toshiba, status); 1985182bcaa5SAzael Avalos if (ret < 0) 1986182bcaa5SAzael Avalos return ret; 1987182bcaa5SAzael Avalos 1988182bcaa5SAzael Avalos toshiba->usbsc_bat_level = status >> HCI_MISC_SHIFT; 1989182bcaa5SAzael Avalos 1990182bcaa5SAzael Avalos return count; 1991182bcaa5SAzael Avalos } 19920c3c0f10SAzael Avalos static DEVICE_ATTR_RW(sleep_functions_on_battery); 1993182bcaa5SAzael Avalos 19949d309848SAzael Avalos static ssize_t usb_rapid_charge_show(struct device *dev, 19959d309848SAzael Avalos struct device_attribute *attr, char *buf) 1996bb3fe01fSAzael Avalos { 1997bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1998bb3fe01fSAzael Avalos u32 state; 1999bb3fe01fSAzael Avalos int ret; 2000bb3fe01fSAzael Avalos 2001bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(toshiba, &state); 2002bb3fe01fSAzael Avalos if (ret < 0) 2003bb3fe01fSAzael Avalos return ret; 2004bb3fe01fSAzael Avalos 2005bb3fe01fSAzael Avalos return sprintf(buf, "%d\n", state); 2006bb3fe01fSAzael Avalos } 2007bb3fe01fSAzael Avalos 20089d309848SAzael Avalos static ssize_t usb_rapid_charge_store(struct device *dev, 2009bb3fe01fSAzael Avalos struct device_attribute *attr, 2010bb3fe01fSAzael Avalos const char *buf, size_t count) 2011bb3fe01fSAzael Avalos { 2012bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2013bb3fe01fSAzael Avalos int state; 2014bb3fe01fSAzael Avalos int ret; 2015bb3fe01fSAzael Avalos 2016bb3fe01fSAzael Avalos ret = kstrtoint(buf, 0, &state); 2017bb3fe01fSAzael Avalos if (ret) 2018bb3fe01fSAzael Avalos return ret; 2019bb3fe01fSAzael Avalos if (state != 0 && state != 1) 2020bb3fe01fSAzael Avalos return -EINVAL; 2021bb3fe01fSAzael Avalos 2022bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_set(toshiba, state); 2023bb3fe01fSAzael Avalos if (ret) 2024bb3fe01fSAzael Avalos return ret; 2025bb3fe01fSAzael Avalos 2026bb3fe01fSAzael Avalos return count; 2027bb3fe01fSAzael Avalos } 20280c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_rapid_charge); 2029bb3fe01fSAzael Avalos 20309d309848SAzael Avalos static ssize_t usb_sleep_music_show(struct device *dev, 20319d309848SAzael Avalos struct device_attribute *attr, char *buf) 2032172ce0a9SAzael Avalos { 2033172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2034172ce0a9SAzael Avalos u32 state; 2035172ce0a9SAzael Avalos int ret; 2036172ce0a9SAzael Avalos 2037172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(toshiba, &state); 2038172ce0a9SAzael Avalos if (ret < 0) 2039172ce0a9SAzael Avalos return ret; 2040172ce0a9SAzael Avalos 2041172ce0a9SAzael Avalos return sprintf(buf, "%d\n", state); 2042172ce0a9SAzael Avalos } 2043172ce0a9SAzael Avalos 20449d309848SAzael Avalos static ssize_t usb_sleep_music_store(struct device *dev, 2045172ce0a9SAzael Avalos struct device_attribute *attr, 2046172ce0a9SAzael Avalos const char *buf, size_t count) 2047172ce0a9SAzael Avalos { 2048172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2049172ce0a9SAzael Avalos int state; 2050172ce0a9SAzael Avalos int ret; 2051172ce0a9SAzael Avalos 2052172ce0a9SAzael Avalos ret = kstrtoint(buf, 0, &state); 2053172ce0a9SAzael Avalos if (ret) 2054172ce0a9SAzael Avalos return ret; 2055172ce0a9SAzael Avalos if (state != 0 && state != 1) 2056172ce0a9SAzael Avalos return -EINVAL; 2057172ce0a9SAzael Avalos 2058172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_set(toshiba, state); 2059172ce0a9SAzael Avalos if (ret) 2060172ce0a9SAzael Avalos return ret; 2061172ce0a9SAzael Avalos 2062172ce0a9SAzael Avalos return count; 2063172ce0a9SAzael Avalos } 20640c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_music); 2065172ce0a9SAzael Avalos 20669d309848SAzael Avalos static ssize_t kbd_function_keys_show(struct device *dev, 20679d309848SAzael Avalos struct device_attribute *attr, char *buf) 2068bae84195SAzael Avalos { 2069bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2070bae84195SAzael Avalos int mode; 2071bae84195SAzael Avalos int ret; 2072bae84195SAzael Avalos 2073bae84195SAzael Avalos ret = toshiba_function_keys_get(toshiba, &mode); 2074bae84195SAzael Avalos if (ret < 0) 2075bae84195SAzael Avalos return ret; 2076bae84195SAzael Avalos 2077bae84195SAzael Avalos return sprintf(buf, "%d\n", mode); 2078bae84195SAzael Avalos } 2079bae84195SAzael Avalos 20809d309848SAzael Avalos static ssize_t kbd_function_keys_store(struct device *dev, 2081bae84195SAzael Avalos struct device_attribute *attr, 2082bae84195SAzael Avalos const char *buf, size_t count) 2083bae84195SAzael Avalos { 2084bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2085bae84195SAzael Avalos int mode; 2086bae84195SAzael Avalos int ret; 2087bae84195SAzael Avalos 2088bae84195SAzael Avalos ret = kstrtoint(buf, 0, &mode); 2089bae84195SAzael Avalos if (ret) 2090bae84195SAzael Avalos return ret; 2091e0769fe6SDarren Hart /* 2092e0769fe6SDarren Hart * Check for the function keys mode where: 2093bae84195SAzael Avalos * 0 - Normal operation (F{1-12} as usual and hotkeys via FN-F{1-12}) 2094bae84195SAzael Avalos * 1 - Special functions (Opposite of the above setting) 2095bae84195SAzael Avalos */ 2096bae84195SAzael Avalos if (mode != 0 && mode != 1) 2097bae84195SAzael Avalos return -EINVAL; 2098bae84195SAzael Avalos 2099bae84195SAzael Avalos ret = toshiba_function_keys_set(toshiba, mode); 2100bae84195SAzael Avalos if (ret) 2101bae84195SAzael Avalos return ret; 2102bae84195SAzael Avalos 2103bae84195SAzael Avalos pr_info("Reboot for changes to KBD Function Keys to take effect"); 2104bae84195SAzael Avalos 2105bae84195SAzael Avalos return count; 2106bae84195SAzael Avalos } 21070c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_function_keys); 2108bae84195SAzael Avalos 21099d309848SAzael Avalos static ssize_t panel_power_on_show(struct device *dev, 21109d309848SAzael Avalos struct device_attribute *attr, char *buf) 211135d53ceaSAzael Avalos { 211235d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 211335d53ceaSAzael Avalos u32 state; 211435d53ceaSAzael Avalos int ret; 211535d53ceaSAzael Avalos 211635d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(toshiba, &state); 211735d53ceaSAzael Avalos if (ret < 0) 211835d53ceaSAzael Avalos return ret; 211935d53ceaSAzael Avalos 212035d53ceaSAzael Avalos return sprintf(buf, "%d\n", state); 212135d53ceaSAzael Avalos } 212235d53ceaSAzael Avalos 21239d309848SAzael Avalos static ssize_t panel_power_on_store(struct device *dev, 212435d53ceaSAzael Avalos struct device_attribute *attr, 212535d53ceaSAzael Avalos const char *buf, size_t count) 212635d53ceaSAzael Avalos { 212735d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 212835d53ceaSAzael Avalos int state; 212935d53ceaSAzael Avalos int ret; 213035d53ceaSAzael Avalos 213135d53ceaSAzael Avalos ret = kstrtoint(buf, 0, &state); 213235d53ceaSAzael Avalos if (ret) 213335d53ceaSAzael Avalos return ret; 213435d53ceaSAzael Avalos if (state != 0 && state != 1) 213535d53ceaSAzael Avalos return -EINVAL; 213635d53ceaSAzael Avalos 213735d53ceaSAzael Avalos ret = toshiba_panel_power_on_set(toshiba, state); 213835d53ceaSAzael Avalos if (ret) 213935d53ceaSAzael Avalos return ret; 214035d53ceaSAzael Avalos 214135d53ceaSAzael Avalos pr_info("Reboot for changes to Panel Power ON to take effect"); 214235d53ceaSAzael Avalos 214335d53ceaSAzael Avalos return count; 214435d53ceaSAzael Avalos } 21450c3c0f10SAzael Avalos static DEVICE_ATTR_RW(panel_power_on); 214635d53ceaSAzael Avalos 21479d309848SAzael Avalos static ssize_t usb_three_show(struct device *dev, 21489d309848SAzael Avalos struct device_attribute *attr, char *buf) 214917fe4b3dSAzael Avalos { 215017fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 215117fe4b3dSAzael Avalos u32 state; 215217fe4b3dSAzael Avalos int ret; 215317fe4b3dSAzael Avalos 215417fe4b3dSAzael Avalos ret = toshiba_usb_three_get(toshiba, &state); 215517fe4b3dSAzael Avalos if (ret < 0) 215617fe4b3dSAzael Avalos return ret; 215717fe4b3dSAzael Avalos 215817fe4b3dSAzael Avalos return sprintf(buf, "%d\n", state); 215917fe4b3dSAzael Avalos } 216017fe4b3dSAzael Avalos 21619d309848SAzael Avalos static ssize_t usb_three_store(struct device *dev, 216217fe4b3dSAzael Avalos struct device_attribute *attr, 216317fe4b3dSAzael Avalos const char *buf, size_t count) 216417fe4b3dSAzael Avalos { 216517fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 216617fe4b3dSAzael Avalos int state; 216717fe4b3dSAzael Avalos int ret; 216817fe4b3dSAzael Avalos 216917fe4b3dSAzael Avalos ret = kstrtoint(buf, 0, &state); 217017fe4b3dSAzael Avalos if (ret) 217117fe4b3dSAzael Avalos return ret; 2172e0769fe6SDarren Hart /* 2173e0769fe6SDarren Hart * Check for USB 3 mode where: 217417fe4b3dSAzael Avalos * 0 - Disabled (Acts like a USB 2 port, saving power) 217517fe4b3dSAzael Avalos * 1 - Enabled 217617fe4b3dSAzael Avalos */ 217717fe4b3dSAzael Avalos if (state != 0 && state != 1) 217817fe4b3dSAzael Avalos return -EINVAL; 217917fe4b3dSAzael Avalos 218017fe4b3dSAzael Avalos ret = toshiba_usb_three_set(toshiba, state); 218117fe4b3dSAzael Avalos if (ret) 218217fe4b3dSAzael Avalos return ret; 218317fe4b3dSAzael Avalos 218417fe4b3dSAzael Avalos pr_info("Reboot for changes to USB 3 to take effect"); 218517fe4b3dSAzael Avalos 218617fe4b3dSAzael Avalos return count; 218717fe4b3dSAzael Avalos } 21880c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_three); 21899bd1213bSAzael Avalos 21909bd1213bSAzael Avalos static struct attribute *toshiba_attributes[] = { 21919bd1213bSAzael Avalos &dev_attr_version.attr, 21929bd1213bSAzael Avalos &dev_attr_fan.attr, 21939bd1213bSAzael Avalos &dev_attr_kbd_backlight_mode.attr, 21949bd1213bSAzael Avalos &dev_attr_kbd_type.attr, 21959bd1213bSAzael Avalos &dev_attr_available_kbd_modes.attr, 21969bd1213bSAzael Avalos &dev_attr_kbd_backlight_timeout.attr, 21979bd1213bSAzael Avalos &dev_attr_touchpad.attr, 21989bd1213bSAzael Avalos &dev_attr_position.attr, 21999bd1213bSAzael Avalos &dev_attr_usb_sleep_charge.attr, 22009bd1213bSAzael Avalos &dev_attr_sleep_functions_on_battery.attr, 22019bd1213bSAzael Avalos &dev_attr_usb_rapid_charge.attr, 22029bd1213bSAzael Avalos &dev_attr_usb_sleep_music.attr, 22039bd1213bSAzael Avalos &dev_attr_kbd_function_keys.attr, 22049bd1213bSAzael Avalos &dev_attr_panel_power_on.attr, 22059bd1213bSAzael Avalos &dev_attr_usb_three.attr, 22069bd1213bSAzael Avalos NULL, 22079bd1213bSAzael Avalos }; 22089bd1213bSAzael Avalos 2209360f0f39SAzael Avalos static umode_t toshiba_sysfs_is_visible(struct kobject *kobj, 2210360f0f39SAzael Avalos struct attribute *attr, int idx) 2211360f0f39SAzael Avalos { 2212360f0f39SAzael Avalos struct device *dev = container_of(kobj, struct device, kobj); 2213360f0f39SAzael Avalos struct toshiba_acpi_dev *drv = dev_get_drvdata(dev); 2214360f0f39SAzael Avalos bool exists = true; 2215360f0f39SAzael Avalos 221694477d4cSAzael Avalos if (attr == &dev_attr_fan.attr) 221794477d4cSAzael Avalos exists = (drv->fan_supported) ? true : false; 221894477d4cSAzael Avalos else if (attr == &dev_attr_kbd_backlight_mode.attr) 2219360f0f39SAzael Avalos exists = (drv->kbd_illum_supported) ? true : false; 2220360f0f39SAzael Avalos else if (attr == &dev_attr_kbd_backlight_timeout.attr) 2221360f0f39SAzael Avalos exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false; 22229d8658acSAzael Avalos else if (attr == &dev_attr_touchpad.attr) 22239d8658acSAzael Avalos exists = (drv->touchpad_supported) ? true : false; 22245a2813e9SAzael Avalos else if (attr == &dev_attr_position.attr) 22255a2813e9SAzael Avalos exists = (drv->accelerometer_supported) ? true : false; 2226e26ffe51SAzael Avalos else if (attr == &dev_attr_usb_sleep_charge.attr) 2227e26ffe51SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2228182bcaa5SAzael Avalos else if (attr == &dev_attr_sleep_functions_on_battery.attr) 2229182bcaa5SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2230bb3fe01fSAzael Avalos else if (attr == &dev_attr_usb_rapid_charge.attr) 2231bb3fe01fSAzael Avalos exists = (drv->usb_rapid_charge_supported) ? true : false; 2232172ce0a9SAzael Avalos else if (attr == &dev_attr_usb_sleep_music.attr) 2233172ce0a9SAzael Avalos exists = (drv->usb_sleep_music_supported) ? true : false; 2234bae84195SAzael Avalos else if (attr == &dev_attr_kbd_function_keys.attr) 2235bae84195SAzael Avalos exists = (drv->kbd_function_keys_supported) ? true : false; 223635d53ceaSAzael Avalos else if (attr == &dev_attr_panel_power_on.attr) 223735d53ceaSAzael Avalos exists = (drv->panel_power_on_supported) ? true : false; 223817fe4b3dSAzael Avalos else if (attr == &dev_attr_usb_three.attr) 223917fe4b3dSAzael Avalos exists = (drv->usb_three_supported) ? true : false; 2240360f0f39SAzael Avalos 2241360f0f39SAzael Avalos return exists ? attr->mode : 0; 2242360f0f39SAzael Avalos } 2243360f0f39SAzael Avalos 22449bd1213bSAzael Avalos static struct attribute_group toshiba_attr_group = { 22459bd1213bSAzael Avalos .is_visible = toshiba_sysfs_is_visible, 22469bd1213bSAzael Avalos .attrs = toshiba_attributes, 22479bd1213bSAzael Avalos }; 22489bd1213bSAzael Avalos 22491f28f290SAzael Avalos /* 2250fc5462f8SAzael Avalos * Misc device 2251fc5462f8SAzael Avalos */ 2252fc5462f8SAzael Avalos static int toshiba_acpi_smm_bridge(SMMRegisters *regs) 2253fc5462f8SAzael Avalos { 2254fc5462f8SAzael Avalos u32 in[TCI_WORDS] = { regs->eax, regs->ebx, regs->ecx, 2255fc5462f8SAzael Avalos regs->edx, regs->esi, regs->edi }; 2256fc5462f8SAzael Avalos u32 out[TCI_WORDS]; 2257fc5462f8SAzael Avalos acpi_status status; 2258fc5462f8SAzael Avalos 2259fc5462f8SAzael Avalos status = tci_raw(toshiba_acpi, in, out); 2260fc5462f8SAzael Avalos if (ACPI_FAILURE(status)) { 2261fc5462f8SAzael Avalos pr_err("ACPI call to query SMM registers failed\n"); 2262fc5462f8SAzael Avalos return -EIO; 2263fc5462f8SAzael Avalos } 2264fc5462f8SAzael Avalos 2265fc5462f8SAzael Avalos /* Fillout the SMM struct with the TCI call results */ 2266fc5462f8SAzael Avalos regs->eax = out[0]; 2267fc5462f8SAzael Avalos regs->ebx = out[1]; 2268fc5462f8SAzael Avalos regs->ecx = out[2]; 2269fc5462f8SAzael Avalos regs->edx = out[3]; 2270fc5462f8SAzael Avalos regs->esi = out[4]; 2271fc5462f8SAzael Avalos regs->edi = out[5]; 2272fc5462f8SAzael Avalos 2273fc5462f8SAzael Avalos return 0; 2274fc5462f8SAzael Avalos } 2275fc5462f8SAzael Avalos 2276fc5462f8SAzael Avalos static long toshiba_acpi_ioctl(struct file *fp, unsigned int cmd, 2277fc5462f8SAzael Avalos unsigned long arg) 2278fc5462f8SAzael Avalos { 2279fc5462f8SAzael Avalos SMMRegisters __user *argp = (SMMRegisters __user *)arg; 2280fc5462f8SAzael Avalos SMMRegisters regs; 2281fc5462f8SAzael Avalos int ret; 2282fc5462f8SAzael Avalos 2283fc5462f8SAzael Avalos if (!argp) 2284fc5462f8SAzael Avalos return -EINVAL; 2285fc5462f8SAzael Avalos 2286fc5462f8SAzael Avalos switch (cmd) { 2287fc5462f8SAzael Avalos case TOSH_SMM: 2288fc5462f8SAzael Avalos if (copy_from_user(®s, argp, sizeof(SMMRegisters))) 2289fc5462f8SAzael Avalos return -EFAULT; 2290fc5462f8SAzael Avalos ret = toshiba_acpi_smm_bridge(®s); 2291fc5462f8SAzael Avalos if (ret) 2292fc5462f8SAzael Avalos return ret; 2293fc5462f8SAzael Avalos if (copy_to_user(argp, ®s, sizeof(SMMRegisters))) 2294fc5462f8SAzael Avalos return -EFAULT; 2295fc5462f8SAzael Avalos break; 2296fc5462f8SAzael Avalos case TOSHIBA_ACPI_SCI: 2297fc5462f8SAzael Avalos if (copy_from_user(®s, argp, sizeof(SMMRegisters))) 2298fc5462f8SAzael Avalos return -EFAULT; 2299fc5462f8SAzael Avalos /* Ensure we are being called with a SCI_{GET, SET} register */ 2300fc5462f8SAzael Avalos if (regs.eax != SCI_GET && regs.eax != SCI_SET) 2301fc5462f8SAzael Avalos return -EINVAL; 2302fc5462f8SAzael Avalos if (!sci_open(toshiba_acpi)) 2303fc5462f8SAzael Avalos return -EIO; 2304fc5462f8SAzael Avalos ret = toshiba_acpi_smm_bridge(®s); 2305fc5462f8SAzael Avalos sci_close(toshiba_acpi); 2306fc5462f8SAzael Avalos if (ret) 2307fc5462f8SAzael Avalos return ret; 2308fc5462f8SAzael Avalos if (copy_to_user(argp, ®s, sizeof(SMMRegisters))) 2309fc5462f8SAzael Avalos return -EFAULT; 2310fc5462f8SAzael Avalos break; 2311fc5462f8SAzael Avalos default: 2312fc5462f8SAzael Avalos return -EINVAL; 2313fc5462f8SAzael Avalos } 2314fc5462f8SAzael Avalos 2315fc5462f8SAzael Avalos return 0; 2316fc5462f8SAzael Avalos } 2317fc5462f8SAzael Avalos 2318fc5462f8SAzael Avalos static const struct file_operations toshiba_acpi_fops = { 2319fc5462f8SAzael Avalos .owner = THIS_MODULE, 2320fc5462f8SAzael Avalos .unlocked_ioctl = toshiba_acpi_ioctl, 2321fc5462f8SAzael Avalos .llseek = noop_llseek, 2322fc5462f8SAzael Avalos }; 2323fc5462f8SAzael Avalos 2324fc5462f8SAzael Avalos /* 23251f28f290SAzael Avalos * Hotkeys 23261f28f290SAzael Avalos */ 23271f28f290SAzael Avalos static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev) 23281f28f290SAzael Avalos { 23291f28f290SAzael Avalos acpi_status status; 23301f28f290SAzael Avalos u32 result; 23311f28f290SAzael Avalos 23321f28f290SAzael Avalos status = acpi_evaluate_object(dev->acpi_dev->handle, 23331f28f290SAzael Avalos "ENAB", NULL, NULL); 23341f28f290SAzael Avalos if (ACPI_FAILURE(status)) 23351f28f290SAzael Avalos return -ENODEV; 23361f28f290SAzael Avalos 2337d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE); 23381f28f290SAzael Avalos if (result == TOS_FAILURE) 23391f28f290SAzael Avalos return -EIO; 23401f28f290SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 23411f28f290SAzael Avalos return -ENODEV; 23421f28f290SAzael Avalos 23431f28f290SAzael Avalos return 0; 23441f28f290SAzael Avalos } 23451f28f290SAzael Avalos 2346fb42d1f4SAzael Avalos static void toshiba_acpi_enable_special_functions(struct toshiba_acpi_dev *dev) 2347fb42d1f4SAzael Avalos { 2348fb42d1f4SAzael Avalos u32 result; 2349fb42d1f4SAzael Avalos 2350fb42d1f4SAzael Avalos /* 2351fb42d1f4SAzael Avalos * Re-activate the hotkeys, but this time, we are using the 2352fb42d1f4SAzael Avalos * "Special Functions" mode. 2353fb42d1f4SAzael Avalos */ 2354d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, 2355fb42d1f4SAzael Avalos HCI_HOTKEY_SPECIAL_FUNCTIONS); 2356fb42d1f4SAzael Avalos if (result != TOS_SUCCESS) 2357fb42d1f4SAzael Avalos pr_err("Could not enable the Special Function mode\n"); 2358fb42d1f4SAzael Avalos } 2359fb42d1f4SAzael Avalos 236029cd293fSSeth Forshee static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, 236129cd293fSSeth Forshee struct serio *port) 236229cd293fSSeth Forshee { 236398280374SGiedrius Statkevičius if (str & I8042_STR_AUXDATA) 236429cd293fSSeth Forshee return false; 236529cd293fSSeth Forshee 236629cd293fSSeth Forshee if (unlikely(data == 0xe0)) 236729cd293fSSeth Forshee return false; 236829cd293fSSeth Forshee 236929cd293fSSeth Forshee if ((data & 0x7f) == TOS1900_FN_SCAN) { 237029cd293fSSeth Forshee schedule_work(&toshiba_acpi->hotkey_work); 237129cd293fSSeth Forshee return true; 237229cd293fSSeth Forshee } 237329cd293fSSeth Forshee 237429cd293fSSeth Forshee return false; 237529cd293fSSeth Forshee } 237629cd293fSSeth Forshee 237729cd293fSSeth Forshee static void toshiba_acpi_hotkey_work(struct work_struct *work) 237829cd293fSSeth Forshee { 237929cd293fSSeth Forshee acpi_handle ec_handle = ec_get_handle(); 238029cd293fSSeth Forshee acpi_status status; 238129cd293fSSeth Forshee 238229cd293fSSeth Forshee if (!ec_handle) 238329cd293fSSeth Forshee return; 238429cd293fSSeth Forshee 238529cd293fSSeth Forshee status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL); 238629cd293fSSeth Forshee if (ACPI_FAILURE(status)) 238729cd293fSSeth Forshee pr_err("ACPI NTFY method execution failed\n"); 238829cd293fSSeth Forshee } 238929cd293fSSeth Forshee 239029cd293fSSeth Forshee /* 239129cd293fSSeth Forshee * Returns hotkey scancode, or < 0 on failure. 239229cd293fSSeth Forshee */ 239329cd293fSSeth Forshee static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev) 239429cd293fSSeth Forshee { 239574facaf7SZhang Rui unsigned long long value; 239629cd293fSSeth Forshee acpi_status status; 239729cd293fSSeth Forshee 239874facaf7SZhang Rui status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO", 239974facaf7SZhang Rui NULL, &value); 240074facaf7SZhang Rui if (ACPI_FAILURE(status)) { 240129cd293fSSeth Forshee pr_err("ACPI INFO method execution failed\n"); 240229cd293fSSeth Forshee return -EIO; 240329cd293fSSeth Forshee } 240429cd293fSSeth Forshee 240574facaf7SZhang Rui return value; 240629cd293fSSeth Forshee } 240729cd293fSSeth Forshee 240829cd293fSSeth Forshee static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev, 240929cd293fSSeth Forshee int scancode) 241029cd293fSSeth Forshee { 241129cd293fSSeth Forshee if (scancode == 0x100) 241229cd293fSSeth Forshee return; 241329cd293fSSeth Forshee 2414e0769fe6SDarren Hart /* Act on key press; ignore key release */ 241529cd293fSSeth Forshee if (scancode & 0x80) 241629cd293fSSeth Forshee return; 241729cd293fSSeth Forshee 241829cd293fSSeth Forshee if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true)) 241929cd293fSSeth Forshee pr_info("Unknown key %x\n", scancode); 242029cd293fSSeth Forshee } 242129cd293fSSeth Forshee 242271454d78SAzael Avalos static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) 242371454d78SAzael Avalos { 242471454d78SAzael Avalos if (dev->info_supported) { 24257deef550SAzael Avalos int scancode = toshiba_acpi_query_hotkey(dev); 24267deef550SAzael Avalos 24277deef550SAzael Avalos if (scancode < 0) { 242871454d78SAzael Avalos pr_err("Failed to query hotkey event\n"); 24297deef550SAzael Avalos } else if (scancode != 0) { 243071454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, scancode); 24317deef550SAzael Avalos dev->key_event_valid = 1; 24327deef550SAzael Avalos dev->last_key_event = scancode; 24337deef550SAzael Avalos } 243471454d78SAzael Avalos } else if (dev->system_event_supported) { 24357deef550SAzael Avalos u32 result; 24367deef550SAzael Avalos u32 value; 24377deef550SAzael Avalos int retries = 3; 24387deef550SAzael Avalos 243971454d78SAzael Avalos do { 24407deef550SAzael Avalos result = hci_read(dev, HCI_SYSTEM_EVENT, &value); 24417deef550SAzael Avalos switch (result) { 244271454d78SAzael Avalos case TOS_SUCCESS: 244371454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, (int)value); 24447deef550SAzael Avalos dev->key_event_valid = 1; 24457deef550SAzael Avalos dev->last_key_event = value; 244671454d78SAzael Avalos break; 244771454d78SAzael Avalos case TOS_NOT_SUPPORTED: 244871454d78SAzael Avalos /* 244971454d78SAzael Avalos * This is a workaround for an unresolved 245071454d78SAzael Avalos * issue on some machines where system events 245171454d78SAzael Avalos * sporadically become disabled. 245271454d78SAzael Avalos */ 24537deef550SAzael Avalos result = hci_write(dev, HCI_SYSTEM_EVENT, 1); 24547deef550SAzael Avalos if (result == TOS_SUCCESS) 245571454d78SAzael Avalos pr_notice("Re-enabled hotkeys\n"); 2456e0769fe6SDarren Hart /* Fall through */ 245771454d78SAzael Avalos default: 245871454d78SAzael Avalos retries--; 245971454d78SAzael Avalos break; 246071454d78SAzael Avalos } 24617deef550SAzael Avalos } while (retries && result != TOS_FIFO_EMPTY); 246271454d78SAzael Avalos } 246371454d78SAzael Avalos } 246471454d78SAzael Avalos 2465b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) 24666335e4d5SMatthew Garrett { 2467fe808bfbSTakashi Iwai const struct key_entry *keymap = toshiba_acpi_keymap; 2468a2b3471bSAzael Avalos acpi_handle ec_handle; 2469a2b3471bSAzael Avalos u32 events_type; 2470a2b3471bSAzael Avalos u32 hci_result; 2471a2b3471bSAzael Avalos int error; 2472a2b3471bSAzael Avalos 2473a88bc06eSAzael Avalos if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) { 2474a88bc06eSAzael Avalos pr_info("WMI event detected, hotkeys will not be monitored\n"); 2475a88bc06eSAzael Avalos return 0; 2476a88bc06eSAzael Avalos } 2477a88bc06eSAzael Avalos 2478a2b3471bSAzael Avalos error = toshiba_acpi_enable_hotkeys(dev); 2479a2b3471bSAzael Avalos if (error) 2480a2b3471bSAzael Avalos return error; 2481a2b3471bSAzael Avalos 2482a2b3471bSAzael Avalos error = toshiba_hotkey_event_type_get(dev, &events_type); 2483a2b3471bSAzael Avalos if (error) { 2484a2b3471bSAzael Avalos pr_err("Unable to query Hotkey Event Type\n"); 2485a2b3471bSAzael Avalos return error; 2486a2b3471bSAzael Avalos } 2487a2b3471bSAzael Avalos dev->hotkey_event_type = events_type; 2488135740deSSeth Forshee 2489135740deSSeth Forshee dev->hotkey_dev = input_allocate_device(); 2490b222cca6SJoe Perches if (!dev->hotkey_dev) 2491135740deSSeth Forshee return -ENOMEM; 2492135740deSSeth Forshee 2493135740deSSeth Forshee dev->hotkey_dev->name = "Toshiba input device"; 24946e02cc7eSSeth Forshee dev->hotkey_dev->phys = "toshiba_acpi/input0"; 2495135740deSSeth Forshee dev->hotkey_dev->id.bustype = BUS_HOST; 2496135740deSSeth Forshee 2497a2b3471bSAzael Avalos if (events_type == HCI_SYSTEM_TYPE1 || 2498a2b3471bSAzael Avalos !dev->kbd_function_keys_supported) 2499a2b3471bSAzael Avalos keymap = toshiba_acpi_keymap; 2500a2b3471bSAzael Avalos else if (events_type == HCI_SYSTEM_TYPE2 || 2501a2b3471bSAzael Avalos dev->kbd_function_keys_supported) 2502fe808bfbSTakashi Iwai keymap = toshiba_acpi_alt_keymap; 2503a2b3471bSAzael Avalos else 2504a2b3471bSAzael Avalos pr_info("Unknown event type received %x\n", events_type); 2505fe808bfbSTakashi Iwai error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL); 2506135740deSSeth Forshee if (error) 2507135740deSSeth Forshee goto err_free_dev; 2508135740deSSeth Forshee 250929cd293fSSeth Forshee /* 251029cd293fSSeth Forshee * For some machines the SCI responsible for providing hotkey 251129cd293fSSeth Forshee * notification doesn't fire. We can trigger the notification 251229cd293fSSeth Forshee * whenever the Fn key is pressed using the NTFY method, if 251329cd293fSSeth Forshee * supported, so if it's present set up an i8042 key filter 251429cd293fSSeth Forshee * for this purpose. 251529cd293fSSeth Forshee */ 251629cd293fSSeth Forshee ec_handle = ec_get_handle(); 2517e2e19606SZhang Rui if (ec_handle && acpi_has_method(ec_handle, "NTFY")) { 251829cd293fSSeth Forshee INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work); 251929cd293fSSeth Forshee 252029cd293fSSeth Forshee error = i8042_install_filter(toshiba_acpi_i8042_filter); 252129cd293fSSeth Forshee if (error) { 252229cd293fSSeth Forshee pr_err("Error installing key filter\n"); 252329cd293fSSeth Forshee goto err_free_keymap; 252429cd293fSSeth Forshee } 252529cd293fSSeth Forshee 252629cd293fSSeth Forshee dev->ntfy_supported = 1; 252729cd293fSSeth Forshee } 252829cd293fSSeth Forshee 252929cd293fSSeth Forshee /* 253029cd293fSSeth Forshee * Determine hotkey query interface. Prefer using the INFO 253129cd293fSSeth Forshee * method when it is available. 253229cd293fSSeth Forshee */ 2533e2e19606SZhang Rui if (acpi_has_method(dev->acpi_dev->handle, "INFO")) 253429cd293fSSeth Forshee dev->info_supported = 1; 2535e2e19606SZhang Rui else { 2536d37782bdSAzael Avalos hci_result = hci_write(dev, HCI_SYSTEM_EVENT, 1); 25371864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) 253829cd293fSSeth Forshee dev->system_event_supported = 1; 253929cd293fSSeth Forshee } 254029cd293fSSeth Forshee 254129cd293fSSeth Forshee if (!dev->info_supported && !dev->system_event_supported) { 254229cd293fSSeth Forshee pr_warn("No hotkey query interface found\n"); 254329cd293fSSeth Forshee goto err_remove_filter; 254429cd293fSSeth Forshee } 254529cd293fSSeth Forshee 2546135740deSSeth Forshee error = input_register_device(dev->hotkey_dev); 2547135740deSSeth Forshee if (error) { 2548135740deSSeth Forshee pr_info("Unable to register input device\n"); 254929cd293fSSeth Forshee goto err_remove_filter; 2550135740deSSeth Forshee } 2551135740deSSeth Forshee 2552135740deSSeth Forshee return 0; 2553135740deSSeth Forshee 255429cd293fSSeth Forshee err_remove_filter: 255529cd293fSSeth Forshee if (dev->ntfy_supported) 255629cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 2557135740deSSeth Forshee err_free_keymap: 2558135740deSSeth Forshee sparse_keymap_free(dev->hotkey_dev); 2559135740deSSeth Forshee err_free_dev: 2560135740deSSeth Forshee input_free_device(dev->hotkey_dev); 2561135740deSSeth Forshee dev->hotkey_dev = NULL; 2562135740deSSeth Forshee return error; 2563135740deSSeth Forshee } 2564135740deSSeth Forshee 2565b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) 256662cce752SSeth Forshee { 256762cce752SSeth Forshee struct backlight_properties props; 256862cce752SSeth Forshee int brightness; 256962cce752SSeth Forshee int ret; 257062cce752SSeth Forshee 257162cce752SSeth Forshee /* 257262cce752SSeth Forshee * Some machines don't support the backlight methods at all, and 257362cce752SSeth Forshee * others support it read-only. Either of these is pretty useless, 257462cce752SSeth Forshee * so only register the backlight device if the backlight method 257562cce752SSeth Forshee * supports both reads and writes. 257662cce752SSeth Forshee */ 257762cce752SSeth Forshee brightness = __get_lcd_brightness(dev); 257862cce752SSeth Forshee if (brightness < 0) 257962cce752SSeth Forshee return 0; 258062cce752SSeth Forshee ret = set_lcd_brightness(dev, brightness); 258162cce752SSeth Forshee if (ret) { 258262cce752SSeth Forshee pr_debug("Backlight method is read-only, disabling backlight support\n"); 258362cce752SSeth Forshee return 0; 258462cce752SSeth Forshee } 258562cce752SSeth Forshee 2586358d6a2cSHans de Goede /* 2587358d6a2cSHans de Goede * Tell acpi-video-detect code to prefer vendor backlight on all 2588358d6a2cSHans de Goede * systems with transflective backlight and on dmi matched systems. 2589358d6a2cSHans de Goede */ 2590358d6a2cSHans de Goede if (dev->tr_backlight_supported || 2591358d6a2cSHans de Goede dmi_check_system(toshiba_vendor_backlight_dmi)) 2592234b7cf8SHans de Goede acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); 2593358d6a2cSHans de Goede 2594234b7cf8SHans de Goede if (acpi_video_get_backlight_type() != acpi_backlight_vendor) 2595358d6a2cSHans de Goede return 0; 2596358d6a2cSHans de Goede 259753039f22SMatthew Garrett memset(&props, 0, sizeof(props)); 259862cce752SSeth Forshee props.type = BACKLIGHT_PLATFORM; 259962cce752SSeth Forshee props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; 260062cce752SSeth Forshee 2601e0769fe6SDarren Hart /* Adding an extra level and having 0 change to transflective mode */ 2602121b7b0dSAkio Idehara if (dev->tr_backlight_supported) 2603121b7b0dSAkio Idehara props.max_brightness++; 2604121b7b0dSAkio Idehara 260562cce752SSeth Forshee dev->backlight_dev = backlight_device_register("toshiba", 260662cce752SSeth Forshee &dev->acpi_dev->dev, 260762cce752SSeth Forshee dev, 260862cce752SSeth Forshee &toshiba_backlight_data, 260962cce752SSeth Forshee &props); 261062cce752SSeth Forshee if (IS_ERR(dev->backlight_dev)) { 261162cce752SSeth Forshee ret = PTR_ERR(dev->backlight_dev); 261262cce752SSeth Forshee pr_err("Could not register toshiba backlight device\n"); 261362cce752SSeth Forshee dev->backlight_dev = NULL; 261462cce752SSeth Forshee return ret; 261562cce752SSeth Forshee } 261662cce752SSeth Forshee 261762cce752SSeth Forshee dev->backlight_dev->props.brightness = brightness; 261862cce752SSeth Forshee return 0; 261962cce752SSeth Forshee } 262062cce752SSeth Forshee 26210409cbceSAzael Avalos static void print_supported_features(struct toshiba_acpi_dev *dev) 26220409cbceSAzael Avalos { 26230409cbceSAzael Avalos pr_info("Supported laptop features:"); 26240409cbceSAzael Avalos 26250409cbceSAzael Avalos if (dev->hotkey_dev) 26260409cbceSAzael Avalos pr_cont(" hotkeys"); 26270409cbceSAzael Avalos if (dev->backlight_dev) 26280409cbceSAzael Avalos pr_cont(" backlight"); 26290409cbceSAzael Avalos if (dev->video_supported) 26300409cbceSAzael Avalos pr_cont(" video-out"); 26310409cbceSAzael Avalos if (dev->fan_supported) 26320409cbceSAzael Avalos pr_cont(" fan"); 26330409cbceSAzael Avalos if (dev->tr_backlight_supported) 26340409cbceSAzael Avalos pr_cont(" transflective-backlight"); 26350409cbceSAzael Avalos if (dev->illumination_supported) 26360409cbceSAzael Avalos pr_cont(" illumination"); 26370409cbceSAzael Avalos if (dev->kbd_illum_supported) 26380409cbceSAzael Avalos pr_cont(" keyboard-backlight"); 26390409cbceSAzael Avalos if (dev->touchpad_supported) 26400409cbceSAzael Avalos pr_cont(" touchpad"); 26410409cbceSAzael Avalos if (dev->eco_supported) 26420409cbceSAzael Avalos pr_cont(" eco-led"); 26430409cbceSAzael Avalos if (dev->accelerometer_supported) 26440409cbceSAzael Avalos pr_cont(" accelerometer-axes"); 26450409cbceSAzael Avalos if (dev->usb_sleep_charge_supported) 26460409cbceSAzael Avalos pr_cont(" usb-sleep-charge"); 26470409cbceSAzael Avalos if (dev->usb_rapid_charge_supported) 26480409cbceSAzael Avalos pr_cont(" usb-rapid-charge"); 26490409cbceSAzael Avalos if (dev->usb_sleep_music_supported) 26500409cbceSAzael Avalos pr_cont(" usb-sleep-music"); 26510409cbceSAzael Avalos if (dev->kbd_function_keys_supported) 26520409cbceSAzael Avalos pr_cont(" special-function-keys"); 26530409cbceSAzael Avalos if (dev->panel_power_on_supported) 26540409cbceSAzael Avalos pr_cont(" panel-power-on"); 26550409cbceSAzael Avalos if (dev->usb_three_supported) 26560409cbceSAzael Avalos pr_cont(" usb3"); 26570409cbceSAzael Avalos 26580409cbceSAzael Avalos pr_cont("\n"); 26590409cbceSAzael Avalos } 26600409cbceSAzael Avalos 266151fac838SRafael J. Wysocki static int toshiba_acpi_remove(struct acpi_device *acpi_dev) 2662135740deSSeth Forshee { 2663135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 2664135740deSSeth Forshee 2665fc5462f8SAzael Avalos misc_deregister(&dev->miscdev); 2666fc5462f8SAzael Avalos 266736d03f93SSeth Forshee remove_toshiba_proc_entries(dev); 2668135740deSSeth Forshee 2669360f0f39SAzael Avalos if (dev->sysfs_created) 2670360f0f39SAzael Avalos sysfs_remove_group(&dev->acpi_dev->dev.kobj, 2671360f0f39SAzael Avalos &toshiba_attr_group); 2672360f0f39SAzael Avalos 267329cd293fSSeth Forshee if (dev->ntfy_supported) { 267429cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 267529cd293fSSeth Forshee cancel_work_sync(&dev->hotkey_work); 267629cd293fSSeth Forshee } 267729cd293fSSeth Forshee 2678135740deSSeth Forshee if (dev->hotkey_dev) { 2679135740deSSeth Forshee input_unregister_device(dev->hotkey_dev); 2680135740deSSeth Forshee sparse_keymap_free(dev->hotkey_dev); 2681135740deSSeth Forshee } 2682135740deSSeth Forshee 2683135740deSSeth Forshee backlight_device_unregister(dev->backlight_dev); 2684135740deSSeth Forshee 2685ea215a3fSAzael Avalos if (dev->illumination_led_registered) 2686135740deSSeth Forshee led_classdev_unregister(&dev->led_dev); 2687135740deSSeth Forshee 2688360f0f39SAzael Avalos if (dev->kbd_led_registered) 2689360f0f39SAzael Avalos led_classdev_unregister(&dev->kbd_led); 2690360f0f39SAzael Avalos 2691ea215a3fSAzael Avalos if (dev->eco_led_registered) 2692def6c4e2SAzael Avalos led_classdev_unregister(&dev->eco_led); 2693def6c4e2SAzael Avalos 269429cd293fSSeth Forshee if (toshiba_acpi) 269529cd293fSSeth Forshee toshiba_acpi = NULL; 269629cd293fSSeth Forshee 2697135740deSSeth Forshee kfree(dev); 2698135740deSSeth Forshee 2699135740deSSeth Forshee return 0; 2700135740deSSeth Forshee } 2701135740deSSeth Forshee 2702b859f159SGreg Kroah-Hartman static const char *find_hci_method(acpi_handle handle) 2703a540d6b5SSeth Forshee { 2704e2e19606SZhang Rui if (acpi_has_method(handle, "GHCI")) 2705a540d6b5SSeth Forshee return "GHCI"; 2706a540d6b5SSeth Forshee 2707e2e19606SZhang Rui if (acpi_has_method(handle, "SPFC")) 2708a540d6b5SSeth Forshee return "SPFC"; 2709a540d6b5SSeth Forshee 2710a540d6b5SSeth Forshee return NULL; 2711a540d6b5SSeth Forshee } 2712a540d6b5SSeth Forshee 2713b859f159SGreg Kroah-Hartman static int toshiba_acpi_add(struct acpi_device *acpi_dev) 2714135740deSSeth Forshee { 2715135740deSSeth Forshee struct toshiba_acpi_dev *dev; 2716a540d6b5SSeth Forshee const char *hci_method; 2717fb42d1f4SAzael Avalos u32 special_functions; 271836d03f93SSeth Forshee u32 dummy; 2719135740deSSeth Forshee int ret = 0; 2720135740deSSeth Forshee 272129cd293fSSeth Forshee if (toshiba_acpi) 272229cd293fSSeth Forshee return -EBUSY; 272329cd293fSSeth Forshee 2724135740deSSeth Forshee pr_info("Toshiba Laptop ACPI Extras version %s\n", 2725135740deSSeth Forshee TOSHIBA_ACPI_VERSION); 2726135740deSSeth Forshee 2727a540d6b5SSeth Forshee hci_method = find_hci_method(acpi_dev->handle); 2728a540d6b5SSeth Forshee if (!hci_method) { 2729a540d6b5SSeth Forshee pr_err("HCI interface not found\n"); 27306e02cc7eSSeth Forshee return -ENODEV; 2731a540d6b5SSeth Forshee } 27326e02cc7eSSeth Forshee 2733135740deSSeth Forshee dev = kzalloc(sizeof(*dev), GFP_KERNEL); 2734135740deSSeth Forshee if (!dev) 2735135740deSSeth Forshee return -ENOMEM; 2736135740deSSeth Forshee dev->acpi_dev = acpi_dev; 2737a540d6b5SSeth Forshee dev->method_hci = hci_method; 2738fc5462f8SAzael Avalos dev->miscdev.minor = MISC_DYNAMIC_MINOR; 2739fc5462f8SAzael Avalos dev->miscdev.name = "toshiba_acpi"; 2740fc5462f8SAzael Avalos dev->miscdev.fops = &toshiba_acpi_fops; 2741fc5462f8SAzael Avalos 2742fc5462f8SAzael Avalos ret = misc_register(&dev->miscdev); 2743fc5462f8SAzael Avalos if (ret) { 2744fc5462f8SAzael Avalos pr_err("Failed to register miscdevice\n"); 2745fc5462f8SAzael Avalos kfree(dev); 2746fc5462f8SAzael Avalos return ret; 2747fc5462f8SAzael Avalos } 2748fc5462f8SAzael Avalos 2749135740deSSeth Forshee acpi_dev->driver_data = dev; 2750360f0f39SAzael Avalos dev_set_drvdata(&acpi_dev->dev, dev); 2751135740deSSeth Forshee 2752a2b3471bSAzael Avalos /* Query the BIOS for supported features */ 2753a2b3471bSAzael Avalos 2754a2b3471bSAzael Avalos /* 2755a2b3471bSAzael Avalos * The "Special Functions" are always supported by the laptops 2756a2b3471bSAzael Avalos * with the new keyboard layout, query for its presence to help 2757a2b3471bSAzael Avalos * determine the keymap layout to use. 2758a2b3471bSAzael Avalos */ 2759fb42d1f4SAzael Avalos ret = toshiba_function_keys_get(dev, &special_functions); 2760a2b3471bSAzael Avalos dev->kbd_function_keys_supported = !ret; 2761a2b3471bSAzael Avalos 27626e02cc7eSSeth Forshee if (toshiba_acpi_setup_keyboard(dev)) 2763135740deSSeth Forshee pr_info("Unable to activate hotkeys\n"); 2764135740deSSeth Forshee 2765695f6060SAzael Avalos /* Determine whether or not BIOS supports transflective backlight */ 2766695f6060SAzael Avalos ret = get_tr_backlight_status(dev, &dummy); 2767695f6060SAzael Avalos dev->tr_backlight_supported = !ret; 2768695f6060SAzael Avalos 276962cce752SSeth Forshee ret = toshiba_acpi_setup_backlight(dev); 277062cce752SSeth Forshee if (ret) 2771135740deSSeth Forshee goto error; 2772135740deSSeth Forshee 2773ea215a3fSAzael Avalos toshiba_illumination_available(dev); 2774ea215a3fSAzael Avalos if (dev->illumination_supported) { 2775135740deSSeth Forshee dev->led_dev.name = "toshiba::illumination"; 2776135740deSSeth Forshee dev->led_dev.max_brightness = 1; 2777135740deSSeth Forshee dev->led_dev.brightness_set = toshiba_illumination_set; 2778135740deSSeth Forshee dev->led_dev.brightness_get = toshiba_illumination_get; 2779135740deSSeth Forshee if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev)) 2780ea215a3fSAzael Avalos dev->illumination_led_registered = true; 2781135740deSSeth Forshee } 2782135740deSSeth Forshee 2783ea215a3fSAzael Avalos toshiba_eco_mode_available(dev); 2784ea215a3fSAzael Avalos if (dev->eco_supported) { 2785def6c4e2SAzael Avalos dev->eco_led.name = "toshiba::eco_mode"; 2786def6c4e2SAzael Avalos dev->eco_led.max_brightness = 1; 2787def6c4e2SAzael Avalos dev->eco_led.brightness_set = toshiba_eco_mode_set_status; 2788def6c4e2SAzael Avalos dev->eco_led.brightness_get = toshiba_eco_mode_get_status; 2789def6c4e2SAzael Avalos if (!led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led)) 2790ea215a3fSAzael Avalos dev->eco_led_registered = true; 2791def6c4e2SAzael Avalos } 2792def6c4e2SAzael Avalos 2793ea215a3fSAzael Avalos toshiba_kbd_illum_available(dev); 2794360f0f39SAzael Avalos /* 2795360f0f39SAzael Avalos * Only register the LED if KBD illumination is supported 2796360f0f39SAzael Avalos * and the keyboard backlight operation mode is set to FN-Z 2797360f0f39SAzael Avalos */ 2798360f0f39SAzael Avalos if (dev->kbd_illum_supported && dev->kbd_mode == SCI_KBD_MODE_FNZ) { 2799360f0f39SAzael Avalos dev->kbd_led.name = "toshiba::kbd_backlight"; 2800360f0f39SAzael Avalos dev->kbd_led.max_brightness = 1; 2801360f0f39SAzael Avalos dev->kbd_led.brightness_set = toshiba_kbd_backlight_set; 2802360f0f39SAzael Avalos dev->kbd_led.brightness_get = toshiba_kbd_backlight_get; 2803360f0f39SAzael Avalos if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led)) 2804ea215a3fSAzael Avalos dev->kbd_led_registered = true; 2805360f0f39SAzael Avalos } 2806360f0f39SAzael Avalos 28079d8658acSAzael Avalos ret = toshiba_touchpad_get(dev, &dummy); 28089d8658acSAzael Avalos dev->touchpad_supported = !ret; 28099d8658acSAzael Avalos 2810ea215a3fSAzael Avalos toshiba_accelerometer_available(dev); 28115a2813e9SAzael Avalos 2812c8c91842SAzael Avalos toshiba_usb_sleep_charge_available(dev); 2813e26ffe51SAzael Avalos 2814bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(dev, &dummy); 2815bb3fe01fSAzael Avalos dev->usb_rapid_charge_supported = !ret; 2816bb3fe01fSAzael Avalos 2817172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(dev, &dummy); 2818172ce0a9SAzael Avalos dev->usb_sleep_music_supported = !ret; 2819172ce0a9SAzael Avalos 282035d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(dev, &dummy); 282135d53ceaSAzael Avalos dev->panel_power_on_supported = !ret; 282235d53ceaSAzael Avalos 282317fe4b3dSAzael Avalos ret = toshiba_usb_three_get(dev, &dummy); 282417fe4b3dSAzael Avalos dev->usb_three_supported = !ret; 282517fe4b3dSAzael Avalos 282636d03f93SSeth Forshee ret = get_video_status(dev, &dummy); 282736d03f93SSeth Forshee dev->video_supported = !ret; 282836d03f93SSeth Forshee 282936d03f93SSeth Forshee ret = get_fan_status(dev, &dummy); 283036d03f93SSeth Forshee dev->fan_supported = !ret; 283136d03f93SSeth Forshee 28320409cbceSAzael Avalos print_supported_features(dev); 28330409cbceSAzael Avalos 2834fb42d1f4SAzael Avalos /* 2835fb42d1f4SAzael Avalos * Enable the "Special Functions" mode only if they are 2836fb42d1f4SAzael Avalos * supported and if they are activated. 2837fb42d1f4SAzael Avalos */ 2838fb42d1f4SAzael Avalos if (dev->kbd_function_keys_supported && special_functions) 2839fb42d1f4SAzael Avalos toshiba_acpi_enable_special_functions(dev); 2840fb42d1f4SAzael Avalos 2841360f0f39SAzael Avalos ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, 2842360f0f39SAzael Avalos &toshiba_attr_group); 2843360f0f39SAzael Avalos if (ret) { 2844360f0f39SAzael Avalos dev->sysfs_created = 0; 2845360f0f39SAzael Avalos goto error; 2846360f0f39SAzael Avalos } 2847360f0f39SAzael Avalos dev->sysfs_created = !ret; 2848360f0f39SAzael Avalos 284936d03f93SSeth Forshee create_toshiba_proc_entries(dev); 285036d03f93SSeth Forshee 285129cd293fSSeth Forshee toshiba_acpi = dev; 285229cd293fSSeth Forshee 2853135740deSSeth Forshee return 0; 2854135740deSSeth Forshee 2855135740deSSeth Forshee error: 285651fac838SRafael J. Wysocki toshiba_acpi_remove(acpi_dev); 2857135740deSSeth Forshee return ret; 2858135740deSSeth Forshee } 2859135740deSSeth Forshee 2860135740deSSeth Forshee static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) 2861135740deSSeth Forshee { 2862135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 286380546905SAzael Avalos int ret; 28646335e4d5SMatthew Garrett 286571454d78SAzael Avalos switch (event) { 286671454d78SAzael Avalos case 0x80: /* Hotkeys and some system events */ 2867a88bc06eSAzael Avalos /* 2868a88bc06eSAzael Avalos * Machines with this WMI GUID aren't supported due to bugs in 2869a88bc06eSAzael Avalos * their AML. 2870a88bc06eSAzael Avalos * 2871a88bc06eSAzael Avalos * Return silently to avoid triggering a netlink event. 2872a88bc06eSAzael Avalos */ 2873a88bc06eSAzael Avalos if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) 2874a88bc06eSAzael Avalos return; 287571454d78SAzael Avalos toshiba_acpi_process_hotkeys(dev); 287611948b93SSeth Forshee break; 2877bab09e23SAzael Avalos case 0x81: /* Dock events */ 2878bab09e23SAzael Avalos case 0x82: 2879bab09e23SAzael Avalos case 0x83: 2880bab09e23SAzael Avalos pr_info("Dock event received %x\n", event); 2881bab09e23SAzael Avalos break; 2882bab09e23SAzael Avalos case 0x88: /* Thermal events */ 2883bab09e23SAzael Avalos pr_info("Thermal event received\n"); 2884bab09e23SAzael Avalos break; 2885bab09e23SAzael Avalos case 0x8f: /* LID closed */ 2886bab09e23SAzael Avalos case 0x90: /* LID is closed and Dock has been ejected */ 2887bab09e23SAzael Avalos break; 2888bab09e23SAzael Avalos case 0x8c: /* SATA power events */ 2889bab09e23SAzael Avalos case 0x8b: 2890bab09e23SAzael Avalos pr_info("SATA power event received %x\n", event); 2891bab09e23SAzael Avalos break; 289280546905SAzael Avalos case 0x92: /* Keyboard backlight mode changed */ 289380546905SAzael Avalos /* Update sysfs entries */ 289480546905SAzael Avalos ret = sysfs_update_group(&acpi_dev->dev.kobj, 289580546905SAzael Avalos &toshiba_attr_group); 289680546905SAzael Avalos if (ret) 289780546905SAzael Avalos pr_err("Unable to update sysfs entries\n"); 289880546905SAzael Avalos break; 2899bab09e23SAzael Avalos case 0x85: /* Unknown */ 2900bab09e23SAzael Avalos case 0x8d: /* Unknown */ 290171454d78SAzael Avalos case 0x8e: /* Unknown */ 2902bab09e23SAzael Avalos case 0x94: /* Unknown */ 2903bab09e23SAzael Avalos case 0x95: /* Unknown */ 290411948b93SSeth Forshee default: 290571454d78SAzael Avalos pr_info("Unknown event received %x\n", event); 290611948b93SSeth Forshee break; 29076335e4d5SMatthew Garrett } 2908bab09e23SAzael Avalos 2909bab09e23SAzael Avalos acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class, 2910bab09e23SAzael Avalos dev_name(&acpi_dev->dev), 2911bab09e23SAzael Avalos event, 0); 291229cd293fSSeth Forshee } 29136335e4d5SMatthew Garrett 29143567a4e2SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 291543d2fd3bSRafael J. Wysocki static int toshiba_acpi_suspend(struct device *device) 291629cd293fSSeth Forshee { 291743d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 29181e574dbfSAzael Avalos 29191e574dbfSAzael Avalos if (dev->hotkey_dev) { 292029cd293fSSeth Forshee u32 result; 292129cd293fSSeth Forshee 2922d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE); 29231e574dbfSAzael Avalos if (result != TOS_SUCCESS) 29241e574dbfSAzael Avalos pr_info("Unable to disable hotkeys\n"); 29251e574dbfSAzael Avalos } 292629cd293fSSeth Forshee 292729cd293fSSeth Forshee return 0; 292829cd293fSSeth Forshee } 292929cd293fSSeth Forshee 293043d2fd3bSRafael J. Wysocki static int toshiba_acpi_resume(struct device *device) 293129cd293fSSeth Forshee { 293243d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 293329cd293fSSeth Forshee 2934e7fdb762SBenjamin Tissoires if (dev->hotkey_dev) { 29351e574dbfSAzael Avalos int error = toshiba_acpi_enable_hotkeys(dev); 29361e574dbfSAzael Avalos 29371f28f290SAzael Avalos if (error) 2938e7fdb762SBenjamin Tissoires pr_info("Unable to re-enable hotkeys\n"); 2939e7fdb762SBenjamin Tissoires } 294029cd293fSSeth Forshee 294129cd293fSSeth Forshee return 0; 294229cd293fSSeth Forshee } 29433567a4e2SRafael J. Wysocki #endif 29446335e4d5SMatthew Garrett 294543d2fd3bSRafael J. Wysocki static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm, 294643d2fd3bSRafael J. Wysocki toshiba_acpi_suspend, toshiba_acpi_resume); 294743d2fd3bSRafael J. Wysocki 2948135740deSSeth Forshee static struct acpi_driver toshiba_acpi_driver = { 2949135740deSSeth Forshee .name = "Toshiba ACPI driver", 2950135740deSSeth Forshee .owner = THIS_MODULE, 2951135740deSSeth Forshee .ids = toshiba_device_ids, 2952135740deSSeth Forshee .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, 2953135740deSSeth Forshee .ops = { 2954135740deSSeth Forshee .add = toshiba_acpi_add, 2955135740deSSeth Forshee .remove = toshiba_acpi_remove, 2956135740deSSeth Forshee .notify = toshiba_acpi_notify, 2957135740deSSeth Forshee }, 295843d2fd3bSRafael J. Wysocki .drv.pm = &toshiba_acpi_pm, 2959135740deSSeth Forshee }; 2960b4f9fe12SLen Brown 2961b4f9fe12SLen Brown static int __init toshiba_acpi_init(void) 2962b4f9fe12SLen Brown { 2963135740deSSeth Forshee int ret; 2964b4f9fe12SLen Brown 2965b4f9fe12SLen Brown toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); 2966b4f9fe12SLen Brown if (!toshiba_proc_dir) { 2967135740deSSeth Forshee pr_err("Unable to create proc dir " PROC_TOSHIBA "\n"); 2968b4f9fe12SLen Brown return -ENODEV; 2969b4f9fe12SLen Brown } 2970b4f9fe12SLen Brown 2971135740deSSeth Forshee ret = acpi_bus_register_driver(&toshiba_acpi_driver); 2972b4f9fe12SLen Brown if (ret) { 2973135740deSSeth Forshee pr_err("Failed to register ACPI driver: %d\n", ret); 2974135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 2975135740deSSeth Forshee } 2976135740deSSeth Forshee 2977b4f9fe12SLen Brown return ret; 2978b4f9fe12SLen Brown } 2979b4f9fe12SLen Brown 2980135740deSSeth Forshee static void __exit toshiba_acpi_exit(void) 2981135740deSSeth Forshee { 2982135740deSSeth Forshee acpi_bus_unregister_driver(&toshiba_acpi_driver); 2983135740deSSeth Forshee if (toshiba_proc_dir) 2984135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 2985b4f9fe12SLen Brown } 2986b4f9fe12SLen Brown 2987b4f9fe12SLen Brown module_init(toshiba_acpi_init); 2988b4f9fe12SLen Brown module_exit(toshiba_acpi_exit); 2989