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 13452cbae01SAzael Avalos #define HCI_HOTKEY_ENABLE 0x01 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; 201b116fd00SAzael Avalos unsigned int special_functions; 202ea215a3fSAzael Avalos 203ea215a3fSAzael Avalos bool kbd_led_registered; 204ea215a3fSAzael Avalos bool illumination_led_registered; 205ea215a3fSAzael Avalos bool eco_led_registered; 206135740deSSeth Forshee }; 207135740deSSeth Forshee 20829cd293fSSeth Forshee static struct toshiba_acpi_dev *toshiba_acpi; 20929cd293fSSeth Forshee 210b4f9fe12SLen Brown static const struct acpi_device_id toshiba_device_ids[] = { 211b4f9fe12SLen Brown {"TOS6200", 0}, 21263a9e016SOndrej Zary {"TOS6207", 0}, 213b4f9fe12SLen Brown {"TOS6208", 0}, 214b4f9fe12SLen Brown {"TOS1900", 0}, 215b4f9fe12SLen Brown {"", 0}, 216b4f9fe12SLen Brown }; 217b4f9fe12SLen Brown MODULE_DEVICE_TABLE(acpi, toshiba_device_ids); 218b4f9fe12SLen Brown 219b859f159SGreg Kroah-Hartman static const struct key_entry toshiba_acpi_keymap[] = { 220fec278a1SUnai Uribarri { KE_KEY, 0x9e, { KEY_RFKILL } }, 221384a7cd9SDmitry Torokhov { KE_KEY, 0x101, { KEY_MUTE } }, 222384a7cd9SDmitry Torokhov { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 223384a7cd9SDmitry Torokhov { KE_KEY, 0x103, { KEY_ZOOMIN } }, 224408a5d13SAzael Avalos { KE_KEY, 0x10f, { KEY_TAB } }, 225af502837SAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 226af502837SAzael Avalos { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 227384a7cd9SDmitry Torokhov { KE_KEY, 0x13b, { KEY_COFFEE } }, 228384a7cd9SDmitry Torokhov { KE_KEY, 0x13c, { KEY_BATTERY } }, 229384a7cd9SDmitry Torokhov { KE_KEY, 0x13d, { KEY_SLEEP } }, 230384a7cd9SDmitry Torokhov { KE_KEY, 0x13e, { KEY_SUSPEND } }, 231384a7cd9SDmitry Torokhov { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } }, 232384a7cd9SDmitry Torokhov { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } }, 233384a7cd9SDmitry Torokhov { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } }, 234384a7cd9SDmitry Torokhov { KE_KEY, 0x142, { KEY_WLAN } }, 235af502837SAzael Avalos { KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } }, 236a49010f5SJon Dowland { KE_KEY, 0x17f, { KEY_FN } }, 237384a7cd9SDmitry Torokhov { KE_KEY, 0xb05, { KEY_PROG2 } }, 238384a7cd9SDmitry Torokhov { KE_KEY, 0xb06, { KEY_WWW } }, 239384a7cd9SDmitry Torokhov { KE_KEY, 0xb07, { KEY_MAIL } }, 240384a7cd9SDmitry Torokhov { KE_KEY, 0xb30, { KEY_STOP } }, 241384a7cd9SDmitry Torokhov { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } }, 242384a7cd9SDmitry Torokhov { KE_KEY, 0xb32, { KEY_NEXTSONG } }, 243384a7cd9SDmitry Torokhov { KE_KEY, 0xb33, { KEY_PLAYPAUSE } }, 244384a7cd9SDmitry Torokhov { KE_KEY, 0xb5a, { KEY_MEDIA } }, 245408a5d13SAzael Avalos { KE_IGNORE, 0x1430, { KEY_RESERVED } }, /* Wake from sleep */ 246408a5d13SAzael Avalos { KE_IGNORE, 0x1501, { KEY_RESERVED } }, /* Output changed */ 247408a5d13SAzael Avalos { KE_IGNORE, 0x1502, { KEY_RESERVED } }, /* HDMI plugged/unplugged */ 248408a5d13SAzael Avalos { KE_IGNORE, 0x1ABE, { KEY_RESERVED } }, /* Protection level set */ 249408a5d13SAzael Avalos { KE_IGNORE, 0x1ABF, { KEY_RESERVED } }, /* Protection level off */ 250384a7cd9SDmitry Torokhov { KE_END, 0 }, 2516335e4d5SMatthew Garrett }; 2526335e4d5SMatthew Garrett 253fe808bfbSTakashi Iwai static const struct key_entry toshiba_acpi_alt_keymap[] = { 254fe808bfbSTakashi Iwai { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 255fe808bfbSTakashi Iwai { KE_KEY, 0x103, { KEY_ZOOMIN } }, 256e6efad7fSAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 257fe808bfbSTakashi Iwai { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 258fe808bfbSTakashi Iwai { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } }, 259fe808bfbSTakashi Iwai { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } }, 260d50c9005SAzael Avalos { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } }, 261fe808bfbSTakashi Iwai { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } }, 262d50c9005SAzael Avalos { KE_KEY, 0x157, { KEY_MUTE } }, 263d50c9005SAzael Avalos { KE_KEY, 0x158, { KEY_WLAN } }, 264fe808bfbSTakashi Iwai { KE_END, 0 }, 265fe808bfbSTakashi Iwai }; 266fe808bfbSTakashi Iwai 267e0769fe6SDarren Hart /* 268358d6a2cSHans de Goede * List of models which have a broken acpi-video backlight interface and thus 269358d6a2cSHans de Goede * need to use the toshiba (vendor) interface instead. 270358d6a2cSHans de Goede */ 271358d6a2cSHans de Goede static const struct dmi_system_id toshiba_vendor_backlight_dmi[] = { 272358d6a2cSHans de Goede {} 273358d6a2cSHans de Goede }; 274358d6a2cSHans de Goede 275358d6a2cSHans de Goede /* 276e0769fe6SDarren Hart * Utility 277b4f9fe12SLen Brown */ 278b4f9fe12SLen Brown 279b5163992SAzael Avalos static inline void _set_bit(u32 *word, u32 mask, int value) 280b4f9fe12SLen Brown { 281b4f9fe12SLen Brown *word = (*word & ~mask) | (mask * value); 282b4f9fe12SLen Brown } 283b4f9fe12SLen Brown 284e0769fe6SDarren Hart /* 285e0769fe6SDarren Hart * ACPI interface wrappers 286b4f9fe12SLen Brown */ 287b4f9fe12SLen Brown 288b4f9fe12SLen Brown static int write_acpi_int(const char *methodName, int val) 289b4f9fe12SLen Brown { 290b4f9fe12SLen Brown acpi_status status; 291b4f9fe12SLen Brown 292619400daSZhang Rui status = acpi_execute_simple_method(NULL, (char *)methodName, val); 29332bcd5cbSSeth Forshee return (status == AE_OK) ? 0 : -EIO; 294b4f9fe12SLen Brown } 295b4f9fe12SLen Brown 296e0769fe6SDarren Hart /* 297e0769fe6SDarren Hart * Perform a raw configuration call. Here we don't care about input or output 298258c5903SAzael Avalos * buffer format. 299b4f9fe12SLen Brown */ 300258c5903SAzael Avalos static acpi_status tci_raw(struct toshiba_acpi_dev *dev, 301258c5903SAzael Avalos const u32 in[TCI_WORDS], u32 out[TCI_WORDS]) 302b4f9fe12SLen Brown { 303b4f9fe12SLen Brown struct acpi_object_list params; 304258c5903SAzael Avalos union acpi_object in_objs[TCI_WORDS]; 305b4f9fe12SLen Brown struct acpi_buffer results; 306258c5903SAzael Avalos union acpi_object out_objs[TCI_WORDS + 1]; 307b4f9fe12SLen Brown acpi_status status; 308b4f9fe12SLen Brown int i; 309b4f9fe12SLen Brown 310258c5903SAzael Avalos params.count = TCI_WORDS; 311b4f9fe12SLen Brown params.pointer = in_objs; 312258c5903SAzael Avalos for (i = 0; i < TCI_WORDS; ++i) { 313b4f9fe12SLen Brown in_objs[i].type = ACPI_TYPE_INTEGER; 314b4f9fe12SLen Brown in_objs[i].integer.value = in[i]; 315b4f9fe12SLen Brown } 316b4f9fe12SLen Brown 317b4f9fe12SLen Brown results.length = sizeof(out_objs); 318b4f9fe12SLen Brown results.pointer = out_objs; 319b4f9fe12SLen Brown 3206e02cc7eSSeth Forshee status = acpi_evaluate_object(dev->acpi_dev->handle, 3216e02cc7eSSeth Forshee (char *)dev->method_hci, ¶ms, 322b4f9fe12SLen Brown &results); 323258c5903SAzael Avalos if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) { 324b5163992SAzael Avalos for (i = 0; i < out_objs->package.count; ++i) 325b4f9fe12SLen Brown out[i] = out_objs->package.elements[i].integer.value; 326b4f9fe12SLen Brown } 327b4f9fe12SLen Brown 328b4f9fe12SLen Brown return status; 329b4f9fe12SLen Brown } 330b4f9fe12SLen Brown 331e0769fe6SDarren Hart /* 332d37782bdSAzael Avalos * Common hci tasks 333b4f9fe12SLen Brown * 334b4f9fe12SLen Brown * In addition to the ACPI status, the HCI system returns a result which 335b4f9fe12SLen Brown * may be useful (such as "not supported"). 336b4f9fe12SLen Brown */ 337b4f9fe12SLen Brown 338d37782bdSAzael Avalos static u32 hci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 339b4f9fe12SLen Brown { 340258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 }; 341258c5903SAzael Avalos u32 out[TCI_WORDS]; 342258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 343893f3f62SAzael Avalos 344893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 345b4f9fe12SLen Brown } 346b4f9fe12SLen Brown 347d37782bdSAzael Avalos static u32 hci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 348b4f9fe12SLen Brown { 349258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 }; 350258c5903SAzael Avalos u32 out[TCI_WORDS]; 351258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 352b5163992SAzael Avalos 353893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 354893f3f62SAzael Avalos return TOS_FAILURE; 355893f3f62SAzael Avalos 356b4f9fe12SLen Brown *out1 = out[2]; 357893f3f62SAzael Avalos 358893f3f62SAzael Avalos return out[0]; 359b4f9fe12SLen Brown } 360b4f9fe12SLen Brown 361e0769fe6SDarren Hart /* 362e0769fe6SDarren Hart * Common sci tasks 36384a6273fSAzael Avalos */ 36484a6273fSAzael Avalos 36584a6273fSAzael Avalos static int sci_open(struct toshiba_acpi_dev *dev) 36684a6273fSAzael Avalos { 367258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 }; 368258c5903SAzael Avalos u32 out[TCI_WORDS]; 36984a6273fSAzael Avalos acpi_status status; 37084a6273fSAzael Avalos 371258c5903SAzael Avalos status = tci_raw(dev, in, out); 3728baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 37384a6273fSAzael Avalos pr_err("ACPI call to open SCI failed\n"); 37484a6273fSAzael Avalos return 0; 37584a6273fSAzael Avalos } 37684a6273fSAzael Avalos 3771864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) { 37884a6273fSAzael Avalos return 1; 3791864bbc2SAzael Avalos } else if (out[0] == TOS_ALREADY_OPEN) { 38084a6273fSAzael Avalos pr_info("Toshiba SCI already opened\n"); 38184a6273fSAzael Avalos return 1; 382fa465739SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 383e0769fe6SDarren Hart /* 384e0769fe6SDarren Hart * Some BIOSes do not have the SCI open/close functions 385fa465739SAzael Avalos * implemented and return 0x8000 (Not Supported), failing to 386fa465739SAzael Avalos * register some supported features. 387fa465739SAzael Avalos * 388fa465739SAzael Avalos * Simply return 1 if we hit those affected laptops to make the 389fa465739SAzael Avalos * supported features work. 390fa465739SAzael Avalos * 391fa465739SAzael Avalos * In the case that some laptops really do not support the SCI, 392fa465739SAzael Avalos * all the SCI dependent functions check for TOS_NOT_SUPPORTED, 393fa465739SAzael Avalos * and thus, not registering support for the queried feature. 394fa465739SAzael Avalos */ 395fa465739SAzael Avalos return 1; 3961864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_PRESENT) { 39784a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 39884a6273fSAzael Avalos } 39984a6273fSAzael Avalos 40084a6273fSAzael Avalos return 0; 40184a6273fSAzael Avalos } 40284a6273fSAzael Avalos 40384a6273fSAzael Avalos static void sci_close(struct toshiba_acpi_dev *dev) 40484a6273fSAzael Avalos { 405258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 }; 406258c5903SAzael Avalos u32 out[TCI_WORDS]; 40784a6273fSAzael Avalos acpi_status status; 40884a6273fSAzael Avalos 409258c5903SAzael Avalos status = tci_raw(dev, in, out); 4108baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 41184a6273fSAzael Avalos pr_err("ACPI call to close SCI failed\n"); 41284a6273fSAzael Avalos return; 41384a6273fSAzael Avalos } 41484a6273fSAzael Avalos 4151864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) 41684a6273fSAzael Avalos return; 4171864bbc2SAzael Avalos else if (out[0] == TOS_NOT_OPENED) 41884a6273fSAzael Avalos pr_info("Toshiba SCI not opened\n"); 4191864bbc2SAzael Avalos else if (out[0] == TOS_NOT_PRESENT) 42084a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 42184a6273fSAzael Avalos } 42284a6273fSAzael Avalos 423893f3f62SAzael Avalos static u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 42484a6273fSAzael Avalos { 425258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 }; 426258c5903SAzael Avalos u32 out[TCI_WORDS]; 427258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 428b5163992SAzael Avalos 429893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 430893f3f62SAzael Avalos return TOS_FAILURE; 431893f3f62SAzael Avalos 43284a6273fSAzael Avalos *out1 = out[2]; 433893f3f62SAzael Avalos 434893f3f62SAzael Avalos return out[0]; 43584a6273fSAzael Avalos } 43684a6273fSAzael Avalos 437893f3f62SAzael Avalos static u32 sci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 43884a6273fSAzael Avalos { 439258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 }; 440258c5903SAzael Avalos u32 out[TCI_WORDS]; 441258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 442893f3f62SAzael Avalos 443893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 44484a6273fSAzael Avalos } 44584a6273fSAzael Avalos 4466c3f6e6cSPierre Ducroquet /* Illumination support */ 447ea215a3fSAzael Avalos static void toshiba_illumination_available(struct toshiba_acpi_dev *dev) 4486c3f6e6cSPierre Ducroquet { 449258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 }; 450258c5903SAzael Avalos u32 out[TCI_WORDS]; 4516c3f6e6cSPierre Ducroquet acpi_status status; 4526c3f6e6cSPierre Ducroquet 453ea215a3fSAzael Avalos dev->illumination_supported = 0; 454ea215a3fSAzael Avalos dev->illumination_led_registered = false; 455ea215a3fSAzael Avalos 456fdb79081SAzael Avalos if (!sci_open(dev)) 457ea215a3fSAzael Avalos return; 458fdb79081SAzael Avalos 459258c5903SAzael Avalos status = tci_raw(dev, in, out); 460fdb79081SAzael Avalos sci_close(dev); 461ea215a3fSAzael Avalos if (ACPI_FAILURE(status)) 462fdb79081SAzael Avalos pr_err("ACPI call to query Illumination support failed\n"); 463ea215a3fSAzael Avalos else if (out[0] == TOS_SUCCESS) 464ea215a3fSAzael Avalos dev->illumination_supported = 1; 4656c3f6e6cSPierre Ducroquet } 4666c3f6e6cSPierre Ducroquet 4676c3f6e6cSPierre Ducroquet static void toshiba_illumination_set(struct led_classdev *cdev, 4686c3f6e6cSPierre Ducroquet enum led_brightness brightness) 4696c3f6e6cSPierre Ducroquet { 470135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 471135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 472e1a949c1SAzael Avalos u32 result; 473e1a949c1SAzael Avalos u32 state; 4746c3f6e6cSPierre Ducroquet 4756c3f6e6cSPierre Ducroquet /* First request : initialize communication. */ 476fdb79081SAzael Avalos if (!sci_open(dev)) 4776c3f6e6cSPierre Ducroquet return; 4786c3f6e6cSPierre Ducroquet 479fdb79081SAzael Avalos /* Switch the illumination on/off */ 480fdb79081SAzael Avalos state = brightness ? 1 : 0; 481893f3f62SAzael Avalos result = sci_write(dev, SCI_ILLUMINATION, state); 482fdb79081SAzael Avalos sci_close(dev); 483a6b5354fSAzael Avalos if (result == TOS_FAILURE) 484fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 4856c3f6e6cSPierre Ducroquet } 4866c3f6e6cSPierre Ducroquet 4876c3f6e6cSPierre Ducroquet static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) 4886c3f6e6cSPierre Ducroquet { 489135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 490135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 491fdb79081SAzael Avalos u32 state, result; 4926c3f6e6cSPierre Ducroquet 4933f75bbe9SAzael Avalos /* First request : initialize communication. */ 494fdb79081SAzael Avalos if (!sci_open(dev)) 4956c3f6e6cSPierre Ducroquet return LED_OFF; 4966c3f6e6cSPierre Ducroquet 4976c3f6e6cSPierre Ducroquet /* Check the illumination */ 498893f3f62SAzael Avalos result = sci_read(dev, SCI_ILLUMINATION, &state); 499fdb79081SAzael Avalos sci_close(dev); 500a6b5354fSAzael Avalos if (result == TOS_FAILURE) { 501fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 502fdb79081SAzael Avalos return LED_OFF; 503e1a949c1SAzael Avalos } else if (result != TOS_SUCCESS) { 5046c3f6e6cSPierre Ducroquet return LED_OFF; 5056c3f6e6cSPierre Ducroquet } 5066c3f6e6cSPierre Ducroquet 507fdb79081SAzael Avalos return state ? LED_FULL : LED_OFF; 5086c3f6e6cSPierre Ducroquet } 5096c3f6e6cSPierre Ducroquet 510360f0f39SAzael Avalos /* KBD Illumination */ 511ea215a3fSAzael Avalos static void toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev) 51293f8c16dSAzael Avalos { 513258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 }; 514258c5903SAzael Avalos u32 out[TCI_WORDS]; 51593f8c16dSAzael Avalos acpi_status status; 51693f8c16dSAzael Avalos 517ea215a3fSAzael Avalos dev->kbd_illum_supported = 0; 518ea215a3fSAzael Avalos dev->kbd_led_registered = false; 519ea215a3fSAzael Avalos 52093f8c16dSAzael Avalos if (!sci_open(dev)) 521ea215a3fSAzael Avalos return; 52293f8c16dSAzael Avalos 523258c5903SAzael Avalos status = tci_raw(dev, in, out); 52493f8c16dSAzael Avalos sci_close(dev); 525a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) { 52693f8c16dSAzael Avalos pr_err("ACPI call to query kbd illumination support failed\n"); 527ea215a3fSAzael Avalos } else if (out[0] == TOS_SUCCESS) { 528e0769fe6SDarren Hart /* 529e0769fe6SDarren Hart * Check for keyboard backlight timeout max value, 53093f8c16dSAzael Avalos * previous kbd backlight implementation set this to 53193f8c16dSAzael Avalos * 0x3c0003, and now the new implementation set this 532e0769fe6SDarren Hart * to 0x3c001a, use this to distinguish between them. 53393f8c16dSAzael Avalos */ 53493f8c16dSAzael Avalos if (out[3] == SCI_KBD_TIME_MAX) 53593f8c16dSAzael Avalos dev->kbd_type = 2; 53693f8c16dSAzael Avalos else 53793f8c16dSAzael Avalos dev->kbd_type = 1; 53893f8c16dSAzael Avalos /* Get the current keyboard backlight mode */ 53993f8c16dSAzael Avalos dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK; 54093f8c16dSAzael Avalos /* Get the current time (1-60 seconds) */ 54193f8c16dSAzael Avalos dev->kbd_time = out[2] >> HCI_MISC_SHIFT; 542ea215a3fSAzael Avalos /* Flag as supported */ 543ea215a3fSAzael Avalos dev->kbd_illum_supported = 1; 544ea215a3fSAzael Avalos } 54593f8c16dSAzael Avalos } 54693f8c16dSAzael Avalos 547360f0f39SAzael Avalos static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time) 548360f0f39SAzael Avalos { 549360f0f39SAzael Avalos u32 result; 550360f0f39SAzael Avalos 551360f0f39SAzael Avalos if (!sci_open(dev)) 552360f0f39SAzael Avalos return -EIO; 553360f0f39SAzael Avalos 554893f3f62SAzael Avalos result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time); 555360f0f39SAzael Avalos sci_close(dev); 556a6b5354fSAzael Avalos if (result == TOS_FAILURE) 557360f0f39SAzael Avalos pr_err("ACPI call to set KBD backlight status failed\n"); 558a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 559360f0f39SAzael Avalos return -ENODEV; 560360f0f39SAzael Avalos 561e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 562360f0f39SAzael Avalos } 563360f0f39SAzael Avalos 564360f0f39SAzael Avalos static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time) 565360f0f39SAzael Avalos { 566360f0f39SAzael Avalos u32 result; 567360f0f39SAzael Avalos 568360f0f39SAzael Avalos if (!sci_open(dev)) 569360f0f39SAzael Avalos return -EIO; 570360f0f39SAzael Avalos 571893f3f62SAzael Avalos result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time); 572360f0f39SAzael Avalos sci_close(dev); 573a6b5354fSAzael Avalos if (result == TOS_FAILURE) 574360f0f39SAzael Avalos pr_err("ACPI call to get KBD backlight status failed\n"); 575a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 576360f0f39SAzael Avalos return -ENODEV; 577360f0f39SAzael Avalos 578e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 579360f0f39SAzael Avalos } 580360f0f39SAzael Avalos 581360f0f39SAzael Avalos static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev) 582360f0f39SAzael Avalos { 583360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 584360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 585e1a949c1SAzael Avalos u32 result; 586e1a949c1SAzael Avalos u32 state; 587360f0f39SAzael Avalos 588360f0f39SAzael Avalos /* Check the keyboard backlight state */ 589d37782bdSAzael Avalos result = hci_read(dev, HCI_KBD_ILLUMINATION, &state); 590a6b5354fSAzael Avalos if (result == TOS_FAILURE) { 591360f0f39SAzael Avalos pr_err("ACPI call to get the keyboard backlight failed\n"); 592360f0f39SAzael Avalos return LED_OFF; 593e1a949c1SAzael Avalos } else if (result != TOS_SUCCESS) { 594360f0f39SAzael Avalos return LED_OFF; 595360f0f39SAzael Avalos } 596360f0f39SAzael Avalos 597360f0f39SAzael Avalos return state ? LED_FULL : LED_OFF; 598360f0f39SAzael Avalos } 599360f0f39SAzael Avalos 600360f0f39SAzael Avalos static void toshiba_kbd_backlight_set(struct led_classdev *cdev, 601360f0f39SAzael Avalos enum led_brightness brightness) 602360f0f39SAzael Avalos { 603360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 604360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 605e1a949c1SAzael Avalos u32 result; 606e1a949c1SAzael Avalos u32 state; 607360f0f39SAzael Avalos 608360f0f39SAzael Avalos /* Set the keyboard backlight state */ 609360f0f39SAzael Avalos state = brightness ? 1 : 0; 610d37782bdSAzael Avalos result = hci_write(dev, HCI_KBD_ILLUMINATION, state); 611a6b5354fSAzael Avalos if (result == TOS_FAILURE) 612360f0f39SAzael Avalos pr_err("ACPI call to set KBD Illumination mode failed\n"); 613360f0f39SAzael Avalos } 614360f0f39SAzael Avalos 6159d8658acSAzael Avalos /* TouchPad support */ 6169d8658acSAzael Avalos static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state) 6179d8658acSAzael Avalos { 6189d8658acSAzael Avalos u32 result; 6199d8658acSAzael Avalos 6209d8658acSAzael Avalos if (!sci_open(dev)) 6219d8658acSAzael Avalos return -EIO; 6229d8658acSAzael Avalos 623893f3f62SAzael Avalos result = sci_write(dev, SCI_TOUCHPAD, state); 6249d8658acSAzael Avalos sci_close(dev); 625a6b5354fSAzael Avalos if (result == TOS_FAILURE) 6269d8658acSAzael Avalos pr_err("ACPI call to set the touchpad failed\n"); 627a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 6289d8658acSAzael Avalos return -ENODEV; 6299d8658acSAzael Avalos 630e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 6319d8658acSAzael Avalos } 6329d8658acSAzael Avalos 6339d8658acSAzael Avalos static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) 6349d8658acSAzael Avalos { 6359d8658acSAzael Avalos u32 result; 6369d8658acSAzael Avalos 6379d8658acSAzael Avalos if (!sci_open(dev)) 6389d8658acSAzael Avalos return -EIO; 6399d8658acSAzael Avalos 640893f3f62SAzael Avalos result = sci_read(dev, SCI_TOUCHPAD, state); 6419d8658acSAzael Avalos sci_close(dev); 642a6b5354fSAzael Avalos if (result == TOS_FAILURE) 6439d8658acSAzael Avalos pr_err("ACPI call to query the touchpad failed\n"); 644a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 6459d8658acSAzael Avalos return -ENODEV; 6469d8658acSAzael Avalos 647e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 6489d8658acSAzael Avalos } 6499d8658acSAzael Avalos 650def6c4e2SAzael Avalos /* Eco Mode support */ 651ea215a3fSAzael Avalos static void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) 652def6c4e2SAzael Avalos { 653def6c4e2SAzael Avalos acpi_status status; 65498fc4ec6SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 }; 655258c5903SAzael Avalos u32 out[TCI_WORDS]; 656def6c4e2SAzael Avalos 657ea215a3fSAzael Avalos dev->eco_supported = 0; 658ea215a3fSAzael Avalos dev->eco_led_registered = false; 659ea215a3fSAzael Avalos 660258c5903SAzael Avalos status = tci_raw(dev, in, out); 6618baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 66298fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 66398fc4ec6SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 664e0769fe6SDarren Hart /* 665e0769fe6SDarren Hart * If we receive 0x8300 (Input Data Error), it means that the 66698fc4ec6SAzael Avalos * LED device is present, but that we just screwed the input 66798fc4ec6SAzael Avalos * parameters. 66898fc4ec6SAzael Avalos * 66998fc4ec6SAzael Avalos * Let's query the status of the LED to see if we really have a 67098fc4ec6SAzael Avalos * success response, indicating the actual presense of the LED, 67198fc4ec6SAzael Avalos * bail out otherwise. 67298fc4ec6SAzael Avalos */ 67398fc4ec6SAzael Avalos in[3] = 1; 67498fc4ec6SAzael Avalos status = tci_raw(dev, in, out); 675a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) 67698fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 67798fc4ec6SAzael Avalos else if (out[0] == TOS_SUCCESS) 678ea215a3fSAzael Avalos dev->eco_supported = 1; 679def6c4e2SAzael Avalos } 680def6c4e2SAzael Avalos } 681def6c4e2SAzael Avalos 682b5163992SAzael Avalos static enum led_brightness 683b5163992SAzael Avalos toshiba_eco_mode_get_status(struct led_classdev *cdev) 684def6c4e2SAzael Avalos { 685def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 686def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 687258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 }; 688258c5903SAzael Avalos u32 out[TCI_WORDS]; 689def6c4e2SAzael Avalos acpi_status status; 690def6c4e2SAzael Avalos 691258c5903SAzael Avalos status = tci_raw(dev, in, out); 692a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) { 693def6c4e2SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 694def6c4e2SAzael Avalos return LED_OFF; 695e1a949c1SAzael Avalos } else if (out[0] != TOS_SUCCESS) { 696e1a949c1SAzael Avalos return LED_OFF; 697def6c4e2SAzael Avalos } 698def6c4e2SAzael Avalos 699def6c4e2SAzael Avalos return out[2] ? LED_FULL : LED_OFF; 700def6c4e2SAzael Avalos } 701def6c4e2SAzael Avalos 702def6c4e2SAzael Avalos static void toshiba_eco_mode_set_status(struct led_classdev *cdev, 703def6c4e2SAzael Avalos enum led_brightness brightness) 704def6c4e2SAzael Avalos { 705def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 706def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 707258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 }; 708258c5903SAzael Avalos u32 out[TCI_WORDS]; 709def6c4e2SAzael Avalos acpi_status status; 710def6c4e2SAzael Avalos 711def6c4e2SAzael Avalos /* Switch the Eco Mode led on/off */ 712def6c4e2SAzael Avalos in[2] = (brightness) ? 1 : 0; 713258c5903SAzael Avalos status = tci_raw(dev, in, out); 714a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) 715def6c4e2SAzael Avalos pr_err("ACPI call to set ECO led failed\n"); 716def6c4e2SAzael Avalos } 717def6c4e2SAzael Avalos 7185a2813e9SAzael Avalos /* Accelerometer support */ 719ea215a3fSAzael Avalos static void toshiba_accelerometer_available(struct toshiba_acpi_dev *dev) 7205a2813e9SAzael Avalos { 721258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 }; 722258c5903SAzael Avalos u32 out[TCI_WORDS]; 7235a2813e9SAzael Avalos acpi_status status; 7245a2813e9SAzael Avalos 725ea215a3fSAzael Avalos dev->accelerometer_supported = 0; 726ea215a3fSAzael Avalos 727e0769fe6SDarren Hart /* 728e0769fe6SDarren Hart * Check if the accelerometer call exists, 7295a2813e9SAzael Avalos * this call also serves as initialization 7305a2813e9SAzael Avalos */ 731258c5903SAzael Avalos status = tci_raw(dev, in, out); 732a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) 7335a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 734ea215a3fSAzael Avalos else if (out[0] == TOS_SUCCESS) 735ea215a3fSAzael Avalos dev->accelerometer_supported = 1; 7365a2813e9SAzael Avalos } 7375a2813e9SAzael Avalos 7385a2813e9SAzael Avalos static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, 7395a2813e9SAzael Avalos u32 *xy, u32 *z) 7405a2813e9SAzael Avalos { 741258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 }; 742258c5903SAzael Avalos u32 out[TCI_WORDS]; 7435a2813e9SAzael Avalos acpi_status status; 7445a2813e9SAzael Avalos 7455a2813e9SAzael Avalos /* Check the Accelerometer status */ 746258c5903SAzael Avalos status = tci_raw(dev, in, out); 747a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) { 7485a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 7495a2813e9SAzael Avalos return -EIO; 750e1a949c1SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 751e1a949c1SAzael Avalos return -ENODEV; 752e1a949c1SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 7535a2813e9SAzael Avalos *xy = out[2]; 7545a2813e9SAzael Avalos *z = out[4]; 7555a2813e9SAzael Avalos return 0; 7565a2813e9SAzael Avalos } 7575a2813e9SAzael Avalos 758e1a949c1SAzael Avalos return -EIO; 759e1a949c1SAzael Avalos } 760e1a949c1SAzael Avalos 761e26ffe51SAzael Avalos /* Sleep (Charge and Music) utilities support */ 762c8c91842SAzael Avalos static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev) 763c8c91842SAzael Avalos { 764c8c91842SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 765c8c91842SAzael Avalos u32 out[TCI_WORDS]; 766c8c91842SAzael Avalos acpi_status status; 767c8c91842SAzael Avalos 768c8c91842SAzael Avalos dev->usb_sleep_charge_supported = 0; 769c8c91842SAzael Avalos 770c8c91842SAzael Avalos if (!sci_open(dev)) 771c8c91842SAzael Avalos return; 772c8c91842SAzael Avalos 773c8c91842SAzael Avalos status = tci_raw(dev, in, out); 7748baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 775c8c91842SAzael Avalos pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); 776c8c91842SAzael Avalos sci_close(dev); 777c8c91842SAzael Avalos return; 778c8c91842SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 779c8c91842SAzael Avalos sci_close(dev); 780c8c91842SAzael Avalos return; 781c8c91842SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 782c8c91842SAzael Avalos dev->usbsc_mode_base = out[4]; 783c8c91842SAzael Avalos } 784c8c91842SAzael Avalos 785c8c91842SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 786c8c91842SAzael Avalos status = tci_raw(dev, in, out); 787ea215a3fSAzael Avalos sci_close(dev); 7888baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 789c8c91842SAzael Avalos pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); 790c8c91842SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 791c8c91842SAzael Avalos dev->usbsc_bat_level = out[2]; 792ea215a3fSAzael Avalos /* Flag as supported */ 793c8c91842SAzael Avalos dev->usb_sleep_charge_supported = 1; 794c8c91842SAzael Avalos } 795c8c91842SAzael Avalos 796c8c91842SAzael Avalos } 797c8c91842SAzael Avalos 798e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, 799e26ffe51SAzael Avalos u32 *mode) 800e26ffe51SAzael Avalos { 801e26ffe51SAzael Avalos u32 result; 802e26ffe51SAzael Avalos 803e26ffe51SAzael Avalos if (!sci_open(dev)) 804e26ffe51SAzael Avalos return -EIO; 805e26ffe51SAzael Avalos 806e26ffe51SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode); 807e26ffe51SAzael Avalos sci_close(dev); 808a6b5354fSAzael Avalos if (result == TOS_FAILURE) 809e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 810a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 811e26ffe51SAzael Avalos return -ENODEV; 812e26ffe51SAzael Avalos 813e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 814e26ffe51SAzael Avalos } 815e26ffe51SAzael Avalos 816e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev, 817e26ffe51SAzael Avalos u32 mode) 818e26ffe51SAzael Avalos { 819e26ffe51SAzael Avalos u32 result; 820e26ffe51SAzael Avalos 821e26ffe51SAzael Avalos if (!sci_open(dev)) 822e26ffe51SAzael Avalos return -EIO; 823e26ffe51SAzael Avalos 824e26ffe51SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode); 825e26ffe51SAzael Avalos sci_close(dev); 826a6b5354fSAzael Avalos if (result == TOS_FAILURE) 827e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 828a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 829e26ffe51SAzael Avalos return -ENODEV; 830e26ffe51SAzael Avalos 831e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 832e26ffe51SAzael Avalos } 833e26ffe51SAzael Avalos 834182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev, 835182bcaa5SAzael Avalos u32 *mode) 836182bcaa5SAzael Avalos { 837182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 838182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 839182bcaa5SAzael Avalos acpi_status status; 840182bcaa5SAzael Avalos 841182bcaa5SAzael Avalos if (!sci_open(dev)) 842182bcaa5SAzael Avalos return -EIO; 843182bcaa5SAzael Avalos 844182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 845182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 846182bcaa5SAzael Avalos sci_close(dev); 8478baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 848182bcaa5SAzael Avalos pr_err("ACPI call to get USB S&C battery level failed\n"); 849182bcaa5SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 850182bcaa5SAzael Avalos return -ENODEV; 851e1a949c1SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 852e1a949c1SAzael Avalos *mode = out[2]; 853e1a949c1SAzael Avalos return 0; 854182bcaa5SAzael Avalos } 855182bcaa5SAzael Avalos 856e1a949c1SAzael Avalos return -EIO; 857182bcaa5SAzael Avalos } 858182bcaa5SAzael Avalos 859182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, 860182bcaa5SAzael Avalos u32 mode) 861182bcaa5SAzael Avalos { 862182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 863182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 864182bcaa5SAzael Avalos acpi_status status; 865182bcaa5SAzael Avalos 866182bcaa5SAzael Avalos if (!sci_open(dev)) 867182bcaa5SAzael Avalos return -EIO; 868182bcaa5SAzael Avalos 869182bcaa5SAzael Avalos in[2] = mode; 870182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 871182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 872182bcaa5SAzael Avalos sci_close(dev); 873a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) 874182bcaa5SAzael Avalos pr_err("ACPI call to set USB S&C battery level failed\n"); 875a6b5354fSAzael Avalos else if (out[0] == TOS_NOT_SUPPORTED) 876182bcaa5SAzael Avalos return -ENODEV; 877182bcaa5SAzael Avalos 878e1a949c1SAzael Avalos return out[0] == TOS_SUCCESS ? 0 : -EIO; 879182bcaa5SAzael Avalos } 880182bcaa5SAzael Avalos 881bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, 882bb3fe01fSAzael Avalos u32 *state) 883bb3fe01fSAzael Avalos { 884bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 885bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 886bb3fe01fSAzael Avalos acpi_status status; 887bb3fe01fSAzael Avalos 888bb3fe01fSAzael Avalos if (!sci_open(dev)) 889bb3fe01fSAzael Avalos return -EIO; 890bb3fe01fSAzael Avalos 891bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 892bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 893bb3fe01fSAzael Avalos sci_close(dev); 8948baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 895bb26f189SAzael Avalos pr_err("ACPI call to get USB Rapid Charge failed\n"); 896a6b5354fSAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 897bb3fe01fSAzael Avalos return -ENODEV; 898e1a949c1SAzael Avalos } else if (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) { 899e1a949c1SAzael Avalos *state = out[2]; 900e1a949c1SAzael Avalos return 0; 901bb3fe01fSAzael Avalos } 902bb3fe01fSAzael Avalos 903e1a949c1SAzael Avalos return -EIO; 904bb3fe01fSAzael Avalos } 905bb3fe01fSAzael Avalos 906bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, 907bb3fe01fSAzael Avalos u32 state) 908bb3fe01fSAzael Avalos { 909bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 910bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 911bb3fe01fSAzael Avalos acpi_status status; 912bb3fe01fSAzael Avalos 913bb3fe01fSAzael Avalos if (!sci_open(dev)) 914bb3fe01fSAzael Avalos return -EIO; 915bb3fe01fSAzael Avalos 916bb3fe01fSAzael Avalos in[2] = state; 917bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 918bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 919bb3fe01fSAzael Avalos sci_close(dev); 920a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) 921bb26f189SAzael Avalos pr_err("ACPI call to set USB Rapid Charge failed\n"); 922a6b5354fSAzael Avalos else if (out[0] == TOS_NOT_SUPPORTED) 923bb3fe01fSAzael Avalos return -ENODEV; 924bb3fe01fSAzael Avalos 925e1a949c1SAzael Avalos return (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) ? 0 : -EIO; 926bb3fe01fSAzael Avalos } 927bb3fe01fSAzael Avalos 928172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state) 929172ce0a9SAzael Avalos { 930172ce0a9SAzael Avalos u32 result; 931172ce0a9SAzael Avalos 932172ce0a9SAzael Avalos if (!sci_open(dev)) 933172ce0a9SAzael Avalos return -EIO; 934172ce0a9SAzael Avalos 935172ce0a9SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state); 936172ce0a9SAzael Avalos sci_close(dev); 937a6b5354fSAzael Avalos if (result == TOS_FAILURE) 938bb26f189SAzael Avalos pr_err("ACPI call to get Sleep and Music failed\n"); 939a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 940172ce0a9SAzael Avalos return -ENODEV; 941172ce0a9SAzael Avalos 942cf680eaeSAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 943172ce0a9SAzael Avalos } 944172ce0a9SAzael Avalos 945172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state) 946172ce0a9SAzael Avalos { 947172ce0a9SAzael Avalos u32 result; 948172ce0a9SAzael Avalos 949172ce0a9SAzael Avalos if (!sci_open(dev)) 950172ce0a9SAzael Avalos return -EIO; 951172ce0a9SAzael Avalos 952172ce0a9SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state); 953172ce0a9SAzael Avalos sci_close(dev); 954a6b5354fSAzael Avalos if (result == TOS_FAILURE) 955bb26f189SAzael Avalos pr_err("ACPI call to set Sleep and Music failed\n"); 956a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 957172ce0a9SAzael Avalos return -ENODEV; 958172ce0a9SAzael Avalos 959e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 960172ce0a9SAzael Avalos } 961172ce0a9SAzael Avalos 962bae84195SAzael Avalos /* Keyboard function keys */ 963bae84195SAzael Avalos static int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode) 964bae84195SAzael Avalos { 965bae84195SAzael Avalos u32 result; 966bae84195SAzael Avalos 967bae84195SAzael Avalos if (!sci_open(dev)) 968bae84195SAzael Avalos return -EIO; 969bae84195SAzael Avalos 970bae84195SAzael Avalos result = sci_read(dev, SCI_KBD_FUNCTION_KEYS, mode); 971bae84195SAzael Avalos sci_close(dev); 972a6b5354fSAzael Avalos if (result == TOS_FAILURE) 973bae84195SAzael Avalos pr_err("ACPI call to get KBD function keys failed\n"); 974a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 975bae84195SAzael Avalos return -ENODEV; 976bae84195SAzael Avalos 977e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 978bae84195SAzael Avalos } 979bae84195SAzael Avalos 980bae84195SAzael Avalos static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode) 981bae84195SAzael Avalos { 982bae84195SAzael Avalos u32 result; 983bae84195SAzael Avalos 984bae84195SAzael Avalos if (!sci_open(dev)) 985bae84195SAzael Avalos return -EIO; 986bae84195SAzael Avalos 987bae84195SAzael Avalos result = sci_write(dev, SCI_KBD_FUNCTION_KEYS, mode); 988bae84195SAzael Avalos sci_close(dev); 989a6b5354fSAzael Avalos if (result == TOS_FAILURE) 990bae84195SAzael Avalos pr_err("ACPI call to set KBD function keys failed\n"); 991a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 992bae84195SAzael Avalos return -ENODEV; 993bae84195SAzael Avalos 994e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 995bae84195SAzael Avalos } 996bae84195SAzael Avalos 99735d53ceaSAzael Avalos /* Panel Power ON */ 99835d53ceaSAzael Avalos static int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state) 99935d53ceaSAzael Avalos { 100035d53ceaSAzael Avalos u32 result; 100135d53ceaSAzael Avalos 100235d53ceaSAzael Avalos if (!sci_open(dev)) 100335d53ceaSAzael Avalos return -EIO; 100435d53ceaSAzael Avalos 100535d53ceaSAzael Avalos result = sci_read(dev, SCI_PANEL_POWER_ON, state); 100635d53ceaSAzael Avalos sci_close(dev); 1007a6b5354fSAzael Avalos if (result == TOS_FAILURE) 100835d53ceaSAzael Avalos pr_err("ACPI call to get Panel Power ON failed\n"); 1009a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 101035d53ceaSAzael Avalos return -ENODEV; 101135d53ceaSAzael Avalos 1012e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 101335d53ceaSAzael Avalos } 101435d53ceaSAzael Avalos 101535d53ceaSAzael Avalos static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state) 101635d53ceaSAzael Avalos { 101735d53ceaSAzael Avalos u32 result; 101835d53ceaSAzael Avalos 101935d53ceaSAzael Avalos if (!sci_open(dev)) 102035d53ceaSAzael Avalos return -EIO; 102135d53ceaSAzael Avalos 102235d53ceaSAzael Avalos result = sci_write(dev, SCI_PANEL_POWER_ON, state); 102335d53ceaSAzael Avalos sci_close(dev); 1024a6b5354fSAzael Avalos if (result == TOS_FAILURE) 102535d53ceaSAzael Avalos pr_err("ACPI call to set Panel Power ON failed\n"); 1026a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 102735d53ceaSAzael Avalos return -ENODEV; 102835d53ceaSAzael Avalos 1029e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 103035d53ceaSAzael Avalos } 103135d53ceaSAzael Avalos 103217fe4b3dSAzael Avalos /* USB Three */ 103317fe4b3dSAzael Avalos static int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state) 103417fe4b3dSAzael Avalos { 103517fe4b3dSAzael Avalos u32 result; 103617fe4b3dSAzael Avalos 103717fe4b3dSAzael Avalos if (!sci_open(dev)) 103817fe4b3dSAzael Avalos return -EIO; 103917fe4b3dSAzael Avalos 104017fe4b3dSAzael Avalos result = sci_read(dev, SCI_USB_THREE, state); 104117fe4b3dSAzael Avalos sci_close(dev); 1042a6b5354fSAzael Avalos if (result == TOS_FAILURE) 104317fe4b3dSAzael Avalos pr_err("ACPI call to get USB 3 failed\n"); 1044a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 104517fe4b3dSAzael Avalos return -ENODEV; 104617fe4b3dSAzael Avalos 1047e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 104817fe4b3dSAzael Avalos } 104917fe4b3dSAzael Avalos 105017fe4b3dSAzael Avalos static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state) 105117fe4b3dSAzael Avalos { 105217fe4b3dSAzael Avalos u32 result; 105317fe4b3dSAzael Avalos 105417fe4b3dSAzael Avalos if (!sci_open(dev)) 105517fe4b3dSAzael Avalos return -EIO; 105617fe4b3dSAzael Avalos 105717fe4b3dSAzael Avalos result = sci_write(dev, SCI_USB_THREE, state); 105817fe4b3dSAzael Avalos sci_close(dev); 1059a6b5354fSAzael Avalos if (result == TOS_FAILURE) 106017fe4b3dSAzael Avalos pr_err("ACPI call to set USB 3 failed\n"); 1061a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 106217fe4b3dSAzael Avalos return -ENODEV; 106317fe4b3dSAzael Avalos 1064e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 106517fe4b3dSAzael Avalos } 106617fe4b3dSAzael Avalos 106756e6b353SAzael Avalos /* Hotkey Event type */ 106856e6b353SAzael Avalos static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev, 106956e6b353SAzael Avalos u32 *type) 107056e6b353SAzael Avalos { 10713b876000SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_SYSTEM_INFO, 0x03, 0, 0, 0 }; 10723b876000SAzael Avalos u32 out[TCI_WORDS]; 10733b876000SAzael Avalos acpi_status status; 107456e6b353SAzael Avalos 10753b876000SAzael Avalos status = tci_raw(dev, in, out); 10763b876000SAzael Avalos if (ACPI_FAILURE(status)) { 107756e6b353SAzael Avalos pr_err("ACPI call to get System type failed\n"); 10783b876000SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 107956e6b353SAzael Avalos return -ENODEV; 1080e1a949c1SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 1081e1a949c1SAzael Avalos *type = out[3]; 1082e1a949c1SAzael Avalos return 0; 108356e6b353SAzael Avalos } 108456e6b353SAzael Avalos 1085e1a949c1SAzael Avalos return -EIO; 108656e6b353SAzael Avalos } 108756e6b353SAzael Avalos 10883f75bbe9SAzael Avalos /* Transflective Backlight */ 1089695f6060SAzael Avalos static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status) 1090121b7b0dSAkio Idehara { 1091e1a949c1SAzael Avalos u32 result = hci_read(dev, HCI_TR_BACKLIGHT, status); 1092121b7b0dSAkio Idehara 1093e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1094e1a949c1SAzael Avalos pr_err("ACPI call to get Transflective Backlight failed\n"); 1095e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1096e1a949c1SAzael Avalos return -ENODEV; 1097e1a949c1SAzael Avalos 1098e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1099121b7b0dSAkio Idehara } 1100121b7b0dSAkio Idehara 1101695f6060SAzael Avalos static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 status) 1102121b7b0dSAkio Idehara { 1103e1a949c1SAzael Avalos u32 result = hci_write(dev, HCI_TR_BACKLIGHT, !status); 1104121b7b0dSAkio Idehara 1105e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1106e1a949c1SAzael Avalos pr_err("ACPI call to set Transflective Backlight failed\n"); 1107e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1108e1a949c1SAzael Avalos return -ENODEV; 1109e1a949c1SAzael Avalos 1110e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1111121b7b0dSAkio Idehara } 1112121b7b0dSAkio Idehara 11133f75bbe9SAzael Avalos static struct proc_dir_entry *toshiba_proc_dir; 1114b4f9fe12SLen Brown 11153f75bbe9SAzael Avalos /* LCD Brightness */ 111662cce752SSeth Forshee static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) 1117b4f9fe12SLen Brown { 1118e1a949c1SAzael Avalos u32 result; 1119b4f9fe12SLen Brown u32 value; 1120121b7b0dSAkio Idehara int brightness = 0; 1121121b7b0dSAkio Idehara 1122121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1123695f6060SAzael Avalos int ret = get_tr_backlight_status(dev, &value); 1124b5163992SAzael Avalos 1125121b7b0dSAkio Idehara if (ret) 1126121b7b0dSAkio Idehara return ret; 1127695f6060SAzael Avalos if (value) 1128121b7b0dSAkio Idehara return 0; 1129121b7b0dSAkio Idehara brightness++; 1130121b7b0dSAkio Idehara } 1131b4f9fe12SLen Brown 1132e1a949c1SAzael Avalos result = hci_read(dev, HCI_LCD_BRIGHTNESS, &value); 1133e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1134e1a949c1SAzael Avalos pr_err("ACPI call to get LCD Brightness failed\n"); 1135e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1136e1a949c1SAzael Avalos return -ENODEV; 1137e1a949c1SAzael Avalos if (result == TOS_SUCCESS) 1138121b7b0dSAkio Idehara return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT); 113932bcd5cbSSeth Forshee 114032bcd5cbSSeth Forshee return -EIO; 1141b4f9fe12SLen Brown } 1142b4f9fe12SLen Brown 114362cce752SSeth Forshee static int get_lcd_brightness(struct backlight_device *bd) 114462cce752SSeth Forshee { 114562cce752SSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 1146b5163992SAzael Avalos 114762cce752SSeth Forshee return __get_lcd_brightness(dev); 114862cce752SSeth Forshee } 114962cce752SSeth Forshee 1150936c8bcdSAlexey Dobriyan static int lcd_proc_show(struct seq_file *m, void *v) 1151b4f9fe12SLen Brown { 1152135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1153121b7b0dSAkio Idehara int levels; 1154e1a949c1SAzael Avalos int value; 1155b4f9fe12SLen Brown 1156135740deSSeth Forshee if (!dev->backlight_dev) 1157135740deSSeth Forshee return -ENODEV; 1158135740deSSeth Forshee 1159121b7b0dSAkio Idehara levels = dev->backlight_dev->props.max_brightness + 1; 116062cce752SSeth Forshee value = get_lcd_brightness(dev->backlight_dev); 1161b4f9fe12SLen Brown if (value >= 0) { 1162936c8bcdSAlexey Dobriyan seq_printf(m, "brightness: %d\n", value); 1163121b7b0dSAkio Idehara seq_printf(m, "brightness_levels: %d\n", levels); 116432bcd5cbSSeth Forshee return 0; 1165b4f9fe12SLen Brown } 1166b4f9fe12SLen Brown 116732bcd5cbSSeth Forshee pr_err("Error reading LCD brightness\n"); 1168e1a949c1SAzael Avalos 116932bcd5cbSSeth Forshee return -EIO; 1170936c8bcdSAlexey Dobriyan } 1171936c8bcdSAlexey Dobriyan 1172936c8bcdSAlexey Dobriyan static int lcd_proc_open(struct inode *inode, struct file *file) 1173936c8bcdSAlexey Dobriyan { 1174d9dda78bSAl Viro return single_open(file, lcd_proc_show, PDE_DATA(inode)); 1175b4f9fe12SLen Brown } 1176b4f9fe12SLen Brown 117762cce752SSeth Forshee static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) 1178b4f9fe12SLen Brown { 1179e1a949c1SAzael Avalos u32 result; 1180b4f9fe12SLen Brown 1181121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1182695f6060SAzael Avalos int ret = set_tr_backlight_status(dev, !value); 1183b5163992SAzael Avalos 1184121b7b0dSAkio Idehara if (ret) 1185121b7b0dSAkio Idehara return ret; 1186121b7b0dSAkio Idehara if (value) 1187121b7b0dSAkio Idehara value--; 1188121b7b0dSAkio Idehara } 1189121b7b0dSAkio Idehara 1190a39f46dfSAzael Avalos value = value << HCI_LCD_BRIGHTNESS_SHIFT; 1191e1a949c1SAzael Avalos result = hci_write(dev, HCI_LCD_BRIGHTNESS, value); 1192e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1193e1a949c1SAzael Avalos pr_err("ACPI call to set LCD Brightness failed\n"); 1194e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1195e1a949c1SAzael Avalos return -ENODEV; 1196e1a949c1SAzael Avalos 1197e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1198b4f9fe12SLen Brown } 1199b4f9fe12SLen Brown 1200b4f9fe12SLen Brown static int set_lcd_status(struct backlight_device *bd) 1201b4f9fe12SLen Brown { 1202135740deSSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 1203b5163992SAzael Avalos 120462cce752SSeth Forshee return set_lcd_brightness(dev, bd->props.brightness); 1205b4f9fe12SLen Brown } 1206b4f9fe12SLen Brown 1207936c8bcdSAlexey Dobriyan static ssize_t lcd_proc_write(struct file *file, const char __user *buf, 1208936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1209b4f9fe12SLen Brown { 1210d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1211936c8bcdSAlexey Dobriyan char cmd[42]; 1212936c8bcdSAlexey Dobriyan size_t len; 1213121b7b0dSAkio Idehara int levels = dev->backlight_dev->props.max_brightness + 1; 1214e1a949c1SAzael Avalos int value; 1215b4f9fe12SLen Brown 1216936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1217936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1218936c8bcdSAlexey Dobriyan return -EFAULT; 1219936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1220936c8bcdSAlexey Dobriyan 1221e1a949c1SAzael Avalos if (sscanf(cmd, " brightness : %i", &value) != 1 && 1222e1a949c1SAzael Avalos value < 0 && value > levels) 1223e1a949c1SAzael Avalos return -EINVAL; 1224e1a949c1SAzael Avalos 1225e1a949c1SAzael Avalos if (set_lcd_brightness(dev, value)) 1226e1a949c1SAzael Avalos return -EIO; 1227e1a949c1SAzael Avalos 1228e1a949c1SAzael Avalos return count; 1229b4f9fe12SLen Brown } 1230b4f9fe12SLen Brown 1231936c8bcdSAlexey Dobriyan static const struct file_operations lcd_proc_fops = { 1232936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1233936c8bcdSAlexey Dobriyan .open = lcd_proc_open, 1234936c8bcdSAlexey Dobriyan .read = seq_read, 1235936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1236936c8bcdSAlexey Dobriyan .release = single_release, 1237936c8bcdSAlexey Dobriyan .write = lcd_proc_write, 1238936c8bcdSAlexey Dobriyan }; 1239936c8bcdSAlexey Dobriyan 1240e1a949c1SAzael Avalos /* Video-Out */ 124136d03f93SSeth Forshee static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status) 124236d03f93SSeth Forshee { 1243e1a949c1SAzael Avalos u32 result = hci_read(dev, HCI_VIDEO_OUT, status); 124436d03f93SSeth Forshee 1245e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1246e1a949c1SAzael Avalos pr_err("ACPI call to get Video-Out failed\n"); 1247e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1248e1a949c1SAzael Avalos return -ENODEV; 1249e1a949c1SAzael Avalos 1250e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 125136d03f93SSeth Forshee } 125236d03f93SSeth Forshee 1253936c8bcdSAlexey Dobriyan static int video_proc_show(struct seq_file *m, void *v) 1254b4f9fe12SLen Brown { 1255135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1256b4f9fe12SLen Brown u32 value; 1257b4f9fe12SLen Brown 1258e1a949c1SAzael Avalos if (!get_video_status(dev, &value)) { 1259b4f9fe12SLen Brown int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; 1260b4f9fe12SLen Brown int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; 1261b4f9fe12SLen Brown int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; 1262b5163992SAzael Avalos 1263936c8bcdSAlexey Dobriyan seq_printf(m, "lcd_out: %d\n", is_lcd); 1264936c8bcdSAlexey Dobriyan seq_printf(m, "crt_out: %d\n", is_crt); 1265936c8bcdSAlexey Dobriyan seq_printf(m, "tv_out: %d\n", is_tv); 1266e1a949c1SAzael Avalos return 0; 1267b4f9fe12SLen Brown } 1268b4f9fe12SLen Brown 1269e1a949c1SAzael Avalos return -EIO; 1270b4f9fe12SLen Brown } 1271b4f9fe12SLen Brown 1272936c8bcdSAlexey Dobriyan static int video_proc_open(struct inode *inode, struct file *file) 1273b4f9fe12SLen Brown { 1274d9dda78bSAl Viro return single_open(file, video_proc_show, PDE_DATA(inode)); 1275936c8bcdSAlexey Dobriyan } 1276936c8bcdSAlexey Dobriyan 1277936c8bcdSAlexey Dobriyan static ssize_t video_proc_write(struct file *file, const char __user *buf, 1278936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1279936c8bcdSAlexey Dobriyan { 1280d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1281e1a949c1SAzael Avalos char *buffer; 1282e1a949c1SAzael Avalos char *cmd; 1283b4f9fe12SLen Brown int remain = count; 1284b4f9fe12SLen Brown int lcd_out = -1; 1285b4f9fe12SLen Brown int crt_out = -1; 1286b4f9fe12SLen Brown int tv_out = -1; 1287e1a949c1SAzael Avalos int value; 1288e1a949c1SAzael Avalos int ret; 1289b4f9fe12SLen Brown u32 video_out; 1290b4f9fe12SLen Brown 1291936c8bcdSAlexey Dobriyan cmd = kmalloc(count + 1, GFP_KERNEL); 1292936c8bcdSAlexey Dobriyan if (!cmd) 1293936c8bcdSAlexey Dobriyan return -ENOMEM; 1294936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, count)) { 1295936c8bcdSAlexey Dobriyan kfree(cmd); 1296936c8bcdSAlexey Dobriyan return -EFAULT; 1297936c8bcdSAlexey Dobriyan } 1298936c8bcdSAlexey Dobriyan cmd[count] = '\0'; 1299936c8bcdSAlexey Dobriyan 1300936c8bcdSAlexey Dobriyan buffer = cmd; 1301936c8bcdSAlexey Dobriyan 1302e0769fe6SDarren Hart /* 1303e0769fe6SDarren Hart * Scan expression. Multiple expressions may be delimited with ; 1304e0769fe6SDarren Hart * NOTE: To keep scanning simple, invalid fields are ignored. 1305b4f9fe12SLen Brown */ 1306b4f9fe12SLen Brown while (remain) { 1307b4f9fe12SLen Brown if (sscanf(buffer, " lcd_out : %i", &value) == 1) 1308b4f9fe12SLen Brown lcd_out = value & 1; 1309b4f9fe12SLen Brown else if (sscanf(buffer, " crt_out : %i", &value) == 1) 1310b4f9fe12SLen Brown crt_out = value & 1; 1311b4f9fe12SLen Brown else if (sscanf(buffer, " tv_out : %i", &value) == 1) 1312b4f9fe12SLen Brown tv_out = value & 1; 1313e0769fe6SDarren Hart /* Advance to one character past the next ; */ 1314b4f9fe12SLen Brown do { 1315b4f9fe12SLen Brown ++buffer; 1316b4f9fe12SLen Brown --remain; 1317b5163992SAzael Avalos } while (remain && *(buffer - 1) != ';'); 1318b4f9fe12SLen Brown } 1319b4f9fe12SLen Brown 1320936c8bcdSAlexey Dobriyan kfree(cmd); 1321936c8bcdSAlexey Dobriyan 132236d03f93SSeth Forshee ret = get_video_status(dev, &video_out); 132336d03f93SSeth Forshee if (!ret) { 1324b4f9fe12SLen Brown unsigned int new_video_out = video_out; 1325b5163992SAzael Avalos 1326b4f9fe12SLen Brown if (lcd_out != -1) 1327b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out); 1328b4f9fe12SLen Brown if (crt_out != -1) 1329b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out); 1330b4f9fe12SLen Brown if (tv_out != -1) 1331b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out); 1332e0769fe6SDarren Hart /* 1333e0769fe6SDarren Hart * To avoid unnecessary video disruption, only write the new 13343f75bbe9SAzael Avalos * video setting if something changed. 13353f75bbe9SAzael Avalos */ 1336b4f9fe12SLen Brown if (new_video_out != video_out) 133732bcd5cbSSeth Forshee ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out); 1338b4f9fe12SLen Brown } 1339b4f9fe12SLen Brown 1340e1a949c1SAzael Avalos return ret ? -EIO : count; 1341b4f9fe12SLen Brown } 1342b4f9fe12SLen Brown 1343936c8bcdSAlexey Dobriyan static const struct file_operations video_proc_fops = { 1344936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1345936c8bcdSAlexey Dobriyan .open = video_proc_open, 1346936c8bcdSAlexey Dobriyan .read = seq_read, 1347936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1348936c8bcdSAlexey Dobriyan .release = single_release, 1349936c8bcdSAlexey Dobriyan .write = video_proc_write, 1350936c8bcdSAlexey Dobriyan }; 1351936c8bcdSAlexey Dobriyan 13523e07e5baSAzael Avalos /* Fan status */ 135336d03f93SSeth Forshee static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status) 135436d03f93SSeth Forshee { 13553e07e5baSAzael Avalos u32 result = hci_read(dev, HCI_FAN, status); 135636d03f93SSeth Forshee 13573e07e5baSAzael Avalos if (result == TOS_FAILURE) 13583e07e5baSAzael Avalos pr_err("ACPI call to get Fan status failed\n"); 13593e07e5baSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 13603e07e5baSAzael Avalos return -ENODEV; 13613e07e5baSAzael Avalos 1362e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 13633e07e5baSAzael Avalos } 13643e07e5baSAzael Avalos 13653e07e5baSAzael Avalos static int set_fan_status(struct toshiba_acpi_dev *dev, u32 status) 13663e07e5baSAzael Avalos { 13673e07e5baSAzael Avalos u32 result = hci_write(dev, HCI_FAN, status); 13683e07e5baSAzael Avalos 13693e07e5baSAzael Avalos if (result == TOS_FAILURE) 13703e07e5baSAzael Avalos pr_err("ACPI call to set Fan status failed\n"); 13713e07e5baSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 13723e07e5baSAzael Avalos return -ENODEV; 13733e07e5baSAzael Avalos 1374e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 137536d03f93SSeth Forshee } 137636d03f93SSeth Forshee 1377936c8bcdSAlexey Dobriyan static int fan_proc_show(struct seq_file *m, void *v) 1378b4f9fe12SLen Brown { 1379135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1380b4f9fe12SLen Brown u32 value; 1381b4f9fe12SLen Brown 13823e07e5baSAzael Avalos if (get_fan_status(dev, &value)) 13833e07e5baSAzael Avalos return -EIO; 13843e07e5baSAzael Avalos 1385936c8bcdSAlexey Dobriyan seq_printf(m, "running: %d\n", (value > 0)); 1386135740deSSeth Forshee seq_printf(m, "force_on: %d\n", dev->force_fan); 1387b4f9fe12SLen Brown 13883e07e5baSAzael Avalos return 0; 1389b4f9fe12SLen Brown } 1390b4f9fe12SLen Brown 1391936c8bcdSAlexey Dobriyan static int fan_proc_open(struct inode *inode, struct file *file) 1392b4f9fe12SLen Brown { 1393d9dda78bSAl Viro return single_open(file, fan_proc_show, PDE_DATA(inode)); 1394936c8bcdSAlexey Dobriyan } 1395936c8bcdSAlexey Dobriyan 1396936c8bcdSAlexey Dobriyan static ssize_t fan_proc_write(struct file *file, const char __user *buf, 1397936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1398936c8bcdSAlexey Dobriyan { 1399d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1400936c8bcdSAlexey Dobriyan char cmd[42]; 1401936c8bcdSAlexey Dobriyan size_t len; 1402b4f9fe12SLen Brown int value; 1403b4f9fe12SLen Brown 1404936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1405936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1406936c8bcdSAlexey Dobriyan return -EFAULT; 1407936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1408936c8bcdSAlexey Dobriyan 14093e07e5baSAzael Avalos if (sscanf(cmd, " force_on : %i", &value) != 1 && 14103e07e5baSAzael Avalos value != 0 && value != 1) 1411b4f9fe12SLen Brown return -EINVAL; 14123e07e5baSAzael Avalos 14133e07e5baSAzael Avalos if (set_fan_status(dev, value)) 14143e07e5baSAzael Avalos return -EIO; 14153e07e5baSAzael Avalos 14163e07e5baSAzael Avalos dev->force_fan = value; 1417b4f9fe12SLen Brown 1418b4f9fe12SLen Brown return count; 1419b4f9fe12SLen Brown } 1420b4f9fe12SLen Brown 1421936c8bcdSAlexey Dobriyan static const struct file_operations fan_proc_fops = { 1422936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1423936c8bcdSAlexey Dobriyan .open = fan_proc_open, 1424936c8bcdSAlexey Dobriyan .read = seq_read, 1425936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1426936c8bcdSAlexey Dobriyan .release = single_release, 1427936c8bcdSAlexey Dobriyan .write = fan_proc_write, 1428936c8bcdSAlexey Dobriyan }; 1429936c8bcdSAlexey Dobriyan 1430936c8bcdSAlexey Dobriyan static int keys_proc_show(struct seq_file *m, void *v) 1431b4f9fe12SLen Brown { 1432135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1433b4f9fe12SLen Brown 1434135740deSSeth Forshee seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid); 1435135740deSSeth Forshee seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event); 14367deef550SAzael Avalos 1437936c8bcdSAlexey Dobriyan return 0; 1438b4f9fe12SLen Brown } 1439b4f9fe12SLen Brown 1440936c8bcdSAlexey Dobriyan static int keys_proc_open(struct inode *inode, struct file *file) 1441b4f9fe12SLen Brown { 1442d9dda78bSAl Viro return single_open(file, keys_proc_show, PDE_DATA(inode)); 1443936c8bcdSAlexey Dobriyan } 1444936c8bcdSAlexey Dobriyan 1445936c8bcdSAlexey Dobriyan static ssize_t keys_proc_write(struct file *file, const char __user *buf, 1446936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1447936c8bcdSAlexey Dobriyan { 1448d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1449936c8bcdSAlexey Dobriyan char cmd[42]; 1450936c8bcdSAlexey Dobriyan size_t len; 1451b4f9fe12SLen Brown int value; 1452b4f9fe12SLen Brown 1453936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1454936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1455936c8bcdSAlexey Dobriyan return -EFAULT; 1456936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1457936c8bcdSAlexey Dobriyan 1458b5163992SAzael Avalos if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) 1459135740deSSeth Forshee dev->key_event_valid = 0; 1460b5163992SAzael Avalos else 1461b4f9fe12SLen Brown return -EINVAL; 1462b4f9fe12SLen Brown 1463b4f9fe12SLen Brown return count; 1464b4f9fe12SLen Brown } 1465b4f9fe12SLen Brown 1466936c8bcdSAlexey Dobriyan static const struct file_operations keys_proc_fops = { 1467936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1468936c8bcdSAlexey Dobriyan .open = keys_proc_open, 1469936c8bcdSAlexey Dobriyan .read = seq_read, 1470936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1471936c8bcdSAlexey Dobriyan .release = single_release, 1472936c8bcdSAlexey Dobriyan .write = keys_proc_write, 1473936c8bcdSAlexey Dobriyan }; 1474936c8bcdSAlexey Dobriyan 1475936c8bcdSAlexey Dobriyan static int version_proc_show(struct seq_file *m, void *v) 1476b4f9fe12SLen Brown { 1477936c8bcdSAlexey Dobriyan seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION); 1478936c8bcdSAlexey Dobriyan seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION); 1479936c8bcdSAlexey Dobriyan return 0; 1480b4f9fe12SLen Brown } 1481b4f9fe12SLen Brown 1482936c8bcdSAlexey Dobriyan static int version_proc_open(struct inode *inode, struct file *file) 1483936c8bcdSAlexey Dobriyan { 1484d9dda78bSAl Viro return single_open(file, version_proc_show, PDE_DATA(inode)); 1485936c8bcdSAlexey Dobriyan } 1486936c8bcdSAlexey Dobriyan 1487936c8bcdSAlexey Dobriyan static const struct file_operations version_proc_fops = { 1488936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1489936c8bcdSAlexey Dobriyan .open = version_proc_open, 1490936c8bcdSAlexey Dobriyan .read = seq_read, 1491936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1492936c8bcdSAlexey Dobriyan .release = single_release, 1493936c8bcdSAlexey Dobriyan }; 1494936c8bcdSAlexey Dobriyan 1495e0769fe6SDarren Hart /* 1496e0769fe6SDarren Hart * Proc and module init 1497b4f9fe12SLen Brown */ 1498b4f9fe12SLen Brown 1499b4f9fe12SLen Brown #define PROC_TOSHIBA "toshiba" 1500b4f9fe12SLen Brown 1501b859f159SGreg Kroah-Hartman static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1502b4f9fe12SLen Brown { 150336d03f93SSeth Forshee if (dev->backlight_dev) 1504135740deSSeth Forshee proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1505135740deSSeth Forshee &lcd_proc_fops, dev); 150636d03f93SSeth Forshee if (dev->video_supported) 1507135740deSSeth Forshee proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1508135740deSSeth Forshee &video_proc_fops, dev); 150936d03f93SSeth Forshee if (dev->fan_supported) 1510135740deSSeth Forshee proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1511135740deSSeth Forshee &fan_proc_fops, dev); 151236d03f93SSeth Forshee if (dev->hotkey_dev) 1513135740deSSeth Forshee proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1514135740deSSeth Forshee &keys_proc_fops, dev); 1515135740deSSeth Forshee proc_create_data("version", S_IRUGO, toshiba_proc_dir, 1516135740deSSeth Forshee &version_proc_fops, dev); 1517b4f9fe12SLen Brown } 1518b4f9fe12SLen Brown 151936d03f93SSeth Forshee static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1520b4f9fe12SLen Brown { 152136d03f93SSeth Forshee if (dev->backlight_dev) 1522936c8bcdSAlexey Dobriyan remove_proc_entry("lcd", toshiba_proc_dir); 152336d03f93SSeth Forshee if (dev->video_supported) 1524936c8bcdSAlexey Dobriyan remove_proc_entry("video", toshiba_proc_dir); 152536d03f93SSeth Forshee if (dev->fan_supported) 1526936c8bcdSAlexey Dobriyan remove_proc_entry("fan", toshiba_proc_dir); 152736d03f93SSeth Forshee if (dev->hotkey_dev) 1528936c8bcdSAlexey Dobriyan remove_proc_entry("keys", toshiba_proc_dir); 1529936c8bcdSAlexey Dobriyan remove_proc_entry("version", toshiba_proc_dir); 1530b4f9fe12SLen Brown } 1531b4f9fe12SLen Brown 1532acc2472eSLionel Debroux static const struct backlight_ops toshiba_backlight_data = { 1533121b7b0dSAkio Idehara .options = BL_CORE_SUSPENDRESUME, 153462cce752SSeth Forshee .get_brightness = get_lcd_brightness, 1535b4f9fe12SLen Brown .update_status = set_lcd_status, 1536b4f9fe12SLen Brown }; 1537b4f9fe12SLen Brown 1538360f0f39SAzael Avalos /* 1539360f0f39SAzael Avalos * Sysfs files 1540360f0f39SAzael Avalos */ 15419d309848SAzael Avalos static ssize_t version_show(struct device *dev, 1542c6c68ff8SAzael Avalos struct device_attribute *attr, char *buf) 1543c6c68ff8SAzael Avalos { 1544c6c68ff8SAzael Avalos return sprintf(buf, "%s\n", TOSHIBA_ACPI_VERSION); 1545c6c68ff8SAzael Avalos } 15460c3c0f10SAzael Avalos static DEVICE_ATTR_RO(version); 1547c6c68ff8SAzael Avalos 15489d309848SAzael Avalos static ssize_t fan_store(struct device *dev, 154994477d4cSAzael Avalos struct device_attribute *attr, 155094477d4cSAzael Avalos const char *buf, size_t count) 155194477d4cSAzael Avalos { 155294477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 155394477d4cSAzael Avalos int state; 155494477d4cSAzael Avalos int ret; 155594477d4cSAzael Avalos 155694477d4cSAzael Avalos ret = kstrtoint(buf, 0, &state); 155794477d4cSAzael Avalos if (ret) 155894477d4cSAzael Avalos return ret; 155994477d4cSAzael Avalos 156094477d4cSAzael Avalos if (state != 0 && state != 1) 156194477d4cSAzael Avalos return -EINVAL; 156294477d4cSAzael Avalos 15633e07e5baSAzael Avalos ret = set_fan_status(toshiba, state); 15643e07e5baSAzael Avalos if (ret) 15653e07e5baSAzael Avalos return ret; 156694477d4cSAzael Avalos 156794477d4cSAzael Avalos return count; 156894477d4cSAzael Avalos } 156994477d4cSAzael Avalos 15709d309848SAzael Avalos static ssize_t fan_show(struct device *dev, 157194477d4cSAzael Avalos struct device_attribute *attr, char *buf) 157294477d4cSAzael Avalos { 157394477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 157494477d4cSAzael Avalos u32 value; 157594477d4cSAzael Avalos int ret; 157694477d4cSAzael Avalos 157794477d4cSAzael Avalos ret = get_fan_status(toshiba, &value); 157894477d4cSAzael Avalos if (ret) 157994477d4cSAzael Avalos return ret; 158094477d4cSAzael Avalos 158194477d4cSAzael Avalos return sprintf(buf, "%d\n", value); 158294477d4cSAzael Avalos } 15830c3c0f10SAzael Avalos static DEVICE_ATTR_RW(fan); 158494477d4cSAzael Avalos 15859d309848SAzael Avalos static ssize_t kbd_backlight_mode_store(struct device *dev, 1586360f0f39SAzael Avalos struct device_attribute *attr, 1587360f0f39SAzael Avalos const char *buf, size_t count) 1588360f0f39SAzael Avalos { 1589360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1590aeaac098SDan Carpenter int mode; 1591aeaac098SDan Carpenter int ret; 1592360f0f39SAzael Avalos 1593aeaac098SDan Carpenter 1594aeaac098SDan Carpenter ret = kstrtoint(buf, 0, &mode); 1595aeaac098SDan Carpenter if (ret) 1596aeaac098SDan Carpenter return ret; 159793f8c16dSAzael Avalos 159893f8c16dSAzael Avalos /* Check for supported modes depending on keyboard backlight type */ 159993f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 160093f8c16dSAzael Avalos /* Type 1 supports SCI_KBD_MODE_FNZ and SCI_KBD_MODE_AUTO */ 1601aeaac098SDan Carpenter if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO) 1602360f0f39SAzael Avalos return -EINVAL; 160393f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 160493f8c16dSAzael Avalos /* Type 2 doesn't support SCI_KBD_MODE_FNZ */ 160593f8c16dSAzael Avalos if (mode != SCI_KBD_MODE_AUTO && mode != SCI_KBD_MODE_ON && 160693f8c16dSAzael Avalos mode != SCI_KBD_MODE_OFF) 160793f8c16dSAzael Avalos return -EINVAL; 160893f8c16dSAzael Avalos } 1609360f0f39SAzael Avalos 1610e0769fe6SDarren Hart /* 1611e0769fe6SDarren Hart * Set the Keyboard Backlight Mode where: 1612360f0f39SAzael Avalos * Auto - KBD backlight turns off automatically in given time 1613360f0f39SAzael Avalos * FN-Z - KBD backlight "toggles" when hotkey pressed 161493f8c16dSAzael Avalos * ON - KBD backlight is always on 161593f8c16dSAzael Avalos * OFF - KBD backlight is always off 1616360f0f39SAzael Avalos */ 161793f8c16dSAzael Avalos 161893f8c16dSAzael Avalos /* Only make a change if the actual mode has changed */ 1619aeaac098SDan Carpenter if (toshiba->kbd_mode != mode) { 162093f8c16dSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 16211e574dbfSAzael Avalos int time = toshiba->kbd_time << HCI_MISC_SHIFT; 162293f8c16dSAzael Avalos 162393f8c16dSAzael Avalos /* OR the "base time" to the actual method format */ 162493f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 162593f8c16dSAzael Avalos /* Type 1 requires the current mode */ 162693f8c16dSAzael Avalos time |= toshiba->kbd_mode; 162793f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 162893f8c16dSAzael Avalos /* Type 2 requires the desired mode */ 162993f8c16dSAzael Avalos time |= mode; 163093f8c16dSAzael Avalos } 163193f8c16dSAzael Avalos 1632aeaac098SDan Carpenter ret = toshiba_kbd_illum_status_set(toshiba, time); 1633aeaac098SDan Carpenter if (ret) 1634aeaac098SDan Carpenter return ret; 163593f8c16dSAzael Avalos 1636360f0f39SAzael Avalos toshiba->kbd_mode = mode; 1637360f0f39SAzael Avalos } 1638360f0f39SAzael Avalos 1639360f0f39SAzael Avalos return count; 1640360f0f39SAzael Avalos } 1641360f0f39SAzael Avalos 16429d309848SAzael Avalos static ssize_t kbd_backlight_mode_show(struct device *dev, 1643360f0f39SAzael Avalos struct device_attribute *attr, 1644360f0f39SAzael Avalos char *buf) 1645360f0f39SAzael Avalos { 1646360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1647360f0f39SAzael Avalos u32 time; 1648360f0f39SAzael Avalos 1649360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1650360f0f39SAzael Avalos return -EIO; 1651360f0f39SAzael Avalos 165293f8c16dSAzael Avalos return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK); 165393f8c16dSAzael Avalos } 16540c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_mode); 165593f8c16dSAzael Avalos 16569d309848SAzael Avalos static ssize_t kbd_type_show(struct device *dev, 16579d309848SAzael Avalos struct device_attribute *attr, char *buf) 165893f8c16dSAzael Avalos { 165993f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 166093f8c16dSAzael Avalos 166193f8c16dSAzael Avalos return sprintf(buf, "%d\n", toshiba->kbd_type); 166293f8c16dSAzael Avalos } 16630c3c0f10SAzael Avalos static DEVICE_ATTR_RO(kbd_type); 166493f8c16dSAzael Avalos 16659d309848SAzael Avalos static ssize_t available_kbd_modes_show(struct device *dev, 166693f8c16dSAzael Avalos struct device_attribute *attr, 166793f8c16dSAzael Avalos char *buf) 166893f8c16dSAzael Avalos { 166993f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 167093f8c16dSAzael Avalos 167193f8c16dSAzael Avalos if (toshiba->kbd_type == 1) 16720b498201SAzael Avalos return sprintf(buf, "0x%x 0x%x\n", 167393f8c16dSAzael Avalos SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO); 167493f8c16dSAzael Avalos 16750b498201SAzael Avalos return sprintf(buf, "0x%x 0x%x 0x%x\n", 167693f8c16dSAzael Avalos SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF); 1677360f0f39SAzael Avalos } 16780c3c0f10SAzael Avalos static DEVICE_ATTR_RO(available_kbd_modes); 1679360f0f39SAzael Avalos 16809d309848SAzael Avalos static ssize_t kbd_backlight_timeout_store(struct device *dev, 1681360f0f39SAzael Avalos struct device_attribute *attr, 1682360f0f39SAzael Avalos const char *buf, size_t count) 1683360f0f39SAzael Avalos { 1684360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1685eabde0faSAzael Avalos int time; 1686eabde0faSAzael Avalos int ret; 1687360f0f39SAzael Avalos 1688eabde0faSAzael Avalos ret = kstrtoint(buf, 0, &time); 1689eabde0faSAzael Avalos if (ret) 1690eabde0faSAzael Avalos return ret; 1691eabde0faSAzael Avalos 1692eabde0faSAzael Avalos /* Check for supported values depending on kbd_type */ 1693eabde0faSAzael Avalos if (toshiba->kbd_type == 1) { 1694eabde0faSAzael Avalos if (time < 0 || time > 60) 1695360f0f39SAzael Avalos return -EINVAL; 1696eabde0faSAzael Avalos } else if (toshiba->kbd_type == 2) { 1697eabde0faSAzael Avalos if (time < 1 || time > 60) 1698eabde0faSAzael Avalos return -EINVAL; 1699eabde0faSAzael Avalos } 1700360f0f39SAzael Avalos 1701eabde0faSAzael Avalos /* Set the Keyboard Backlight Timeout */ 1702eabde0faSAzael Avalos 1703eabde0faSAzael Avalos /* Only make a change if the actual timeout has changed */ 1704eabde0faSAzael Avalos if (toshiba->kbd_time != time) { 1705eabde0faSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 1706360f0f39SAzael Avalos time = time << HCI_MISC_SHIFT; 1707eabde0faSAzael Avalos /* OR the "base time" to the actual method format */ 1708eabde0faSAzael Avalos if (toshiba->kbd_type == 1) 1709eabde0faSAzael Avalos time |= SCI_KBD_MODE_FNZ; 1710eabde0faSAzael Avalos else if (toshiba->kbd_type == 2) 1711eabde0faSAzael Avalos time |= SCI_KBD_MODE_AUTO; 1712eabde0faSAzael Avalos 1713eabde0faSAzael Avalos ret = toshiba_kbd_illum_status_set(toshiba, time); 1714eabde0faSAzael Avalos if (ret) 1715eabde0faSAzael Avalos return ret; 1716eabde0faSAzael Avalos 1717360f0f39SAzael Avalos toshiba->kbd_time = time >> HCI_MISC_SHIFT; 1718360f0f39SAzael Avalos } 1719360f0f39SAzael Avalos 1720360f0f39SAzael Avalos return count; 1721360f0f39SAzael Avalos } 1722360f0f39SAzael Avalos 17239d309848SAzael Avalos static ssize_t kbd_backlight_timeout_show(struct device *dev, 1724360f0f39SAzael Avalos struct device_attribute *attr, 1725360f0f39SAzael Avalos char *buf) 1726360f0f39SAzael Avalos { 1727360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1728360f0f39SAzael Avalos u32 time; 1729360f0f39SAzael Avalos 1730360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1731360f0f39SAzael Avalos return -EIO; 1732360f0f39SAzael Avalos 1733360f0f39SAzael Avalos return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT); 1734360f0f39SAzael Avalos } 17350c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_timeout); 1736360f0f39SAzael Avalos 17379d309848SAzael Avalos static ssize_t touchpad_store(struct device *dev, 17389d8658acSAzael Avalos struct device_attribute *attr, 17399d8658acSAzael Avalos const char *buf, size_t count) 17409d8658acSAzael Avalos { 17419d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 17429d8658acSAzael Avalos int state; 1743c8a41669SAzael Avalos int ret; 17449d8658acSAzael Avalos 17459d8658acSAzael Avalos /* Set the TouchPad on/off, 0 - Disable | 1 - Enable */ 1746c8a41669SAzael Avalos ret = kstrtoint(buf, 0, &state); 1747c8a41669SAzael Avalos if (ret) 1748c8a41669SAzael Avalos return ret; 1749c8a41669SAzael Avalos if (state != 0 && state != 1) 1750c8a41669SAzael Avalos return -EINVAL; 1751c8a41669SAzael Avalos 1752c8a41669SAzael Avalos ret = toshiba_touchpad_set(toshiba, state); 1753c8a41669SAzael Avalos if (ret) 1754c8a41669SAzael Avalos return ret; 17559d8658acSAzael Avalos 17569d8658acSAzael Avalos return count; 17579d8658acSAzael Avalos } 17589d8658acSAzael Avalos 17599d309848SAzael Avalos static ssize_t touchpad_show(struct device *dev, 17609d8658acSAzael Avalos struct device_attribute *attr, char *buf) 17619d8658acSAzael Avalos { 17629d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 17639d8658acSAzael Avalos u32 state; 17649d8658acSAzael Avalos int ret; 17659d8658acSAzael Avalos 17669d8658acSAzael Avalos ret = toshiba_touchpad_get(toshiba, &state); 17679d8658acSAzael Avalos if (ret < 0) 17689d8658acSAzael Avalos return ret; 17699d8658acSAzael Avalos 17709d8658acSAzael Avalos return sprintf(buf, "%i\n", state); 17719d8658acSAzael Avalos } 17720c3c0f10SAzael Avalos static DEVICE_ATTR_RW(touchpad); 17739d8658acSAzael Avalos 17749d309848SAzael Avalos static ssize_t position_show(struct device *dev, 17755a2813e9SAzael Avalos struct device_attribute *attr, char *buf) 17765a2813e9SAzael Avalos { 17775a2813e9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 17785a2813e9SAzael Avalos u32 xyval, zval, tmp; 17795a2813e9SAzael Avalos u16 x, y, z; 17805a2813e9SAzael Avalos int ret; 17815a2813e9SAzael Avalos 17825a2813e9SAzael Avalos xyval = zval = 0; 17835a2813e9SAzael Avalos ret = toshiba_accelerometer_get(toshiba, &xyval, &zval); 17845a2813e9SAzael Avalos if (ret < 0) 17855a2813e9SAzael Avalos return ret; 17865a2813e9SAzael Avalos 17875a2813e9SAzael Avalos x = xyval & HCI_ACCEL_MASK; 17885a2813e9SAzael Avalos tmp = xyval >> HCI_MISC_SHIFT; 17895a2813e9SAzael Avalos y = tmp & HCI_ACCEL_MASK; 17905a2813e9SAzael Avalos z = zval & HCI_ACCEL_MASK; 17915a2813e9SAzael Avalos 17925a2813e9SAzael Avalos return sprintf(buf, "%d %d %d\n", x, y, z); 17935a2813e9SAzael Avalos } 17940c3c0f10SAzael Avalos static DEVICE_ATTR_RO(position); 17955a2813e9SAzael Avalos 17969d309848SAzael Avalos static ssize_t usb_sleep_charge_show(struct device *dev, 17979d309848SAzael Avalos struct device_attribute *attr, char *buf) 1798e26ffe51SAzael Avalos { 1799e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1800e26ffe51SAzael Avalos u32 mode; 1801e26ffe51SAzael Avalos int ret; 1802e26ffe51SAzael Avalos 1803e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_get(toshiba, &mode); 1804e26ffe51SAzael Avalos if (ret < 0) 1805e26ffe51SAzael Avalos return ret; 1806e26ffe51SAzael Avalos 1807e26ffe51SAzael Avalos return sprintf(buf, "%x\n", mode & SCI_USB_CHARGE_MODE_MASK); 1808e26ffe51SAzael Avalos } 1809e26ffe51SAzael Avalos 18109d309848SAzael Avalos static ssize_t usb_sleep_charge_store(struct device *dev, 1811e26ffe51SAzael Avalos struct device_attribute *attr, 1812e26ffe51SAzael Avalos const char *buf, size_t count) 1813e26ffe51SAzael Avalos { 1814e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1815e26ffe51SAzael Avalos u32 mode; 1816e26ffe51SAzael Avalos int state; 1817e26ffe51SAzael Avalos int ret; 1818e26ffe51SAzael Avalos 1819e26ffe51SAzael Avalos ret = kstrtoint(buf, 0, &state); 1820e26ffe51SAzael Avalos if (ret) 1821e26ffe51SAzael Avalos return ret; 1822e0769fe6SDarren Hart /* 1823e0769fe6SDarren Hart * Check for supported values, where: 1824e26ffe51SAzael Avalos * 0 - Disabled 1825e26ffe51SAzael Avalos * 1 - Alternate (Non USB conformant devices that require more power) 1826e26ffe51SAzael Avalos * 2 - Auto (USB conformant devices) 1827c8c91842SAzael Avalos * 3 - Typical 1828e26ffe51SAzael Avalos */ 1829c8c91842SAzael Avalos if (state != 0 && state != 1 && state != 2 && state != 3) 1830e26ffe51SAzael Avalos return -EINVAL; 1831e26ffe51SAzael Avalos 1832e26ffe51SAzael Avalos /* Set the USB charging mode to internal value */ 1833c8c91842SAzael Avalos mode = toshiba->usbsc_mode_base; 1834e26ffe51SAzael Avalos if (state == 0) 1835c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_DISABLED; 1836e26ffe51SAzael Avalos else if (state == 1) 1837c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_ALTERNATE; 1838e26ffe51SAzael Avalos else if (state == 2) 1839c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_AUTO; 1840c8c91842SAzael Avalos else if (state == 3) 1841c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_TYPICAL; 1842e26ffe51SAzael Avalos 1843e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_set(toshiba, mode); 1844e26ffe51SAzael Avalos if (ret) 1845e26ffe51SAzael Avalos return ret; 1846e26ffe51SAzael Avalos 1847e26ffe51SAzael Avalos return count; 1848e26ffe51SAzael Avalos } 18490c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_charge); 1850e26ffe51SAzael Avalos 1851182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_show(struct device *dev, 1852182bcaa5SAzael Avalos struct device_attribute *attr, 1853182bcaa5SAzael Avalos char *buf) 1854182bcaa5SAzael Avalos { 1855182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1856182bcaa5SAzael Avalos u32 state; 1857182bcaa5SAzael Avalos int bat_lvl; 1858182bcaa5SAzael Avalos int status; 1859182bcaa5SAzael Avalos int ret; 1860182bcaa5SAzael Avalos int tmp; 1861182bcaa5SAzael Avalos 1862182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_get(toshiba, &state); 1863182bcaa5SAzael Avalos if (ret < 0) 1864182bcaa5SAzael Avalos return ret; 1865182bcaa5SAzael Avalos 1866182bcaa5SAzael Avalos /* Determine the status: 0x4 - Enabled | 0x1 - Disabled */ 1867182bcaa5SAzael Avalos tmp = state & SCI_USB_CHARGE_BAT_MASK; 1868182bcaa5SAzael Avalos status = (tmp == 0x4) ? 1 : 0; 1869182bcaa5SAzael Avalos /* Determine the battery level set */ 1870182bcaa5SAzael Avalos bat_lvl = state >> HCI_MISC_SHIFT; 1871182bcaa5SAzael Avalos 1872182bcaa5SAzael Avalos return sprintf(buf, "%d %d\n", status, bat_lvl); 1873182bcaa5SAzael Avalos } 1874182bcaa5SAzael Avalos 1875182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_store(struct device *dev, 1876182bcaa5SAzael Avalos struct device_attribute *attr, 1877182bcaa5SAzael Avalos const char *buf, size_t count) 1878182bcaa5SAzael Avalos { 1879182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1880182bcaa5SAzael Avalos u32 status; 1881182bcaa5SAzael Avalos int value; 1882182bcaa5SAzael Avalos int ret; 1883182bcaa5SAzael Avalos int tmp; 1884182bcaa5SAzael Avalos 1885182bcaa5SAzael Avalos ret = kstrtoint(buf, 0, &value); 1886182bcaa5SAzael Avalos if (ret) 1887182bcaa5SAzael Avalos return ret; 1888182bcaa5SAzael Avalos 1889e0769fe6SDarren Hart /* 1890e0769fe6SDarren Hart * Set the status of the function: 1891182bcaa5SAzael Avalos * 0 - Disabled 1892182bcaa5SAzael Avalos * 1-100 - Enabled 1893182bcaa5SAzael Avalos */ 1894182bcaa5SAzael Avalos if (value < 0 || value > 100) 1895182bcaa5SAzael Avalos return -EINVAL; 1896182bcaa5SAzael Avalos 1897182bcaa5SAzael Avalos if (value == 0) { 1898182bcaa5SAzael Avalos tmp = toshiba->usbsc_bat_level << HCI_MISC_SHIFT; 1899182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_OFF; 1900182bcaa5SAzael Avalos } else { 1901182bcaa5SAzael Avalos tmp = value << HCI_MISC_SHIFT; 1902182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_ON; 1903182bcaa5SAzael Avalos } 1904182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_set(toshiba, status); 1905182bcaa5SAzael Avalos if (ret < 0) 1906182bcaa5SAzael Avalos return ret; 1907182bcaa5SAzael Avalos 1908182bcaa5SAzael Avalos toshiba->usbsc_bat_level = status >> HCI_MISC_SHIFT; 1909182bcaa5SAzael Avalos 1910182bcaa5SAzael Avalos return count; 1911182bcaa5SAzael Avalos } 19120c3c0f10SAzael Avalos static DEVICE_ATTR_RW(sleep_functions_on_battery); 1913182bcaa5SAzael Avalos 19149d309848SAzael Avalos static ssize_t usb_rapid_charge_show(struct device *dev, 19159d309848SAzael Avalos struct device_attribute *attr, char *buf) 1916bb3fe01fSAzael Avalos { 1917bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1918bb3fe01fSAzael Avalos u32 state; 1919bb3fe01fSAzael Avalos int ret; 1920bb3fe01fSAzael Avalos 1921bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(toshiba, &state); 1922bb3fe01fSAzael Avalos if (ret < 0) 1923bb3fe01fSAzael Avalos return ret; 1924bb3fe01fSAzael Avalos 1925bb3fe01fSAzael Avalos return sprintf(buf, "%d\n", state); 1926bb3fe01fSAzael Avalos } 1927bb3fe01fSAzael Avalos 19289d309848SAzael Avalos static ssize_t usb_rapid_charge_store(struct device *dev, 1929bb3fe01fSAzael Avalos struct device_attribute *attr, 1930bb3fe01fSAzael Avalos const char *buf, size_t count) 1931bb3fe01fSAzael Avalos { 1932bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1933bb3fe01fSAzael Avalos int state; 1934bb3fe01fSAzael Avalos int ret; 1935bb3fe01fSAzael Avalos 1936bb3fe01fSAzael Avalos ret = kstrtoint(buf, 0, &state); 1937bb3fe01fSAzael Avalos if (ret) 1938bb3fe01fSAzael Avalos return ret; 1939bb3fe01fSAzael Avalos if (state != 0 && state != 1) 1940bb3fe01fSAzael Avalos return -EINVAL; 1941bb3fe01fSAzael Avalos 1942bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_set(toshiba, state); 1943bb3fe01fSAzael Avalos if (ret) 1944bb3fe01fSAzael Avalos return ret; 1945bb3fe01fSAzael Avalos 1946bb3fe01fSAzael Avalos return count; 1947bb3fe01fSAzael Avalos } 19480c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_rapid_charge); 1949bb3fe01fSAzael Avalos 19509d309848SAzael Avalos static ssize_t usb_sleep_music_show(struct device *dev, 19519d309848SAzael Avalos struct device_attribute *attr, char *buf) 1952172ce0a9SAzael Avalos { 1953172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1954172ce0a9SAzael Avalos u32 state; 1955172ce0a9SAzael Avalos int ret; 1956172ce0a9SAzael Avalos 1957172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(toshiba, &state); 1958172ce0a9SAzael Avalos if (ret < 0) 1959172ce0a9SAzael Avalos return ret; 1960172ce0a9SAzael Avalos 1961172ce0a9SAzael Avalos return sprintf(buf, "%d\n", state); 1962172ce0a9SAzael Avalos } 1963172ce0a9SAzael Avalos 19649d309848SAzael Avalos static ssize_t usb_sleep_music_store(struct device *dev, 1965172ce0a9SAzael Avalos struct device_attribute *attr, 1966172ce0a9SAzael Avalos const char *buf, size_t count) 1967172ce0a9SAzael Avalos { 1968172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1969172ce0a9SAzael Avalos int state; 1970172ce0a9SAzael Avalos int ret; 1971172ce0a9SAzael Avalos 1972172ce0a9SAzael Avalos ret = kstrtoint(buf, 0, &state); 1973172ce0a9SAzael Avalos if (ret) 1974172ce0a9SAzael Avalos return ret; 1975172ce0a9SAzael Avalos if (state != 0 && state != 1) 1976172ce0a9SAzael Avalos return -EINVAL; 1977172ce0a9SAzael Avalos 1978172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_set(toshiba, state); 1979172ce0a9SAzael Avalos if (ret) 1980172ce0a9SAzael Avalos return ret; 1981172ce0a9SAzael Avalos 1982172ce0a9SAzael Avalos return count; 1983172ce0a9SAzael Avalos } 19840c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_music); 1985172ce0a9SAzael Avalos 19869d309848SAzael Avalos static ssize_t kbd_function_keys_show(struct device *dev, 19879d309848SAzael Avalos struct device_attribute *attr, char *buf) 1988bae84195SAzael Avalos { 1989bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1990bae84195SAzael Avalos int mode; 1991bae84195SAzael Avalos int ret; 1992bae84195SAzael Avalos 1993bae84195SAzael Avalos ret = toshiba_function_keys_get(toshiba, &mode); 1994bae84195SAzael Avalos if (ret < 0) 1995bae84195SAzael Avalos return ret; 1996bae84195SAzael Avalos 1997bae84195SAzael Avalos return sprintf(buf, "%d\n", mode); 1998bae84195SAzael Avalos } 1999bae84195SAzael Avalos 20009d309848SAzael Avalos static ssize_t kbd_function_keys_store(struct device *dev, 2001bae84195SAzael Avalos struct device_attribute *attr, 2002bae84195SAzael Avalos const char *buf, size_t count) 2003bae84195SAzael Avalos { 2004bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2005bae84195SAzael Avalos int mode; 2006bae84195SAzael Avalos int ret; 2007bae84195SAzael Avalos 2008bae84195SAzael Avalos ret = kstrtoint(buf, 0, &mode); 2009bae84195SAzael Avalos if (ret) 2010bae84195SAzael Avalos return ret; 2011e0769fe6SDarren Hart /* 2012e0769fe6SDarren Hart * Check for the function keys mode where: 2013bae84195SAzael Avalos * 0 - Normal operation (F{1-12} as usual and hotkeys via FN-F{1-12}) 2014bae84195SAzael Avalos * 1 - Special functions (Opposite of the above setting) 2015bae84195SAzael Avalos */ 2016bae84195SAzael Avalos if (mode != 0 && mode != 1) 2017bae84195SAzael Avalos return -EINVAL; 2018bae84195SAzael Avalos 2019bae84195SAzael Avalos ret = toshiba_function_keys_set(toshiba, mode); 2020bae84195SAzael Avalos if (ret) 2021bae84195SAzael Avalos return ret; 2022bae84195SAzael Avalos 2023bae84195SAzael Avalos pr_info("Reboot for changes to KBD Function Keys to take effect"); 2024bae84195SAzael Avalos 2025bae84195SAzael Avalos return count; 2026bae84195SAzael Avalos } 20270c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_function_keys); 2028bae84195SAzael Avalos 20299d309848SAzael Avalos static ssize_t panel_power_on_show(struct device *dev, 20309d309848SAzael Avalos struct device_attribute *attr, char *buf) 203135d53ceaSAzael Avalos { 203235d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 203335d53ceaSAzael Avalos u32 state; 203435d53ceaSAzael Avalos int ret; 203535d53ceaSAzael Avalos 203635d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(toshiba, &state); 203735d53ceaSAzael Avalos if (ret < 0) 203835d53ceaSAzael Avalos return ret; 203935d53ceaSAzael Avalos 204035d53ceaSAzael Avalos return sprintf(buf, "%d\n", state); 204135d53ceaSAzael Avalos } 204235d53ceaSAzael Avalos 20439d309848SAzael Avalos static ssize_t panel_power_on_store(struct device *dev, 204435d53ceaSAzael Avalos struct device_attribute *attr, 204535d53ceaSAzael Avalos const char *buf, size_t count) 204635d53ceaSAzael Avalos { 204735d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 204835d53ceaSAzael Avalos int state; 204935d53ceaSAzael Avalos int ret; 205035d53ceaSAzael Avalos 205135d53ceaSAzael Avalos ret = kstrtoint(buf, 0, &state); 205235d53ceaSAzael Avalos if (ret) 205335d53ceaSAzael Avalos return ret; 205435d53ceaSAzael Avalos if (state != 0 && state != 1) 205535d53ceaSAzael Avalos return -EINVAL; 205635d53ceaSAzael Avalos 205735d53ceaSAzael Avalos ret = toshiba_panel_power_on_set(toshiba, state); 205835d53ceaSAzael Avalos if (ret) 205935d53ceaSAzael Avalos return ret; 206035d53ceaSAzael Avalos 206135d53ceaSAzael Avalos pr_info("Reboot for changes to Panel Power ON to take effect"); 206235d53ceaSAzael Avalos 206335d53ceaSAzael Avalos return count; 206435d53ceaSAzael Avalos } 20650c3c0f10SAzael Avalos static DEVICE_ATTR_RW(panel_power_on); 206635d53ceaSAzael Avalos 20679d309848SAzael Avalos static ssize_t usb_three_show(struct device *dev, 20689d309848SAzael Avalos struct device_attribute *attr, char *buf) 206917fe4b3dSAzael Avalos { 207017fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 207117fe4b3dSAzael Avalos u32 state; 207217fe4b3dSAzael Avalos int ret; 207317fe4b3dSAzael Avalos 207417fe4b3dSAzael Avalos ret = toshiba_usb_three_get(toshiba, &state); 207517fe4b3dSAzael Avalos if (ret < 0) 207617fe4b3dSAzael Avalos return ret; 207717fe4b3dSAzael Avalos 207817fe4b3dSAzael Avalos return sprintf(buf, "%d\n", state); 207917fe4b3dSAzael Avalos } 208017fe4b3dSAzael Avalos 20819d309848SAzael Avalos static ssize_t usb_three_store(struct device *dev, 208217fe4b3dSAzael Avalos struct device_attribute *attr, 208317fe4b3dSAzael Avalos const char *buf, size_t count) 208417fe4b3dSAzael Avalos { 208517fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 208617fe4b3dSAzael Avalos int state; 208717fe4b3dSAzael Avalos int ret; 208817fe4b3dSAzael Avalos 208917fe4b3dSAzael Avalos ret = kstrtoint(buf, 0, &state); 209017fe4b3dSAzael Avalos if (ret) 209117fe4b3dSAzael Avalos return ret; 2092e0769fe6SDarren Hart /* 2093e0769fe6SDarren Hart * Check for USB 3 mode where: 209417fe4b3dSAzael Avalos * 0 - Disabled (Acts like a USB 2 port, saving power) 209517fe4b3dSAzael Avalos * 1 - Enabled 209617fe4b3dSAzael Avalos */ 209717fe4b3dSAzael Avalos if (state != 0 && state != 1) 209817fe4b3dSAzael Avalos return -EINVAL; 209917fe4b3dSAzael Avalos 210017fe4b3dSAzael Avalos ret = toshiba_usb_three_set(toshiba, state); 210117fe4b3dSAzael Avalos if (ret) 210217fe4b3dSAzael Avalos return ret; 210317fe4b3dSAzael Avalos 210417fe4b3dSAzael Avalos pr_info("Reboot for changes to USB 3 to take effect"); 210517fe4b3dSAzael Avalos 210617fe4b3dSAzael Avalos return count; 210717fe4b3dSAzael Avalos } 21080c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_three); 21099bd1213bSAzael Avalos 21109bd1213bSAzael Avalos static struct attribute *toshiba_attributes[] = { 21119bd1213bSAzael Avalos &dev_attr_version.attr, 21129bd1213bSAzael Avalos &dev_attr_fan.attr, 21139bd1213bSAzael Avalos &dev_attr_kbd_backlight_mode.attr, 21149bd1213bSAzael Avalos &dev_attr_kbd_type.attr, 21159bd1213bSAzael Avalos &dev_attr_available_kbd_modes.attr, 21169bd1213bSAzael Avalos &dev_attr_kbd_backlight_timeout.attr, 21179bd1213bSAzael Avalos &dev_attr_touchpad.attr, 21189bd1213bSAzael Avalos &dev_attr_position.attr, 21199bd1213bSAzael Avalos &dev_attr_usb_sleep_charge.attr, 21209bd1213bSAzael Avalos &dev_attr_sleep_functions_on_battery.attr, 21219bd1213bSAzael Avalos &dev_attr_usb_rapid_charge.attr, 21229bd1213bSAzael Avalos &dev_attr_usb_sleep_music.attr, 21239bd1213bSAzael Avalos &dev_attr_kbd_function_keys.attr, 21249bd1213bSAzael Avalos &dev_attr_panel_power_on.attr, 21259bd1213bSAzael Avalos &dev_attr_usb_three.attr, 21269bd1213bSAzael Avalos NULL, 21279bd1213bSAzael Avalos }; 21289bd1213bSAzael Avalos 2129360f0f39SAzael Avalos static umode_t toshiba_sysfs_is_visible(struct kobject *kobj, 2130360f0f39SAzael Avalos struct attribute *attr, int idx) 2131360f0f39SAzael Avalos { 2132360f0f39SAzael Avalos struct device *dev = container_of(kobj, struct device, kobj); 2133360f0f39SAzael Avalos struct toshiba_acpi_dev *drv = dev_get_drvdata(dev); 2134360f0f39SAzael Avalos bool exists = true; 2135360f0f39SAzael Avalos 213694477d4cSAzael Avalos if (attr == &dev_attr_fan.attr) 213794477d4cSAzael Avalos exists = (drv->fan_supported) ? true : false; 213894477d4cSAzael Avalos else if (attr == &dev_attr_kbd_backlight_mode.attr) 2139360f0f39SAzael Avalos exists = (drv->kbd_illum_supported) ? true : false; 2140360f0f39SAzael Avalos else if (attr == &dev_attr_kbd_backlight_timeout.attr) 2141360f0f39SAzael Avalos exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false; 21429d8658acSAzael Avalos else if (attr == &dev_attr_touchpad.attr) 21439d8658acSAzael Avalos exists = (drv->touchpad_supported) ? true : false; 21445a2813e9SAzael Avalos else if (attr == &dev_attr_position.attr) 21455a2813e9SAzael Avalos exists = (drv->accelerometer_supported) ? true : false; 2146e26ffe51SAzael Avalos else if (attr == &dev_attr_usb_sleep_charge.attr) 2147e26ffe51SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2148182bcaa5SAzael Avalos else if (attr == &dev_attr_sleep_functions_on_battery.attr) 2149182bcaa5SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2150bb3fe01fSAzael Avalos else if (attr == &dev_attr_usb_rapid_charge.attr) 2151bb3fe01fSAzael Avalos exists = (drv->usb_rapid_charge_supported) ? true : false; 2152172ce0a9SAzael Avalos else if (attr == &dev_attr_usb_sleep_music.attr) 2153172ce0a9SAzael Avalos exists = (drv->usb_sleep_music_supported) ? true : false; 2154bae84195SAzael Avalos else if (attr == &dev_attr_kbd_function_keys.attr) 2155bae84195SAzael Avalos exists = (drv->kbd_function_keys_supported) ? true : false; 215635d53ceaSAzael Avalos else if (attr == &dev_attr_panel_power_on.attr) 215735d53ceaSAzael Avalos exists = (drv->panel_power_on_supported) ? true : false; 215817fe4b3dSAzael Avalos else if (attr == &dev_attr_usb_three.attr) 215917fe4b3dSAzael Avalos exists = (drv->usb_three_supported) ? true : false; 2160360f0f39SAzael Avalos 2161360f0f39SAzael Avalos return exists ? attr->mode : 0; 2162360f0f39SAzael Avalos } 2163360f0f39SAzael Avalos 21649bd1213bSAzael Avalos static struct attribute_group toshiba_attr_group = { 21659bd1213bSAzael Avalos .is_visible = toshiba_sysfs_is_visible, 21669bd1213bSAzael Avalos .attrs = toshiba_attributes, 21679bd1213bSAzael Avalos }; 21689bd1213bSAzael Avalos 21691f28f290SAzael Avalos /* 2170fc5462f8SAzael Avalos * Misc device 2171fc5462f8SAzael Avalos */ 2172fc5462f8SAzael Avalos static int toshiba_acpi_smm_bridge(SMMRegisters *regs) 2173fc5462f8SAzael Avalos { 2174fc5462f8SAzael Avalos u32 in[TCI_WORDS] = { regs->eax, regs->ebx, regs->ecx, 2175fc5462f8SAzael Avalos regs->edx, regs->esi, regs->edi }; 2176fc5462f8SAzael Avalos u32 out[TCI_WORDS]; 2177fc5462f8SAzael Avalos acpi_status status; 2178fc5462f8SAzael Avalos 2179fc5462f8SAzael Avalos status = tci_raw(toshiba_acpi, in, out); 2180fc5462f8SAzael Avalos if (ACPI_FAILURE(status)) { 2181fc5462f8SAzael Avalos pr_err("ACPI call to query SMM registers failed\n"); 2182fc5462f8SAzael Avalos return -EIO; 2183fc5462f8SAzael Avalos } 2184fc5462f8SAzael Avalos 2185fc5462f8SAzael Avalos /* Fillout the SMM struct with the TCI call results */ 2186fc5462f8SAzael Avalos regs->eax = out[0]; 2187fc5462f8SAzael Avalos regs->ebx = out[1]; 2188fc5462f8SAzael Avalos regs->ecx = out[2]; 2189fc5462f8SAzael Avalos regs->edx = out[3]; 2190fc5462f8SAzael Avalos regs->esi = out[4]; 2191fc5462f8SAzael Avalos regs->edi = out[5]; 2192fc5462f8SAzael Avalos 2193fc5462f8SAzael Avalos return 0; 2194fc5462f8SAzael Avalos } 2195fc5462f8SAzael Avalos 2196fc5462f8SAzael Avalos static long toshiba_acpi_ioctl(struct file *fp, unsigned int cmd, 2197fc5462f8SAzael Avalos unsigned long arg) 2198fc5462f8SAzael Avalos { 2199fc5462f8SAzael Avalos SMMRegisters __user *argp = (SMMRegisters __user *)arg; 2200fc5462f8SAzael Avalos SMMRegisters regs; 2201fc5462f8SAzael Avalos int ret; 2202fc5462f8SAzael Avalos 2203fc5462f8SAzael Avalos if (!argp) 2204fc5462f8SAzael Avalos return -EINVAL; 2205fc5462f8SAzael Avalos 2206fc5462f8SAzael Avalos switch (cmd) { 2207fc5462f8SAzael Avalos case TOSH_SMM: 2208fc5462f8SAzael Avalos if (copy_from_user(®s, argp, sizeof(SMMRegisters))) 2209fc5462f8SAzael Avalos return -EFAULT; 2210fc5462f8SAzael Avalos ret = toshiba_acpi_smm_bridge(®s); 2211fc5462f8SAzael Avalos if (ret) 2212fc5462f8SAzael Avalos return ret; 2213fc5462f8SAzael Avalos if (copy_to_user(argp, ®s, sizeof(SMMRegisters))) 2214fc5462f8SAzael Avalos return -EFAULT; 2215fc5462f8SAzael Avalos break; 2216fc5462f8SAzael Avalos case TOSHIBA_ACPI_SCI: 2217fc5462f8SAzael Avalos if (copy_from_user(®s, argp, sizeof(SMMRegisters))) 2218fc5462f8SAzael Avalos return -EFAULT; 2219fc5462f8SAzael Avalos /* Ensure we are being called with a SCI_{GET, SET} register */ 2220fc5462f8SAzael Avalos if (regs.eax != SCI_GET && regs.eax != SCI_SET) 2221fc5462f8SAzael Avalos return -EINVAL; 2222fc5462f8SAzael Avalos if (!sci_open(toshiba_acpi)) 2223fc5462f8SAzael Avalos return -EIO; 2224fc5462f8SAzael Avalos ret = toshiba_acpi_smm_bridge(®s); 2225fc5462f8SAzael Avalos sci_close(toshiba_acpi); 2226fc5462f8SAzael Avalos if (ret) 2227fc5462f8SAzael Avalos return ret; 2228fc5462f8SAzael Avalos if (copy_to_user(argp, ®s, sizeof(SMMRegisters))) 2229fc5462f8SAzael Avalos return -EFAULT; 2230fc5462f8SAzael Avalos break; 2231fc5462f8SAzael Avalos default: 2232fc5462f8SAzael Avalos return -EINVAL; 2233fc5462f8SAzael Avalos } 2234fc5462f8SAzael Avalos 2235fc5462f8SAzael Avalos return 0; 2236fc5462f8SAzael Avalos } 2237fc5462f8SAzael Avalos 2238fc5462f8SAzael Avalos static const struct file_operations toshiba_acpi_fops = { 2239fc5462f8SAzael Avalos .owner = THIS_MODULE, 2240fc5462f8SAzael Avalos .unlocked_ioctl = toshiba_acpi_ioctl, 2241fc5462f8SAzael Avalos .llseek = noop_llseek, 2242fc5462f8SAzael Avalos }; 2243fc5462f8SAzael Avalos 2244fc5462f8SAzael Avalos /* 22451f28f290SAzael Avalos * Hotkeys 22461f28f290SAzael Avalos */ 22471f28f290SAzael Avalos static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev) 22481f28f290SAzael Avalos { 22491f28f290SAzael Avalos acpi_status status; 22501f28f290SAzael Avalos u32 result; 22511f28f290SAzael Avalos 22521f28f290SAzael Avalos status = acpi_evaluate_object(dev->acpi_dev->handle, 22531f28f290SAzael Avalos "ENAB", NULL, NULL); 22541f28f290SAzael Avalos if (ACPI_FAILURE(status)) 22551f28f290SAzael Avalos return -ENODEV; 22561f28f290SAzael Avalos 2257b116fd00SAzael Avalos /* 2258b116fd00SAzael Avalos * Enable the "Special Functions" mode only if they are 2259b116fd00SAzael Avalos * supported and if they are activated. 2260b116fd00SAzael Avalos */ 2261b116fd00SAzael Avalos if (dev->kbd_function_keys_supported && dev->special_functions) 2262b116fd00SAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, 2263b116fd00SAzael Avalos HCI_HOTKEY_SPECIAL_FUNCTIONS); 2264b116fd00SAzael Avalos else 2265d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE); 2266b116fd00SAzael Avalos 22671f28f290SAzael Avalos if (result == TOS_FAILURE) 22681f28f290SAzael Avalos return -EIO; 22691f28f290SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 22701f28f290SAzael Avalos return -ENODEV; 22711f28f290SAzael Avalos 22721f28f290SAzael Avalos return 0; 22731f28f290SAzael Avalos } 22741f28f290SAzael Avalos 227529cd293fSSeth Forshee static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, 227629cd293fSSeth Forshee struct serio *port) 227729cd293fSSeth Forshee { 227898280374SGiedrius Statkevičius if (str & I8042_STR_AUXDATA) 227929cd293fSSeth Forshee return false; 228029cd293fSSeth Forshee 228129cd293fSSeth Forshee if (unlikely(data == 0xe0)) 228229cd293fSSeth Forshee return false; 228329cd293fSSeth Forshee 228429cd293fSSeth Forshee if ((data & 0x7f) == TOS1900_FN_SCAN) { 228529cd293fSSeth Forshee schedule_work(&toshiba_acpi->hotkey_work); 228629cd293fSSeth Forshee return true; 228729cd293fSSeth Forshee } 228829cd293fSSeth Forshee 228929cd293fSSeth Forshee return false; 229029cd293fSSeth Forshee } 229129cd293fSSeth Forshee 229229cd293fSSeth Forshee static void toshiba_acpi_hotkey_work(struct work_struct *work) 229329cd293fSSeth Forshee { 229429cd293fSSeth Forshee acpi_handle ec_handle = ec_get_handle(); 229529cd293fSSeth Forshee acpi_status status; 229629cd293fSSeth Forshee 229729cd293fSSeth Forshee if (!ec_handle) 229829cd293fSSeth Forshee return; 229929cd293fSSeth Forshee 230029cd293fSSeth Forshee status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL); 230129cd293fSSeth Forshee if (ACPI_FAILURE(status)) 230229cd293fSSeth Forshee pr_err("ACPI NTFY method execution failed\n"); 230329cd293fSSeth Forshee } 230429cd293fSSeth Forshee 230529cd293fSSeth Forshee /* 230629cd293fSSeth Forshee * Returns hotkey scancode, or < 0 on failure. 230729cd293fSSeth Forshee */ 230829cd293fSSeth Forshee static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev) 230929cd293fSSeth Forshee { 231074facaf7SZhang Rui unsigned long long value; 231129cd293fSSeth Forshee acpi_status status; 231229cd293fSSeth Forshee 231374facaf7SZhang Rui status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO", 231474facaf7SZhang Rui NULL, &value); 231574facaf7SZhang Rui if (ACPI_FAILURE(status)) { 231629cd293fSSeth Forshee pr_err("ACPI INFO method execution failed\n"); 231729cd293fSSeth Forshee return -EIO; 231829cd293fSSeth Forshee } 231929cd293fSSeth Forshee 232074facaf7SZhang Rui return value; 232129cd293fSSeth Forshee } 232229cd293fSSeth Forshee 232329cd293fSSeth Forshee static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev, 232429cd293fSSeth Forshee int scancode) 232529cd293fSSeth Forshee { 232629cd293fSSeth Forshee if (scancode == 0x100) 232729cd293fSSeth Forshee return; 232829cd293fSSeth Forshee 2329e0769fe6SDarren Hart /* Act on key press; ignore key release */ 233029cd293fSSeth Forshee if (scancode & 0x80) 233129cd293fSSeth Forshee return; 233229cd293fSSeth Forshee 233329cd293fSSeth Forshee if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true)) 233429cd293fSSeth Forshee pr_info("Unknown key %x\n", scancode); 233529cd293fSSeth Forshee } 233629cd293fSSeth Forshee 233771454d78SAzael Avalos static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) 233871454d78SAzael Avalos { 233971454d78SAzael Avalos if (dev->info_supported) { 23407deef550SAzael Avalos int scancode = toshiba_acpi_query_hotkey(dev); 23417deef550SAzael Avalos 23427deef550SAzael Avalos if (scancode < 0) { 234371454d78SAzael Avalos pr_err("Failed to query hotkey event\n"); 23447deef550SAzael Avalos } else if (scancode != 0) { 234571454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, scancode); 23467deef550SAzael Avalos dev->key_event_valid = 1; 23477deef550SAzael Avalos dev->last_key_event = scancode; 23487deef550SAzael Avalos } 234971454d78SAzael Avalos } else if (dev->system_event_supported) { 23507deef550SAzael Avalos u32 result; 23517deef550SAzael Avalos u32 value; 23527deef550SAzael Avalos int retries = 3; 23537deef550SAzael Avalos 235471454d78SAzael Avalos do { 23557deef550SAzael Avalos result = hci_read(dev, HCI_SYSTEM_EVENT, &value); 23567deef550SAzael Avalos switch (result) { 235771454d78SAzael Avalos case TOS_SUCCESS: 235871454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, (int)value); 23597deef550SAzael Avalos dev->key_event_valid = 1; 23607deef550SAzael Avalos dev->last_key_event = value; 236171454d78SAzael Avalos break; 236271454d78SAzael Avalos case TOS_NOT_SUPPORTED: 236371454d78SAzael Avalos /* 236471454d78SAzael Avalos * This is a workaround for an unresolved 236571454d78SAzael Avalos * issue on some machines where system events 236671454d78SAzael Avalos * sporadically become disabled. 236771454d78SAzael Avalos */ 23687deef550SAzael Avalos result = hci_write(dev, HCI_SYSTEM_EVENT, 1); 23697deef550SAzael Avalos if (result == TOS_SUCCESS) 237071454d78SAzael Avalos pr_notice("Re-enabled hotkeys\n"); 2371e0769fe6SDarren Hart /* Fall through */ 237271454d78SAzael Avalos default: 237371454d78SAzael Avalos retries--; 237471454d78SAzael Avalos break; 237571454d78SAzael Avalos } 23767deef550SAzael Avalos } while (retries && result != TOS_FIFO_EMPTY); 237771454d78SAzael Avalos } 237871454d78SAzael Avalos } 237971454d78SAzael Avalos 2380b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) 23816335e4d5SMatthew Garrett { 2382fe808bfbSTakashi Iwai const struct key_entry *keymap = toshiba_acpi_keymap; 2383a2b3471bSAzael Avalos acpi_handle ec_handle; 2384a2b3471bSAzael Avalos int error; 2385a2b3471bSAzael Avalos 2386a88bc06eSAzael Avalos if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) { 2387a88bc06eSAzael Avalos pr_info("WMI event detected, hotkeys will not be monitored\n"); 2388a88bc06eSAzael Avalos return 0; 2389a88bc06eSAzael Avalos } 2390a88bc06eSAzael Avalos 2391a2b3471bSAzael Avalos error = toshiba_acpi_enable_hotkeys(dev); 2392a2b3471bSAzael Avalos if (error) 2393a2b3471bSAzael Avalos return error; 2394a2b3471bSAzael Avalos 239510e6aaabSAzael Avalos if (toshiba_hotkey_event_type_get(dev, &dev->hotkey_event_type)) 239653147b6cSAzael Avalos pr_notice("Unable to query Hotkey Event Type\n"); 239753147b6cSAzael Avalos 2398135740deSSeth Forshee dev->hotkey_dev = input_allocate_device(); 2399b222cca6SJoe Perches if (!dev->hotkey_dev) 2400135740deSSeth Forshee return -ENOMEM; 2401135740deSSeth Forshee 2402135740deSSeth Forshee dev->hotkey_dev->name = "Toshiba input device"; 24036e02cc7eSSeth Forshee dev->hotkey_dev->phys = "toshiba_acpi/input0"; 2404135740deSSeth Forshee dev->hotkey_dev->id.bustype = BUS_HOST; 2405135740deSSeth Forshee 240610e6aaabSAzael Avalos if (dev->hotkey_event_type == HCI_SYSTEM_TYPE1 || 2407a2b3471bSAzael Avalos !dev->kbd_function_keys_supported) 2408a2b3471bSAzael Avalos keymap = toshiba_acpi_keymap; 240910e6aaabSAzael Avalos else if (dev->hotkey_event_type == HCI_SYSTEM_TYPE2 || 2410a2b3471bSAzael Avalos dev->kbd_function_keys_supported) 2411fe808bfbSTakashi Iwai keymap = toshiba_acpi_alt_keymap; 2412a2b3471bSAzael Avalos else 241310e6aaabSAzael Avalos pr_info("Unknown event type received %x\n", 241410e6aaabSAzael Avalos dev->hotkey_event_type); 2415fe808bfbSTakashi Iwai error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL); 2416135740deSSeth Forshee if (error) 2417135740deSSeth Forshee goto err_free_dev; 2418135740deSSeth Forshee 241929cd293fSSeth Forshee /* 242029cd293fSSeth Forshee * For some machines the SCI responsible for providing hotkey 242129cd293fSSeth Forshee * notification doesn't fire. We can trigger the notification 242229cd293fSSeth Forshee * whenever the Fn key is pressed using the NTFY method, if 242329cd293fSSeth Forshee * supported, so if it's present set up an i8042 key filter 242429cd293fSSeth Forshee * for this purpose. 242529cd293fSSeth Forshee */ 242629cd293fSSeth Forshee ec_handle = ec_get_handle(); 2427e2e19606SZhang Rui if (ec_handle && acpi_has_method(ec_handle, "NTFY")) { 242829cd293fSSeth Forshee INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work); 242929cd293fSSeth Forshee 243029cd293fSSeth Forshee error = i8042_install_filter(toshiba_acpi_i8042_filter); 243129cd293fSSeth Forshee if (error) { 243229cd293fSSeth Forshee pr_err("Error installing key filter\n"); 243329cd293fSSeth Forshee goto err_free_keymap; 243429cd293fSSeth Forshee } 243529cd293fSSeth Forshee 243629cd293fSSeth Forshee dev->ntfy_supported = 1; 243729cd293fSSeth Forshee } 243829cd293fSSeth Forshee 243929cd293fSSeth Forshee /* 244029cd293fSSeth Forshee * Determine hotkey query interface. Prefer using the INFO 244129cd293fSSeth Forshee * method when it is available. 244229cd293fSSeth Forshee */ 2443e2e19606SZhang Rui if (acpi_has_method(dev->acpi_dev->handle, "INFO")) 244429cd293fSSeth Forshee dev->info_supported = 1; 244510e6aaabSAzael Avalos else if (hci_write(dev, HCI_SYSTEM_EVENT, 1) == TOS_SUCCESS) 244629cd293fSSeth Forshee dev->system_event_supported = 1; 244729cd293fSSeth Forshee 244829cd293fSSeth Forshee if (!dev->info_supported && !dev->system_event_supported) { 244929cd293fSSeth Forshee pr_warn("No hotkey query interface found\n"); 245029cd293fSSeth Forshee goto err_remove_filter; 245129cd293fSSeth Forshee } 245229cd293fSSeth Forshee 2453135740deSSeth Forshee error = input_register_device(dev->hotkey_dev); 2454135740deSSeth Forshee if (error) { 2455135740deSSeth Forshee pr_info("Unable to register input device\n"); 245629cd293fSSeth Forshee goto err_remove_filter; 2457135740deSSeth Forshee } 2458135740deSSeth Forshee 2459135740deSSeth Forshee return 0; 2460135740deSSeth Forshee 246129cd293fSSeth Forshee err_remove_filter: 246229cd293fSSeth Forshee if (dev->ntfy_supported) 246329cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 2464135740deSSeth Forshee err_free_keymap: 2465135740deSSeth Forshee sparse_keymap_free(dev->hotkey_dev); 2466135740deSSeth Forshee err_free_dev: 2467135740deSSeth Forshee input_free_device(dev->hotkey_dev); 2468135740deSSeth Forshee dev->hotkey_dev = NULL; 2469135740deSSeth Forshee return error; 2470135740deSSeth Forshee } 2471135740deSSeth Forshee 2472b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) 247362cce752SSeth Forshee { 247462cce752SSeth Forshee struct backlight_properties props; 247562cce752SSeth Forshee int brightness; 247662cce752SSeth Forshee int ret; 247762cce752SSeth Forshee 247862cce752SSeth Forshee /* 247962cce752SSeth Forshee * Some machines don't support the backlight methods at all, and 248062cce752SSeth Forshee * others support it read-only. Either of these is pretty useless, 248162cce752SSeth Forshee * so only register the backlight device if the backlight method 248262cce752SSeth Forshee * supports both reads and writes. 248362cce752SSeth Forshee */ 248462cce752SSeth Forshee brightness = __get_lcd_brightness(dev); 248562cce752SSeth Forshee if (brightness < 0) 248662cce752SSeth Forshee return 0; 2487*bae5336fSAzael Avalos /* 2488*bae5336fSAzael Avalos * If transflective backlight is supported and the brightness is zero 2489*bae5336fSAzael Avalos * (lowest brightness level), the set_lcd_brightness function will 2490*bae5336fSAzael Avalos * activate the transflective backlight, making the LCD appear to be 2491*bae5336fSAzael Avalos * turned off, simply increment the brightness level to avoid that. 2492*bae5336fSAzael Avalos */ 2493*bae5336fSAzael Avalos if (dev->tr_backlight_supported && brightness == 0) 2494*bae5336fSAzael Avalos brightness++; 249562cce752SSeth Forshee ret = set_lcd_brightness(dev, brightness); 249662cce752SSeth Forshee if (ret) { 249762cce752SSeth Forshee pr_debug("Backlight method is read-only, disabling backlight support\n"); 249862cce752SSeth Forshee return 0; 249962cce752SSeth Forshee } 250062cce752SSeth Forshee 2501358d6a2cSHans de Goede /* 2502358d6a2cSHans de Goede * Tell acpi-video-detect code to prefer vendor backlight on all 2503358d6a2cSHans de Goede * systems with transflective backlight and on dmi matched systems. 2504358d6a2cSHans de Goede */ 2505358d6a2cSHans de Goede if (dev->tr_backlight_supported || 2506358d6a2cSHans de Goede dmi_check_system(toshiba_vendor_backlight_dmi)) 2507234b7cf8SHans de Goede acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); 2508358d6a2cSHans de Goede 2509234b7cf8SHans de Goede if (acpi_video_get_backlight_type() != acpi_backlight_vendor) 2510358d6a2cSHans de Goede return 0; 2511358d6a2cSHans de Goede 251253039f22SMatthew Garrett memset(&props, 0, sizeof(props)); 251362cce752SSeth Forshee props.type = BACKLIGHT_PLATFORM; 251462cce752SSeth Forshee props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; 251562cce752SSeth Forshee 2516e0769fe6SDarren Hart /* Adding an extra level and having 0 change to transflective mode */ 2517121b7b0dSAkio Idehara if (dev->tr_backlight_supported) 2518121b7b0dSAkio Idehara props.max_brightness++; 2519121b7b0dSAkio Idehara 252062cce752SSeth Forshee dev->backlight_dev = backlight_device_register("toshiba", 252162cce752SSeth Forshee &dev->acpi_dev->dev, 252262cce752SSeth Forshee dev, 252362cce752SSeth Forshee &toshiba_backlight_data, 252462cce752SSeth Forshee &props); 252562cce752SSeth Forshee if (IS_ERR(dev->backlight_dev)) { 252662cce752SSeth Forshee ret = PTR_ERR(dev->backlight_dev); 252762cce752SSeth Forshee pr_err("Could not register toshiba backlight device\n"); 252862cce752SSeth Forshee dev->backlight_dev = NULL; 252962cce752SSeth Forshee return ret; 253062cce752SSeth Forshee } 253162cce752SSeth Forshee 253262cce752SSeth Forshee dev->backlight_dev->props.brightness = brightness; 253362cce752SSeth Forshee return 0; 253462cce752SSeth Forshee } 253562cce752SSeth Forshee 25360409cbceSAzael Avalos static void print_supported_features(struct toshiba_acpi_dev *dev) 25370409cbceSAzael Avalos { 25380409cbceSAzael Avalos pr_info("Supported laptop features:"); 25390409cbceSAzael Avalos 25400409cbceSAzael Avalos if (dev->hotkey_dev) 25410409cbceSAzael Avalos pr_cont(" hotkeys"); 25420409cbceSAzael Avalos if (dev->backlight_dev) 25430409cbceSAzael Avalos pr_cont(" backlight"); 25440409cbceSAzael Avalos if (dev->video_supported) 25450409cbceSAzael Avalos pr_cont(" video-out"); 25460409cbceSAzael Avalos if (dev->fan_supported) 25470409cbceSAzael Avalos pr_cont(" fan"); 25480409cbceSAzael Avalos if (dev->tr_backlight_supported) 25490409cbceSAzael Avalos pr_cont(" transflective-backlight"); 25500409cbceSAzael Avalos if (dev->illumination_supported) 25510409cbceSAzael Avalos pr_cont(" illumination"); 25520409cbceSAzael Avalos if (dev->kbd_illum_supported) 25530409cbceSAzael Avalos pr_cont(" keyboard-backlight"); 25540409cbceSAzael Avalos if (dev->touchpad_supported) 25550409cbceSAzael Avalos pr_cont(" touchpad"); 25560409cbceSAzael Avalos if (dev->eco_supported) 25570409cbceSAzael Avalos pr_cont(" eco-led"); 25580409cbceSAzael Avalos if (dev->accelerometer_supported) 25590409cbceSAzael Avalos pr_cont(" accelerometer-axes"); 25600409cbceSAzael Avalos if (dev->usb_sleep_charge_supported) 25610409cbceSAzael Avalos pr_cont(" usb-sleep-charge"); 25620409cbceSAzael Avalos if (dev->usb_rapid_charge_supported) 25630409cbceSAzael Avalos pr_cont(" usb-rapid-charge"); 25640409cbceSAzael Avalos if (dev->usb_sleep_music_supported) 25650409cbceSAzael Avalos pr_cont(" usb-sleep-music"); 25660409cbceSAzael Avalos if (dev->kbd_function_keys_supported) 25670409cbceSAzael Avalos pr_cont(" special-function-keys"); 25680409cbceSAzael Avalos if (dev->panel_power_on_supported) 25690409cbceSAzael Avalos pr_cont(" panel-power-on"); 25700409cbceSAzael Avalos if (dev->usb_three_supported) 25710409cbceSAzael Avalos pr_cont(" usb3"); 25720409cbceSAzael Avalos 25730409cbceSAzael Avalos pr_cont("\n"); 25740409cbceSAzael Avalos } 25750409cbceSAzael Avalos 257651fac838SRafael J. Wysocki static int toshiba_acpi_remove(struct acpi_device *acpi_dev) 2577135740deSSeth Forshee { 2578135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 2579135740deSSeth Forshee 2580fc5462f8SAzael Avalos misc_deregister(&dev->miscdev); 2581fc5462f8SAzael Avalos 258236d03f93SSeth Forshee remove_toshiba_proc_entries(dev); 2583135740deSSeth Forshee 2584360f0f39SAzael Avalos if (dev->sysfs_created) 2585360f0f39SAzael Avalos sysfs_remove_group(&dev->acpi_dev->dev.kobj, 2586360f0f39SAzael Avalos &toshiba_attr_group); 2587360f0f39SAzael Avalos 258829cd293fSSeth Forshee if (dev->ntfy_supported) { 258929cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 259029cd293fSSeth Forshee cancel_work_sync(&dev->hotkey_work); 259129cd293fSSeth Forshee } 259229cd293fSSeth Forshee 2593135740deSSeth Forshee if (dev->hotkey_dev) { 2594135740deSSeth Forshee input_unregister_device(dev->hotkey_dev); 2595135740deSSeth Forshee sparse_keymap_free(dev->hotkey_dev); 2596135740deSSeth Forshee } 2597135740deSSeth Forshee 2598135740deSSeth Forshee backlight_device_unregister(dev->backlight_dev); 2599135740deSSeth Forshee 2600ea215a3fSAzael Avalos if (dev->illumination_led_registered) 2601135740deSSeth Forshee led_classdev_unregister(&dev->led_dev); 2602135740deSSeth Forshee 2603360f0f39SAzael Avalos if (dev->kbd_led_registered) 2604360f0f39SAzael Avalos led_classdev_unregister(&dev->kbd_led); 2605360f0f39SAzael Avalos 2606ea215a3fSAzael Avalos if (dev->eco_led_registered) 2607def6c4e2SAzael Avalos led_classdev_unregister(&dev->eco_led); 2608def6c4e2SAzael Avalos 260929cd293fSSeth Forshee if (toshiba_acpi) 261029cd293fSSeth Forshee toshiba_acpi = NULL; 261129cd293fSSeth Forshee 2612135740deSSeth Forshee kfree(dev); 2613135740deSSeth Forshee 2614135740deSSeth Forshee return 0; 2615135740deSSeth Forshee } 2616135740deSSeth Forshee 2617b859f159SGreg Kroah-Hartman static const char *find_hci_method(acpi_handle handle) 2618a540d6b5SSeth Forshee { 2619e2e19606SZhang Rui if (acpi_has_method(handle, "GHCI")) 2620a540d6b5SSeth Forshee return "GHCI"; 2621a540d6b5SSeth Forshee 2622e2e19606SZhang Rui if (acpi_has_method(handle, "SPFC")) 2623a540d6b5SSeth Forshee return "SPFC"; 2624a540d6b5SSeth Forshee 2625a540d6b5SSeth Forshee return NULL; 2626a540d6b5SSeth Forshee } 2627a540d6b5SSeth Forshee 2628b859f159SGreg Kroah-Hartman static int toshiba_acpi_add(struct acpi_device *acpi_dev) 2629135740deSSeth Forshee { 2630135740deSSeth Forshee struct toshiba_acpi_dev *dev; 2631a540d6b5SSeth Forshee const char *hci_method; 263236d03f93SSeth Forshee u32 dummy; 2633135740deSSeth Forshee int ret = 0; 2634135740deSSeth Forshee 263529cd293fSSeth Forshee if (toshiba_acpi) 263629cd293fSSeth Forshee return -EBUSY; 263729cd293fSSeth Forshee 2638135740deSSeth Forshee pr_info("Toshiba Laptop ACPI Extras version %s\n", 2639135740deSSeth Forshee TOSHIBA_ACPI_VERSION); 2640135740deSSeth Forshee 2641a540d6b5SSeth Forshee hci_method = find_hci_method(acpi_dev->handle); 2642a540d6b5SSeth Forshee if (!hci_method) { 2643a540d6b5SSeth Forshee pr_err("HCI interface not found\n"); 26446e02cc7eSSeth Forshee return -ENODEV; 2645a540d6b5SSeth Forshee } 26466e02cc7eSSeth Forshee 2647135740deSSeth Forshee dev = kzalloc(sizeof(*dev), GFP_KERNEL); 2648135740deSSeth Forshee if (!dev) 2649135740deSSeth Forshee return -ENOMEM; 2650135740deSSeth Forshee dev->acpi_dev = acpi_dev; 2651a540d6b5SSeth Forshee dev->method_hci = hci_method; 2652fc5462f8SAzael Avalos dev->miscdev.minor = MISC_DYNAMIC_MINOR; 2653fc5462f8SAzael Avalos dev->miscdev.name = "toshiba_acpi"; 2654fc5462f8SAzael Avalos dev->miscdev.fops = &toshiba_acpi_fops; 2655fc5462f8SAzael Avalos 2656fc5462f8SAzael Avalos ret = misc_register(&dev->miscdev); 2657fc5462f8SAzael Avalos if (ret) { 2658fc5462f8SAzael Avalos pr_err("Failed to register miscdevice\n"); 2659fc5462f8SAzael Avalos kfree(dev); 2660fc5462f8SAzael Avalos return ret; 2661fc5462f8SAzael Avalos } 2662fc5462f8SAzael Avalos 2663135740deSSeth Forshee acpi_dev->driver_data = dev; 2664360f0f39SAzael Avalos dev_set_drvdata(&acpi_dev->dev, dev); 2665135740deSSeth Forshee 2666a2b3471bSAzael Avalos /* Query the BIOS for supported features */ 2667a2b3471bSAzael Avalos 2668a2b3471bSAzael Avalos /* 2669a2b3471bSAzael Avalos * The "Special Functions" are always supported by the laptops 2670a2b3471bSAzael Avalos * with the new keyboard layout, query for its presence to help 2671a2b3471bSAzael Avalos * determine the keymap layout to use. 2672a2b3471bSAzael Avalos */ 2673b116fd00SAzael Avalos ret = toshiba_function_keys_get(dev, &dev->special_functions); 2674a2b3471bSAzael Avalos dev->kbd_function_keys_supported = !ret; 2675a2b3471bSAzael Avalos 2676d2f20619SAzael Avalos dev->hotkey_event_type = 0; 26776e02cc7eSSeth Forshee if (toshiba_acpi_setup_keyboard(dev)) 2678135740deSSeth Forshee pr_info("Unable to activate hotkeys\n"); 2679135740deSSeth Forshee 2680695f6060SAzael Avalos /* Determine whether or not BIOS supports transflective backlight */ 2681695f6060SAzael Avalos ret = get_tr_backlight_status(dev, &dummy); 2682695f6060SAzael Avalos dev->tr_backlight_supported = !ret; 2683695f6060SAzael Avalos 268462cce752SSeth Forshee ret = toshiba_acpi_setup_backlight(dev); 268562cce752SSeth Forshee if (ret) 2686135740deSSeth Forshee goto error; 2687135740deSSeth Forshee 2688ea215a3fSAzael Avalos toshiba_illumination_available(dev); 2689ea215a3fSAzael Avalos if (dev->illumination_supported) { 2690135740deSSeth Forshee dev->led_dev.name = "toshiba::illumination"; 2691135740deSSeth Forshee dev->led_dev.max_brightness = 1; 2692135740deSSeth Forshee dev->led_dev.brightness_set = toshiba_illumination_set; 2693135740deSSeth Forshee dev->led_dev.brightness_get = toshiba_illumination_get; 2694135740deSSeth Forshee if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev)) 2695ea215a3fSAzael Avalos dev->illumination_led_registered = true; 2696135740deSSeth Forshee } 2697135740deSSeth Forshee 2698ea215a3fSAzael Avalos toshiba_eco_mode_available(dev); 2699ea215a3fSAzael Avalos if (dev->eco_supported) { 2700def6c4e2SAzael Avalos dev->eco_led.name = "toshiba::eco_mode"; 2701def6c4e2SAzael Avalos dev->eco_led.max_brightness = 1; 2702def6c4e2SAzael Avalos dev->eco_led.brightness_set = toshiba_eco_mode_set_status; 2703def6c4e2SAzael Avalos dev->eco_led.brightness_get = toshiba_eco_mode_get_status; 2704def6c4e2SAzael Avalos if (!led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led)) 2705ea215a3fSAzael Avalos dev->eco_led_registered = true; 2706def6c4e2SAzael Avalos } 2707def6c4e2SAzael Avalos 2708ea215a3fSAzael Avalos toshiba_kbd_illum_available(dev); 2709360f0f39SAzael Avalos /* 2710360f0f39SAzael Avalos * Only register the LED if KBD illumination is supported 2711360f0f39SAzael Avalos * and the keyboard backlight operation mode is set to FN-Z 2712360f0f39SAzael Avalos */ 2713360f0f39SAzael Avalos if (dev->kbd_illum_supported && dev->kbd_mode == SCI_KBD_MODE_FNZ) { 2714360f0f39SAzael Avalos dev->kbd_led.name = "toshiba::kbd_backlight"; 2715360f0f39SAzael Avalos dev->kbd_led.max_brightness = 1; 2716360f0f39SAzael Avalos dev->kbd_led.brightness_set = toshiba_kbd_backlight_set; 2717360f0f39SAzael Avalos dev->kbd_led.brightness_get = toshiba_kbd_backlight_get; 2718360f0f39SAzael Avalos if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led)) 2719ea215a3fSAzael Avalos dev->kbd_led_registered = true; 2720360f0f39SAzael Avalos } 2721360f0f39SAzael Avalos 27229d8658acSAzael Avalos ret = toshiba_touchpad_get(dev, &dummy); 27239d8658acSAzael Avalos dev->touchpad_supported = !ret; 27249d8658acSAzael Avalos 2725ea215a3fSAzael Avalos toshiba_accelerometer_available(dev); 27265a2813e9SAzael Avalos 2727c8c91842SAzael Avalos toshiba_usb_sleep_charge_available(dev); 2728e26ffe51SAzael Avalos 2729bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(dev, &dummy); 2730bb3fe01fSAzael Avalos dev->usb_rapid_charge_supported = !ret; 2731bb3fe01fSAzael Avalos 2732172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(dev, &dummy); 2733172ce0a9SAzael Avalos dev->usb_sleep_music_supported = !ret; 2734172ce0a9SAzael Avalos 273535d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(dev, &dummy); 273635d53ceaSAzael Avalos dev->panel_power_on_supported = !ret; 273735d53ceaSAzael Avalos 273817fe4b3dSAzael Avalos ret = toshiba_usb_three_get(dev, &dummy); 273917fe4b3dSAzael Avalos dev->usb_three_supported = !ret; 274017fe4b3dSAzael Avalos 274136d03f93SSeth Forshee ret = get_video_status(dev, &dummy); 274236d03f93SSeth Forshee dev->video_supported = !ret; 274336d03f93SSeth Forshee 274436d03f93SSeth Forshee ret = get_fan_status(dev, &dummy); 274536d03f93SSeth Forshee dev->fan_supported = !ret; 274636d03f93SSeth Forshee 27470409cbceSAzael Avalos print_supported_features(dev); 27480409cbceSAzael Avalos 2749360f0f39SAzael Avalos ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, 2750360f0f39SAzael Avalos &toshiba_attr_group); 2751360f0f39SAzael Avalos if (ret) { 2752360f0f39SAzael Avalos dev->sysfs_created = 0; 2753360f0f39SAzael Avalos goto error; 2754360f0f39SAzael Avalos } 2755360f0f39SAzael Avalos dev->sysfs_created = !ret; 2756360f0f39SAzael Avalos 275736d03f93SSeth Forshee create_toshiba_proc_entries(dev); 275836d03f93SSeth Forshee 275929cd293fSSeth Forshee toshiba_acpi = dev; 276029cd293fSSeth Forshee 2761135740deSSeth Forshee return 0; 2762135740deSSeth Forshee 2763135740deSSeth Forshee error: 276451fac838SRafael J. Wysocki toshiba_acpi_remove(acpi_dev); 2765135740deSSeth Forshee return ret; 2766135740deSSeth Forshee } 2767135740deSSeth Forshee 2768135740deSSeth Forshee static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) 2769135740deSSeth Forshee { 2770135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 277180546905SAzael Avalos int ret; 27726335e4d5SMatthew Garrett 277371454d78SAzael Avalos switch (event) { 277471454d78SAzael Avalos case 0x80: /* Hotkeys and some system events */ 2775a88bc06eSAzael Avalos /* 2776a88bc06eSAzael Avalos * Machines with this WMI GUID aren't supported due to bugs in 2777a88bc06eSAzael Avalos * their AML. 2778a88bc06eSAzael Avalos * 2779a88bc06eSAzael Avalos * Return silently to avoid triggering a netlink event. 2780a88bc06eSAzael Avalos */ 2781a88bc06eSAzael Avalos if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) 2782a88bc06eSAzael Avalos return; 278371454d78SAzael Avalos toshiba_acpi_process_hotkeys(dev); 278411948b93SSeth Forshee break; 2785bab09e23SAzael Avalos case 0x81: /* Dock events */ 2786bab09e23SAzael Avalos case 0x82: 2787bab09e23SAzael Avalos case 0x83: 2788bab09e23SAzael Avalos pr_info("Dock event received %x\n", event); 2789bab09e23SAzael Avalos break; 2790bab09e23SAzael Avalos case 0x88: /* Thermal events */ 2791bab09e23SAzael Avalos pr_info("Thermal event received\n"); 2792bab09e23SAzael Avalos break; 2793bab09e23SAzael Avalos case 0x8f: /* LID closed */ 2794bab09e23SAzael Avalos case 0x90: /* LID is closed and Dock has been ejected */ 2795bab09e23SAzael Avalos break; 2796bab09e23SAzael Avalos case 0x8c: /* SATA power events */ 2797bab09e23SAzael Avalos case 0x8b: 2798bab09e23SAzael Avalos pr_info("SATA power event received %x\n", event); 2799bab09e23SAzael Avalos break; 280080546905SAzael Avalos case 0x92: /* Keyboard backlight mode changed */ 280180546905SAzael Avalos /* Update sysfs entries */ 280280546905SAzael Avalos ret = sysfs_update_group(&acpi_dev->dev.kobj, 280380546905SAzael Avalos &toshiba_attr_group); 280480546905SAzael Avalos if (ret) 280580546905SAzael Avalos pr_err("Unable to update sysfs entries\n"); 280680546905SAzael Avalos break; 2807bab09e23SAzael Avalos case 0x85: /* Unknown */ 2808bab09e23SAzael Avalos case 0x8d: /* Unknown */ 280971454d78SAzael Avalos case 0x8e: /* Unknown */ 2810bab09e23SAzael Avalos case 0x94: /* Unknown */ 2811bab09e23SAzael Avalos case 0x95: /* Unknown */ 281211948b93SSeth Forshee default: 281371454d78SAzael Avalos pr_info("Unknown event received %x\n", event); 281411948b93SSeth Forshee break; 28156335e4d5SMatthew Garrett } 2816bab09e23SAzael Avalos 2817bab09e23SAzael Avalos acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class, 2818bab09e23SAzael Avalos dev_name(&acpi_dev->dev), 281913ae84f9SAzael Avalos event, (event == 0x80) ? 282013ae84f9SAzael Avalos dev->last_key_event : 0); 282129cd293fSSeth Forshee } 28226335e4d5SMatthew Garrett 28233567a4e2SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 282443d2fd3bSRafael J. Wysocki static int toshiba_acpi_suspend(struct device *device) 282529cd293fSSeth Forshee { 282643d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 28271e574dbfSAzael Avalos 28281e574dbfSAzael Avalos if (dev->hotkey_dev) { 282929cd293fSSeth Forshee u32 result; 283029cd293fSSeth Forshee 2831d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE); 28321e574dbfSAzael Avalos if (result != TOS_SUCCESS) 28331e574dbfSAzael Avalos pr_info("Unable to disable hotkeys\n"); 28341e574dbfSAzael Avalos } 283529cd293fSSeth Forshee 283629cd293fSSeth Forshee return 0; 283729cd293fSSeth Forshee } 283829cd293fSSeth Forshee 283943d2fd3bSRafael J. Wysocki static int toshiba_acpi_resume(struct device *device) 284029cd293fSSeth Forshee { 284143d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 284229cd293fSSeth Forshee 2843e7fdb762SBenjamin Tissoires if (dev->hotkey_dev) { 28441e574dbfSAzael Avalos int error = toshiba_acpi_enable_hotkeys(dev); 28451e574dbfSAzael Avalos 28461f28f290SAzael Avalos if (error) 2847e7fdb762SBenjamin Tissoires pr_info("Unable to re-enable hotkeys\n"); 2848e7fdb762SBenjamin Tissoires } 284929cd293fSSeth Forshee 285029cd293fSSeth Forshee return 0; 285129cd293fSSeth Forshee } 28523567a4e2SRafael J. Wysocki #endif 28536335e4d5SMatthew Garrett 285443d2fd3bSRafael J. Wysocki static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm, 285543d2fd3bSRafael J. Wysocki toshiba_acpi_suspend, toshiba_acpi_resume); 285643d2fd3bSRafael J. Wysocki 2857135740deSSeth Forshee static struct acpi_driver toshiba_acpi_driver = { 2858135740deSSeth Forshee .name = "Toshiba ACPI driver", 2859135740deSSeth Forshee .owner = THIS_MODULE, 2860135740deSSeth Forshee .ids = toshiba_device_ids, 2861135740deSSeth Forshee .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, 2862135740deSSeth Forshee .ops = { 2863135740deSSeth Forshee .add = toshiba_acpi_add, 2864135740deSSeth Forshee .remove = toshiba_acpi_remove, 2865135740deSSeth Forshee .notify = toshiba_acpi_notify, 2866135740deSSeth Forshee }, 286743d2fd3bSRafael J. Wysocki .drv.pm = &toshiba_acpi_pm, 2868135740deSSeth Forshee }; 2869b4f9fe12SLen Brown 2870b4f9fe12SLen Brown static int __init toshiba_acpi_init(void) 2871b4f9fe12SLen Brown { 2872135740deSSeth Forshee int ret; 2873b4f9fe12SLen Brown 2874b4f9fe12SLen Brown toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); 2875b4f9fe12SLen Brown if (!toshiba_proc_dir) { 2876135740deSSeth Forshee pr_err("Unable to create proc dir " PROC_TOSHIBA "\n"); 2877b4f9fe12SLen Brown return -ENODEV; 2878b4f9fe12SLen Brown } 2879b4f9fe12SLen Brown 2880135740deSSeth Forshee ret = acpi_bus_register_driver(&toshiba_acpi_driver); 2881b4f9fe12SLen Brown if (ret) { 2882135740deSSeth Forshee pr_err("Failed to register ACPI driver: %d\n", ret); 2883135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 2884135740deSSeth Forshee } 2885135740deSSeth Forshee 2886b4f9fe12SLen Brown return ret; 2887b4f9fe12SLen Brown } 2888b4f9fe12SLen Brown 2889135740deSSeth Forshee static void __exit toshiba_acpi_exit(void) 2890135740deSSeth Forshee { 2891135740deSSeth Forshee acpi_bus_unregister_driver(&toshiba_acpi_driver); 2892135740deSSeth Forshee if (toshiba_proc_dir) 2893135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 2894b4f9fe12SLen Brown } 2895b4f9fe12SLen Brown 2896b4f9fe12SLen Brown module_init(toshiba_acpi_init); 2897b4f9fe12SLen Brown module_exit(toshiba_acpi_exit); 2898