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 34495078f8SAzael Avalos #define TOSHIBA_ACPI_VERSION "0.23" 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 96e1a949c1SAzael 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_SUCCESS) 463ea215a3fSAzael Avalos dev->illumination_supported = 1; 4646c3f6e6cSPierre Ducroquet } 4656c3f6e6cSPierre Ducroquet 4666c3f6e6cSPierre Ducroquet static void toshiba_illumination_set(struct led_classdev *cdev, 4676c3f6e6cSPierre Ducroquet enum led_brightness brightness) 4686c3f6e6cSPierre Ducroquet { 469135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 470135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 471e1a949c1SAzael Avalos u32 result; 472e1a949c1SAzael Avalos u32 state; 4736c3f6e6cSPierre Ducroquet 4746c3f6e6cSPierre Ducroquet /* First request : initialize communication. */ 475fdb79081SAzael Avalos if (!sci_open(dev)) 4766c3f6e6cSPierre Ducroquet return; 4776c3f6e6cSPierre Ducroquet 478fdb79081SAzael Avalos /* Switch the illumination on/off */ 479fdb79081SAzael Avalos state = brightness ? 1 : 0; 480893f3f62SAzael Avalos result = sci_write(dev, SCI_ILLUMINATION, state); 481fdb79081SAzael Avalos sci_close(dev); 482a6b5354fSAzael Avalos if (result == TOS_FAILURE) 483fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 4846c3f6e6cSPierre Ducroquet } 4856c3f6e6cSPierre Ducroquet 4866c3f6e6cSPierre Ducroquet static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) 4876c3f6e6cSPierre Ducroquet { 488135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 489135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 490fdb79081SAzael Avalos u32 state, result; 4916c3f6e6cSPierre Ducroquet 4923f75bbe9SAzael Avalos /* First request : initialize communication. */ 493fdb79081SAzael Avalos if (!sci_open(dev)) 4946c3f6e6cSPierre Ducroquet return LED_OFF; 4956c3f6e6cSPierre Ducroquet 4966c3f6e6cSPierre Ducroquet /* Check the illumination */ 497893f3f62SAzael Avalos result = sci_read(dev, SCI_ILLUMINATION, &state); 498fdb79081SAzael Avalos sci_close(dev); 499a6b5354fSAzael Avalos if (result == TOS_FAILURE) { 500fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 501fdb79081SAzael Avalos return LED_OFF; 502e1a949c1SAzael Avalos } else if (result != TOS_SUCCESS) { 5036c3f6e6cSPierre Ducroquet return LED_OFF; 5046c3f6e6cSPierre Ducroquet } 5056c3f6e6cSPierre Ducroquet 506fdb79081SAzael Avalos return state ? LED_FULL : LED_OFF; 5076c3f6e6cSPierre Ducroquet } 5086c3f6e6cSPierre Ducroquet 509360f0f39SAzael Avalos /* KBD Illumination */ 510ea215a3fSAzael Avalos static void toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev) 51193f8c16dSAzael Avalos { 512258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 }; 513258c5903SAzael Avalos u32 out[TCI_WORDS]; 51493f8c16dSAzael Avalos acpi_status status; 51593f8c16dSAzael Avalos 516ea215a3fSAzael Avalos dev->kbd_illum_supported = 0; 517ea215a3fSAzael Avalos dev->kbd_led_registered = false; 518ea215a3fSAzael Avalos 51993f8c16dSAzael Avalos if (!sci_open(dev)) 520ea215a3fSAzael Avalos return; 52193f8c16dSAzael Avalos 522258c5903SAzael Avalos status = tci_raw(dev, in, out); 52393f8c16dSAzael Avalos sci_close(dev); 524a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) { 52593f8c16dSAzael Avalos pr_err("ACPI call to query kbd illumination support failed\n"); 526ea215a3fSAzael Avalos } else if (out[0] == TOS_SUCCESS) { 527e0769fe6SDarren Hart /* 528e0769fe6SDarren Hart * Check for keyboard backlight timeout max value, 52993f8c16dSAzael Avalos * previous kbd backlight implementation set this to 53093f8c16dSAzael Avalos * 0x3c0003, and now the new implementation set this 531e0769fe6SDarren Hart * to 0x3c001a, use this to distinguish between them. 53293f8c16dSAzael Avalos */ 53393f8c16dSAzael Avalos if (out[3] == SCI_KBD_TIME_MAX) 53493f8c16dSAzael Avalos dev->kbd_type = 2; 53593f8c16dSAzael Avalos else 53693f8c16dSAzael Avalos dev->kbd_type = 1; 53793f8c16dSAzael Avalos /* Get the current keyboard backlight mode */ 53893f8c16dSAzael Avalos dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK; 53993f8c16dSAzael Avalos /* Get the current time (1-60 seconds) */ 54093f8c16dSAzael Avalos dev->kbd_time = out[2] >> HCI_MISC_SHIFT; 541ea215a3fSAzael Avalos /* Flag as supported */ 542ea215a3fSAzael Avalos dev->kbd_illum_supported = 1; 543ea215a3fSAzael Avalos } 54493f8c16dSAzael Avalos } 54593f8c16dSAzael Avalos 546360f0f39SAzael Avalos static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time) 547360f0f39SAzael Avalos { 548360f0f39SAzael Avalos u32 result; 549360f0f39SAzael Avalos 550360f0f39SAzael Avalos if (!sci_open(dev)) 551360f0f39SAzael Avalos return -EIO; 552360f0f39SAzael Avalos 553893f3f62SAzael Avalos result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time); 554360f0f39SAzael Avalos sci_close(dev); 555a6b5354fSAzael Avalos if (result == TOS_FAILURE) 556360f0f39SAzael Avalos pr_err("ACPI call to set KBD backlight status failed\n"); 557a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 558360f0f39SAzael Avalos return -ENODEV; 559360f0f39SAzael Avalos 560e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 561360f0f39SAzael Avalos } 562360f0f39SAzael Avalos 563360f0f39SAzael Avalos static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time) 564360f0f39SAzael Avalos { 565360f0f39SAzael Avalos u32 result; 566360f0f39SAzael Avalos 567360f0f39SAzael Avalos if (!sci_open(dev)) 568360f0f39SAzael Avalos return -EIO; 569360f0f39SAzael Avalos 570893f3f62SAzael Avalos result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time); 571360f0f39SAzael Avalos sci_close(dev); 572a6b5354fSAzael Avalos if (result == TOS_FAILURE) 573360f0f39SAzael Avalos pr_err("ACPI call to get KBD backlight status failed\n"); 574a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 575360f0f39SAzael Avalos return -ENODEV; 576360f0f39SAzael Avalos 577e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 578360f0f39SAzael Avalos } 579360f0f39SAzael Avalos 580360f0f39SAzael Avalos static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev) 581360f0f39SAzael Avalos { 582360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 583360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 584e1a949c1SAzael Avalos u32 result; 585e1a949c1SAzael Avalos u32 state; 586360f0f39SAzael Avalos 587360f0f39SAzael Avalos /* Check the keyboard backlight state */ 588d37782bdSAzael Avalos result = hci_read(dev, HCI_KBD_ILLUMINATION, &state); 589a6b5354fSAzael Avalos if (result == TOS_FAILURE) { 590360f0f39SAzael Avalos pr_err("ACPI call to get the keyboard backlight failed\n"); 591360f0f39SAzael Avalos return LED_OFF; 592e1a949c1SAzael Avalos } else if (result != TOS_SUCCESS) { 593360f0f39SAzael Avalos return LED_OFF; 594360f0f39SAzael Avalos } 595360f0f39SAzael Avalos 596360f0f39SAzael Avalos return state ? LED_FULL : LED_OFF; 597360f0f39SAzael Avalos } 598360f0f39SAzael Avalos 599360f0f39SAzael Avalos static void toshiba_kbd_backlight_set(struct led_classdev *cdev, 600360f0f39SAzael Avalos enum led_brightness brightness) 601360f0f39SAzael Avalos { 602360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 603360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 604e1a949c1SAzael Avalos u32 result; 605e1a949c1SAzael Avalos u32 state; 606360f0f39SAzael Avalos 607360f0f39SAzael Avalos /* Set the keyboard backlight state */ 608360f0f39SAzael Avalos state = brightness ? 1 : 0; 609d37782bdSAzael Avalos result = hci_write(dev, HCI_KBD_ILLUMINATION, state); 610a6b5354fSAzael Avalos if (result == TOS_FAILURE) 611360f0f39SAzael Avalos pr_err("ACPI call to set KBD Illumination mode failed\n"); 612360f0f39SAzael Avalos } 613360f0f39SAzael Avalos 6149d8658acSAzael Avalos /* TouchPad support */ 6159d8658acSAzael Avalos static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state) 6169d8658acSAzael Avalos { 6179d8658acSAzael Avalos u32 result; 6189d8658acSAzael Avalos 6199d8658acSAzael Avalos if (!sci_open(dev)) 6209d8658acSAzael Avalos return -EIO; 6219d8658acSAzael Avalos 622893f3f62SAzael Avalos result = sci_write(dev, SCI_TOUCHPAD, state); 6239d8658acSAzael Avalos sci_close(dev); 624a6b5354fSAzael Avalos if (result == TOS_FAILURE) 6259d8658acSAzael Avalos pr_err("ACPI call to set the touchpad failed\n"); 626a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 6279d8658acSAzael Avalos return -ENODEV; 6289d8658acSAzael Avalos 629e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 6309d8658acSAzael Avalos } 6319d8658acSAzael Avalos 6329d8658acSAzael Avalos static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) 6339d8658acSAzael Avalos { 6349d8658acSAzael Avalos u32 result; 6359d8658acSAzael Avalos 6369d8658acSAzael Avalos if (!sci_open(dev)) 6379d8658acSAzael Avalos return -EIO; 6389d8658acSAzael Avalos 639893f3f62SAzael Avalos result = sci_read(dev, SCI_TOUCHPAD, state); 6409d8658acSAzael Avalos sci_close(dev); 641a6b5354fSAzael Avalos if (result == TOS_FAILURE) 6429d8658acSAzael Avalos pr_err("ACPI call to query the touchpad failed\n"); 643a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 6449d8658acSAzael Avalos return -ENODEV; 6459d8658acSAzael Avalos 646e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 6479d8658acSAzael Avalos } 6489d8658acSAzael Avalos 649def6c4e2SAzael Avalos /* Eco Mode support */ 650ea215a3fSAzael Avalos static void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) 651def6c4e2SAzael Avalos { 652def6c4e2SAzael Avalos acpi_status status; 65398fc4ec6SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 }; 654258c5903SAzael Avalos u32 out[TCI_WORDS]; 655def6c4e2SAzael Avalos 656ea215a3fSAzael Avalos dev->eco_supported = 0; 657ea215a3fSAzael Avalos dev->eco_led_registered = false; 658ea215a3fSAzael Avalos 659258c5903SAzael Avalos status = tci_raw(dev, in, out); 6608baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 66198fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 66298fc4ec6SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 663e0769fe6SDarren Hart /* 664e0769fe6SDarren Hart * If we receive 0x8300 (Input Data Error), it means that the 66598fc4ec6SAzael Avalos * LED device is present, but that we just screwed the input 66698fc4ec6SAzael Avalos * parameters. 66798fc4ec6SAzael Avalos * 66898fc4ec6SAzael Avalos * Let's query the status of the LED to see if we really have a 66998fc4ec6SAzael Avalos * success response, indicating the actual presense of the LED, 67098fc4ec6SAzael Avalos * bail out otherwise. 67198fc4ec6SAzael Avalos */ 67298fc4ec6SAzael Avalos in[3] = 1; 67398fc4ec6SAzael Avalos status = tci_raw(dev, in, out); 674a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) 67598fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 67698fc4ec6SAzael Avalos else if (out[0] == TOS_SUCCESS) 677ea215a3fSAzael Avalos dev->eco_supported = 1; 678def6c4e2SAzael Avalos } 679def6c4e2SAzael Avalos } 680def6c4e2SAzael Avalos 681b5163992SAzael Avalos static enum led_brightness 682b5163992SAzael Avalos toshiba_eco_mode_get_status(struct led_classdev *cdev) 683def6c4e2SAzael Avalos { 684def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 685def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 686258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 }; 687258c5903SAzael Avalos u32 out[TCI_WORDS]; 688def6c4e2SAzael Avalos acpi_status status; 689def6c4e2SAzael Avalos 690258c5903SAzael Avalos status = tci_raw(dev, in, out); 691a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) { 692def6c4e2SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 693def6c4e2SAzael Avalos return LED_OFF; 694e1a949c1SAzael Avalos } else if (out[0] != TOS_SUCCESS) { 695e1a949c1SAzael Avalos return LED_OFF; 696def6c4e2SAzael Avalos } 697def6c4e2SAzael Avalos 698def6c4e2SAzael Avalos return out[2] ? LED_FULL : LED_OFF; 699def6c4e2SAzael Avalos } 700def6c4e2SAzael Avalos 701def6c4e2SAzael Avalos static void toshiba_eco_mode_set_status(struct led_classdev *cdev, 702def6c4e2SAzael Avalos enum led_brightness brightness) 703def6c4e2SAzael Avalos { 704def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 705def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 706258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 }; 707258c5903SAzael Avalos u32 out[TCI_WORDS]; 708def6c4e2SAzael Avalos acpi_status status; 709def6c4e2SAzael Avalos 710def6c4e2SAzael Avalos /* Switch the Eco Mode led on/off */ 711def6c4e2SAzael Avalos in[2] = (brightness) ? 1 : 0; 712258c5903SAzael Avalos status = tci_raw(dev, in, out); 713a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) 714def6c4e2SAzael Avalos pr_err("ACPI call to set ECO led failed\n"); 715def6c4e2SAzael Avalos } 716def6c4e2SAzael Avalos 7175a2813e9SAzael Avalos /* Accelerometer support */ 718ea215a3fSAzael Avalos static void toshiba_accelerometer_available(struct toshiba_acpi_dev *dev) 7195a2813e9SAzael Avalos { 720258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 }; 721258c5903SAzael Avalos u32 out[TCI_WORDS]; 7225a2813e9SAzael Avalos acpi_status status; 7235a2813e9SAzael Avalos 724ea215a3fSAzael Avalos dev->accelerometer_supported = 0; 725ea215a3fSAzael Avalos 726e0769fe6SDarren Hart /* 727e0769fe6SDarren Hart * Check if the accelerometer call exists, 7285a2813e9SAzael Avalos * this call also serves as initialization 7295a2813e9SAzael Avalos */ 730258c5903SAzael Avalos status = tci_raw(dev, in, out); 731a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) 7325a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 733ea215a3fSAzael Avalos else if (out[0] == TOS_SUCCESS) 734ea215a3fSAzael Avalos dev->accelerometer_supported = 1; 7355a2813e9SAzael Avalos } 7365a2813e9SAzael Avalos 7375a2813e9SAzael Avalos static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, 7385a2813e9SAzael Avalos u32 *xy, u32 *z) 7395a2813e9SAzael Avalos { 740258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 }; 741258c5903SAzael Avalos u32 out[TCI_WORDS]; 7425a2813e9SAzael Avalos acpi_status status; 7435a2813e9SAzael Avalos 7445a2813e9SAzael Avalos /* Check the Accelerometer status */ 745258c5903SAzael Avalos status = tci_raw(dev, in, out); 746a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) { 7475a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 7485a2813e9SAzael Avalos return -EIO; 749e1a949c1SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 750e1a949c1SAzael Avalos return -ENODEV; 751e1a949c1SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 7525a2813e9SAzael Avalos *xy = out[2]; 7535a2813e9SAzael Avalos *z = out[4]; 7545a2813e9SAzael Avalos return 0; 7555a2813e9SAzael Avalos } 7565a2813e9SAzael Avalos 757e1a949c1SAzael Avalos return -EIO; 758e1a949c1SAzael Avalos } 759e1a949c1SAzael Avalos 760e26ffe51SAzael Avalos /* Sleep (Charge and Music) utilities support */ 761c8c91842SAzael Avalos static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev) 762c8c91842SAzael Avalos { 763c8c91842SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 764c8c91842SAzael Avalos u32 out[TCI_WORDS]; 765c8c91842SAzael Avalos acpi_status status; 766c8c91842SAzael Avalos 767c8c91842SAzael Avalos dev->usb_sleep_charge_supported = 0; 768c8c91842SAzael Avalos 769c8c91842SAzael Avalos if (!sci_open(dev)) 770c8c91842SAzael Avalos return; 771c8c91842SAzael Avalos 772c8c91842SAzael Avalos status = tci_raw(dev, in, out); 7738baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 774c8c91842SAzael Avalos pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); 775c8c91842SAzael Avalos sci_close(dev); 776c8c91842SAzael Avalos return; 777c8c91842SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 778c8c91842SAzael Avalos sci_close(dev); 779c8c91842SAzael Avalos return; 780c8c91842SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 781c8c91842SAzael Avalos dev->usbsc_mode_base = out[4]; 782c8c91842SAzael Avalos } 783c8c91842SAzael Avalos 784c8c91842SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 785c8c91842SAzael Avalos status = tci_raw(dev, in, out); 786ea215a3fSAzael Avalos sci_close(dev); 7878baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 788c8c91842SAzael Avalos pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); 789c8c91842SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 790c8c91842SAzael Avalos dev->usbsc_bat_level = out[2]; 791ea215a3fSAzael Avalos /* Flag as supported */ 792c8c91842SAzael Avalos dev->usb_sleep_charge_supported = 1; 793c8c91842SAzael Avalos } 794c8c91842SAzael Avalos 795c8c91842SAzael Avalos } 796c8c91842SAzael Avalos 797e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, 798e26ffe51SAzael Avalos u32 *mode) 799e26ffe51SAzael Avalos { 800e26ffe51SAzael Avalos u32 result; 801e26ffe51SAzael Avalos 802e26ffe51SAzael Avalos if (!sci_open(dev)) 803e26ffe51SAzael Avalos return -EIO; 804e26ffe51SAzael Avalos 805e26ffe51SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode); 806e26ffe51SAzael Avalos sci_close(dev); 807a6b5354fSAzael Avalos if (result == TOS_FAILURE) 808e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 809a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 810e26ffe51SAzael Avalos return -ENODEV; 811e26ffe51SAzael Avalos 812e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 813e26ffe51SAzael Avalos } 814e26ffe51SAzael Avalos 815e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev, 816e26ffe51SAzael Avalos u32 mode) 817e26ffe51SAzael Avalos { 818e26ffe51SAzael Avalos u32 result; 819e26ffe51SAzael Avalos 820e26ffe51SAzael Avalos if (!sci_open(dev)) 821e26ffe51SAzael Avalos return -EIO; 822e26ffe51SAzael Avalos 823e26ffe51SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode); 824e26ffe51SAzael Avalos sci_close(dev); 825a6b5354fSAzael Avalos if (result == TOS_FAILURE) 826e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 827a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 828e26ffe51SAzael Avalos return -ENODEV; 829e26ffe51SAzael Avalos 830e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 831e26ffe51SAzael Avalos } 832e26ffe51SAzael Avalos 833182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev, 834182bcaa5SAzael Avalos u32 *mode) 835182bcaa5SAzael Avalos { 836182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 837182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 838182bcaa5SAzael Avalos acpi_status status; 839182bcaa5SAzael Avalos 840182bcaa5SAzael Avalos if (!sci_open(dev)) 841182bcaa5SAzael Avalos return -EIO; 842182bcaa5SAzael Avalos 843182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 844182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 845182bcaa5SAzael Avalos sci_close(dev); 8468baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 847182bcaa5SAzael Avalos pr_err("ACPI call to get USB S&C battery level failed\n"); 848182bcaa5SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 849182bcaa5SAzael Avalos return -ENODEV; 850e1a949c1SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 851e1a949c1SAzael Avalos *mode = out[2]; 852e1a949c1SAzael Avalos return 0; 853182bcaa5SAzael Avalos } 854182bcaa5SAzael Avalos 855e1a949c1SAzael Avalos return -EIO; 856182bcaa5SAzael Avalos } 857182bcaa5SAzael Avalos 858182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, 859182bcaa5SAzael Avalos u32 mode) 860182bcaa5SAzael Avalos { 861182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 862182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 863182bcaa5SAzael Avalos acpi_status status; 864182bcaa5SAzael Avalos 865182bcaa5SAzael Avalos if (!sci_open(dev)) 866182bcaa5SAzael Avalos return -EIO; 867182bcaa5SAzael Avalos 868182bcaa5SAzael Avalos in[2] = mode; 869182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 870182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 871182bcaa5SAzael Avalos sci_close(dev); 872a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) 873182bcaa5SAzael Avalos pr_err("ACPI call to set USB S&C battery level failed\n"); 874a6b5354fSAzael Avalos else if (out[0] == TOS_NOT_SUPPORTED) 875182bcaa5SAzael Avalos return -ENODEV; 876182bcaa5SAzael Avalos 877e1a949c1SAzael Avalos return out[0] == TOS_SUCCESS ? 0 : -EIO; 878182bcaa5SAzael Avalos } 879182bcaa5SAzael Avalos 880bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, 881bb3fe01fSAzael Avalos u32 *state) 882bb3fe01fSAzael Avalos { 883bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 884bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 885bb3fe01fSAzael Avalos acpi_status status; 886bb3fe01fSAzael Avalos 887bb3fe01fSAzael Avalos if (!sci_open(dev)) 888bb3fe01fSAzael Avalos return -EIO; 889bb3fe01fSAzael Avalos 890bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 891bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 892bb3fe01fSAzael Avalos sci_close(dev); 8938baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 894bb26f189SAzael Avalos pr_err("ACPI call to get USB Rapid Charge failed\n"); 895a6b5354fSAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 896bb3fe01fSAzael Avalos return -ENODEV; 897e1a949c1SAzael Avalos } else if (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) { 898e1a949c1SAzael Avalos *state = out[2]; 899e1a949c1SAzael Avalos return 0; 900bb3fe01fSAzael Avalos } 901bb3fe01fSAzael Avalos 902e1a949c1SAzael Avalos return -EIO; 903bb3fe01fSAzael Avalos } 904bb3fe01fSAzael Avalos 905bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, 906bb3fe01fSAzael Avalos u32 state) 907bb3fe01fSAzael Avalos { 908bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 909bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 910bb3fe01fSAzael Avalos acpi_status status; 911bb3fe01fSAzael Avalos 912bb3fe01fSAzael Avalos if (!sci_open(dev)) 913bb3fe01fSAzael Avalos return -EIO; 914bb3fe01fSAzael Avalos 915bb3fe01fSAzael Avalos in[2] = state; 916bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 917bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 918bb3fe01fSAzael Avalos sci_close(dev); 919a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) 920bb26f189SAzael Avalos pr_err("ACPI call to set USB Rapid Charge failed\n"); 921a6b5354fSAzael Avalos else if (out[0] == TOS_NOT_SUPPORTED) 922bb3fe01fSAzael Avalos return -ENODEV; 923bb3fe01fSAzael Avalos 924e1a949c1SAzael Avalos return (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) ? 0 : -EIO; 925bb3fe01fSAzael Avalos } 926bb3fe01fSAzael Avalos 927172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state) 928172ce0a9SAzael Avalos { 929172ce0a9SAzael Avalos u32 result; 930172ce0a9SAzael Avalos 931172ce0a9SAzael Avalos if (!sci_open(dev)) 932172ce0a9SAzael Avalos return -EIO; 933172ce0a9SAzael Avalos 934172ce0a9SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state); 935172ce0a9SAzael Avalos sci_close(dev); 936a6b5354fSAzael Avalos if (result == TOS_FAILURE) 937bb26f189SAzael Avalos pr_err("ACPI call to get Sleep and Music failed\n"); 938a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 939172ce0a9SAzael Avalos return -ENODEV; 940172ce0a9SAzael Avalos 941cf680eaeSAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 942172ce0a9SAzael Avalos } 943172ce0a9SAzael Avalos 944172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state) 945172ce0a9SAzael Avalos { 946172ce0a9SAzael Avalos u32 result; 947172ce0a9SAzael Avalos 948172ce0a9SAzael Avalos if (!sci_open(dev)) 949172ce0a9SAzael Avalos return -EIO; 950172ce0a9SAzael Avalos 951172ce0a9SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state); 952172ce0a9SAzael Avalos sci_close(dev); 953a6b5354fSAzael Avalos if (result == TOS_FAILURE) 954bb26f189SAzael Avalos pr_err("ACPI call to set Sleep and Music failed\n"); 955a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 956172ce0a9SAzael Avalos return -ENODEV; 957172ce0a9SAzael Avalos 958e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 959172ce0a9SAzael Avalos } 960172ce0a9SAzael Avalos 961bae84195SAzael Avalos /* Keyboard function keys */ 962bae84195SAzael Avalos static int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode) 963bae84195SAzael Avalos { 964bae84195SAzael Avalos u32 result; 965bae84195SAzael Avalos 966bae84195SAzael Avalos if (!sci_open(dev)) 967bae84195SAzael Avalos return -EIO; 968bae84195SAzael Avalos 969bae84195SAzael Avalos result = sci_read(dev, SCI_KBD_FUNCTION_KEYS, mode); 970bae84195SAzael Avalos sci_close(dev); 971a6b5354fSAzael Avalos if (result == TOS_FAILURE) 972bae84195SAzael Avalos pr_err("ACPI call to get KBD function keys failed\n"); 973a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 974bae84195SAzael Avalos return -ENODEV; 975bae84195SAzael Avalos 976e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 977bae84195SAzael Avalos } 978bae84195SAzael Avalos 979bae84195SAzael Avalos static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode) 980bae84195SAzael Avalos { 981bae84195SAzael Avalos u32 result; 982bae84195SAzael Avalos 983bae84195SAzael Avalos if (!sci_open(dev)) 984bae84195SAzael Avalos return -EIO; 985bae84195SAzael Avalos 986bae84195SAzael Avalos result = sci_write(dev, SCI_KBD_FUNCTION_KEYS, mode); 987bae84195SAzael Avalos sci_close(dev); 988a6b5354fSAzael Avalos if (result == TOS_FAILURE) 989bae84195SAzael Avalos pr_err("ACPI call to set KBD function keys failed\n"); 990a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 991bae84195SAzael Avalos return -ENODEV; 992bae84195SAzael Avalos 993e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 994bae84195SAzael Avalos } 995bae84195SAzael Avalos 99635d53ceaSAzael Avalos /* Panel Power ON */ 99735d53ceaSAzael Avalos static int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state) 99835d53ceaSAzael Avalos { 99935d53ceaSAzael Avalos u32 result; 100035d53ceaSAzael Avalos 100135d53ceaSAzael Avalos if (!sci_open(dev)) 100235d53ceaSAzael Avalos return -EIO; 100335d53ceaSAzael Avalos 100435d53ceaSAzael Avalos result = sci_read(dev, SCI_PANEL_POWER_ON, state); 100535d53ceaSAzael Avalos sci_close(dev); 1006a6b5354fSAzael Avalos if (result == TOS_FAILURE) 100735d53ceaSAzael Avalos pr_err("ACPI call to get Panel Power ON failed\n"); 1008a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 100935d53ceaSAzael Avalos return -ENODEV; 101035d53ceaSAzael Avalos 1011e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 101235d53ceaSAzael Avalos } 101335d53ceaSAzael Avalos 101435d53ceaSAzael Avalos static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state) 101535d53ceaSAzael Avalos { 101635d53ceaSAzael Avalos u32 result; 101735d53ceaSAzael Avalos 101835d53ceaSAzael Avalos if (!sci_open(dev)) 101935d53ceaSAzael Avalos return -EIO; 102035d53ceaSAzael Avalos 102135d53ceaSAzael Avalos result = sci_write(dev, SCI_PANEL_POWER_ON, state); 102235d53ceaSAzael Avalos sci_close(dev); 1023a6b5354fSAzael Avalos if (result == TOS_FAILURE) 102435d53ceaSAzael Avalos pr_err("ACPI call to set Panel Power ON failed\n"); 1025a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 102635d53ceaSAzael Avalos return -ENODEV; 102735d53ceaSAzael Avalos 1028e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 102935d53ceaSAzael Avalos } 103035d53ceaSAzael Avalos 103117fe4b3dSAzael Avalos /* USB Three */ 103217fe4b3dSAzael Avalos static int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state) 103317fe4b3dSAzael Avalos { 103417fe4b3dSAzael Avalos u32 result; 103517fe4b3dSAzael Avalos 103617fe4b3dSAzael Avalos if (!sci_open(dev)) 103717fe4b3dSAzael Avalos return -EIO; 103817fe4b3dSAzael Avalos 103917fe4b3dSAzael Avalos result = sci_read(dev, SCI_USB_THREE, state); 104017fe4b3dSAzael Avalos sci_close(dev); 1041a6b5354fSAzael Avalos if (result == TOS_FAILURE) 104217fe4b3dSAzael Avalos pr_err("ACPI call to get USB 3 failed\n"); 1043a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 104417fe4b3dSAzael Avalos return -ENODEV; 104517fe4b3dSAzael Avalos 1046e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 104717fe4b3dSAzael Avalos } 104817fe4b3dSAzael Avalos 104917fe4b3dSAzael Avalos static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state) 105017fe4b3dSAzael Avalos { 105117fe4b3dSAzael Avalos u32 result; 105217fe4b3dSAzael Avalos 105317fe4b3dSAzael Avalos if (!sci_open(dev)) 105417fe4b3dSAzael Avalos return -EIO; 105517fe4b3dSAzael Avalos 105617fe4b3dSAzael Avalos result = sci_write(dev, SCI_USB_THREE, state); 105717fe4b3dSAzael Avalos sci_close(dev); 1058a6b5354fSAzael Avalos if (result == TOS_FAILURE) 105917fe4b3dSAzael Avalos pr_err("ACPI call to set USB 3 failed\n"); 1060a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 106117fe4b3dSAzael Avalos return -ENODEV; 106217fe4b3dSAzael Avalos 1063e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 106417fe4b3dSAzael Avalos } 106517fe4b3dSAzael Avalos 106656e6b353SAzael Avalos /* Hotkey Event type */ 106756e6b353SAzael Avalos static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev, 106856e6b353SAzael Avalos u32 *type) 106956e6b353SAzael Avalos { 10703b876000SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_SYSTEM_INFO, 0x03, 0, 0, 0 }; 10713b876000SAzael Avalos u32 out[TCI_WORDS]; 10723b876000SAzael Avalos acpi_status status; 107356e6b353SAzael Avalos 10743b876000SAzael Avalos status = tci_raw(dev, in, out); 10753b876000SAzael Avalos if (ACPI_FAILURE(status)) { 107656e6b353SAzael Avalos pr_err("ACPI call to get System type failed\n"); 10773b876000SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 107856e6b353SAzael Avalos return -ENODEV; 1079e1a949c1SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 1080e1a949c1SAzael Avalos *type = out[3]; 1081e1a949c1SAzael Avalos return 0; 108256e6b353SAzael Avalos } 108356e6b353SAzael Avalos 1084e1a949c1SAzael Avalos return -EIO; 108556e6b353SAzael Avalos } 108656e6b353SAzael Avalos 10873f75bbe9SAzael Avalos /* Transflective Backlight */ 1088695f6060SAzael Avalos static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status) 1089121b7b0dSAkio Idehara { 1090e1a949c1SAzael Avalos u32 result = hci_read(dev, HCI_TR_BACKLIGHT, status); 1091121b7b0dSAkio Idehara 1092e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1093e1a949c1SAzael Avalos pr_err("ACPI call to get Transflective Backlight failed\n"); 1094e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1095e1a949c1SAzael Avalos return -ENODEV; 1096e1a949c1SAzael Avalos 1097e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1098121b7b0dSAkio Idehara } 1099121b7b0dSAkio Idehara 1100695f6060SAzael Avalos static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 status) 1101121b7b0dSAkio Idehara { 1102e1a949c1SAzael Avalos u32 result = hci_write(dev, HCI_TR_BACKLIGHT, !status); 1103121b7b0dSAkio Idehara 1104e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1105e1a949c1SAzael Avalos pr_err("ACPI call to set Transflective Backlight failed\n"); 1106e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1107e1a949c1SAzael Avalos return -ENODEV; 1108e1a949c1SAzael Avalos 1109e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1110121b7b0dSAkio Idehara } 1111121b7b0dSAkio Idehara 11123f75bbe9SAzael Avalos static struct proc_dir_entry *toshiba_proc_dir; 1113b4f9fe12SLen Brown 11143f75bbe9SAzael Avalos /* LCD Brightness */ 111562cce752SSeth Forshee static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) 1116b4f9fe12SLen Brown { 1117e1a949c1SAzael Avalos u32 result; 1118b4f9fe12SLen Brown u32 value; 1119121b7b0dSAkio Idehara int brightness = 0; 1120121b7b0dSAkio Idehara 1121121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1122695f6060SAzael Avalos int ret = get_tr_backlight_status(dev, &value); 1123b5163992SAzael Avalos 1124121b7b0dSAkio Idehara if (ret) 1125121b7b0dSAkio Idehara return ret; 1126695f6060SAzael Avalos if (value) 1127121b7b0dSAkio Idehara return 0; 1128121b7b0dSAkio Idehara brightness++; 1129121b7b0dSAkio Idehara } 1130b4f9fe12SLen Brown 1131e1a949c1SAzael Avalos result = hci_read(dev, HCI_LCD_BRIGHTNESS, &value); 1132e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1133e1a949c1SAzael Avalos pr_err("ACPI call to get LCD Brightness failed\n"); 1134e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1135e1a949c1SAzael Avalos return -ENODEV; 1136e1a949c1SAzael Avalos if (result == TOS_SUCCESS) 1137121b7b0dSAkio Idehara return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT); 113832bcd5cbSSeth Forshee 113932bcd5cbSSeth Forshee return -EIO; 1140b4f9fe12SLen Brown } 1141b4f9fe12SLen Brown 114262cce752SSeth Forshee static int get_lcd_brightness(struct backlight_device *bd) 114362cce752SSeth Forshee { 114462cce752SSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 1145b5163992SAzael Avalos 114662cce752SSeth Forshee return __get_lcd_brightness(dev); 114762cce752SSeth Forshee } 114862cce752SSeth Forshee 1149936c8bcdSAlexey Dobriyan static int lcd_proc_show(struct seq_file *m, void *v) 1150b4f9fe12SLen Brown { 1151135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1152121b7b0dSAkio Idehara int levels; 1153e1a949c1SAzael Avalos int value; 1154b4f9fe12SLen Brown 1155135740deSSeth Forshee if (!dev->backlight_dev) 1156135740deSSeth Forshee return -ENODEV; 1157135740deSSeth Forshee 1158121b7b0dSAkio Idehara levels = dev->backlight_dev->props.max_brightness + 1; 115962cce752SSeth Forshee value = get_lcd_brightness(dev->backlight_dev); 1160b4f9fe12SLen Brown if (value >= 0) { 1161936c8bcdSAlexey Dobriyan seq_printf(m, "brightness: %d\n", value); 1162121b7b0dSAkio Idehara seq_printf(m, "brightness_levels: %d\n", levels); 116332bcd5cbSSeth Forshee return 0; 1164b4f9fe12SLen Brown } 1165b4f9fe12SLen Brown 116632bcd5cbSSeth Forshee pr_err("Error reading LCD brightness\n"); 1167e1a949c1SAzael Avalos 116832bcd5cbSSeth Forshee return -EIO; 1169936c8bcdSAlexey Dobriyan } 1170936c8bcdSAlexey Dobriyan 1171936c8bcdSAlexey Dobriyan static int lcd_proc_open(struct inode *inode, struct file *file) 1172936c8bcdSAlexey Dobriyan { 1173d9dda78bSAl Viro return single_open(file, lcd_proc_show, PDE_DATA(inode)); 1174b4f9fe12SLen Brown } 1175b4f9fe12SLen Brown 117662cce752SSeth Forshee static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) 1177b4f9fe12SLen Brown { 1178e1a949c1SAzael Avalos u32 result; 1179b4f9fe12SLen Brown 1180121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1181695f6060SAzael Avalos int ret = set_tr_backlight_status(dev, !value); 1182b5163992SAzael Avalos 1183121b7b0dSAkio Idehara if (ret) 1184121b7b0dSAkio Idehara return ret; 1185121b7b0dSAkio Idehara if (value) 1186121b7b0dSAkio Idehara value--; 1187121b7b0dSAkio Idehara } 1188121b7b0dSAkio Idehara 1189a39f46dfSAzael Avalos value = value << HCI_LCD_BRIGHTNESS_SHIFT; 1190e1a949c1SAzael Avalos result = hci_write(dev, HCI_LCD_BRIGHTNESS, value); 1191e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1192e1a949c1SAzael Avalos pr_err("ACPI call to set LCD Brightness failed\n"); 1193e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1194e1a949c1SAzael Avalos return -ENODEV; 1195e1a949c1SAzael Avalos 1196e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1197b4f9fe12SLen Brown } 1198b4f9fe12SLen Brown 1199b4f9fe12SLen Brown static int set_lcd_status(struct backlight_device *bd) 1200b4f9fe12SLen Brown { 1201135740deSSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 1202b5163992SAzael Avalos 120362cce752SSeth Forshee return set_lcd_brightness(dev, bd->props.brightness); 1204b4f9fe12SLen Brown } 1205b4f9fe12SLen Brown 1206936c8bcdSAlexey Dobriyan static ssize_t lcd_proc_write(struct file *file, const char __user *buf, 1207936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1208b4f9fe12SLen Brown { 1209d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1210936c8bcdSAlexey Dobriyan char cmd[42]; 1211936c8bcdSAlexey Dobriyan size_t len; 1212121b7b0dSAkio Idehara int levels = dev->backlight_dev->props.max_brightness + 1; 1213e1a949c1SAzael Avalos int value; 1214b4f9fe12SLen Brown 1215936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1216936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1217936c8bcdSAlexey Dobriyan return -EFAULT; 1218936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1219936c8bcdSAlexey Dobriyan 1220e1a949c1SAzael Avalos if (sscanf(cmd, " brightness : %i", &value) != 1 && 1221e1a949c1SAzael Avalos value < 0 && value > levels) 1222e1a949c1SAzael Avalos return -EINVAL; 1223e1a949c1SAzael Avalos 1224e1a949c1SAzael Avalos if (set_lcd_brightness(dev, value)) 1225e1a949c1SAzael Avalos return -EIO; 1226e1a949c1SAzael Avalos 1227e1a949c1SAzael Avalos return count; 1228b4f9fe12SLen Brown } 1229b4f9fe12SLen Brown 1230936c8bcdSAlexey Dobriyan static const struct file_operations lcd_proc_fops = { 1231936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1232936c8bcdSAlexey Dobriyan .open = lcd_proc_open, 1233936c8bcdSAlexey Dobriyan .read = seq_read, 1234936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1235936c8bcdSAlexey Dobriyan .release = single_release, 1236936c8bcdSAlexey Dobriyan .write = lcd_proc_write, 1237936c8bcdSAlexey Dobriyan }; 1238936c8bcdSAlexey Dobriyan 1239e1a949c1SAzael Avalos /* Video-Out */ 124036d03f93SSeth Forshee static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status) 124136d03f93SSeth Forshee { 1242e1a949c1SAzael Avalos u32 result = hci_read(dev, HCI_VIDEO_OUT, status); 124336d03f93SSeth Forshee 1244e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1245e1a949c1SAzael Avalos pr_err("ACPI call to get Video-Out failed\n"); 1246e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1247e1a949c1SAzael Avalos return -ENODEV; 1248e1a949c1SAzael Avalos 1249e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 125036d03f93SSeth Forshee } 125136d03f93SSeth Forshee 1252936c8bcdSAlexey Dobriyan static int video_proc_show(struct seq_file *m, void *v) 1253b4f9fe12SLen Brown { 1254135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1255b4f9fe12SLen Brown u32 value; 1256b4f9fe12SLen Brown 1257e1a949c1SAzael Avalos if (!get_video_status(dev, &value)) { 1258b4f9fe12SLen Brown int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; 1259b4f9fe12SLen Brown int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; 1260b4f9fe12SLen Brown int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; 1261b5163992SAzael Avalos 1262936c8bcdSAlexey Dobriyan seq_printf(m, "lcd_out: %d\n", is_lcd); 1263936c8bcdSAlexey Dobriyan seq_printf(m, "crt_out: %d\n", is_crt); 1264936c8bcdSAlexey Dobriyan seq_printf(m, "tv_out: %d\n", is_tv); 1265e1a949c1SAzael Avalos return 0; 1266b4f9fe12SLen Brown } 1267b4f9fe12SLen Brown 1268e1a949c1SAzael Avalos return -EIO; 1269b4f9fe12SLen Brown } 1270b4f9fe12SLen Brown 1271936c8bcdSAlexey Dobriyan static int video_proc_open(struct inode *inode, struct file *file) 1272b4f9fe12SLen Brown { 1273d9dda78bSAl Viro return single_open(file, video_proc_show, PDE_DATA(inode)); 1274936c8bcdSAlexey Dobriyan } 1275936c8bcdSAlexey Dobriyan 1276936c8bcdSAlexey Dobriyan static ssize_t video_proc_write(struct file *file, const char __user *buf, 1277936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1278936c8bcdSAlexey Dobriyan { 1279d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1280e1a949c1SAzael Avalos char *buffer; 1281e1a949c1SAzael Avalos char *cmd; 1282b4f9fe12SLen Brown int remain = count; 1283b4f9fe12SLen Brown int lcd_out = -1; 1284b4f9fe12SLen Brown int crt_out = -1; 1285b4f9fe12SLen Brown int tv_out = -1; 1286e1a949c1SAzael Avalos int value; 1287e1a949c1SAzael Avalos int ret; 1288b4f9fe12SLen Brown u32 video_out; 1289b4f9fe12SLen Brown 1290936c8bcdSAlexey Dobriyan cmd = kmalloc(count + 1, GFP_KERNEL); 1291936c8bcdSAlexey Dobriyan if (!cmd) 1292936c8bcdSAlexey Dobriyan return -ENOMEM; 1293936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, count)) { 1294936c8bcdSAlexey Dobriyan kfree(cmd); 1295936c8bcdSAlexey Dobriyan return -EFAULT; 1296936c8bcdSAlexey Dobriyan } 1297936c8bcdSAlexey Dobriyan cmd[count] = '\0'; 1298936c8bcdSAlexey Dobriyan 1299936c8bcdSAlexey Dobriyan buffer = cmd; 1300936c8bcdSAlexey Dobriyan 1301e0769fe6SDarren Hart /* 1302e0769fe6SDarren Hart * Scan expression. Multiple expressions may be delimited with ; 1303e0769fe6SDarren Hart * NOTE: To keep scanning simple, invalid fields are ignored. 1304b4f9fe12SLen Brown */ 1305b4f9fe12SLen Brown while (remain) { 1306b4f9fe12SLen Brown if (sscanf(buffer, " lcd_out : %i", &value) == 1) 1307b4f9fe12SLen Brown lcd_out = value & 1; 1308b4f9fe12SLen Brown else if (sscanf(buffer, " crt_out : %i", &value) == 1) 1309b4f9fe12SLen Brown crt_out = value & 1; 1310b4f9fe12SLen Brown else if (sscanf(buffer, " tv_out : %i", &value) == 1) 1311b4f9fe12SLen Brown tv_out = value & 1; 1312e0769fe6SDarren Hart /* Advance to one character past the next ; */ 1313b4f9fe12SLen Brown do { 1314b4f9fe12SLen Brown ++buffer; 1315b4f9fe12SLen Brown --remain; 1316b5163992SAzael Avalos } while (remain && *(buffer - 1) != ';'); 1317b4f9fe12SLen Brown } 1318b4f9fe12SLen Brown 1319936c8bcdSAlexey Dobriyan kfree(cmd); 1320936c8bcdSAlexey Dobriyan 132136d03f93SSeth Forshee ret = get_video_status(dev, &video_out); 132236d03f93SSeth Forshee if (!ret) { 1323b4f9fe12SLen Brown unsigned int new_video_out = video_out; 1324b5163992SAzael Avalos 1325b4f9fe12SLen Brown if (lcd_out != -1) 1326b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out); 1327b4f9fe12SLen Brown if (crt_out != -1) 1328b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out); 1329b4f9fe12SLen Brown if (tv_out != -1) 1330b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out); 1331e0769fe6SDarren Hart /* 1332e0769fe6SDarren Hart * To avoid unnecessary video disruption, only write the new 13333f75bbe9SAzael Avalos * video setting if something changed. 13343f75bbe9SAzael Avalos */ 1335b4f9fe12SLen Brown if (new_video_out != video_out) 133632bcd5cbSSeth Forshee ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out); 1337b4f9fe12SLen Brown } 1338b4f9fe12SLen Brown 1339e1a949c1SAzael Avalos return ret ? -EIO : count; 1340b4f9fe12SLen Brown } 1341b4f9fe12SLen Brown 1342936c8bcdSAlexey Dobriyan static const struct file_operations video_proc_fops = { 1343936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1344936c8bcdSAlexey Dobriyan .open = video_proc_open, 1345936c8bcdSAlexey Dobriyan .read = seq_read, 1346936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1347936c8bcdSAlexey Dobriyan .release = single_release, 1348936c8bcdSAlexey Dobriyan .write = video_proc_write, 1349936c8bcdSAlexey Dobriyan }; 1350936c8bcdSAlexey Dobriyan 13513e07e5baSAzael Avalos /* Fan status */ 135236d03f93SSeth Forshee static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status) 135336d03f93SSeth Forshee { 13543e07e5baSAzael Avalos u32 result = hci_read(dev, HCI_FAN, status); 135536d03f93SSeth Forshee 13563e07e5baSAzael Avalos if (result == TOS_FAILURE) 13573e07e5baSAzael Avalos pr_err("ACPI call to get Fan status failed\n"); 13583e07e5baSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 13593e07e5baSAzael Avalos return -ENODEV; 13603e07e5baSAzael Avalos 1361e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 13623e07e5baSAzael Avalos } 13633e07e5baSAzael Avalos 13643e07e5baSAzael Avalos static int set_fan_status(struct toshiba_acpi_dev *dev, u32 status) 13653e07e5baSAzael Avalos { 13663e07e5baSAzael Avalos u32 result = hci_write(dev, HCI_FAN, status); 13673e07e5baSAzael Avalos 13683e07e5baSAzael Avalos if (result == TOS_FAILURE) 13693e07e5baSAzael Avalos pr_err("ACPI call to set Fan status failed\n"); 13703e07e5baSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 13713e07e5baSAzael Avalos return -ENODEV; 13723e07e5baSAzael Avalos 1373e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 137436d03f93SSeth Forshee } 137536d03f93SSeth Forshee 1376936c8bcdSAlexey Dobriyan static int fan_proc_show(struct seq_file *m, void *v) 1377b4f9fe12SLen Brown { 1378135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1379b4f9fe12SLen Brown u32 value; 1380b4f9fe12SLen Brown 13813e07e5baSAzael Avalos if (get_fan_status(dev, &value)) 13823e07e5baSAzael Avalos return -EIO; 13833e07e5baSAzael Avalos 1384936c8bcdSAlexey Dobriyan seq_printf(m, "running: %d\n", (value > 0)); 1385135740deSSeth Forshee seq_printf(m, "force_on: %d\n", dev->force_fan); 1386b4f9fe12SLen Brown 13873e07e5baSAzael Avalos return 0; 1388b4f9fe12SLen Brown } 1389b4f9fe12SLen Brown 1390936c8bcdSAlexey Dobriyan static int fan_proc_open(struct inode *inode, struct file *file) 1391b4f9fe12SLen Brown { 1392d9dda78bSAl Viro return single_open(file, fan_proc_show, PDE_DATA(inode)); 1393936c8bcdSAlexey Dobriyan } 1394936c8bcdSAlexey Dobriyan 1395936c8bcdSAlexey Dobriyan static ssize_t fan_proc_write(struct file *file, const char __user *buf, 1396936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1397936c8bcdSAlexey Dobriyan { 1398d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1399936c8bcdSAlexey Dobriyan char cmd[42]; 1400936c8bcdSAlexey Dobriyan size_t len; 1401b4f9fe12SLen Brown int value; 1402b4f9fe12SLen Brown 1403936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1404936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1405936c8bcdSAlexey Dobriyan return -EFAULT; 1406936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1407936c8bcdSAlexey Dobriyan 14083e07e5baSAzael Avalos if (sscanf(cmd, " force_on : %i", &value) != 1 && 14093e07e5baSAzael Avalos value != 0 && value != 1) 1410b4f9fe12SLen Brown return -EINVAL; 14113e07e5baSAzael Avalos 14123e07e5baSAzael Avalos if (set_fan_status(dev, value)) 14133e07e5baSAzael Avalos return -EIO; 14143e07e5baSAzael Avalos 14153e07e5baSAzael Avalos dev->force_fan = value; 1416b4f9fe12SLen Brown 1417b4f9fe12SLen Brown return count; 1418b4f9fe12SLen Brown } 1419b4f9fe12SLen Brown 1420936c8bcdSAlexey Dobriyan static const struct file_operations fan_proc_fops = { 1421936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1422936c8bcdSAlexey Dobriyan .open = fan_proc_open, 1423936c8bcdSAlexey Dobriyan .read = seq_read, 1424936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1425936c8bcdSAlexey Dobriyan .release = single_release, 1426936c8bcdSAlexey Dobriyan .write = fan_proc_write, 1427936c8bcdSAlexey Dobriyan }; 1428936c8bcdSAlexey Dobriyan 1429936c8bcdSAlexey Dobriyan static int keys_proc_show(struct seq_file *m, void *v) 1430b4f9fe12SLen Brown { 1431135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1432b4f9fe12SLen Brown 1433135740deSSeth Forshee seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid); 1434135740deSSeth Forshee seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event); 14357deef550SAzael Avalos 1436936c8bcdSAlexey Dobriyan return 0; 1437b4f9fe12SLen Brown } 1438b4f9fe12SLen Brown 1439936c8bcdSAlexey Dobriyan static int keys_proc_open(struct inode *inode, struct file *file) 1440b4f9fe12SLen Brown { 1441d9dda78bSAl Viro return single_open(file, keys_proc_show, PDE_DATA(inode)); 1442936c8bcdSAlexey Dobriyan } 1443936c8bcdSAlexey Dobriyan 1444936c8bcdSAlexey Dobriyan static ssize_t keys_proc_write(struct file *file, const char __user *buf, 1445936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1446936c8bcdSAlexey Dobriyan { 1447d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1448936c8bcdSAlexey Dobriyan char cmd[42]; 1449936c8bcdSAlexey Dobriyan size_t len; 1450b4f9fe12SLen Brown int value; 1451b4f9fe12SLen Brown 1452936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1453936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1454936c8bcdSAlexey Dobriyan return -EFAULT; 1455936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1456936c8bcdSAlexey Dobriyan 1457b5163992SAzael Avalos if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) 1458135740deSSeth Forshee dev->key_event_valid = 0; 1459b5163992SAzael Avalos else 1460b4f9fe12SLen Brown return -EINVAL; 1461b4f9fe12SLen Brown 1462b4f9fe12SLen Brown return count; 1463b4f9fe12SLen Brown } 1464b4f9fe12SLen Brown 1465936c8bcdSAlexey Dobriyan static const struct file_operations keys_proc_fops = { 1466936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1467936c8bcdSAlexey Dobriyan .open = keys_proc_open, 1468936c8bcdSAlexey Dobriyan .read = seq_read, 1469936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1470936c8bcdSAlexey Dobriyan .release = single_release, 1471936c8bcdSAlexey Dobriyan .write = keys_proc_write, 1472936c8bcdSAlexey Dobriyan }; 1473936c8bcdSAlexey Dobriyan 1474936c8bcdSAlexey Dobriyan static int version_proc_show(struct seq_file *m, void *v) 1475b4f9fe12SLen Brown { 1476936c8bcdSAlexey Dobriyan seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION); 1477936c8bcdSAlexey Dobriyan seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION); 1478936c8bcdSAlexey Dobriyan return 0; 1479b4f9fe12SLen Brown } 1480b4f9fe12SLen Brown 1481936c8bcdSAlexey Dobriyan static int version_proc_open(struct inode *inode, struct file *file) 1482936c8bcdSAlexey Dobriyan { 1483d9dda78bSAl Viro return single_open(file, version_proc_show, PDE_DATA(inode)); 1484936c8bcdSAlexey Dobriyan } 1485936c8bcdSAlexey Dobriyan 1486936c8bcdSAlexey Dobriyan static const struct file_operations version_proc_fops = { 1487936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1488936c8bcdSAlexey Dobriyan .open = version_proc_open, 1489936c8bcdSAlexey Dobriyan .read = seq_read, 1490936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1491936c8bcdSAlexey Dobriyan .release = single_release, 1492936c8bcdSAlexey Dobriyan }; 1493936c8bcdSAlexey Dobriyan 1494e0769fe6SDarren Hart /* 1495e0769fe6SDarren Hart * Proc and module init 1496b4f9fe12SLen Brown */ 1497b4f9fe12SLen Brown 1498b4f9fe12SLen Brown #define PROC_TOSHIBA "toshiba" 1499b4f9fe12SLen Brown 1500b859f159SGreg Kroah-Hartman static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1501b4f9fe12SLen Brown { 150236d03f93SSeth Forshee if (dev->backlight_dev) 1503135740deSSeth Forshee proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1504135740deSSeth Forshee &lcd_proc_fops, dev); 150536d03f93SSeth Forshee if (dev->video_supported) 1506135740deSSeth Forshee proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1507135740deSSeth Forshee &video_proc_fops, dev); 150836d03f93SSeth Forshee if (dev->fan_supported) 1509135740deSSeth Forshee proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1510135740deSSeth Forshee &fan_proc_fops, dev); 151136d03f93SSeth Forshee if (dev->hotkey_dev) 1512135740deSSeth Forshee proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1513135740deSSeth Forshee &keys_proc_fops, dev); 1514135740deSSeth Forshee proc_create_data("version", S_IRUGO, toshiba_proc_dir, 1515135740deSSeth Forshee &version_proc_fops, dev); 1516b4f9fe12SLen Brown } 1517b4f9fe12SLen Brown 151836d03f93SSeth Forshee static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1519b4f9fe12SLen Brown { 152036d03f93SSeth Forshee if (dev->backlight_dev) 1521936c8bcdSAlexey Dobriyan remove_proc_entry("lcd", toshiba_proc_dir); 152236d03f93SSeth Forshee if (dev->video_supported) 1523936c8bcdSAlexey Dobriyan remove_proc_entry("video", toshiba_proc_dir); 152436d03f93SSeth Forshee if (dev->fan_supported) 1525936c8bcdSAlexey Dobriyan remove_proc_entry("fan", toshiba_proc_dir); 152636d03f93SSeth Forshee if (dev->hotkey_dev) 1527936c8bcdSAlexey Dobriyan remove_proc_entry("keys", toshiba_proc_dir); 1528936c8bcdSAlexey Dobriyan remove_proc_entry("version", toshiba_proc_dir); 1529b4f9fe12SLen Brown } 1530b4f9fe12SLen Brown 1531acc2472eSLionel Debroux static const struct backlight_ops toshiba_backlight_data = { 1532121b7b0dSAkio Idehara .options = BL_CORE_SUSPENDRESUME, 153362cce752SSeth Forshee .get_brightness = get_lcd_brightness, 1534b4f9fe12SLen Brown .update_status = set_lcd_status, 1535b4f9fe12SLen Brown }; 1536b4f9fe12SLen Brown 1537360f0f39SAzael Avalos /* 1538360f0f39SAzael Avalos * Sysfs files 1539360f0f39SAzael Avalos */ 15409d309848SAzael Avalos static ssize_t version_show(struct device *dev, 1541c6c68ff8SAzael Avalos struct device_attribute *attr, char *buf) 1542c6c68ff8SAzael Avalos { 1543c6c68ff8SAzael Avalos return sprintf(buf, "%s\n", TOSHIBA_ACPI_VERSION); 1544c6c68ff8SAzael Avalos } 15450c3c0f10SAzael Avalos static DEVICE_ATTR_RO(version); 1546c6c68ff8SAzael Avalos 15479d309848SAzael Avalos static ssize_t fan_store(struct device *dev, 154894477d4cSAzael Avalos struct device_attribute *attr, 154994477d4cSAzael Avalos const char *buf, size_t count) 155094477d4cSAzael Avalos { 155194477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 155294477d4cSAzael Avalos int state; 155394477d4cSAzael Avalos int ret; 155494477d4cSAzael Avalos 155594477d4cSAzael Avalos ret = kstrtoint(buf, 0, &state); 155694477d4cSAzael Avalos if (ret) 155794477d4cSAzael Avalos return ret; 155894477d4cSAzael Avalos 155994477d4cSAzael Avalos if (state != 0 && state != 1) 156094477d4cSAzael Avalos return -EINVAL; 156194477d4cSAzael Avalos 15623e07e5baSAzael Avalos ret = set_fan_status(toshiba, state); 15633e07e5baSAzael Avalos if (ret) 15643e07e5baSAzael Avalos return ret; 156594477d4cSAzael Avalos 156694477d4cSAzael Avalos return count; 156794477d4cSAzael Avalos } 156894477d4cSAzael Avalos 15699d309848SAzael Avalos static ssize_t fan_show(struct device *dev, 157094477d4cSAzael Avalos struct device_attribute *attr, char *buf) 157194477d4cSAzael Avalos { 157294477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 157394477d4cSAzael Avalos u32 value; 157494477d4cSAzael Avalos int ret; 157594477d4cSAzael Avalos 157694477d4cSAzael Avalos ret = get_fan_status(toshiba, &value); 157794477d4cSAzael Avalos if (ret) 157894477d4cSAzael Avalos return ret; 157994477d4cSAzael Avalos 158094477d4cSAzael Avalos return sprintf(buf, "%d\n", value); 158194477d4cSAzael Avalos } 15820c3c0f10SAzael Avalos static DEVICE_ATTR_RW(fan); 158394477d4cSAzael Avalos 15849d309848SAzael Avalos static ssize_t kbd_backlight_mode_store(struct device *dev, 1585360f0f39SAzael Avalos struct device_attribute *attr, 1586360f0f39SAzael Avalos const char *buf, size_t count) 1587360f0f39SAzael Avalos { 1588360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1589aeaac098SDan Carpenter int mode; 1590aeaac098SDan Carpenter int ret; 1591360f0f39SAzael Avalos 1592aeaac098SDan Carpenter 1593aeaac098SDan Carpenter ret = kstrtoint(buf, 0, &mode); 1594aeaac098SDan Carpenter if (ret) 1595aeaac098SDan Carpenter return ret; 159693f8c16dSAzael Avalos 159793f8c16dSAzael Avalos /* Check for supported modes depending on keyboard backlight type */ 159893f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 159993f8c16dSAzael Avalos /* Type 1 supports SCI_KBD_MODE_FNZ and SCI_KBD_MODE_AUTO */ 1600aeaac098SDan Carpenter if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO) 1601360f0f39SAzael Avalos return -EINVAL; 160293f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 160393f8c16dSAzael Avalos /* Type 2 doesn't support SCI_KBD_MODE_FNZ */ 160493f8c16dSAzael Avalos if (mode != SCI_KBD_MODE_AUTO && mode != SCI_KBD_MODE_ON && 160593f8c16dSAzael Avalos mode != SCI_KBD_MODE_OFF) 160693f8c16dSAzael Avalos return -EINVAL; 160793f8c16dSAzael Avalos } 1608360f0f39SAzael Avalos 1609e0769fe6SDarren Hart /* 1610e0769fe6SDarren Hart * Set the Keyboard Backlight Mode where: 1611360f0f39SAzael Avalos * Auto - KBD backlight turns off automatically in given time 1612360f0f39SAzael Avalos * FN-Z - KBD backlight "toggles" when hotkey pressed 161393f8c16dSAzael Avalos * ON - KBD backlight is always on 161493f8c16dSAzael Avalos * OFF - KBD backlight is always off 1615360f0f39SAzael Avalos */ 161693f8c16dSAzael Avalos 161793f8c16dSAzael Avalos /* Only make a change if the actual mode has changed */ 1618aeaac098SDan Carpenter if (toshiba->kbd_mode != mode) { 161993f8c16dSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 16201e574dbfSAzael Avalos int time = toshiba->kbd_time << HCI_MISC_SHIFT; 162193f8c16dSAzael Avalos 162293f8c16dSAzael Avalos /* OR the "base time" to the actual method format */ 162393f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 162493f8c16dSAzael Avalos /* Type 1 requires the current mode */ 162593f8c16dSAzael Avalos time |= toshiba->kbd_mode; 162693f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 162793f8c16dSAzael Avalos /* Type 2 requires the desired mode */ 162893f8c16dSAzael Avalos time |= mode; 162993f8c16dSAzael Avalos } 163093f8c16dSAzael Avalos 1631aeaac098SDan Carpenter ret = toshiba_kbd_illum_status_set(toshiba, time); 1632aeaac098SDan Carpenter if (ret) 1633aeaac098SDan Carpenter return ret; 163493f8c16dSAzael Avalos 1635360f0f39SAzael Avalos toshiba->kbd_mode = mode; 1636360f0f39SAzael Avalos } 1637360f0f39SAzael Avalos 1638360f0f39SAzael Avalos return count; 1639360f0f39SAzael Avalos } 1640360f0f39SAzael Avalos 16419d309848SAzael Avalos static ssize_t kbd_backlight_mode_show(struct device *dev, 1642360f0f39SAzael Avalos struct device_attribute *attr, 1643360f0f39SAzael Avalos char *buf) 1644360f0f39SAzael Avalos { 1645360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1646360f0f39SAzael Avalos u32 time; 1647360f0f39SAzael Avalos 1648360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1649360f0f39SAzael Avalos return -EIO; 1650360f0f39SAzael Avalos 165193f8c16dSAzael Avalos return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK); 165293f8c16dSAzael Avalos } 16530c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_mode); 165493f8c16dSAzael Avalos 16559d309848SAzael Avalos static ssize_t kbd_type_show(struct device *dev, 16569d309848SAzael Avalos struct device_attribute *attr, char *buf) 165793f8c16dSAzael Avalos { 165893f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 165993f8c16dSAzael Avalos 166093f8c16dSAzael Avalos return sprintf(buf, "%d\n", toshiba->kbd_type); 166193f8c16dSAzael Avalos } 16620c3c0f10SAzael Avalos static DEVICE_ATTR_RO(kbd_type); 166393f8c16dSAzael Avalos 16649d309848SAzael Avalos static ssize_t available_kbd_modes_show(struct device *dev, 166593f8c16dSAzael Avalos struct device_attribute *attr, 166693f8c16dSAzael Avalos char *buf) 166793f8c16dSAzael Avalos { 166893f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 166993f8c16dSAzael Avalos 167093f8c16dSAzael Avalos if (toshiba->kbd_type == 1) 167193f8c16dSAzael Avalos return sprintf(buf, "%x %x\n", 167293f8c16dSAzael Avalos SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO); 167393f8c16dSAzael Avalos 167493f8c16dSAzael Avalos return sprintf(buf, "%x %x %x\n", 167593f8c16dSAzael Avalos SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF); 1676360f0f39SAzael Avalos } 16770c3c0f10SAzael Avalos static DEVICE_ATTR_RO(available_kbd_modes); 1678360f0f39SAzael Avalos 16799d309848SAzael Avalos static ssize_t kbd_backlight_timeout_store(struct device *dev, 1680360f0f39SAzael Avalos struct device_attribute *attr, 1681360f0f39SAzael Avalos const char *buf, size_t count) 1682360f0f39SAzael Avalos { 1683360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1684eabde0faSAzael Avalos int time; 1685eabde0faSAzael Avalos int ret; 1686360f0f39SAzael Avalos 1687eabde0faSAzael Avalos ret = kstrtoint(buf, 0, &time); 1688eabde0faSAzael Avalos if (ret) 1689eabde0faSAzael Avalos return ret; 1690eabde0faSAzael Avalos 1691eabde0faSAzael Avalos /* Check for supported values depending on kbd_type */ 1692eabde0faSAzael Avalos if (toshiba->kbd_type == 1) { 1693eabde0faSAzael Avalos if (time < 0 || time > 60) 1694360f0f39SAzael Avalos return -EINVAL; 1695eabde0faSAzael Avalos } else if (toshiba->kbd_type == 2) { 1696eabde0faSAzael Avalos if (time < 1 || time > 60) 1697eabde0faSAzael Avalos return -EINVAL; 1698eabde0faSAzael Avalos } 1699360f0f39SAzael Avalos 1700eabde0faSAzael Avalos /* Set the Keyboard Backlight Timeout */ 1701eabde0faSAzael Avalos 1702eabde0faSAzael Avalos /* Only make a change if the actual timeout has changed */ 1703eabde0faSAzael Avalos if (toshiba->kbd_time != time) { 1704eabde0faSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 1705360f0f39SAzael Avalos time = time << HCI_MISC_SHIFT; 1706eabde0faSAzael Avalos /* OR the "base time" to the actual method format */ 1707eabde0faSAzael Avalos if (toshiba->kbd_type == 1) 1708eabde0faSAzael Avalos time |= SCI_KBD_MODE_FNZ; 1709eabde0faSAzael Avalos else if (toshiba->kbd_type == 2) 1710eabde0faSAzael Avalos time |= SCI_KBD_MODE_AUTO; 1711eabde0faSAzael Avalos 1712eabde0faSAzael Avalos ret = toshiba_kbd_illum_status_set(toshiba, time); 1713eabde0faSAzael Avalos if (ret) 1714eabde0faSAzael Avalos return ret; 1715eabde0faSAzael Avalos 1716360f0f39SAzael Avalos toshiba->kbd_time = time >> HCI_MISC_SHIFT; 1717360f0f39SAzael Avalos } 1718360f0f39SAzael Avalos 1719360f0f39SAzael Avalos return count; 1720360f0f39SAzael Avalos } 1721360f0f39SAzael Avalos 17229d309848SAzael Avalos static ssize_t kbd_backlight_timeout_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 1732360f0f39SAzael Avalos return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT); 1733360f0f39SAzael Avalos } 17340c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_timeout); 1735360f0f39SAzael Avalos 17369d309848SAzael Avalos static ssize_t touchpad_store(struct device *dev, 17379d8658acSAzael Avalos struct device_attribute *attr, 17389d8658acSAzael Avalos const char *buf, size_t count) 17399d8658acSAzael Avalos { 17409d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 17419d8658acSAzael Avalos int state; 1742c8a41669SAzael Avalos int ret; 17439d8658acSAzael Avalos 17449d8658acSAzael Avalos /* Set the TouchPad on/off, 0 - Disable | 1 - Enable */ 1745c8a41669SAzael Avalos ret = kstrtoint(buf, 0, &state); 1746c8a41669SAzael Avalos if (ret) 1747c8a41669SAzael Avalos return ret; 1748c8a41669SAzael Avalos if (state != 0 && state != 1) 1749c8a41669SAzael Avalos return -EINVAL; 1750c8a41669SAzael Avalos 1751c8a41669SAzael Avalos ret = toshiba_touchpad_set(toshiba, state); 1752c8a41669SAzael Avalos if (ret) 1753c8a41669SAzael Avalos return ret; 17549d8658acSAzael Avalos 17559d8658acSAzael Avalos return count; 17569d8658acSAzael Avalos } 17579d8658acSAzael Avalos 17589d309848SAzael Avalos static ssize_t touchpad_show(struct device *dev, 17599d8658acSAzael Avalos struct device_attribute *attr, char *buf) 17609d8658acSAzael Avalos { 17619d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 17629d8658acSAzael Avalos u32 state; 17639d8658acSAzael Avalos int ret; 17649d8658acSAzael Avalos 17659d8658acSAzael Avalos ret = toshiba_touchpad_get(toshiba, &state); 17669d8658acSAzael Avalos if (ret < 0) 17679d8658acSAzael Avalos return ret; 17689d8658acSAzael Avalos 17699d8658acSAzael Avalos return sprintf(buf, "%i\n", state); 17709d8658acSAzael Avalos } 17710c3c0f10SAzael Avalos static DEVICE_ATTR_RW(touchpad); 17729d8658acSAzael Avalos 17739d309848SAzael Avalos static ssize_t position_show(struct device *dev, 17745a2813e9SAzael Avalos struct device_attribute *attr, char *buf) 17755a2813e9SAzael Avalos { 17765a2813e9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 17775a2813e9SAzael Avalos u32 xyval, zval, tmp; 17785a2813e9SAzael Avalos u16 x, y, z; 17795a2813e9SAzael Avalos int ret; 17805a2813e9SAzael Avalos 17815a2813e9SAzael Avalos xyval = zval = 0; 17825a2813e9SAzael Avalos ret = toshiba_accelerometer_get(toshiba, &xyval, &zval); 17835a2813e9SAzael Avalos if (ret < 0) 17845a2813e9SAzael Avalos return ret; 17855a2813e9SAzael Avalos 17865a2813e9SAzael Avalos x = xyval & HCI_ACCEL_MASK; 17875a2813e9SAzael Avalos tmp = xyval >> HCI_MISC_SHIFT; 17885a2813e9SAzael Avalos y = tmp & HCI_ACCEL_MASK; 17895a2813e9SAzael Avalos z = zval & HCI_ACCEL_MASK; 17905a2813e9SAzael Avalos 17915a2813e9SAzael Avalos return sprintf(buf, "%d %d %d\n", x, y, z); 17925a2813e9SAzael Avalos } 17930c3c0f10SAzael Avalos static DEVICE_ATTR_RO(position); 17945a2813e9SAzael Avalos 17959d309848SAzael Avalos static ssize_t usb_sleep_charge_show(struct device *dev, 17969d309848SAzael Avalos struct device_attribute *attr, char *buf) 1797e26ffe51SAzael Avalos { 1798e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1799e26ffe51SAzael Avalos u32 mode; 1800e26ffe51SAzael Avalos int ret; 1801e26ffe51SAzael Avalos 1802e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_get(toshiba, &mode); 1803e26ffe51SAzael Avalos if (ret < 0) 1804e26ffe51SAzael Avalos return ret; 1805e26ffe51SAzael Avalos 1806e26ffe51SAzael Avalos return sprintf(buf, "%x\n", mode & SCI_USB_CHARGE_MODE_MASK); 1807e26ffe51SAzael Avalos } 1808e26ffe51SAzael Avalos 18099d309848SAzael Avalos static ssize_t usb_sleep_charge_store(struct device *dev, 1810e26ffe51SAzael Avalos struct device_attribute *attr, 1811e26ffe51SAzael Avalos const char *buf, size_t count) 1812e26ffe51SAzael Avalos { 1813e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1814e26ffe51SAzael Avalos u32 mode; 1815e26ffe51SAzael Avalos int state; 1816e26ffe51SAzael Avalos int ret; 1817e26ffe51SAzael Avalos 1818e26ffe51SAzael Avalos ret = kstrtoint(buf, 0, &state); 1819e26ffe51SAzael Avalos if (ret) 1820e26ffe51SAzael Avalos return ret; 1821e0769fe6SDarren Hart /* 1822e0769fe6SDarren Hart * Check for supported values, where: 1823e26ffe51SAzael Avalos * 0 - Disabled 1824e26ffe51SAzael Avalos * 1 - Alternate (Non USB conformant devices that require more power) 1825e26ffe51SAzael Avalos * 2 - Auto (USB conformant devices) 1826c8c91842SAzael Avalos * 3 - Typical 1827e26ffe51SAzael Avalos */ 1828c8c91842SAzael Avalos if (state != 0 && state != 1 && state != 2 && state != 3) 1829e26ffe51SAzael Avalos return -EINVAL; 1830e26ffe51SAzael Avalos 1831e26ffe51SAzael Avalos /* Set the USB charging mode to internal value */ 1832c8c91842SAzael Avalos mode = toshiba->usbsc_mode_base; 1833e26ffe51SAzael Avalos if (state == 0) 1834c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_DISABLED; 1835e26ffe51SAzael Avalos else if (state == 1) 1836c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_ALTERNATE; 1837e26ffe51SAzael Avalos else if (state == 2) 1838c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_AUTO; 1839c8c91842SAzael Avalos else if (state == 3) 1840c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_TYPICAL; 1841e26ffe51SAzael Avalos 1842e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_set(toshiba, mode); 1843e26ffe51SAzael Avalos if (ret) 1844e26ffe51SAzael Avalos return ret; 1845e26ffe51SAzael Avalos 1846e26ffe51SAzael Avalos return count; 1847e26ffe51SAzael Avalos } 18480c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_charge); 1849e26ffe51SAzael Avalos 1850182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_show(struct device *dev, 1851182bcaa5SAzael Avalos struct device_attribute *attr, 1852182bcaa5SAzael Avalos char *buf) 1853182bcaa5SAzael Avalos { 1854182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1855182bcaa5SAzael Avalos u32 state; 1856182bcaa5SAzael Avalos int bat_lvl; 1857182bcaa5SAzael Avalos int status; 1858182bcaa5SAzael Avalos int ret; 1859182bcaa5SAzael Avalos int tmp; 1860182bcaa5SAzael Avalos 1861182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_get(toshiba, &state); 1862182bcaa5SAzael Avalos if (ret < 0) 1863182bcaa5SAzael Avalos return ret; 1864182bcaa5SAzael Avalos 1865182bcaa5SAzael Avalos /* Determine the status: 0x4 - Enabled | 0x1 - Disabled */ 1866182bcaa5SAzael Avalos tmp = state & SCI_USB_CHARGE_BAT_MASK; 1867182bcaa5SAzael Avalos status = (tmp == 0x4) ? 1 : 0; 1868182bcaa5SAzael Avalos /* Determine the battery level set */ 1869182bcaa5SAzael Avalos bat_lvl = state >> HCI_MISC_SHIFT; 1870182bcaa5SAzael Avalos 1871182bcaa5SAzael Avalos return sprintf(buf, "%d %d\n", status, bat_lvl); 1872182bcaa5SAzael Avalos } 1873182bcaa5SAzael Avalos 1874182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_store(struct device *dev, 1875182bcaa5SAzael Avalos struct device_attribute *attr, 1876182bcaa5SAzael Avalos const char *buf, size_t count) 1877182bcaa5SAzael Avalos { 1878182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1879182bcaa5SAzael Avalos u32 status; 1880182bcaa5SAzael Avalos int value; 1881182bcaa5SAzael Avalos int ret; 1882182bcaa5SAzael Avalos int tmp; 1883182bcaa5SAzael Avalos 1884182bcaa5SAzael Avalos ret = kstrtoint(buf, 0, &value); 1885182bcaa5SAzael Avalos if (ret) 1886182bcaa5SAzael Avalos return ret; 1887182bcaa5SAzael Avalos 1888e0769fe6SDarren Hart /* 1889e0769fe6SDarren Hart * Set the status of the function: 1890182bcaa5SAzael Avalos * 0 - Disabled 1891182bcaa5SAzael Avalos * 1-100 - Enabled 1892182bcaa5SAzael Avalos */ 1893182bcaa5SAzael Avalos if (value < 0 || value > 100) 1894182bcaa5SAzael Avalos return -EINVAL; 1895182bcaa5SAzael Avalos 1896182bcaa5SAzael Avalos if (value == 0) { 1897182bcaa5SAzael Avalos tmp = toshiba->usbsc_bat_level << HCI_MISC_SHIFT; 1898182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_OFF; 1899182bcaa5SAzael Avalos } else { 1900182bcaa5SAzael Avalos tmp = value << HCI_MISC_SHIFT; 1901182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_ON; 1902182bcaa5SAzael Avalos } 1903182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_set(toshiba, status); 1904182bcaa5SAzael Avalos if (ret < 0) 1905182bcaa5SAzael Avalos return ret; 1906182bcaa5SAzael Avalos 1907182bcaa5SAzael Avalos toshiba->usbsc_bat_level = status >> HCI_MISC_SHIFT; 1908182bcaa5SAzael Avalos 1909182bcaa5SAzael Avalos return count; 1910182bcaa5SAzael Avalos } 19110c3c0f10SAzael Avalos static DEVICE_ATTR_RW(sleep_functions_on_battery); 1912182bcaa5SAzael Avalos 19139d309848SAzael Avalos static ssize_t usb_rapid_charge_show(struct device *dev, 19149d309848SAzael Avalos struct device_attribute *attr, char *buf) 1915bb3fe01fSAzael Avalos { 1916bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1917bb3fe01fSAzael Avalos u32 state; 1918bb3fe01fSAzael Avalos int ret; 1919bb3fe01fSAzael Avalos 1920bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(toshiba, &state); 1921bb3fe01fSAzael Avalos if (ret < 0) 1922bb3fe01fSAzael Avalos return ret; 1923bb3fe01fSAzael Avalos 1924bb3fe01fSAzael Avalos return sprintf(buf, "%d\n", state); 1925bb3fe01fSAzael Avalos } 1926bb3fe01fSAzael Avalos 19279d309848SAzael Avalos static ssize_t usb_rapid_charge_store(struct device *dev, 1928bb3fe01fSAzael Avalos struct device_attribute *attr, 1929bb3fe01fSAzael Avalos const char *buf, size_t count) 1930bb3fe01fSAzael Avalos { 1931bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1932bb3fe01fSAzael Avalos int state; 1933bb3fe01fSAzael Avalos int ret; 1934bb3fe01fSAzael Avalos 1935bb3fe01fSAzael Avalos ret = kstrtoint(buf, 0, &state); 1936bb3fe01fSAzael Avalos if (ret) 1937bb3fe01fSAzael Avalos return ret; 1938bb3fe01fSAzael Avalos if (state != 0 && state != 1) 1939bb3fe01fSAzael Avalos return -EINVAL; 1940bb3fe01fSAzael Avalos 1941bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_set(toshiba, state); 1942bb3fe01fSAzael Avalos if (ret) 1943bb3fe01fSAzael Avalos return ret; 1944bb3fe01fSAzael Avalos 1945bb3fe01fSAzael Avalos return count; 1946bb3fe01fSAzael Avalos } 19470c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_rapid_charge); 1948bb3fe01fSAzael Avalos 19499d309848SAzael Avalos static ssize_t usb_sleep_music_show(struct device *dev, 19509d309848SAzael Avalos struct device_attribute *attr, char *buf) 1951172ce0a9SAzael Avalos { 1952172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1953172ce0a9SAzael Avalos u32 state; 1954172ce0a9SAzael Avalos int ret; 1955172ce0a9SAzael Avalos 1956172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(toshiba, &state); 1957172ce0a9SAzael Avalos if (ret < 0) 1958172ce0a9SAzael Avalos return ret; 1959172ce0a9SAzael Avalos 1960172ce0a9SAzael Avalos return sprintf(buf, "%d\n", state); 1961172ce0a9SAzael Avalos } 1962172ce0a9SAzael Avalos 19639d309848SAzael Avalos static ssize_t usb_sleep_music_store(struct device *dev, 1964172ce0a9SAzael Avalos struct device_attribute *attr, 1965172ce0a9SAzael Avalos const char *buf, size_t count) 1966172ce0a9SAzael Avalos { 1967172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1968172ce0a9SAzael Avalos int state; 1969172ce0a9SAzael Avalos int ret; 1970172ce0a9SAzael Avalos 1971172ce0a9SAzael Avalos ret = kstrtoint(buf, 0, &state); 1972172ce0a9SAzael Avalos if (ret) 1973172ce0a9SAzael Avalos return ret; 1974172ce0a9SAzael Avalos if (state != 0 && state != 1) 1975172ce0a9SAzael Avalos return -EINVAL; 1976172ce0a9SAzael Avalos 1977172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_set(toshiba, state); 1978172ce0a9SAzael Avalos if (ret) 1979172ce0a9SAzael Avalos return ret; 1980172ce0a9SAzael Avalos 1981172ce0a9SAzael Avalos return count; 1982172ce0a9SAzael Avalos } 19830c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_music); 1984172ce0a9SAzael Avalos 19859d309848SAzael Avalos static ssize_t kbd_function_keys_show(struct device *dev, 19869d309848SAzael Avalos struct device_attribute *attr, char *buf) 1987bae84195SAzael Avalos { 1988bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1989bae84195SAzael Avalos int mode; 1990bae84195SAzael Avalos int ret; 1991bae84195SAzael Avalos 1992bae84195SAzael Avalos ret = toshiba_function_keys_get(toshiba, &mode); 1993bae84195SAzael Avalos if (ret < 0) 1994bae84195SAzael Avalos return ret; 1995bae84195SAzael Avalos 1996bae84195SAzael Avalos return sprintf(buf, "%d\n", mode); 1997bae84195SAzael Avalos } 1998bae84195SAzael Avalos 19999d309848SAzael Avalos static ssize_t kbd_function_keys_store(struct device *dev, 2000bae84195SAzael Avalos struct device_attribute *attr, 2001bae84195SAzael Avalos const char *buf, size_t count) 2002bae84195SAzael Avalos { 2003bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2004bae84195SAzael Avalos int mode; 2005bae84195SAzael Avalos int ret; 2006bae84195SAzael Avalos 2007bae84195SAzael Avalos ret = kstrtoint(buf, 0, &mode); 2008bae84195SAzael Avalos if (ret) 2009bae84195SAzael Avalos return ret; 2010e0769fe6SDarren Hart /* 2011e0769fe6SDarren Hart * Check for the function keys mode where: 2012bae84195SAzael Avalos * 0 - Normal operation (F{1-12} as usual and hotkeys via FN-F{1-12}) 2013bae84195SAzael Avalos * 1 - Special functions (Opposite of the above setting) 2014bae84195SAzael Avalos */ 2015bae84195SAzael Avalos if (mode != 0 && mode != 1) 2016bae84195SAzael Avalos return -EINVAL; 2017bae84195SAzael Avalos 2018bae84195SAzael Avalos ret = toshiba_function_keys_set(toshiba, mode); 2019bae84195SAzael Avalos if (ret) 2020bae84195SAzael Avalos return ret; 2021bae84195SAzael Avalos 2022bae84195SAzael Avalos pr_info("Reboot for changes to KBD Function Keys to take effect"); 2023bae84195SAzael Avalos 2024bae84195SAzael Avalos return count; 2025bae84195SAzael Avalos } 20260c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_function_keys); 2027bae84195SAzael Avalos 20289d309848SAzael Avalos static ssize_t panel_power_on_show(struct device *dev, 20299d309848SAzael Avalos struct device_attribute *attr, char *buf) 203035d53ceaSAzael Avalos { 203135d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 203235d53ceaSAzael Avalos u32 state; 203335d53ceaSAzael Avalos int ret; 203435d53ceaSAzael Avalos 203535d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(toshiba, &state); 203635d53ceaSAzael Avalos if (ret < 0) 203735d53ceaSAzael Avalos return ret; 203835d53ceaSAzael Avalos 203935d53ceaSAzael Avalos return sprintf(buf, "%d\n", state); 204035d53ceaSAzael Avalos } 204135d53ceaSAzael Avalos 20429d309848SAzael Avalos static ssize_t panel_power_on_store(struct device *dev, 204335d53ceaSAzael Avalos struct device_attribute *attr, 204435d53ceaSAzael Avalos const char *buf, size_t count) 204535d53ceaSAzael Avalos { 204635d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 204735d53ceaSAzael Avalos int state; 204835d53ceaSAzael Avalos int ret; 204935d53ceaSAzael Avalos 205035d53ceaSAzael Avalos ret = kstrtoint(buf, 0, &state); 205135d53ceaSAzael Avalos if (ret) 205235d53ceaSAzael Avalos return ret; 205335d53ceaSAzael Avalos if (state != 0 && state != 1) 205435d53ceaSAzael Avalos return -EINVAL; 205535d53ceaSAzael Avalos 205635d53ceaSAzael Avalos ret = toshiba_panel_power_on_set(toshiba, state); 205735d53ceaSAzael Avalos if (ret) 205835d53ceaSAzael Avalos return ret; 205935d53ceaSAzael Avalos 206035d53ceaSAzael Avalos pr_info("Reboot for changes to Panel Power ON to take effect"); 206135d53ceaSAzael Avalos 206235d53ceaSAzael Avalos return count; 206335d53ceaSAzael Avalos } 20640c3c0f10SAzael Avalos static DEVICE_ATTR_RW(panel_power_on); 206535d53ceaSAzael Avalos 20669d309848SAzael Avalos static ssize_t usb_three_show(struct device *dev, 20679d309848SAzael Avalos struct device_attribute *attr, char *buf) 206817fe4b3dSAzael Avalos { 206917fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 207017fe4b3dSAzael Avalos u32 state; 207117fe4b3dSAzael Avalos int ret; 207217fe4b3dSAzael Avalos 207317fe4b3dSAzael Avalos ret = toshiba_usb_three_get(toshiba, &state); 207417fe4b3dSAzael Avalos if (ret < 0) 207517fe4b3dSAzael Avalos return ret; 207617fe4b3dSAzael Avalos 207717fe4b3dSAzael Avalos return sprintf(buf, "%d\n", state); 207817fe4b3dSAzael Avalos } 207917fe4b3dSAzael Avalos 20809d309848SAzael Avalos static ssize_t usb_three_store(struct device *dev, 208117fe4b3dSAzael Avalos struct device_attribute *attr, 208217fe4b3dSAzael Avalos const char *buf, size_t count) 208317fe4b3dSAzael Avalos { 208417fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 208517fe4b3dSAzael Avalos int state; 208617fe4b3dSAzael Avalos int ret; 208717fe4b3dSAzael Avalos 208817fe4b3dSAzael Avalos ret = kstrtoint(buf, 0, &state); 208917fe4b3dSAzael Avalos if (ret) 209017fe4b3dSAzael Avalos return ret; 2091e0769fe6SDarren Hart /* 2092e0769fe6SDarren Hart * Check for USB 3 mode where: 209317fe4b3dSAzael Avalos * 0 - Disabled (Acts like a USB 2 port, saving power) 209417fe4b3dSAzael Avalos * 1 - Enabled 209517fe4b3dSAzael Avalos */ 209617fe4b3dSAzael Avalos if (state != 0 && state != 1) 209717fe4b3dSAzael Avalos return -EINVAL; 209817fe4b3dSAzael Avalos 209917fe4b3dSAzael Avalos ret = toshiba_usb_three_set(toshiba, state); 210017fe4b3dSAzael Avalos if (ret) 210117fe4b3dSAzael Avalos return ret; 210217fe4b3dSAzael Avalos 210317fe4b3dSAzael Avalos pr_info("Reboot for changes to USB 3 to take effect"); 210417fe4b3dSAzael Avalos 210517fe4b3dSAzael Avalos return count; 210617fe4b3dSAzael Avalos } 21070c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_three); 21089bd1213bSAzael Avalos 21099bd1213bSAzael Avalos static struct attribute *toshiba_attributes[] = { 21109bd1213bSAzael Avalos &dev_attr_version.attr, 21119bd1213bSAzael Avalos &dev_attr_fan.attr, 21129bd1213bSAzael Avalos &dev_attr_kbd_backlight_mode.attr, 21139bd1213bSAzael Avalos &dev_attr_kbd_type.attr, 21149bd1213bSAzael Avalos &dev_attr_available_kbd_modes.attr, 21159bd1213bSAzael Avalos &dev_attr_kbd_backlight_timeout.attr, 21169bd1213bSAzael Avalos &dev_attr_touchpad.attr, 21179bd1213bSAzael Avalos &dev_attr_position.attr, 21189bd1213bSAzael Avalos &dev_attr_usb_sleep_charge.attr, 21199bd1213bSAzael Avalos &dev_attr_sleep_functions_on_battery.attr, 21209bd1213bSAzael Avalos &dev_attr_usb_rapid_charge.attr, 21219bd1213bSAzael Avalos &dev_attr_usb_sleep_music.attr, 21229bd1213bSAzael Avalos &dev_attr_kbd_function_keys.attr, 21239bd1213bSAzael Avalos &dev_attr_panel_power_on.attr, 21249bd1213bSAzael Avalos &dev_attr_usb_three.attr, 21259bd1213bSAzael Avalos NULL, 21269bd1213bSAzael Avalos }; 21279bd1213bSAzael Avalos 2128360f0f39SAzael Avalos static umode_t toshiba_sysfs_is_visible(struct kobject *kobj, 2129360f0f39SAzael Avalos struct attribute *attr, int idx) 2130360f0f39SAzael Avalos { 2131360f0f39SAzael Avalos struct device *dev = container_of(kobj, struct device, kobj); 2132360f0f39SAzael Avalos struct toshiba_acpi_dev *drv = dev_get_drvdata(dev); 2133360f0f39SAzael Avalos bool exists = true; 2134360f0f39SAzael Avalos 213594477d4cSAzael Avalos if (attr == &dev_attr_fan.attr) 213694477d4cSAzael Avalos exists = (drv->fan_supported) ? true : false; 213794477d4cSAzael Avalos else if (attr == &dev_attr_kbd_backlight_mode.attr) 2138360f0f39SAzael Avalos exists = (drv->kbd_illum_supported) ? true : false; 2139360f0f39SAzael Avalos else if (attr == &dev_attr_kbd_backlight_timeout.attr) 2140360f0f39SAzael Avalos exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false; 21419d8658acSAzael Avalos else if (attr == &dev_attr_touchpad.attr) 21429d8658acSAzael Avalos exists = (drv->touchpad_supported) ? true : false; 21435a2813e9SAzael Avalos else if (attr == &dev_attr_position.attr) 21445a2813e9SAzael Avalos exists = (drv->accelerometer_supported) ? true : false; 2145e26ffe51SAzael Avalos else if (attr == &dev_attr_usb_sleep_charge.attr) 2146e26ffe51SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2147182bcaa5SAzael Avalos else if (attr == &dev_attr_sleep_functions_on_battery.attr) 2148182bcaa5SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2149bb3fe01fSAzael Avalos else if (attr == &dev_attr_usb_rapid_charge.attr) 2150bb3fe01fSAzael Avalos exists = (drv->usb_rapid_charge_supported) ? true : false; 2151172ce0a9SAzael Avalos else if (attr == &dev_attr_usb_sleep_music.attr) 2152172ce0a9SAzael Avalos exists = (drv->usb_sleep_music_supported) ? true : false; 2153bae84195SAzael Avalos else if (attr == &dev_attr_kbd_function_keys.attr) 2154bae84195SAzael Avalos exists = (drv->kbd_function_keys_supported) ? true : false; 215535d53ceaSAzael Avalos else if (attr == &dev_attr_panel_power_on.attr) 215635d53ceaSAzael Avalos exists = (drv->panel_power_on_supported) ? true : false; 215717fe4b3dSAzael Avalos else if (attr == &dev_attr_usb_three.attr) 215817fe4b3dSAzael Avalos exists = (drv->usb_three_supported) ? true : false; 2159360f0f39SAzael Avalos 2160360f0f39SAzael Avalos return exists ? attr->mode : 0; 2161360f0f39SAzael Avalos } 2162360f0f39SAzael Avalos 21639bd1213bSAzael Avalos static struct attribute_group toshiba_attr_group = { 21649bd1213bSAzael Avalos .is_visible = toshiba_sysfs_is_visible, 21659bd1213bSAzael Avalos .attrs = toshiba_attributes, 21669bd1213bSAzael Avalos }; 21679bd1213bSAzael Avalos 21681f28f290SAzael Avalos /* 2169fc5462f8SAzael Avalos * Misc device 2170fc5462f8SAzael Avalos */ 2171fc5462f8SAzael Avalos static int toshiba_acpi_smm_bridge(SMMRegisters *regs) 2172fc5462f8SAzael Avalos { 2173fc5462f8SAzael Avalos u32 in[TCI_WORDS] = { regs->eax, regs->ebx, regs->ecx, 2174fc5462f8SAzael Avalos regs->edx, regs->esi, regs->edi }; 2175fc5462f8SAzael Avalos u32 out[TCI_WORDS]; 2176fc5462f8SAzael Avalos acpi_status status; 2177fc5462f8SAzael Avalos 2178fc5462f8SAzael Avalos status = tci_raw(toshiba_acpi, in, out); 2179fc5462f8SAzael Avalos if (ACPI_FAILURE(status)) { 2180fc5462f8SAzael Avalos pr_err("ACPI call to query SMM registers failed\n"); 2181fc5462f8SAzael Avalos return -EIO; 2182fc5462f8SAzael Avalos } 2183fc5462f8SAzael Avalos 2184fc5462f8SAzael Avalos /* Fillout the SMM struct with the TCI call results */ 2185fc5462f8SAzael Avalos regs->eax = out[0]; 2186fc5462f8SAzael Avalos regs->ebx = out[1]; 2187fc5462f8SAzael Avalos regs->ecx = out[2]; 2188fc5462f8SAzael Avalos regs->edx = out[3]; 2189fc5462f8SAzael Avalos regs->esi = out[4]; 2190fc5462f8SAzael Avalos regs->edi = out[5]; 2191fc5462f8SAzael Avalos 2192fc5462f8SAzael Avalos return 0; 2193fc5462f8SAzael Avalos } 2194fc5462f8SAzael Avalos 2195fc5462f8SAzael Avalos static long toshiba_acpi_ioctl(struct file *fp, unsigned int cmd, 2196fc5462f8SAzael Avalos unsigned long arg) 2197fc5462f8SAzael Avalos { 2198fc5462f8SAzael Avalos SMMRegisters __user *argp = (SMMRegisters __user *)arg; 2199fc5462f8SAzael Avalos SMMRegisters regs; 2200fc5462f8SAzael Avalos int ret; 2201fc5462f8SAzael Avalos 2202fc5462f8SAzael Avalos if (!argp) 2203fc5462f8SAzael Avalos return -EINVAL; 2204fc5462f8SAzael Avalos 2205fc5462f8SAzael Avalos switch (cmd) { 2206fc5462f8SAzael Avalos case TOSH_SMM: 2207fc5462f8SAzael Avalos if (copy_from_user(®s, argp, sizeof(SMMRegisters))) 2208fc5462f8SAzael Avalos return -EFAULT; 2209fc5462f8SAzael Avalos ret = toshiba_acpi_smm_bridge(®s); 2210fc5462f8SAzael Avalos if (ret) 2211fc5462f8SAzael Avalos return ret; 2212fc5462f8SAzael Avalos if (copy_to_user(argp, ®s, sizeof(SMMRegisters))) 2213fc5462f8SAzael Avalos return -EFAULT; 2214fc5462f8SAzael Avalos break; 2215fc5462f8SAzael Avalos case TOSHIBA_ACPI_SCI: 2216fc5462f8SAzael Avalos if (copy_from_user(®s, argp, sizeof(SMMRegisters))) 2217fc5462f8SAzael Avalos return -EFAULT; 2218fc5462f8SAzael Avalos /* Ensure we are being called with a SCI_{GET, SET} register */ 2219fc5462f8SAzael Avalos if (regs.eax != SCI_GET && regs.eax != SCI_SET) 2220fc5462f8SAzael Avalos return -EINVAL; 2221fc5462f8SAzael Avalos if (!sci_open(toshiba_acpi)) 2222fc5462f8SAzael Avalos return -EIO; 2223fc5462f8SAzael Avalos ret = toshiba_acpi_smm_bridge(®s); 2224fc5462f8SAzael Avalos sci_close(toshiba_acpi); 2225fc5462f8SAzael Avalos if (ret) 2226fc5462f8SAzael Avalos return ret; 2227fc5462f8SAzael Avalos if (copy_to_user(argp, ®s, sizeof(SMMRegisters))) 2228fc5462f8SAzael Avalos return -EFAULT; 2229fc5462f8SAzael Avalos break; 2230fc5462f8SAzael Avalos default: 2231fc5462f8SAzael Avalos return -EINVAL; 2232fc5462f8SAzael Avalos } 2233fc5462f8SAzael Avalos 2234fc5462f8SAzael Avalos return 0; 2235fc5462f8SAzael Avalos } 2236fc5462f8SAzael Avalos 2237fc5462f8SAzael Avalos static const struct file_operations toshiba_acpi_fops = { 2238fc5462f8SAzael Avalos .owner = THIS_MODULE, 2239fc5462f8SAzael Avalos .unlocked_ioctl = toshiba_acpi_ioctl, 2240fc5462f8SAzael Avalos .llseek = noop_llseek, 2241fc5462f8SAzael Avalos }; 2242fc5462f8SAzael Avalos 2243fc5462f8SAzael Avalos /* 22441f28f290SAzael Avalos * Hotkeys 22451f28f290SAzael Avalos */ 22461f28f290SAzael Avalos static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev) 22471f28f290SAzael Avalos { 22481f28f290SAzael Avalos acpi_status status; 22491f28f290SAzael Avalos u32 result; 22501f28f290SAzael Avalos 22511f28f290SAzael Avalos status = acpi_evaluate_object(dev->acpi_dev->handle, 22521f28f290SAzael Avalos "ENAB", NULL, NULL); 22531f28f290SAzael Avalos if (ACPI_FAILURE(status)) 22541f28f290SAzael Avalos return -ENODEV; 22551f28f290SAzael Avalos 2256d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE); 22571f28f290SAzael Avalos if (result == TOS_FAILURE) 22581f28f290SAzael Avalos return -EIO; 22591f28f290SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 22601f28f290SAzael Avalos return -ENODEV; 22611f28f290SAzael Avalos 22621f28f290SAzael Avalos return 0; 22631f28f290SAzael Avalos } 22641f28f290SAzael Avalos 2265fb42d1f4SAzael Avalos static void toshiba_acpi_enable_special_functions(struct toshiba_acpi_dev *dev) 2266fb42d1f4SAzael Avalos { 2267fb42d1f4SAzael Avalos u32 result; 2268fb42d1f4SAzael Avalos 2269fb42d1f4SAzael Avalos /* 2270fb42d1f4SAzael Avalos * Re-activate the hotkeys, but this time, we are using the 2271fb42d1f4SAzael Avalos * "Special Functions" mode. 2272fb42d1f4SAzael Avalos */ 2273d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, 2274fb42d1f4SAzael Avalos HCI_HOTKEY_SPECIAL_FUNCTIONS); 2275fb42d1f4SAzael Avalos if (result != TOS_SUCCESS) 2276fb42d1f4SAzael Avalos pr_err("Could not enable the Special Function mode\n"); 2277fb42d1f4SAzael Avalos } 2278fb42d1f4SAzael Avalos 227929cd293fSSeth Forshee static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, 228029cd293fSSeth Forshee struct serio *port) 228129cd293fSSeth Forshee { 228298280374SGiedrius Statkevičius if (str & I8042_STR_AUXDATA) 228329cd293fSSeth Forshee return false; 228429cd293fSSeth Forshee 228529cd293fSSeth Forshee if (unlikely(data == 0xe0)) 228629cd293fSSeth Forshee return false; 228729cd293fSSeth Forshee 228829cd293fSSeth Forshee if ((data & 0x7f) == TOS1900_FN_SCAN) { 228929cd293fSSeth Forshee schedule_work(&toshiba_acpi->hotkey_work); 229029cd293fSSeth Forshee return true; 229129cd293fSSeth Forshee } 229229cd293fSSeth Forshee 229329cd293fSSeth Forshee return false; 229429cd293fSSeth Forshee } 229529cd293fSSeth Forshee 229629cd293fSSeth Forshee static void toshiba_acpi_hotkey_work(struct work_struct *work) 229729cd293fSSeth Forshee { 229829cd293fSSeth Forshee acpi_handle ec_handle = ec_get_handle(); 229929cd293fSSeth Forshee acpi_status status; 230029cd293fSSeth Forshee 230129cd293fSSeth Forshee if (!ec_handle) 230229cd293fSSeth Forshee return; 230329cd293fSSeth Forshee 230429cd293fSSeth Forshee status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL); 230529cd293fSSeth Forshee if (ACPI_FAILURE(status)) 230629cd293fSSeth Forshee pr_err("ACPI NTFY method execution failed\n"); 230729cd293fSSeth Forshee } 230829cd293fSSeth Forshee 230929cd293fSSeth Forshee /* 231029cd293fSSeth Forshee * Returns hotkey scancode, or < 0 on failure. 231129cd293fSSeth Forshee */ 231229cd293fSSeth Forshee static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev) 231329cd293fSSeth Forshee { 231474facaf7SZhang Rui unsigned long long value; 231529cd293fSSeth Forshee acpi_status status; 231629cd293fSSeth Forshee 231774facaf7SZhang Rui status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO", 231874facaf7SZhang Rui NULL, &value); 231974facaf7SZhang Rui if (ACPI_FAILURE(status)) { 232029cd293fSSeth Forshee pr_err("ACPI INFO method execution failed\n"); 232129cd293fSSeth Forshee return -EIO; 232229cd293fSSeth Forshee } 232329cd293fSSeth Forshee 232474facaf7SZhang Rui return value; 232529cd293fSSeth Forshee } 232629cd293fSSeth Forshee 232729cd293fSSeth Forshee static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev, 232829cd293fSSeth Forshee int scancode) 232929cd293fSSeth Forshee { 233029cd293fSSeth Forshee if (scancode == 0x100) 233129cd293fSSeth Forshee return; 233229cd293fSSeth Forshee 2333e0769fe6SDarren Hart /* Act on key press; ignore key release */ 233429cd293fSSeth Forshee if (scancode & 0x80) 233529cd293fSSeth Forshee return; 233629cd293fSSeth Forshee 233729cd293fSSeth Forshee if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true)) 233829cd293fSSeth Forshee pr_info("Unknown key %x\n", scancode); 233929cd293fSSeth Forshee } 234029cd293fSSeth Forshee 234171454d78SAzael Avalos static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) 234271454d78SAzael Avalos { 234371454d78SAzael Avalos if (dev->info_supported) { 23447deef550SAzael Avalos int scancode = toshiba_acpi_query_hotkey(dev); 23457deef550SAzael Avalos 23467deef550SAzael Avalos if (scancode < 0) { 234771454d78SAzael Avalos pr_err("Failed to query hotkey event\n"); 23487deef550SAzael Avalos } else if (scancode != 0) { 234971454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, scancode); 23507deef550SAzael Avalos dev->key_event_valid = 1; 23517deef550SAzael Avalos dev->last_key_event = scancode; 23527deef550SAzael Avalos } 235371454d78SAzael Avalos } else if (dev->system_event_supported) { 23547deef550SAzael Avalos u32 result; 23557deef550SAzael Avalos u32 value; 23567deef550SAzael Avalos int retries = 3; 23577deef550SAzael Avalos 235871454d78SAzael Avalos do { 23597deef550SAzael Avalos result = hci_read(dev, HCI_SYSTEM_EVENT, &value); 23607deef550SAzael Avalos switch (result) { 236171454d78SAzael Avalos case TOS_SUCCESS: 236271454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, (int)value); 23637deef550SAzael Avalos dev->key_event_valid = 1; 23647deef550SAzael Avalos dev->last_key_event = value; 236571454d78SAzael Avalos break; 236671454d78SAzael Avalos case TOS_NOT_SUPPORTED: 236771454d78SAzael Avalos /* 236871454d78SAzael Avalos * This is a workaround for an unresolved 236971454d78SAzael Avalos * issue on some machines where system events 237071454d78SAzael Avalos * sporadically become disabled. 237171454d78SAzael Avalos */ 23727deef550SAzael Avalos result = hci_write(dev, HCI_SYSTEM_EVENT, 1); 23737deef550SAzael Avalos if (result == TOS_SUCCESS) 237471454d78SAzael Avalos pr_notice("Re-enabled hotkeys\n"); 2375e0769fe6SDarren Hart /* Fall through */ 237671454d78SAzael Avalos default: 237771454d78SAzael Avalos retries--; 237871454d78SAzael Avalos break; 237971454d78SAzael Avalos } 23807deef550SAzael Avalos } while (retries && result != TOS_FIFO_EMPTY); 238171454d78SAzael Avalos } 238271454d78SAzael Avalos } 238371454d78SAzael Avalos 2384b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) 23856335e4d5SMatthew Garrett { 2386fe808bfbSTakashi Iwai const struct key_entry *keymap = toshiba_acpi_keymap; 2387a2b3471bSAzael Avalos acpi_handle ec_handle; 2388a2b3471bSAzael Avalos u32 events_type; 2389a2b3471bSAzael Avalos u32 hci_result; 2390a2b3471bSAzael Avalos int error; 2391a2b3471bSAzael Avalos 2392a88bc06eSAzael Avalos if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) { 2393a88bc06eSAzael Avalos pr_info("WMI event detected, hotkeys will not be monitored\n"); 2394a88bc06eSAzael Avalos return 0; 2395a88bc06eSAzael Avalos } 2396a88bc06eSAzael Avalos 2397a2b3471bSAzael Avalos error = toshiba_acpi_enable_hotkeys(dev); 2398a2b3471bSAzael Avalos if (error) 2399a2b3471bSAzael Avalos return error; 2400a2b3471bSAzael Avalos 2401*53147b6cSAzael Avalos if (toshiba_hotkey_event_type_get(dev, &events_type)) 2402*53147b6cSAzael Avalos pr_notice("Unable to query Hotkey Event Type\n"); 2403*53147b6cSAzael Avalos 2404a2b3471bSAzael Avalos dev->hotkey_event_type = events_type; 2405135740deSSeth Forshee 2406135740deSSeth Forshee dev->hotkey_dev = input_allocate_device(); 2407b222cca6SJoe Perches if (!dev->hotkey_dev) 2408135740deSSeth Forshee return -ENOMEM; 2409135740deSSeth Forshee 2410135740deSSeth Forshee dev->hotkey_dev->name = "Toshiba input device"; 24116e02cc7eSSeth Forshee dev->hotkey_dev->phys = "toshiba_acpi/input0"; 2412135740deSSeth Forshee dev->hotkey_dev->id.bustype = BUS_HOST; 2413135740deSSeth Forshee 2414a2b3471bSAzael Avalos if (events_type == HCI_SYSTEM_TYPE1 || 2415a2b3471bSAzael Avalos !dev->kbd_function_keys_supported) 2416a2b3471bSAzael Avalos keymap = toshiba_acpi_keymap; 2417a2b3471bSAzael Avalos else if (events_type == HCI_SYSTEM_TYPE2 || 2418a2b3471bSAzael Avalos dev->kbd_function_keys_supported) 2419fe808bfbSTakashi Iwai keymap = toshiba_acpi_alt_keymap; 2420a2b3471bSAzael Avalos else 2421a2b3471bSAzael Avalos pr_info("Unknown event type received %x\n", events_type); 2422fe808bfbSTakashi Iwai error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL); 2423135740deSSeth Forshee if (error) 2424135740deSSeth Forshee goto err_free_dev; 2425135740deSSeth Forshee 242629cd293fSSeth Forshee /* 242729cd293fSSeth Forshee * For some machines the SCI responsible for providing hotkey 242829cd293fSSeth Forshee * notification doesn't fire. We can trigger the notification 242929cd293fSSeth Forshee * whenever the Fn key is pressed using the NTFY method, if 243029cd293fSSeth Forshee * supported, so if it's present set up an i8042 key filter 243129cd293fSSeth Forshee * for this purpose. 243229cd293fSSeth Forshee */ 243329cd293fSSeth Forshee ec_handle = ec_get_handle(); 2434e2e19606SZhang Rui if (ec_handle && acpi_has_method(ec_handle, "NTFY")) { 243529cd293fSSeth Forshee INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work); 243629cd293fSSeth Forshee 243729cd293fSSeth Forshee error = i8042_install_filter(toshiba_acpi_i8042_filter); 243829cd293fSSeth Forshee if (error) { 243929cd293fSSeth Forshee pr_err("Error installing key filter\n"); 244029cd293fSSeth Forshee goto err_free_keymap; 244129cd293fSSeth Forshee } 244229cd293fSSeth Forshee 244329cd293fSSeth Forshee dev->ntfy_supported = 1; 244429cd293fSSeth Forshee } 244529cd293fSSeth Forshee 244629cd293fSSeth Forshee /* 244729cd293fSSeth Forshee * Determine hotkey query interface. Prefer using the INFO 244829cd293fSSeth Forshee * method when it is available. 244929cd293fSSeth Forshee */ 2450e2e19606SZhang Rui if (acpi_has_method(dev->acpi_dev->handle, "INFO")) 245129cd293fSSeth Forshee dev->info_supported = 1; 2452e2e19606SZhang Rui else { 2453d37782bdSAzael Avalos hci_result = hci_write(dev, HCI_SYSTEM_EVENT, 1); 24541864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) 245529cd293fSSeth Forshee dev->system_event_supported = 1; 245629cd293fSSeth Forshee } 245729cd293fSSeth Forshee 245829cd293fSSeth Forshee if (!dev->info_supported && !dev->system_event_supported) { 245929cd293fSSeth Forshee pr_warn("No hotkey query interface found\n"); 246029cd293fSSeth Forshee goto err_remove_filter; 246129cd293fSSeth Forshee } 246229cd293fSSeth Forshee 2463135740deSSeth Forshee error = input_register_device(dev->hotkey_dev); 2464135740deSSeth Forshee if (error) { 2465135740deSSeth Forshee pr_info("Unable to register input device\n"); 246629cd293fSSeth Forshee goto err_remove_filter; 2467135740deSSeth Forshee } 2468135740deSSeth Forshee 2469135740deSSeth Forshee return 0; 2470135740deSSeth Forshee 247129cd293fSSeth Forshee err_remove_filter: 247229cd293fSSeth Forshee if (dev->ntfy_supported) 247329cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 2474135740deSSeth Forshee err_free_keymap: 2475135740deSSeth Forshee sparse_keymap_free(dev->hotkey_dev); 2476135740deSSeth Forshee err_free_dev: 2477135740deSSeth Forshee input_free_device(dev->hotkey_dev); 2478135740deSSeth Forshee dev->hotkey_dev = NULL; 2479135740deSSeth Forshee return error; 2480135740deSSeth Forshee } 2481135740deSSeth Forshee 2482b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) 248362cce752SSeth Forshee { 248462cce752SSeth Forshee struct backlight_properties props; 248562cce752SSeth Forshee int brightness; 248662cce752SSeth Forshee int ret; 248762cce752SSeth Forshee 248862cce752SSeth Forshee /* 248962cce752SSeth Forshee * Some machines don't support the backlight methods at all, and 249062cce752SSeth Forshee * others support it read-only. Either of these is pretty useless, 249162cce752SSeth Forshee * so only register the backlight device if the backlight method 249262cce752SSeth Forshee * supports both reads and writes. 249362cce752SSeth Forshee */ 249462cce752SSeth Forshee brightness = __get_lcd_brightness(dev); 249562cce752SSeth Forshee if (brightness < 0) 249662cce752SSeth Forshee return 0; 249762cce752SSeth Forshee ret = set_lcd_brightness(dev, brightness); 249862cce752SSeth Forshee if (ret) { 249962cce752SSeth Forshee pr_debug("Backlight method is read-only, disabling backlight support\n"); 250062cce752SSeth Forshee return 0; 250162cce752SSeth Forshee } 250262cce752SSeth Forshee 2503358d6a2cSHans de Goede /* 2504358d6a2cSHans de Goede * Tell acpi-video-detect code to prefer vendor backlight on all 2505358d6a2cSHans de Goede * systems with transflective backlight and on dmi matched systems. 2506358d6a2cSHans de Goede */ 2507358d6a2cSHans de Goede if (dev->tr_backlight_supported || 2508358d6a2cSHans de Goede dmi_check_system(toshiba_vendor_backlight_dmi)) 2509234b7cf8SHans de Goede acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); 2510358d6a2cSHans de Goede 2511234b7cf8SHans de Goede if (acpi_video_get_backlight_type() != acpi_backlight_vendor) 2512358d6a2cSHans de Goede return 0; 2513358d6a2cSHans de Goede 251453039f22SMatthew Garrett memset(&props, 0, sizeof(props)); 251562cce752SSeth Forshee props.type = BACKLIGHT_PLATFORM; 251662cce752SSeth Forshee props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; 251762cce752SSeth Forshee 2518e0769fe6SDarren Hart /* Adding an extra level and having 0 change to transflective mode */ 2519121b7b0dSAkio Idehara if (dev->tr_backlight_supported) 2520121b7b0dSAkio Idehara props.max_brightness++; 2521121b7b0dSAkio Idehara 252262cce752SSeth Forshee dev->backlight_dev = backlight_device_register("toshiba", 252362cce752SSeth Forshee &dev->acpi_dev->dev, 252462cce752SSeth Forshee dev, 252562cce752SSeth Forshee &toshiba_backlight_data, 252662cce752SSeth Forshee &props); 252762cce752SSeth Forshee if (IS_ERR(dev->backlight_dev)) { 252862cce752SSeth Forshee ret = PTR_ERR(dev->backlight_dev); 252962cce752SSeth Forshee pr_err("Could not register toshiba backlight device\n"); 253062cce752SSeth Forshee dev->backlight_dev = NULL; 253162cce752SSeth Forshee return ret; 253262cce752SSeth Forshee } 253362cce752SSeth Forshee 253462cce752SSeth Forshee dev->backlight_dev->props.brightness = brightness; 253562cce752SSeth Forshee return 0; 253662cce752SSeth Forshee } 253762cce752SSeth Forshee 25380409cbceSAzael Avalos static void print_supported_features(struct toshiba_acpi_dev *dev) 25390409cbceSAzael Avalos { 25400409cbceSAzael Avalos pr_info("Supported laptop features:"); 25410409cbceSAzael Avalos 25420409cbceSAzael Avalos if (dev->hotkey_dev) 25430409cbceSAzael Avalos pr_cont(" hotkeys"); 25440409cbceSAzael Avalos if (dev->backlight_dev) 25450409cbceSAzael Avalos pr_cont(" backlight"); 25460409cbceSAzael Avalos if (dev->video_supported) 25470409cbceSAzael Avalos pr_cont(" video-out"); 25480409cbceSAzael Avalos if (dev->fan_supported) 25490409cbceSAzael Avalos pr_cont(" fan"); 25500409cbceSAzael Avalos if (dev->tr_backlight_supported) 25510409cbceSAzael Avalos pr_cont(" transflective-backlight"); 25520409cbceSAzael Avalos if (dev->illumination_supported) 25530409cbceSAzael Avalos pr_cont(" illumination"); 25540409cbceSAzael Avalos if (dev->kbd_illum_supported) 25550409cbceSAzael Avalos pr_cont(" keyboard-backlight"); 25560409cbceSAzael Avalos if (dev->touchpad_supported) 25570409cbceSAzael Avalos pr_cont(" touchpad"); 25580409cbceSAzael Avalos if (dev->eco_supported) 25590409cbceSAzael Avalos pr_cont(" eco-led"); 25600409cbceSAzael Avalos if (dev->accelerometer_supported) 25610409cbceSAzael Avalos pr_cont(" accelerometer-axes"); 25620409cbceSAzael Avalos if (dev->usb_sleep_charge_supported) 25630409cbceSAzael Avalos pr_cont(" usb-sleep-charge"); 25640409cbceSAzael Avalos if (dev->usb_rapid_charge_supported) 25650409cbceSAzael Avalos pr_cont(" usb-rapid-charge"); 25660409cbceSAzael Avalos if (dev->usb_sleep_music_supported) 25670409cbceSAzael Avalos pr_cont(" usb-sleep-music"); 25680409cbceSAzael Avalos if (dev->kbd_function_keys_supported) 25690409cbceSAzael Avalos pr_cont(" special-function-keys"); 25700409cbceSAzael Avalos if (dev->panel_power_on_supported) 25710409cbceSAzael Avalos pr_cont(" panel-power-on"); 25720409cbceSAzael Avalos if (dev->usb_three_supported) 25730409cbceSAzael Avalos pr_cont(" usb3"); 25740409cbceSAzael Avalos 25750409cbceSAzael Avalos pr_cont("\n"); 25760409cbceSAzael Avalos } 25770409cbceSAzael Avalos 257851fac838SRafael J. Wysocki static int toshiba_acpi_remove(struct acpi_device *acpi_dev) 2579135740deSSeth Forshee { 2580135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 2581135740deSSeth Forshee 2582fc5462f8SAzael Avalos misc_deregister(&dev->miscdev); 2583fc5462f8SAzael Avalos 258436d03f93SSeth Forshee remove_toshiba_proc_entries(dev); 2585135740deSSeth Forshee 2586360f0f39SAzael Avalos if (dev->sysfs_created) 2587360f0f39SAzael Avalos sysfs_remove_group(&dev->acpi_dev->dev.kobj, 2588360f0f39SAzael Avalos &toshiba_attr_group); 2589360f0f39SAzael Avalos 259029cd293fSSeth Forshee if (dev->ntfy_supported) { 259129cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 259229cd293fSSeth Forshee cancel_work_sync(&dev->hotkey_work); 259329cd293fSSeth Forshee } 259429cd293fSSeth Forshee 2595135740deSSeth Forshee if (dev->hotkey_dev) { 2596135740deSSeth Forshee input_unregister_device(dev->hotkey_dev); 2597135740deSSeth Forshee sparse_keymap_free(dev->hotkey_dev); 2598135740deSSeth Forshee } 2599135740deSSeth Forshee 2600135740deSSeth Forshee backlight_device_unregister(dev->backlight_dev); 2601135740deSSeth Forshee 2602ea215a3fSAzael Avalos if (dev->illumination_led_registered) 2603135740deSSeth Forshee led_classdev_unregister(&dev->led_dev); 2604135740deSSeth Forshee 2605360f0f39SAzael Avalos if (dev->kbd_led_registered) 2606360f0f39SAzael Avalos led_classdev_unregister(&dev->kbd_led); 2607360f0f39SAzael Avalos 2608ea215a3fSAzael Avalos if (dev->eco_led_registered) 2609def6c4e2SAzael Avalos led_classdev_unregister(&dev->eco_led); 2610def6c4e2SAzael Avalos 261129cd293fSSeth Forshee if (toshiba_acpi) 261229cd293fSSeth Forshee toshiba_acpi = NULL; 261329cd293fSSeth Forshee 2614135740deSSeth Forshee kfree(dev); 2615135740deSSeth Forshee 2616135740deSSeth Forshee return 0; 2617135740deSSeth Forshee } 2618135740deSSeth Forshee 2619b859f159SGreg Kroah-Hartman static const char *find_hci_method(acpi_handle handle) 2620a540d6b5SSeth Forshee { 2621e2e19606SZhang Rui if (acpi_has_method(handle, "GHCI")) 2622a540d6b5SSeth Forshee return "GHCI"; 2623a540d6b5SSeth Forshee 2624e2e19606SZhang Rui if (acpi_has_method(handle, "SPFC")) 2625a540d6b5SSeth Forshee return "SPFC"; 2626a540d6b5SSeth Forshee 2627a540d6b5SSeth Forshee return NULL; 2628a540d6b5SSeth Forshee } 2629a540d6b5SSeth Forshee 2630b859f159SGreg Kroah-Hartman static int toshiba_acpi_add(struct acpi_device *acpi_dev) 2631135740deSSeth Forshee { 2632135740deSSeth Forshee struct toshiba_acpi_dev *dev; 2633a540d6b5SSeth Forshee const char *hci_method; 2634fb42d1f4SAzael Avalos u32 special_functions; 263536d03f93SSeth Forshee u32 dummy; 2636135740deSSeth Forshee int ret = 0; 2637135740deSSeth Forshee 263829cd293fSSeth Forshee if (toshiba_acpi) 263929cd293fSSeth Forshee return -EBUSY; 264029cd293fSSeth Forshee 2641135740deSSeth Forshee pr_info("Toshiba Laptop ACPI Extras version %s\n", 2642135740deSSeth Forshee TOSHIBA_ACPI_VERSION); 2643135740deSSeth Forshee 2644a540d6b5SSeth Forshee hci_method = find_hci_method(acpi_dev->handle); 2645a540d6b5SSeth Forshee if (!hci_method) { 2646a540d6b5SSeth Forshee pr_err("HCI interface not found\n"); 26476e02cc7eSSeth Forshee return -ENODEV; 2648a540d6b5SSeth Forshee } 26496e02cc7eSSeth Forshee 2650135740deSSeth Forshee dev = kzalloc(sizeof(*dev), GFP_KERNEL); 2651135740deSSeth Forshee if (!dev) 2652135740deSSeth Forshee return -ENOMEM; 2653135740deSSeth Forshee dev->acpi_dev = acpi_dev; 2654a540d6b5SSeth Forshee dev->method_hci = hci_method; 2655fc5462f8SAzael Avalos dev->miscdev.minor = MISC_DYNAMIC_MINOR; 2656fc5462f8SAzael Avalos dev->miscdev.name = "toshiba_acpi"; 2657fc5462f8SAzael Avalos dev->miscdev.fops = &toshiba_acpi_fops; 2658fc5462f8SAzael Avalos 2659fc5462f8SAzael Avalos ret = misc_register(&dev->miscdev); 2660fc5462f8SAzael Avalos if (ret) { 2661fc5462f8SAzael Avalos pr_err("Failed to register miscdevice\n"); 2662fc5462f8SAzael Avalos kfree(dev); 2663fc5462f8SAzael Avalos return ret; 2664fc5462f8SAzael Avalos } 2665fc5462f8SAzael Avalos 2666135740deSSeth Forshee acpi_dev->driver_data = dev; 2667360f0f39SAzael Avalos dev_set_drvdata(&acpi_dev->dev, dev); 2668135740deSSeth Forshee 2669a2b3471bSAzael Avalos /* Query the BIOS for supported features */ 2670a2b3471bSAzael Avalos 2671a2b3471bSAzael Avalos /* 2672a2b3471bSAzael Avalos * The "Special Functions" are always supported by the laptops 2673a2b3471bSAzael Avalos * with the new keyboard layout, query for its presence to help 2674a2b3471bSAzael Avalos * determine the keymap layout to use. 2675a2b3471bSAzael Avalos */ 2676fb42d1f4SAzael Avalos ret = toshiba_function_keys_get(dev, &special_functions); 2677a2b3471bSAzael Avalos dev->kbd_function_keys_supported = !ret; 2678a2b3471bSAzael Avalos 26796e02cc7eSSeth Forshee if (toshiba_acpi_setup_keyboard(dev)) 2680135740deSSeth Forshee pr_info("Unable to activate hotkeys\n"); 2681135740deSSeth Forshee 2682695f6060SAzael Avalos /* Determine whether or not BIOS supports transflective backlight */ 2683695f6060SAzael Avalos ret = get_tr_backlight_status(dev, &dummy); 2684695f6060SAzael Avalos dev->tr_backlight_supported = !ret; 2685695f6060SAzael Avalos 268662cce752SSeth Forshee ret = toshiba_acpi_setup_backlight(dev); 268762cce752SSeth Forshee if (ret) 2688135740deSSeth Forshee goto error; 2689135740deSSeth Forshee 2690ea215a3fSAzael Avalos toshiba_illumination_available(dev); 2691ea215a3fSAzael Avalos if (dev->illumination_supported) { 2692135740deSSeth Forshee dev->led_dev.name = "toshiba::illumination"; 2693135740deSSeth Forshee dev->led_dev.max_brightness = 1; 2694135740deSSeth Forshee dev->led_dev.brightness_set = toshiba_illumination_set; 2695135740deSSeth Forshee dev->led_dev.brightness_get = toshiba_illumination_get; 2696135740deSSeth Forshee if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev)) 2697ea215a3fSAzael Avalos dev->illumination_led_registered = true; 2698135740deSSeth Forshee } 2699135740deSSeth Forshee 2700ea215a3fSAzael Avalos toshiba_eco_mode_available(dev); 2701ea215a3fSAzael Avalos if (dev->eco_supported) { 2702def6c4e2SAzael Avalos dev->eco_led.name = "toshiba::eco_mode"; 2703def6c4e2SAzael Avalos dev->eco_led.max_brightness = 1; 2704def6c4e2SAzael Avalos dev->eco_led.brightness_set = toshiba_eco_mode_set_status; 2705def6c4e2SAzael Avalos dev->eco_led.brightness_get = toshiba_eco_mode_get_status; 2706def6c4e2SAzael Avalos if (!led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led)) 2707ea215a3fSAzael Avalos dev->eco_led_registered = true; 2708def6c4e2SAzael Avalos } 2709def6c4e2SAzael Avalos 2710ea215a3fSAzael Avalos toshiba_kbd_illum_available(dev); 2711360f0f39SAzael Avalos /* 2712360f0f39SAzael Avalos * Only register the LED if KBD illumination is supported 2713360f0f39SAzael Avalos * and the keyboard backlight operation mode is set to FN-Z 2714360f0f39SAzael Avalos */ 2715360f0f39SAzael Avalos if (dev->kbd_illum_supported && dev->kbd_mode == SCI_KBD_MODE_FNZ) { 2716360f0f39SAzael Avalos dev->kbd_led.name = "toshiba::kbd_backlight"; 2717360f0f39SAzael Avalos dev->kbd_led.max_brightness = 1; 2718360f0f39SAzael Avalos dev->kbd_led.brightness_set = toshiba_kbd_backlight_set; 2719360f0f39SAzael Avalos dev->kbd_led.brightness_get = toshiba_kbd_backlight_get; 2720360f0f39SAzael Avalos if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led)) 2721ea215a3fSAzael Avalos dev->kbd_led_registered = true; 2722360f0f39SAzael Avalos } 2723360f0f39SAzael Avalos 27249d8658acSAzael Avalos ret = toshiba_touchpad_get(dev, &dummy); 27259d8658acSAzael Avalos dev->touchpad_supported = !ret; 27269d8658acSAzael Avalos 2727ea215a3fSAzael Avalos toshiba_accelerometer_available(dev); 27285a2813e9SAzael Avalos 2729c8c91842SAzael Avalos toshiba_usb_sleep_charge_available(dev); 2730e26ffe51SAzael Avalos 2731bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(dev, &dummy); 2732bb3fe01fSAzael Avalos dev->usb_rapid_charge_supported = !ret; 2733bb3fe01fSAzael Avalos 2734172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(dev, &dummy); 2735172ce0a9SAzael Avalos dev->usb_sleep_music_supported = !ret; 2736172ce0a9SAzael Avalos 273735d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(dev, &dummy); 273835d53ceaSAzael Avalos dev->panel_power_on_supported = !ret; 273935d53ceaSAzael Avalos 274017fe4b3dSAzael Avalos ret = toshiba_usb_three_get(dev, &dummy); 274117fe4b3dSAzael Avalos dev->usb_three_supported = !ret; 274217fe4b3dSAzael Avalos 274336d03f93SSeth Forshee ret = get_video_status(dev, &dummy); 274436d03f93SSeth Forshee dev->video_supported = !ret; 274536d03f93SSeth Forshee 274636d03f93SSeth Forshee ret = get_fan_status(dev, &dummy); 274736d03f93SSeth Forshee dev->fan_supported = !ret; 274836d03f93SSeth Forshee 27490409cbceSAzael Avalos print_supported_features(dev); 27500409cbceSAzael Avalos 2751fb42d1f4SAzael Avalos /* 2752fb42d1f4SAzael Avalos * Enable the "Special Functions" mode only if they are 2753fb42d1f4SAzael Avalos * supported and if they are activated. 2754fb42d1f4SAzael Avalos */ 2755fb42d1f4SAzael Avalos if (dev->kbd_function_keys_supported && special_functions) 2756fb42d1f4SAzael Avalos toshiba_acpi_enable_special_functions(dev); 2757fb42d1f4SAzael Avalos 2758360f0f39SAzael Avalos ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, 2759360f0f39SAzael Avalos &toshiba_attr_group); 2760360f0f39SAzael Avalos if (ret) { 2761360f0f39SAzael Avalos dev->sysfs_created = 0; 2762360f0f39SAzael Avalos goto error; 2763360f0f39SAzael Avalos } 2764360f0f39SAzael Avalos dev->sysfs_created = !ret; 2765360f0f39SAzael Avalos 276636d03f93SSeth Forshee create_toshiba_proc_entries(dev); 276736d03f93SSeth Forshee 276829cd293fSSeth Forshee toshiba_acpi = dev; 276929cd293fSSeth Forshee 2770135740deSSeth Forshee return 0; 2771135740deSSeth Forshee 2772135740deSSeth Forshee error: 277351fac838SRafael J. Wysocki toshiba_acpi_remove(acpi_dev); 2774135740deSSeth Forshee return ret; 2775135740deSSeth Forshee } 2776135740deSSeth Forshee 2777135740deSSeth Forshee static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) 2778135740deSSeth Forshee { 2779135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 278080546905SAzael Avalos int ret; 27816335e4d5SMatthew Garrett 278271454d78SAzael Avalos switch (event) { 278371454d78SAzael Avalos case 0x80: /* Hotkeys and some system events */ 2784a88bc06eSAzael Avalos /* 2785a88bc06eSAzael Avalos * Machines with this WMI GUID aren't supported due to bugs in 2786a88bc06eSAzael Avalos * their AML. 2787a88bc06eSAzael Avalos * 2788a88bc06eSAzael Avalos * Return silently to avoid triggering a netlink event. 2789a88bc06eSAzael Avalos */ 2790a88bc06eSAzael Avalos if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) 2791a88bc06eSAzael Avalos return; 279271454d78SAzael Avalos toshiba_acpi_process_hotkeys(dev); 279311948b93SSeth Forshee break; 2794bab09e23SAzael Avalos case 0x81: /* Dock events */ 2795bab09e23SAzael Avalos case 0x82: 2796bab09e23SAzael Avalos case 0x83: 2797bab09e23SAzael Avalos pr_info("Dock event received %x\n", event); 2798bab09e23SAzael Avalos break; 2799bab09e23SAzael Avalos case 0x88: /* Thermal events */ 2800bab09e23SAzael Avalos pr_info("Thermal event received\n"); 2801bab09e23SAzael Avalos break; 2802bab09e23SAzael Avalos case 0x8f: /* LID closed */ 2803bab09e23SAzael Avalos case 0x90: /* LID is closed and Dock has been ejected */ 2804bab09e23SAzael Avalos break; 2805bab09e23SAzael Avalos case 0x8c: /* SATA power events */ 2806bab09e23SAzael Avalos case 0x8b: 2807bab09e23SAzael Avalos pr_info("SATA power event received %x\n", event); 2808bab09e23SAzael Avalos break; 280980546905SAzael Avalos case 0x92: /* Keyboard backlight mode changed */ 281080546905SAzael Avalos /* Update sysfs entries */ 281180546905SAzael Avalos ret = sysfs_update_group(&acpi_dev->dev.kobj, 281280546905SAzael Avalos &toshiba_attr_group); 281380546905SAzael Avalos if (ret) 281480546905SAzael Avalos pr_err("Unable to update sysfs entries\n"); 281580546905SAzael Avalos break; 2816bab09e23SAzael Avalos case 0x85: /* Unknown */ 2817bab09e23SAzael Avalos case 0x8d: /* Unknown */ 281871454d78SAzael Avalos case 0x8e: /* Unknown */ 2819bab09e23SAzael Avalos case 0x94: /* Unknown */ 2820bab09e23SAzael Avalos case 0x95: /* Unknown */ 282111948b93SSeth Forshee default: 282271454d78SAzael Avalos pr_info("Unknown event received %x\n", event); 282311948b93SSeth Forshee break; 28246335e4d5SMatthew Garrett } 2825bab09e23SAzael Avalos 2826bab09e23SAzael Avalos acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class, 2827bab09e23SAzael Avalos dev_name(&acpi_dev->dev), 2828bab09e23SAzael Avalos event, 0); 282929cd293fSSeth Forshee } 28306335e4d5SMatthew Garrett 28313567a4e2SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 283243d2fd3bSRafael J. Wysocki static int toshiba_acpi_suspend(struct device *device) 283329cd293fSSeth Forshee { 283443d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 28351e574dbfSAzael Avalos 28361e574dbfSAzael Avalos if (dev->hotkey_dev) { 283729cd293fSSeth Forshee u32 result; 283829cd293fSSeth Forshee 2839d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE); 28401e574dbfSAzael Avalos if (result != TOS_SUCCESS) 28411e574dbfSAzael Avalos pr_info("Unable to disable hotkeys\n"); 28421e574dbfSAzael Avalos } 284329cd293fSSeth Forshee 284429cd293fSSeth Forshee return 0; 284529cd293fSSeth Forshee } 284629cd293fSSeth Forshee 284743d2fd3bSRafael J. Wysocki static int toshiba_acpi_resume(struct device *device) 284829cd293fSSeth Forshee { 284943d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 285029cd293fSSeth Forshee 2851e7fdb762SBenjamin Tissoires if (dev->hotkey_dev) { 28521e574dbfSAzael Avalos int error = toshiba_acpi_enable_hotkeys(dev); 28531e574dbfSAzael Avalos 28541f28f290SAzael Avalos if (error) 2855e7fdb762SBenjamin Tissoires pr_info("Unable to re-enable hotkeys\n"); 2856e7fdb762SBenjamin Tissoires } 285729cd293fSSeth Forshee 285829cd293fSSeth Forshee return 0; 285929cd293fSSeth Forshee } 28603567a4e2SRafael J. Wysocki #endif 28616335e4d5SMatthew Garrett 286243d2fd3bSRafael J. Wysocki static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm, 286343d2fd3bSRafael J. Wysocki toshiba_acpi_suspend, toshiba_acpi_resume); 286443d2fd3bSRafael J. Wysocki 2865135740deSSeth Forshee static struct acpi_driver toshiba_acpi_driver = { 2866135740deSSeth Forshee .name = "Toshiba ACPI driver", 2867135740deSSeth Forshee .owner = THIS_MODULE, 2868135740deSSeth Forshee .ids = toshiba_device_ids, 2869135740deSSeth Forshee .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, 2870135740deSSeth Forshee .ops = { 2871135740deSSeth Forshee .add = toshiba_acpi_add, 2872135740deSSeth Forshee .remove = toshiba_acpi_remove, 2873135740deSSeth Forshee .notify = toshiba_acpi_notify, 2874135740deSSeth Forshee }, 287543d2fd3bSRafael J. Wysocki .drv.pm = &toshiba_acpi_pm, 2876135740deSSeth Forshee }; 2877b4f9fe12SLen Brown 2878b4f9fe12SLen Brown static int __init toshiba_acpi_init(void) 2879b4f9fe12SLen Brown { 2880135740deSSeth Forshee int ret; 2881b4f9fe12SLen Brown 2882b4f9fe12SLen Brown toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); 2883b4f9fe12SLen Brown if (!toshiba_proc_dir) { 2884135740deSSeth Forshee pr_err("Unable to create proc dir " PROC_TOSHIBA "\n"); 2885b4f9fe12SLen Brown return -ENODEV; 2886b4f9fe12SLen Brown } 2887b4f9fe12SLen Brown 2888135740deSSeth Forshee ret = acpi_bus_register_driver(&toshiba_acpi_driver); 2889b4f9fe12SLen Brown if (ret) { 2890135740deSSeth Forshee pr_err("Failed to register ACPI driver: %d\n", ret); 2891135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 2892135740deSSeth Forshee } 2893135740deSSeth Forshee 2894b4f9fe12SLen Brown return ret; 2895b4f9fe12SLen Brown } 2896b4f9fe12SLen Brown 2897135740deSSeth Forshee static void __exit toshiba_acpi_exit(void) 2898135740deSSeth Forshee { 2899135740deSSeth Forshee acpi_bus_unregister_driver(&toshiba_acpi_driver); 2900135740deSSeth Forshee if (toshiba_proc_dir) 2901135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 2902b4f9fe12SLen Brown } 2903b4f9fe12SLen Brown 2904b4f9fe12SLen Brown module_init(toshiba_acpi_init); 2905b4f9fe12SLen Brown module_exit(toshiba_acpi_exit); 2906