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> 542fdde834SAzael Avalos #include <linux/rfkill.h> 55fc5462f8SAzael Avalos #include <linux/toshiba.h> 56358d6a2cSHans de Goede #include <acpi/video.h> 57b4f9fe12SLen Brown 58b4f9fe12SLen Brown MODULE_AUTHOR("John Belmonte"); 59b4f9fe12SLen Brown MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); 60b4f9fe12SLen Brown MODULE_LICENSE("GPL"); 61b4f9fe12SLen Brown 62f11f999eSSeth Forshee #define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100" 63f11f999eSSeth Forshee 6429cd293fSSeth Forshee /* Scan code for Fn key on TOS1900 models */ 6529cd293fSSeth Forshee #define TOS1900_FN_SCAN 0x6e 6629cd293fSSeth Forshee 67b4f9fe12SLen Brown /* Toshiba ACPI method paths */ 68b4f9fe12SLen Brown #define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX" 69b4f9fe12SLen Brown 70e0769fe6SDarren Hart /* 71e0769fe6SDarren Hart * The Toshiba configuration interface is composed of the HCI and the SCI, 72258c5903SAzael Avalos * which are defined as follows: 73b4f9fe12SLen Brown * 74b4f9fe12SLen Brown * HCI is Toshiba's "Hardware Control Interface" which is supposed to 75b4f9fe12SLen Brown * be uniform across all their models. Ideally we would just call 76b4f9fe12SLen Brown * dedicated ACPI methods instead of using this primitive interface. 77b4f9fe12SLen Brown * However the ACPI methods seem to be incomplete in some areas (for 78b4f9fe12SLen Brown * example they allow setting, but not reading, the LCD brightness value), 79b4f9fe12SLen Brown * so this is still useful. 8084a6273fSAzael Avalos * 8184a6273fSAzael Avalos * SCI stands for "System Configuration Interface" which aim is to 8284a6273fSAzael Avalos * conceal differences in hardware between different models. 83b4f9fe12SLen Brown */ 84b4f9fe12SLen Brown 85258c5903SAzael Avalos #define TCI_WORDS 6 86b4f9fe12SLen Brown 873f75bbe9SAzael Avalos /* Operations */ 88b4f9fe12SLen Brown #define HCI_SET 0xff00 89b4f9fe12SLen Brown #define HCI_GET 0xfe00 9084a6273fSAzael Avalos #define SCI_OPEN 0xf100 9184a6273fSAzael Avalos #define SCI_CLOSE 0xf200 9284a6273fSAzael Avalos #define SCI_GET 0xf300 9384a6273fSAzael Avalos #define SCI_SET 0xf400 94b4f9fe12SLen Brown 953f75bbe9SAzael Avalos /* Return codes */ 961864bbc2SAzael Avalos #define TOS_SUCCESS 0x0000 97e1a949c1SAzael Avalos #define TOS_SUCCESS2 0x0001 981864bbc2SAzael Avalos #define TOS_OPEN_CLOSE_OK 0x0044 991864bbc2SAzael Avalos #define TOS_FAILURE 0x1000 1001864bbc2SAzael Avalos #define TOS_NOT_SUPPORTED 0x8000 1011864bbc2SAzael Avalos #define TOS_ALREADY_OPEN 0x8100 1021864bbc2SAzael Avalos #define TOS_NOT_OPENED 0x8200 1031864bbc2SAzael Avalos #define TOS_INPUT_DATA_ERROR 0x8300 1041864bbc2SAzael Avalos #define TOS_WRITE_PROTECTED 0x8400 1051864bbc2SAzael Avalos #define TOS_NOT_PRESENT 0x8600 1061864bbc2SAzael Avalos #define TOS_FIFO_EMPTY 0x8c00 1071864bbc2SAzael Avalos #define TOS_DATA_NOT_AVAILABLE 0x8d20 1081864bbc2SAzael Avalos #define TOS_NOT_INITIALIZED 0x8d50 10998fc4ec6SAzael Avalos #define TOS_NOT_INSTALLED 0x8e00 110b4f9fe12SLen Brown 1113f75bbe9SAzael Avalos /* Registers */ 112b4f9fe12SLen Brown #define HCI_FAN 0x0004 113121b7b0dSAkio Idehara #define HCI_TR_BACKLIGHT 0x0005 114b4f9fe12SLen Brown #define HCI_SYSTEM_EVENT 0x0016 115b4f9fe12SLen Brown #define HCI_VIDEO_OUT 0x001c 116b4f9fe12SLen Brown #define HCI_HOTKEY_EVENT 0x001e 117b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS 0x002a 1186873f46aSAzael Avalos #define HCI_WIRELESS 0x0056 1195a2813e9SAzael Avalos #define HCI_ACCELEROMETER 0x006d 120763ff32fSAzael Avalos #define HCI_COOLING_METHOD 0x007f 121360f0f39SAzael Avalos #define HCI_KBD_ILLUMINATION 0x0095 122def6c4e2SAzael Avalos #define HCI_ECO_MODE 0x0097 1235a2813e9SAzael Avalos #define HCI_ACCELEROMETER2 0x00a6 12456e6b353SAzael Avalos #define HCI_SYSTEM_INFO 0xc000 12535d53ceaSAzael Avalos #define SCI_PANEL_POWER_ON 0x010d 126fdb79081SAzael Avalos #define SCI_ILLUMINATION 0x014e 127e26ffe51SAzael Avalos #define SCI_USB_SLEEP_CHARGE 0x0150 128360f0f39SAzael Avalos #define SCI_KBD_ILLUM_STATUS 0x015c 129172ce0a9SAzael Avalos #define SCI_USB_SLEEP_MUSIC 0x015e 13017fe4b3dSAzael Avalos #define SCI_USB_THREE 0x0169 1319d8658acSAzael Avalos #define SCI_TOUCHPAD 0x050e 132bae84195SAzael Avalos #define SCI_KBD_FUNCTION_KEYS 0x0522 133b4f9fe12SLen Brown 1343f75bbe9SAzael Avalos /* Field definitions */ 1355a2813e9SAzael Avalos #define HCI_ACCEL_MASK 0x7fff 13629cd293fSSeth Forshee #define HCI_HOTKEY_DISABLE 0x0b 13752cbae01SAzael Avalos #define HCI_HOTKEY_ENABLE 0x01 138fb42d1f4SAzael Avalos #define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10 139b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_BITS 3 140b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) 141b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS) 142360f0f39SAzael Avalos #define HCI_MISC_SHIFT 0x10 14356e6b353SAzael Avalos #define HCI_SYSTEM_TYPE1 0x10 14456e6b353SAzael Avalos #define HCI_SYSTEM_TYPE2 0x11 145b4f9fe12SLen Brown #define HCI_VIDEO_OUT_LCD 0x1 146b4f9fe12SLen Brown #define HCI_VIDEO_OUT_CRT 0x2 147b4f9fe12SLen Brown #define HCI_VIDEO_OUT_TV 0x4 14893f8c16dSAzael Avalos #define SCI_KBD_MODE_MASK 0x1f 149360f0f39SAzael Avalos #define SCI_KBD_MODE_FNZ 0x1 150360f0f39SAzael Avalos #define SCI_KBD_MODE_AUTO 0x2 15193f8c16dSAzael Avalos #define SCI_KBD_MODE_ON 0x8 15293f8c16dSAzael Avalos #define SCI_KBD_MODE_OFF 0x10 15393f8c16dSAzael Avalos #define SCI_KBD_TIME_MAX 0x3c001a 1546873f46aSAzael Avalos #define HCI_WIRELESS_STATUS 0x1 1556873f46aSAzael Avalos #define HCI_WIRELESS_WWAN 0x3 1566873f46aSAzael Avalos #define HCI_WIRELESS_WWAN_STATUS 0x2000 1576873f46aSAzael Avalos #define HCI_WIRELESS_WWAN_POWER 0x4000 158e26ffe51SAzael Avalos #define SCI_USB_CHARGE_MODE_MASK 0xff 159c8c91842SAzael Avalos #define SCI_USB_CHARGE_DISABLED 0x00 160c8c91842SAzael Avalos #define SCI_USB_CHARGE_ALTERNATE 0x09 161c8c91842SAzael Avalos #define SCI_USB_CHARGE_TYPICAL 0x11 162c8c91842SAzael Avalos #define SCI_USB_CHARGE_AUTO 0x21 163182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_MASK 0x7 164182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_OFF 0x1 165182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_ON 0x4 166182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL 0x0200 167bb3fe01fSAzael Avalos #define SCI_USB_CHARGE_RAPID_DSP 0x0300 168b4f9fe12SLen Brown 169135740deSSeth Forshee struct toshiba_acpi_dev { 170135740deSSeth Forshee struct acpi_device *acpi_dev; 171135740deSSeth Forshee const char *method_hci; 172135740deSSeth Forshee struct input_dev *hotkey_dev; 17329cd293fSSeth Forshee struct work_struct hotkey_work; 174135740deSSeth Forshee struct backlight_device *backlight_dev; 175135740deSSeth Forshee struct led_classdev led_dev; 176360f0f39SAzael Avalos struct led_classdev kbd_led; 177def6c4e2SAzael Avalos struct led_classdev eco_led; 178fc5462f8SAzael Avalos struct miscdevice miscdev; 1792fdde834SAzael Avalos struct rfkill *wwan_rfk; 18036d03f93SSeth Forshee 181135740deSSeth Forshee int force_fan; 182135740deSSeth Forshee int last_key_event; 183135740deSSeth Forshee int key_event_valid; 18493f8c16dSAzael Avalos int kbd_type; 185360f0f39SAzael Avalos int kbd_mode; 186360f0f39SAzael Avalos int kbd_time; 187182bcaa5SAzael Avalos int usbsc_bat_level; 188c8c91842SAzael Avalos int usbsc_mode_base; 189a2b3471bSAzael Avalos int hotkey_event_type; 190763ff32fSAzael Avalos int max_cooling_method; 191135740deSSeth Forshee 192592b746cSDan Carpenter unsigned int illumination_supported:1; 193592b746cSDan Carpenter unsigned int video_supported:1; 194592b746cSDan Carpenter unsigned int fan_supported:1; 195592b746cSDan Carpenter unsigned int system_event_supported:1; 19629cd293fSSeth Forshee unsigned int ntfy_supported:1; 19729cd293fSSeth Forshee unsigned int info_supported:1; 198121b7b0dSAkio Idehara unsigned int tr_backlight_supported:1; 199360f0f39SAzael Avalos unsigned int kbd_illum_supported:1; 2009d8658acSAzael Avalos unsigned int touchpad_supported:1; 201def6c4e2SAzael Avalos unsigned int eco_supported:1; 2025a2813e9SAzael Avalos unsigned int accelerometer_supported:1; 203e26ffe51SAzael Avalos unsigned int usb_sleep_charge_supported:1; 204bb3fe01fSAzael Avalos unsigned int usb_rapid_charge_supported:1; 205172ce0a9SAzael Avalos unsigned int usb_sleep_music_supported:1; 206bae84195SAzael Avalos unsigned int kbd_function_keys_supported:1; 20735d53ceaSAzael Avalos unsigned int panel_power_on_supported:1; 20817fe4b3dSAzael Avalos unsigned int usb_three_supported:1; 2096873f46aSAzael Avalos unsigned int wwan_supported:1; 210763ff32fSAzael Avalos unsigned int cooling_method_supported:1; 211360f0f39SAzael Avalos unsigned int sysfs_created:1; 212b116fd00SAzael Avalos unsigned int special_functions; 213ea215a3fSAzael Avalos 21465e3cf9cSAzael Avalos bool kbd_event_generated; 215ea215a3fSAzael Avalos bool kbd_led_registered; 216ea215a3fSAzael Avalos bool illumination_led_registered; 217ea215a3fSAzael Avalos bool eco_led_registered; 2186873f46aSAzael Avalos bool killswitch; 219135740deSSeth Forshee }; 220135740deSSeth Forshee 22129cd293fSSeth Forshee static struct toshiba_acpi_dev *toshiba_acpi; 22229cd293fSSeth Forshee 223b4f9fe12SLen Brown static const struct acpi_device_id toshiba_device_ids[] = { 224b4f9fe12SLen Brown {"TOS6200", 0}, 22563a9e016SOndrej Zary {"TOS6207", 0}, 226b4f9fe12SLen Brown {"TOS6208", 0}, 227b4f9fe12SLen Brown {"TOS1900", 0}, 228b4f9fe12SLen Brown {"", 0}, 229b4f9fe12SLen Brown }; 230b4f9fe12SLen Brown MODULE_DEVICE_TABLE(acpi, toshiba_device_ids); 231b4f9fe12SLen Brown 232b859f159SGreg Kroah-Hartman static const struct key_entry toshiba_acpi_keymap[] = { 233fec278a1SUnai Uribarri { KE_KEY, 0x9e, { KEY_RFKILL } }, 234384a7cd9SDmitry Torokhov { KE_KEY, 0x101, { KEY_MUTE } }, 235384a7cd9SDmitry Torokhov { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 236384a7cd9SDmitry Torokhov { KE_KEY, 0x103, { KEY_ZOOMIN } }, 237408a5d13SAzael Avalos { KE_KEY, 0x10f, { KEY_TAB } }, 238af502837SAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 239af502837SAzael Avalos { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 240384a7cd9SDmitry Torokhov { KE_KEY, 0x13b, { KEY_COFFEE } }, 241384a7cd9SDmitry Torokhov { KE_KEY, 0x13c, { KEY_BATTERY } }, 242384a7cd9SDmitry Torokhov { KE_KEY, 0x13d, { KEY_SLEEP } }, 243384a7cd9SDmitry Torokhov { KE_KEY, 0x13e, { KEY_SUSPEND } }, 244384a7cd9SDmitry Torokhov { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } }, 245384a7cd9SDmitry Torokhov { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } }, 246384a7cd9SDmitry Torokhov { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } }, 247384a7cd9SDmitry Torokhov { KE_KEY, 0x142, { KEY_WLAN } }, 248af502837SAzael Avalos { KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } }, 249a49010f5SJon Dowland { KE_KEY, 0x17f, { KEY_FN } }, 250384a7cd9SDmitry Torokhov { KE_KEY, 0xb05, { KEY_PROG2 } }, 251384a7cd9SDmitry Torokhov { KE_KEY, 0xb06, { KEY_WWW } }, 252384a7cd9SDmitry Torokhov { KE_KEY, 0xb07, { KEY_MAIL } }, 253384a7cd9SDmitry Torokhov { KE_KEY, 0xb30, { KEY_STOP } }, 254384a7cd9SDmitry Torokhov { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } }, 255384a7cd9SDmitry Torokhov { KE_KEY, 0xb32, { KEY_NEXTSONG } }, 256384a7cd9SDmitry Torokhov { KE_KEY, 0xb33, { KEY_PLAYPAUSE } }, 257384a7cd9SDmitry Torokhov { KE_KEY, 0xb5a, { KEY_MEDIA } }, 258408a5d13SAzael Avalos { KE_IGNORE, 0x1430, { KEY_RESERVED } }, /* Wake from sleep */ 259408a5d13SAzael Avalos { KE_IGNORE, 0x1501, { KEY_RESERVED } }, /* Output changed */ 260408a5d13SAzael Avalos { KE_IGNORE, 0x1502, { KEY_RESERVED } }, /* HDMI plugged/unplugged */ 261408a5d13SAzael Avalos { KE_IGNORE, 0x1ABE, { KEY_RESERVED } }, /* Protection level set */ 262408a5d13SAzael Avalos { KE_IGNORE, 0x1ABF, { KEY_RESERVED } }, /* Protection level off */ 263384a7cd9SDmitry Torokhov { KE_END, 0 }, 2646335e4d5SMatthew Garrett }; 2656335e4d5SMatthew Garrett 266fe808bfbSTakashi Iwai static const struct key_entry toshiba_acpi_alt_keymap[] = { 267fe808bfbSTakashi Iwai { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 268fe808bfbSTakashi Iwai { KE_KEY, 0x103, { KEY_ZOOMIN } }, 269e6efad7fSAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 270fe808bfbSTakashi Iwai { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 271fe808bfbSTakashi Iwai { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } }, 272fe808bfbSTakashi Iwai { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } }, 273d50c9005SAzael Avalos { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } }, 274fe808bfbSTakashi Iwai { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } }, 275d50c9005SAzael Avalos { KE_KEY, 0x157, { KEY_MUTE } }, 276d50c9005SAzael Avalos { KE_KEY, 0x158, { KEY_WLAN } }, 277fe808bfbSTakashi Iwai { KE_END, 0 }, 278fe808bfbSTakashi Iwai }; 279fe808bfbSTakashi Iwai 280e0769fe6SDarren Hart /* 281358d6a2cSHans de Goede * List of models which have a broken acpi-video backlight interface and thus 282358d6a2cSHans de Goede * need to use the toshiba (vendor) interface instead. 283358d6a2cSHans de Goede */ 284358d6a2cSHans de Goede static const struct dmi_system_id toshiba_vendor_backlight_dmi[] = { 285358d6a2cSHans de Goede {} 286358d6a2cSHans de Goede }; 287358d6a2cSHans de Goede 288358d6a2cSHans de Goede /* 289e0769fe6SDarren Hart * Utility 290b4f9fe12SLen Brown */ 291b4f9fe12SLen Brown 292b5163992SAzael Avalos static inline void _set_bit(u32 *word, u32 mask, int value) 293b4f9fe12SLen Brown { 294b4f9fe12SLen Brown *word = (*word & ~mask) | (mask * value); 295b4f9fe12SLen Brown } 296b4f9fe12SLen Brown 297e0769fe6SDarren Hart /* 298e0769fe6SDarren Hart * ACPI interface wrappers 299b4f9fe12SLen Brown */ 300b4f9fe12SLen Brown 301b4f9fe12SLen Brown static int write_acpi_int(const char *methodName, int val) 302b4f9fe12SLen Brown { 303b4f9fe12SLen Brown acpi_status status; 304b4f9fe12SLen Brown 305619400daSZhang Rui status = acpi_execute_simple_method(NULL, (char *)methodName, val); 30632bcd5cbSSeth Forshee return (status == AE_OK) ? 0 : -EIO; 307b4f9fe12SLen Brown } 308b4f9fe12SLen Brown 309e0769fe6SDarren Hart /* 310e0769fe6SDarren Hart * Perform a raw configuration call. Here we don't care about input or output 311258c5903SAzael Avalos * buffer format. 312b4f9fe12SLen Brown */ 313258c5903SAzael Avalos static acpi_status tci_raw(struct toshiba_acpi_dev *dev, 314258c5903SAzael Avalos const u32 in[TCI_WORDS], u32 out[TCI_WORDS]) 315b4f9fe12SLen Brown { 316b4f9fe12SLen Brown struct acpi_object_list params; 317258c5903SAzael Avalos union acpi_object in_objs[TCI_WORDS]; 318b4f9fe12SLen Brown struct acpi_buffer results; 319258c5903SAzael Avalos union acpi_object out_objs[TCI_WORDS + 1]; 320b4f9fe12SLen Brown acpi_status status; 321b4f9fe12SLen Brown int i; 322b4f9fe12SLen Brown 323258c5903SAzael Avalos params.count = TCI_WORDS; 324b4f9fe12SLen Brown params.pointer = in_objs; 325258c5903SAzael Avalos for (i = 0; i < TCI_WORDS; ++i) { 326b4f9fe12SLen Brown in_objs[i].type = ACPI_TYPE_INTEGER; 327b4f9fe12SLen Brown in_objs[i].integer.value = in[i]; 328b4f9fe12SLen Brown } 329b4f9fe12SLen Brown 330b4f9fe12SLen Brown results.length = sizeof(out_objs); 331b4f9fe12SLen Brown results.pointer = out_objs; 332b4f9fe12SLen Brown 3336e02cc7eSSeth Forshee status = acpi_evaluate_object(dev->acpi_dev->handle, 3346e02cc7eSSeth Forshee (char *)dev->method_hci, ¶ms, 335b4f9fe12SLen Brown &results); 336258c5903SAzael Avalos if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) { 337b5163992SAzael Avalos for (i = 0; i < out_objs->package.count; ++i) 338b4f9fe12SLen Brown out[i] = out_objs->package.elements[i].integer.value; 339b4f9fe12SLen Brown } 340b4f9fe12SLen Brown 341b4f9fe12SLen Brown return status; 342b4f9fe12SLen Brown } 343b4f9fe12SLen Brown 344e0769fe6SDarren Hart /* 345d37782bdSAzael Avalos * Common hci tasks 346b4f9fe12SLen Brown * 347b4f9fe12SLen Brown * In addition to the ACPI status, the HCI system returns a result which 348b4f9fe12SLen Brown * may be useful (such as "not supported"). 349b4f9fe12SLen Brown */ 350b4f9fe12SLen Brown 351d37782bdSAzael Avalos static u32 hci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 352b4f9fe12SLen Brown { 353258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 }; 354258c5903SAzael Avalos u32 out[TCI_WORDS]; 355258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 356893f3f62SAzael Avalos 357893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 358b4f9fe12SLen Brown } 359b4f9fe12SLen Brown 360d37782bdSAzael Avalos static u32 hci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 361b4f9fe12SLen Brown { 362258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 }; 363258c5903SAzael Avalos u32 out[TCI_WORDS]; 364258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 365b5163992SAzael Avalos 366893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 367893f3f62SAzael Avalos return TOS_FAILURE; 368893f3f62SAzael Avalos 369b4f9fe12SLen Brown *out1 = out[2]; 370893f3f62SAzael Avalos 371893f3f62SAzael Avalos return out[0]; 372b4f9fe12SLen Brown } 373b4f9fe12SLen Brown 374e0769fe6SDarren Hart /* 375e0769fe6SDarren Hart * Common sci tasks 37684a6273fSAzael Avalos */ 37784a6273fSAzael Avalos 37884a6273fSAzael Avalos static int sci_open(struct toshiba_acpi_dev *dev) 37984a6273fSAzael Avalos { 380258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 }; 381258c5903SAzael Avalos u32 out[TCI_WORDS]; 38284a6273fSAzael Avalos acpi_status status; 38384a6273fSAzael Avalos 384258c5903SAzael Avalos status = tci_raw(dev, in, out); 3858baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 38684a6273fSAzael Avalos pr_err("ACPI call to open SCI failed\n"); 38784a6273fSAzael Avalos return 0; 38884a6273fSAzael Avalos } 38984a6273fSAzael Avalos 3901864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) { 39184a6273fSAzael Avalos return 1; 3921864bbc2SAzael Avalos } else if (out[0] == TOS_ALREADY_OPEN) { 39384a6273fSAzael Avalos pr_info("Toshiba SCI already opened\n"); 39484a6273fSAzael Avalos return 1; 395fa465739SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 396e0769fe6SDarren Hart /* 397e0769fe6SDarren Hart * Some BIOSes do not have the SCI open/close functions 398fa465739SAzael Avalos * implemented and return 0x8000 (Not Supported), failing to 399fa465739SAzael Avalos * register some supported features. 400fa465739SAzael Avalos * 401fa465739SAzael Avalos * Simply return 1 if we hit those affected laptops to make the 402fa465739SAzael Avalos * supported features work. 403fa465739SAzael Avalos * 404fa465739SAzael Avalos * In the case that some laptops really do not support the SCI, 405fa465739SAzael Avalos * all the SCI dependent functions check for TOS_NOT_SUPPORTED, 406fa465739SAzael Avalos * and thus, not registering support for the queried feature. 407fa465739SAzael Avalos */ 408fa465739SAzael Avalos return 1; 4091864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_PRESENT) { 41084a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 41184a6273fSAzael Avalos } 41284a6273fSAzael Avalos 41384a6273fSAzael Avalos return 0; 41484a6273fSAzael Avalos } 41584a6273fSAzael Avalos 41684a6273fSAzael Avalos static void sci_close(struct toshiba_acpi_dev *dev) 41784a6273fSAzael Avalos { 418258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 }; 419258c5903SAzael Avalos u32 out[TCI_WORDS]; 42084a6273fSAzael Avalos acpi_status status; 42184a6273fSAzael Avalos 422258c5903SAzael Avalos status = tci_raw(dev, in, out); 4238baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 42484a6273fSAzael Avalos pr_err("ACPI call to close SCI failed\n"); 42584a6273fSAzael Avalos return; 42684a6273fSAzael Avalos } 42784a6273fSAzael Avalos 4281864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) 42984a6273fSAzael Avalos return; 4301864bbc2SAzael Avalos else if (out[0] == TOS_NOT_OPENED) 43184a6273fSAzael Avalos pr_info("Toshiba SCI not opened\n"); 4321864bbc2SAzael Avalos else if (out[0] == TOS_NOT_PRESENT) 43384a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 43484a6273fSAzael Avalos } 43584a6273fSAzael Avalos 436893f3f62SAzael Avalos static u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 43784a6273fSAzael Avalos { 438258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 }; 439258c5903SAzael Avalos u32 out[TCI_WORDS]; 440258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 441b5163992SAzael Avalos 442893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 443893f3f62SAzael Avalos return TOS_FAILURE; 444893f3f62SAzael Avalos 44584a6273fSAzael Avalos *out1 = out[2]; 446893f3f62SAzael Avalos 447893f3f62SAzael Avalos return out[0]; 44884a6273fSAzael Avalos } 44984a6273fSAzael Avalos 450893f3f62SAzael Avalos static u32 sci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 45184a6273fSAzael Avalos { 452258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 }; 453258c5903SAzael Avalos u32 out[TCI_WORDS]; 454258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 455893f3f62SAzael Avalos 456893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 45784a6273fSAzael Avalos } 45884a6273fSAzael Avalos 4596c3f6e6cSPierre Ducroquet /* Illumination support */ 460ea215a3fSAzael Avalos static void toshiba_illumination_available(struct toshiba_acpi_dev *dev) 4616c3f6e6cSPierre Ducroquet { 462258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 }; 463258c5903SAzael Avalos u32 out[TCI_WORDS]; 4646c3f6e6cSPierre Ducroquet acpi_status status; 4656c3f6e6cSPierre Ducroquet 466ea215a3fSAzael Avalos dev->illumination_supported = 0; 467ea215a3fSAzael Avalos dev->illumination_led_registered = false; 468ea215a3fSAzael Avalos 469fdb79081SAzael Avalos if (!sci_open(dev)) 470ea215a3fSAzael Avalos return; 471fdb79081SAzael Avalos 472258c5903SAzael Avalos status = tci_raw(dev, in, out); 473fdb79081SAzael Avalos sci_close(dev); 474ea215a3fSAzael Avalos if (ACPI_FAILURE(status)) 475fdb79081SAzael Avalos pr_err("ACPI call to query Illumination support failed\n"); 476ea215a3fSAzael Avalos else if (out[0] == TOS_SUCCESS) 477ea215a3fSAzael Avalos dev->illumination_supported = 1; 4786c3f6e6cSPierre Ducroquet } 4796c3f6e6cSPierre Ducroquet 4806c3f6e6cSPierre Ducroquet static void toshiba_illumination_set(struct led_classdev *cdev, 4816c3f6e6cSPierre Ducroquet enum led_brightness brightness) 4826c3f6e6cSPierre Ducroquet { 483135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 484135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 485e1a949c1SAzael Avalos u32 result; 486e1a949c1SAzael Avalos u32 state; 4876c3f6e6cSPierre Ducroquet 4886c3f6e6cSPierre Ducroquet /* First request : initialize communication. */ 489fdb79081SAzael Avalos if (!sci_open(dev)) 4906c3f6e6cSPierre Ducroquet return; 4916c3f6e6cSPierre Ducroquet 492fdb79081SAzael Avalos /* Switch the illumination on/off */ 493fdb79081SAzael Avalos state = brightness ? 1 : 0; 494893f3f62SAzael Avalos result = sci_write(dev, SCI_ILLUMINATION, state); 495fdb79081SAzael Avalos sci_close(dev); 496a6b5354fSAzael Avalos if (result == TOS_FAILURE) 497fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 4986c3f6e6cSPierre Ducroquet } 4996c3f6e6cSPierre Ducroquet 5006c3f6e6cSPierre Ducroquet static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) 5016c3f6e6cSPierre Ducroquet { 502135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 503135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 504fdb79081SAzael Avalos u32 state, result; 5056c3f6e6cSPierre Ducroquet 5063f75bbe9SAzael Avalos /* First request : initialize communication. */ 507fdb79081SAzael Avalos if (!sci_open(dev)) 5086c3f6e6cSPierre Ducroquet return LED_OFF; 5096c3f6e6cSPierre Ducroquet 5106c3f6e6cSPierre Ducroquet /* Check the illumination */ 511893f3f62SAzael Avalos result = sci_read(dev, SCI_ILLUMINATION, &state); 512fdb79081SAzael Avalos sci_close(dev); 513a6b5354fSAzael Avalos if (result == TOS_FAILURE) { 514fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 515fdb79081SAzael Avalos return LED_OFF; 516e1a949c1SAzael Avalos } else if (result != TOS_SUCCESS) { 5176c3f6e6cSPierre Ducroquet return LED_OFF; 5186c3f6e6cSPierre Ducroquet } 5196c3f6e6cSPierre Ducroquet 520fdb79081SAzael Avalos return state ? LED_FULL : LED_OFF; 5216c3f6e6cSPierre Ducroquet } 5226c3f6e6cSPierre Ducroquet 523360f0f39SAzael Avalos /* KBD Illumination */ 524ea215a3fSAzael Avalos static void toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev) 52593f8c16dSAzael Avalos { 526258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 }; 527258c5903SAzael Avalos u32 out[TCI_WORDS]; 52893f8c16dSAzael Avalos acpi_status status; 52993f8c16dSAzael Avalos 530ea215a3fSAzael Avalos dev->kbd_illum_supported = 0; 531ea215a3fSAzael Avalos dev->kbd_led_registered = false; 53265e3cf9cSAzael Avalos dev->kbd_event_generated = false; 533ea215a3fSAzael Avalos 53493f8c16dSAzael Avalos if (!sci_open(dev)) 535ea215a3fSAzael Avalos return; 53693f8c16dSAzael Avalos 537258c5903SAzael Avalos status = tci_raw(dev, in, out); 53893f8c16dSAzael Avalos sci_close(dev); 539a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) { 54093f8c16dSAzael Avalos pr_err("ACPI call to query kbd illumination support failed\n"); 541ea215a3fSAzael Avalos } else if (out[0] == TOS_SUCCESS) { 542e0769fe6SDarren Hart /* 543e0769fe6SDarren Hart * Check for keyboard backlight timeout max value, 54493f8c16dSAzael Avalos * previous kbd backlight implementation set this to 54593f8c16dSAzael Avalos * 0x3c0003, and now the new implementation set this 546e0769fe6SDarren Hart * to 0x3c001a, use this to distinguish between them. 54793f8c16dSAzael Avalos */ 54893f8c16dSAzael Avalos if (out[3] == SCI_KBD_TIME_MAX) 54993f8c16dSAzael Avalos dev->kbd_type = 2; 55093f8c16dSAzael Avalos else 55193f8c16dSAzael Avalos dev->kbd_type = 1; 55293f8c16dSAzael Avalos /* Get the current keyboard backlight mode */ 55393f8c16dSAzael Avalos dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK; 55493f8c16dSAzael Avalos /* Get the current time (1-60 seconds) */ 55593f8c16dSAzael Avalos dev->kbd_time = out[2] >> HCI_MISC_SHIFT; 556ea215a3fSAzael Avalos /* Flag as supported */ 557ea215a3fSAzael Avalos dev->kbd_illum_supported = 1; 558ea215a3fSAzael Avalos } 55993f8c16dSAzael Avalos } 56093f8c16dSAzael Avalos 561360f0f39SAzael Avalos static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time) 562360f0f39SAzael Avalos { 563360f0f39SAzael Avalos u32 result; 564360f0f39SAzael Avalos 565360f0f39SAzael Avalos if (!sci_open(dev)) 566360f0f39SAzael Avalos return -EIO; 567360f0f39SAzael Avalos 568893f3f62SAzael Avalos result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time); 569360f0f39SAzael Avalos sci_close(dev); 570a6b5354fSAzael Avalos if (result == TOS_FAILURE) 571360f0f39SAzael Avalos pr_err("ACPI call to set KBD backlight status failed\n"); 572a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 573360f0f39SAzael Avalos return -ENODEV; 574360f0f39SAzael Avalos 575e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 576360f0f39SAzael Avalos } 577360f0f39SAzael Avalos 578360f0f39SAzael Avalos static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time) 579360f0f39SAzael Avalos { 580360f0f39SAzael Avalos u32 result; 581360f0f39SAzael Avalos 582360f0f39SAzael Avalos if (!sci_open(dev)) 583360f0f39SAzael Avalos return -EIO; 584360f0f39SAzael Avalos 585893f3f62SAzael Avalos result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time); 586360f0f39SAzael Avalos sci_close(dev); 587a6b5354fSAzael Avalos if (result == TOS_FAILURE) 588360f0f39SAzael Avalos pr_err("ACPI call to get KBD backlight status failed\n"); 589a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 590360f0f39SAzael Avalos return -ENODEV; 591360f0f39SAzael Avalos 592e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 593360f0f39SAzael Avalos } 594360f0f39SAzael Avalos 595360f0f39SAzael Avalos static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev) 596360f0f39SAzael Avalos { 597360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 598360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 599e1a949c1SAzael Avalos u32 result; 600e1a949c1SAzael Avalos u32 state; 601360f0f39SAzael Avalos 602360f0f39SAzael Avalos /* Check the keyboard backlight state */ 603d37782bdSAzael Avalos result = hci_read(dev, HCI_KBD_ILLUMINATION, &state); 604a6b5354fSAzael Avalos if (result == TOS_FAILURE) { 605360f0f39SAzael Avalos pr_err("ACPI call to get the keyboard backlight failed\n"); 606360f0f39SAzael Avalos return LED_OFF; 607e1a949c1SAzael Avalos } else if (result != TOS_SUCCESS) { 608360f0f39SAzael Avalos return LED_OFF; 609360f0f39SAzael Avalos } 610360f0f39SAzael Avalos 611360f0f39SAzael Avalos return state ? LED_FULL : LED_OFF; 612360f0f39SAzael Avalos } 613360f0f39SAzael Avalos 614360f0f39SAzael Avalos static void toshiba_kbd_backlight_set(struct led_classdev *cdev, 615360f0f39SAzael Avalos enum led_brightness brightness) 616360f0f39SAzael Avalos { 617360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 618360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 619e1a949c1SAzael Avalos u32 result; 620e1a949c1SAzael Avalos u32 state; 621360f0f39SAzael Avalos 622360f0f39SAzael Avalos /* Set the keyboard backlight state */ 623360f0f39SAzael Avalos state = brightness ? 1 : 0; 624d37782bdSAzael Avalos result = hci_write(dev, HCI_KBD_ILLUMINATION, state); 625a6b5354fSAzael Avalos if (result == TOS_FAILURE) 626360f0f39SAzael Avalos pr_err("ACPI call to set KBD Illumination mode failed\n"); 627360f0f39SAzael Avalos } 628360f0f39SAzael Avalos 6299d8658acSAzael Avalos /* TouchPad support */ 6309d8658acSAzael Avalos static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state) 6319d8658acSAzael Avalos { 6329d8658acSAzael Avalos u32 result; 6339d8658acSAzael Avalos 6349d8658acSAzael Avalos if (!sci_open(dev)) 6359d8658acSAzael Avalos return -EIO; 6369d8658acSAzael Avalos 637893f3f62SAzael Avalos result = sci_write(dev, SCI_TOUCHPAD, state); 6389d8658acSAzael Avalos sci_close(dev); 639a6b5354fSAzael Avalos if (result == TOS_FAILURE) 6409d8658acSAzael Avalos pr_err("ACPI call to set the touchpad failed\n"); 641a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 6429d8658acSAzael Avalos return -ENODEV; 6439d8658acSAzael Avalos 644e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 6459d8658acSAzael Avalos } 6469d8658acSAzael Avalos 6479d8658acSAzael Avalos static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) 6489d8658acSAzael Avalos { 6499d8658acSAzael Avalos u32 result; 6509d8658acSAzael Avalos 6519d8658acSAzael Avalos if (!sci_open(dev)) 6529d8658acSAzael Avalos return -EIO; 6539d8658acSAzael Avalos 654893f3f62SAzael Avalos result = sci_read(dev, SCI_TOUCHPAD, state); 6559d8658acSAzael Avalos sci_close(dev); 656a6b5354fSAzael Avalos if (result == TOS_FAILURE) 6579d8658acSAzael Avalos pr_err("ACPI call to query the touchpad failed\n"); 658a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 6599d8658acSAzael Avalos return -ENODEV; 6609d8658acSAzael Avalos 661e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 6629d8658acSAzael Avalos } 6639d8658acSAzael Avalos 664def6c4e2SAzael Avalos /* Eco Mode support */ 665ea215a3fSAzael Avalos static void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) 666def6c4e2SAzael Avalos { 667def6c4e2SAzael Avalos acpi_status status; 66898fc4ec6SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 }; 669258c5903SAzael Avalos u32 out[TCI_WORDS]; 670def6c4e2SAzael Avalos 671ea215a3fSAzael Avalos dev->eco_supported = 0; 672ea215a3fSAzael Avalos dev->eco_led_registered = false; 673ea215a3fSAzael Avalos 674258c5903SAzael Avalos status = tci_raw(dev, in, out); 6758baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 67698fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 67798fc4ec6SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 678e0769fe6SDarren Hart /* 679e0769fe6SDarren Hart * If we receive 0x8300 (Input Data Error), it means that the 68098fc4ec6SAzael Avalos * LED device is present, but that we just screwed the input 68198fc4ec6SAzael Avalos * parameters. 68298fc4ec6SAzael Avalos * 68398fc4ec6SAzael Avalos * Let's query the status of the LED to see if we really have a 68498fc4ec6SAzael Avalos * success response, indicating the actual presense of the LED, 68598fc4ec6SAzael Avalos * bail out otherwise. 68698fc4ec6SAzael Avalos */ 68798fc4ec6SAzael Avalos in[3] = 1; 68898fc4ec6SAzael Avalos status = tci_raw(dev, in, out); 689a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) 69098fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 69198fc4ec6SAzael Avalos else if (out[0] == TOS_SUCCESS) 692ea215a3fSAzael Avalos dev->eco_supported = 1; 693def6c4e2SAzael Avalos } 694def6c4e2SAzael Avalos } 695def6c4e2SAzael Avalos 696b5163992SAzael Avalos static enum led_brightness 697b5163992SAzael Avalos toshiba_eco_mode_get_status(struct led_classdev *cdev) 698def6c4e2SAzael Avalos { 699def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 700def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 701258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 }; 702258c5903SAzael Avalos u32 out[TCI_WORDS]; 703def6c4e2SAzael Avalos acpi_status status; 704def6c4e2SAzael Avalos 705258c5903SAzael Avalos status = tci_raw(dev, in, out); 706a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) { 707def6c4e2SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 708def6c4e2SAzael Avalos return LED_OFF; 709e1a949c1SAzael Avalos } else if (out[0] != TOS_SUCCESS) { 710e1a949c1SAzael Avalos return LED_OFF; 711def6c4e2SAzael Avalos } 712def6c4e2SAzael Avalos 713def6c4e2SAzael Avalos return out[2] ? LED_FULL : LED_OFF; 714def6c4e2SAzael Avalos } 715def6c4e2SAzael Avalos 716def6c4e2SAzael Avalos static void toshiba_eco_mode_set_status(struct led_classdev *cdev, 717def6c4e2SAzael Avalos enum led_brightness brightness) 718def6c4e2SAzael Avalos { 719def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 720def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 721258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 }; 722258c5903SAzael Avalos u32 out[TCI_WORDS]; 723def6c4e2SAzael Avalos acpi_status status; 724def6c4e2SAzael Avalos 725def6c4e2SAzael Avalos /* Switch the Eco Mode led on/off */ 726def6c4e2SAzael Avalos in[2] = (brightness) ? 1 : 0; 727258c5903SAzael Avalos status = tci_raw(dev, in, out); 728a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) 729def6c4e2SAzael Avalos pr_err("ACPI call to set ECO led failed\n"); 730def6c4e2SAzael Avalos } 731def6c4e2SAzael Avalos 7325a2813e9SAzael Avalos /* Accelerometer support */ 733ea215a3fSAzael Avalos static void toshiba_accelerometer_available(struct toshiba_acpi_dev *dev) 7345a2813e9SAzael Avalos { 735258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 }; 736258c5903SAzael Avalos u32 out[TCI_WORDS]; 7375a2813e9SAzael Avalos acpi_status status; 7385a2813e9SAzael Avalos 739ea215a3fSAzael Avalos dev->accelerometer_supported = 0; 740ea215a3fSAzael Avalos 741e0769fe6SDarren Hart /* 742e0769fe6SDarren Hart * Check if the accelerometer call exists, 7435a2813e9SAzael Avalos * this call also serves as initialization 7445a2813e9SAzael Avalos */ 745258c5903SAzael Avalos status = tci_raw(dev, in, out); 746a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) 7475a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 748ea215a3fSAzael Avalos else if (out[0] == TOS_SUCCESS) 749ea215a3fSAzael Avalos dev->accelerometer_supported = 1; 7505a2813e9SAzael Avalos } 7515a2813e9SAzael Avalos 7525a2813e9SAzael Avalos static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, 7535a2813e9SAzael Avalos u32 *xy, u32 *z) 7545a2813e9SAzael Avalos { 755258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 }; 756258c5903SAzael Avalos u32 out[TCI_WORDS]; 7575a2813e9SAzael Avalos acpi_status status; 7585a2813e9SAzael Avalos 7595a2813e9SAzael Avalos /* Check the Accelerometer status */ 760258c5903SAzael Avalos status = tci_raw(dev, in, out); 761a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) { 7625a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 7635a2813e9SAzael Avalos return -EIO; 764e1a949c1SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 765e1a949c1SAzael Avalos return -ENODEV; 766e1a949c1SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 7675a2813e9SAzael Avalos *xy = out[2]; 7685a2813e9SAzael Avalos *z = out[4]; 7695a2813e9SAzael Avalos return 0; 7705a2813e9SAzael Avalos } 7715a2813e9SAzael Avalos 772e1a949c1SAzael Avalos return -EIO; 773e1a949c1SAzael Avalos } 774e1a949c1SAzael Avalos 775e26ffe51SAzael Avalos /* Sleep (Charge and Music) utilities support */ 776c8c91842SAzael Avalos static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev) 777c8c91842SAzael Avalos { 778c8c91842SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 779c8c91842SAzael Avalos u32 out[TCI_WORDS]; 780c8c91842SAzael Avalos acpi_status status; 781c8c91842SAzael Avalos 782c8c91842SAzael Avalos dev->usb_sleep_charge_supported = 0; 783c8c91842SAzael Avalos 784c8c91842SAzael Avalos if (!sci_open(dev)) 785c8c91842SAzael Avalos return; 786c8c91842SAzael Avalos 787c8c91842SAzael Avalos status = tci_raw(dev, in, out); 7888baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 789c8c91842SAzael Avalos pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); 790c8c91842SAzael Avalos sci_close(dev); 791c8c91842SAzael Avalos return; 792c8c91842SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 793c8c91842SAzael Avalos sci_close(dev); 794c8c91842SAzael Avalos return; 795c8c91842SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 796c8c91842SAzael Avalos dev->usbsc_mode_base = out[4]; 797c8c91842SAzael Avalos } 798c8c91842SAzael Avalos 799c8c91842SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 800c8c91842SAzael Avalos status = tci_raw(dev, in, out); 801ea215a3fSAzael Avalos sci_close(dev); 8028baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 803c8c91842SAzael Avalos pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); 804c8c91842SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 805c8c91842SAzael Avalos dev->usbsc_bat_level = out[2]; 806ea215a3fSAzael Avalos /* Flag as supported */ 807c8c91842SAzael Avalos dev->usb_sleep_charge_supported = 1; 808c8c91842SAzael Avalos } 809c8c91842SAzael Avalos 810c8c91842SAzael Avalos } 811c8c91842SAzael Avalos 812e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, 813e26ffe51SAzael Avalos u32 *mode) 814e26ffe51SAzael Avalos { 815e26ffe51SAzael Avalos u32 result; 816e26ffe51SAzael Avalos 817e26ffe51SAzael Avalos if (!sci_open(dev)) 818e26ffe51SAzael Avalos return -EIO; 819e26ffe51SAzael Avalos 820e26ffe51SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode); 821e26ffe51SAzael Avalos sci_close(dev); 822a6b5354fSAzael Avalos if (result == TOS_FAILURE) 823e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 824a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 825e26ffe51SAzael Avalos return -ENODEV; 826e26ffe51SAzael Avalos 827e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 828e26ffe51SAzael Avalos } 829e26ffe51SAzael Avalos 830e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev, 831e26ffe51SAzael Avalos u32 mode) 832e26ffe51SAzael Avalos { 833e26ffe51SAzael Avalos u32 result; 834e26ffe51SAzael Avalos 835e26ffe51SAzael Avalos if (!sci_open(dev)) 836e26ffe51SAzael Avalos return -EIO; 837e26ffe51SAzael Avalos 838e26ffe51SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode); 839e26ffe51SAzael Avalos sci_close(dev); 840a6b5354fSAzael Avalos if (result == TOS_FAILURE) 841e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 842a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 843e26ffe51SAzael Avalos return -ENODEV; 844e26ffe51SAzael Avalos 845e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 846e26ffe51SAzael Avalos } 847e26ffe51SAzael Avalos 848182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev, 849182bcaa5SAzael Avalos u32 *mode) 850182bcaa5SAzael Avalos { 851182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 852182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 853182bcaa5SAzael Avalos acpi_status status; 854182bcaa5SAzael Avalos 855182bcaa5SAzael Avalos if (!sci_open(dev)) 856182bcaa5SAzael Avalos return -EIO; 857182bcaa5SAzael Avalos 858182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 859182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 860182bcaa5SAzael Avalos sci_close(dev); 8618baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 862182bcaa5SAzael Avalos pr_err("ACPI call to get USB S&C battery level failed\n"); 863182bcaa5SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 864182bcaa5SAzael Avalos return -ENODEV; 865e1a949c1SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 866e1a949c1SAzael Avalos *mode = out[2]; 867e1a949c1SAzael Avalos return 0; 868182bcaa5SAzael Avalos } 869182bcaa5SAzael Avalos 870e1a949c1SAzael Avalos return -EIO; 871182bcaa5SAzael Avalos } 872182bcaa5SAzael Avalos 873182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, 874182bcaa5SAzael Avalos u32 mode) 875182bcaa5SAzael Avalos { 876182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 877182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 878182bcaa5SAzael Avalos acpi_status status; 879182bcaa5SAzael Avalos 880182bcaa5SAzael Avalos if (!sci_open(dev)) 881182bcaa5SAzael Avalos return -EIO; 882182bcaa5SAzael Avalos 883182bcaa5SAzael Avalos in[2] = mode; 884182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 885182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 886182bcaa5SAzael Avalos sci_close(dev); 887a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) 888182bcaa5SAzael Avalos pr_err("ACPI call to set USB S&C battery level failed\n"); 889a6b5354fSAzael Avalos else if (out[0] == TOS_NOT_SUPPORTED) 890182bcaa5SAzael Avalos return -ENODEV; 891182bcaa5SAzael Avalos 892e1a949c1SAzael Avalos return out[0] == TOS_SUCCESS ? 0 : -EIO; 893182bcaa5SAzael Avalos } 894182bcaa5SAzael Avalos 895bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, 896bb3fe01fSAzael Avalos u32 *state) 897bb3fe01fSAzael Avalos { 898bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 899bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 900bb3fe01fSAzael Avalos acpi_status status; 901bb3fe01fSAzael Avalos 902bb3fe01fSAzael Avalos if (!sci_open(dev)) 903bb3fe01fSAzael Avalos return -EIO; 904bb3fe01fSAzael Avalos 905bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 906bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 907bb3fe01fSAzael Avalos sci_close(dev); 9088baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 909bb26f189SAzael Avalos pr_err("ACPI call to get USB Rapid Charge failed\n"); 910a6b5354fSAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 911bb3fe01fSAzael Avalos return -ENODEV; 912e1a949c1SAzael Avalos } else if (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) { 913e1a949c1SAzael Avalos *state = out[2]; 914e1a949c1SAzael Avalos return 0; 915bb3fe01fSAzael Avalos } 916bb3fe01fSAzael Avalos 917e1a949c1SAzael Avalos return -EIO; 918bb3fe01fSAzael Avalos } 919bb3fe01fSAzael Avalos 920bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, 921bb3fe01fSAzael Avalos u32 state) 922bb3fe01fSAzael Avalos { 923bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 924bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 925bb3fe01fSAzael Avalos acpi_status status; 926bb3fe01fSAzael Avalos 927bb3fe01fSAzael Avalos if (!sci_open(dev)) 928bb3fe01fSAzael Avalos return -EIO; 929bb3fe01fSAzael Avalos 930bb3fe01fSAzael Avalos in[2] = state; 931bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 932bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 933bb3fe01fSAzael Avalos sci_close(dev); 934a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) 935bb26f189SAzael Avalos pr_err("ACPI call to set USB Rapid Charge failed\n"); 936a6b5354fSAzael Avalos else if (out[0] == TOS_NOT_SUPPORTED) 937bb3fe01fSAzael Avalos return -ENODEV; 938bb3fe01fSAzael Avalos 939e1a949c1SAzael Avalos return (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) ? 0 : -EIO; 940bb3fe01fSAzael Avalos } 941bb3fe01fSAzael Avalos 942172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state) 943172ce0a9SAzael Avalos { 944172ce0a9SAzael Avalos u32 result; 945172ce0a9SAzael Avalos 946172ce0a9SAzael Avalos if (!sci_open(dev)) 947172ce0a9SAzael Avalos return -EIO; 948172ce0a9SAzael Avalos 949172ce0a9SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state); 950172ce0a9SAzael Avalos sci_close(dev); 951a6b5354fSAzael Avalos if (result == TOS_FAILURE) 952bb26f189SAzael Avalos pr_err("ACPI call to get Sleep and Music failed\n"); 953a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 954172ce0a9SAzael Avalos return -ENODEV; 955172ce0a9SAzael Avalos 956cf680eaeSAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 957172ce0a9SAzael Avalos } 958172ce0a9SAzael Avalos 959172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state) 960172ce0a9SAzael Avalos { 961172ce0a9SAzael Avalos u32 result; 962172ce0a9SAzael Avalos 963172ce0a9SAzael Avalos if (!sci_open(dev)) 964172ce0a9SAzael Avalos return -EIO; 965172ce0a9SAzael Avalos 966172ce0a9SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state); 967172ce0a9SAzael Avalos sci_close(dev); 968a6b5354fSAzael Avalos if (result == TOS_FAILURE) 969bb26f189SAzael Avalos pr_err("ACPI call to set Sleep and Music failed\n"); 970a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 971172ce0a9SAzael Avalos return -ENODEV; 972172ce0a9SAzael Avalos 973e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 974172ce0a9SAzael Avalos } 975172ce0a9SAzael Avalos 976bae84195SAzael Avalos /* Keyboard function keys */ 977bae84195SAzael Avalos static int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode) 978bae84195SAzael Avalos { 979bae84195SAzael Avalos u32 result; 980bae84195SAzael Avalos 981bae84195SAzael Avalos if (!sci_open(dev)) 982bae84195SAzael Avalos return -EIO; 983bae84195SAzael Avalos 984bae84195SAzael Avalos result = sci_read(dev, SCI_KBD_FUNCTION_KEYS, mode); 985bae84195SAzael Avalos sci_close(dev); 986a6b5354fSAzael Avalos if (result == TOS_FAILURE) 987bae84195SAzael Avalos pr_err("ACPI call to get KBD function keys failed\n"); 988a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 989bae84195SAzael Avalos return -ENODEV; 990bae84195SAzael Avalos 991e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 992bae84195SAzael Avalos } 993bae84195SAzael Avalos 994bae84195SAzael Avalos static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode) 995bae84195SAzael Avalos { 996bae84195SAzael Avalos u32 result; 997bae84195SAzael Avalos 998bae84195SAzael Avalos if (!sci_open(dev)) 999bae84195SAzael Avalos return -EIO; 1000bae84195SAzael Avalos 1001bae84195SAzael Avalos result = sci_write(dev, SCI_KBD_FUNCTION_KEYS, mode); 1002bae84195SAzael Avalos sci_close(dev); 1003a6b5354fSAzael Avalos if (result == TOS_FAILURE) 1004bae84195SAzael Avalos pr_err("ACPI call to set KBD function keys failed\n"); 1005a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1006bae84195SAzael Avalos return -ENODEV; 1007bae84195SAzael Avalos 1008e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 1009bae84195SAzael Avalos } 1010bae84195SAzael Avalos 101135d53ceaSAzael Avalos /* Panel Power ON */ 101235d53ceaSAzael Avalos static int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state) 101335d53ceaSAzael Avalos { 101435d53ceaSAzael Avalos u32 result; 101535d53ceaSAzael Avalos 101635d53ceaSAzael Avalos if (!sci_open(dev)) 101735d53ceaSAzael Avalos return -EIO; 101835d53ceaSAzael Avalos 101935d53ceaSAzael Avalos result = sci_read(dev, SCI_PANEL_POWER_ON, state); 102035d53ceaSAzael Avalos sci_close(dev); 1021a6b5354fSAzael Avalos if (result == TOS_FAILURE) 102235d53ceaSAzael Avalos pr_err("ACPI call to get Panel Power ON failed\n"); 1023a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 102435d53ceaSAzael Avalos return -ENODEV; 102535d53ceaSAzael Avalos 1026e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 102735d53ceaSAzael Avalos } 102835d53ceaSAzael Avalos 102935d53ceaSAzael Avalos static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state) 103035d53ceaSAzael Avalos { 103135d53ceaSAzael Avalos u32 result; 103235d53ceaSAzael Avalos 103335d53ceaSAzael Avalos if (!sci_open(dev)) 103435d53ceaSAzael Avalos return -EIO; 103535d53ceaSAzael Avalos 103635d53ceaSAzael Avalos result = sci_write(dev, SCI_PANEL_POWER_ON, state); 103735d53ceaSAzael Avalos sci_close(dev); 1038a6b5354fSAzael Avalos if (result == TOS_FAILURE) 103935d53ceaSAzael Avalos pr_err("ACPI call to set Panel Power ON failed\n"); 1040a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 104135d53ceaSAzael Avalos return -ENODEV; 104235d53ceaSAzael Avalos 1043e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 104435d53ceaSAzael Avalos } 104535d53ceaSAzael Avalos 104617fe4b3dSAzael Avalos /* USB Three */ 104717fe4b3dSAzael Avalos static int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state) 104817fe4b3dSAzael Avalos { 104917fe4b3dSAzael Avalos u32 result; 105017fe4b3dSAzael Avalos 105117fe4b3dSAzael Avalos if (!sci_open(dev)) 105217fe4b3dSAzael Avalos return -EIO; 105317fe4b3dSAzael Avalos 105417fe4b3dSAzael Avalos result = sci_read(dev, SCI_USB_THREE, state); 105517fe4b3dSAzael Avalos sci_close(dev); 1056a6b5354fSAzael Avalos if (result == TOS_FAILURE) 105717fe4b3dSAzael Avalos pr_err("ACPI call to get USB 3 failed\n"); 1058a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 105917fe4b3dSAzael Avalos return -ENODEV; 106017fe4b3dSAzael Avalos 1061e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 106217fe4b3dSAzael Avalos } 106317fe4b3dSAzael Avalos 106417fe4b3dSAzael Avalos static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state) 106517fe4b3dSAzael Avalos { 106617fe4b3dSAzael Avalos u32 result; 106717fe4b3dSAzael Avalos 106817fe4b3dSAzael Avalos if (!sci_open(dev)) 106917fe4b3dSAzael Avalos return -EIO; 107017fe4b3dSAzael Avalos 107117fe4b3dSAzael Avalos result = sci_write(dev, SCI_USB_THREE, state); 107217fe4b3dSAzael Avalos sci_close(dev); 1073a6b5354fSAzael Avalos if (result == TOS_FAILURE) 107417fe4b3dSAzael Avalos pr_err("ACPI call to set USB 3 failed\n"); 1075a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 107617fe4b3dSAzael Avalos return -ENODEV; 107717fe4b3dSAzael Avalos 1078e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 107917fe4b3dSAzael Avalos } 108017fe4b3dSAzael Avalos 108156e6b353SAzael Avalos /* Hotkey Event type */ 108256e6b353SAzael Avalos static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev, 108356e6b353SAzael Avalos u32 *type) 108456e6b353SAzael Avalos { 10853b876000SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_SYSTEM_INFO, 0x03, 0, 0, 0 }; 10863b876000SAzael Avalos u32 out[TCI_WORDS]; 10873b876000SAzael Avalos acpi_status status; 108856e6b353SAzael Avalos 10893b876000SAzael Avalos status = tci_raw(dev, in, out); 10903b876000SAzael Avalos if (ACPI_FAILURE(status)) { 109156e6b353SAzael Avalos pr_err("ACPI call to get System type failed\n"); 10923b876000SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 109356e6b353SAzael Avalos return -ENODEV; 1094e1a949c1SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 1095e1a949c1SAzael Avalos *type = out[3]; 1096e1a949c1SAzael Avalos return 0; 109756e6b353SAzael Avalos } 109856e6b353SAzael Avalos 1099e1a949c1SAzael Avalos return -EIO; 110056e6b353SAzael Avalos } 110156e6b353SAzael Avalos 11026873f46aSAzael Avalos /* Wireless status (RFKill, WLAN, BT, WWAN) */ 11036873f46aSAzael Avalos static int toshiba_wireless_status(struct toshiba_acpi_dev *dev) 11046873f46aSAzael Avalos { 11056873f46aSAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_WIRELESS, 0, 0, 0, 0 }; 11066873f46aSAzael Avalos u32 out[TCI_WORDS]; 11076873f46aSAzael Avalos acpi_status status; 11086873f46aSAzael Avalos 11096873f46aSAzael Avalos in[3] = HCI_WIRELESS_STATUS; 11106873f46aSAzael Avalos status = tci_raw(dev, in, out); 11116873f46aSAzael Avalos 11126873f46aSAzael Avalos if (ACPI_FAILURE(status)) { 11136873f46aSAzael Avalos pr_err("ACPI call to get Wireless status failed\n"); 11146873f46aSAzael Avalos return -EIO; 11156873f46aSAzael Avalos } 11166873f46aSAzael Avalos 11176873f46aSAzael Avalos if (out[0] == TOS_NOT_SUPPORTED) 11186873f46aSAzael Avalos return -ENODEV; 11196873f46aSAzael Avalos 11206873f46aSAzael Avalos if (out[0] != TOS_SUCCESS) 11216873f46aSAzael Avalos return -EIO; 11226873f46aSAzael Avalos 11236873f46aSAzael Avalos dev->killswitch = !!(out[2] & HCI_WIRELESS_STATUS); 11246873f46aSAzael Avalos 11256873f46aSAzael Avalos return 0; 11266873f46aSAzael Avalos } 11276873f46aSAzael Avalos 11286873f46aSAzael Avalos /* WWAN */ 11296873f46aSAzael Avalos static void toshiba_wwan_available(struct toshiba_acpi_dev *dev) 11306873f46aSAzael Avalos { 11316873f46aSAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_WIRELESS, 0, 0, 0, 0 }; 11326873f46aSAzael Avalos u32 out[TCI_WORDS]; 11336873f46aSAzael Avalos acpi_status status; 11346873f46aSAzael Avalos 11356873f46aSAzael Avalos dev->wwan_supported = 0; 11366873f46aSAzael Avalos 11376873f46aSAzael Avalos /* 11386873f46aSAzael Avalos * WWAN support can be queried by setting the in[3] value to 11396873f46aSAzael Avalos * HCI_WIRELESS_WWAN (0x03). 11406873f46aSAzael Avalos * 11416873f46aSAzael Avalos * If supported, out[0] contains TOS_SUCCESS and out[2] contains 11426873f46aSAzael Avalos * HCI_WIRELESS_WWAN_STATUS (0x2000). 11436873f46aSAzael Avalos * 11446873f46aSAzael Avalos * If not supported, out[0] contains TOS_INPUT_DATA_ERROR (0x8300) 11456873f46aSAzael Avalos * or TOS_NOT_SUPPORTED (0x8000). 11466873f46aSAzael Avalos */ 11476873f46aSAzael Avalos in[3] = HCI_WIRELESS_WWAN; 11486873f46aSAzael Avalos status = tci_raw(dev, in, out); 11496873f46aSAzael Avalos 11506873f46aSAzael Avalos if (ACPI_FAILURE(status)) { 11516873f46aSAzael Avalos pr_err("ACPI call to get WWAN status failed\n"); 11526873f46aSAzael Avalos return; 11536873f46aSAzael Avalos } 11546873f46aSAzael Avalos 11556873f46aSAzael Avalos if (out[0] != TOS_SUCCESS) 11566873f46aSAzael Avalos return; 11576873f46aSAzael Avalos 11586873f46aSAzael Avalos dev->wwan_supported = (out[2] == HCI_WIRELESS_WWAN_STATUS); 11596873f46aSAzael Avalos } 11606873f46aSAzael Avalos 11616873f46aSAzael Avalos static int toshiba_wwan_set(struct toshiba_acpi_dev *dev, u32 state) 11626873f46aSAzael Avalos { 11636873f46aSAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, HCI_WIRELESS, state, 0, 0, 0 }; 11646873f46aSAzael Avalos u32 out[TCI_WORDS]; 11656873f46aSAzael Avalos acpi_status status; 11666873f46aSAzael Avalos 11676873f46aSAzael Avalos in[3] = HCI_WIRELESS_WWAN_STATUS; 11686873f46aSAzael Avalos status = tci_raw(dev, in, out); 11696873f46aSAzael Avalos 11706873f46aSAzael Avalos if (ACPI_FAILURE(status)) { 11716873f46aSAzael Avalos pr_err("ACPI call to set WWAN status failed\n"); 11726873f46aSAzael Avalos return -EIO; 11736873f46aSAzael Avalos } 11746873f46aSAzael Avalos 11756873f46aSAzael Avalos if (out[0] == TOS_NOT_SUPPORTED) 11766873f46aSAzael Avalos return -ENODEV; 11776873f46aSAzael Avalos 11786873f46aSAzael Avalos if (out[0] != TOS_SUCCESS) 11796873f46aSAzael Avalos return -EIO; 11806873f46aSAzael Avalos 11816873f46aSAzael Avalos /* 11826873f46aSAzael Avalos * Some devices only need to call HCI_WIRELESS_WWAN_STATUS to 11836873f46aSAzael Avalos * (de)activate the device, but some others need the 11846873f46aSAzael Avalos * HCI_WIRELESS_WWAN_POWER call as well. 11856873f46aSAzael Avalos */ 11866873f46aSAzael Avalos in[3] = HCI_WIRELESS_WWAN_POWER; 11876873f46aSAzael Avalos status = tci_raw(dev, in, out); 11886873f46aSAzael Avalos 11896873f46aSAzael Avalos if (ACPI_FAILURE(status)) { 11906873f46aSAzael Avalos pr_err("ACPI call to set WWAN power failed\n"); 11916873f46aSAzael Avalos return -EIO; 11926873f46aSAzael Avalos } 11936873f46aSAzael Avalos 11946873f46aSAzael Avalos if (out[0] == TOS_NOT_SUPPORTED) 11956873f46aSAzael Avalos return -ENODEV; 11966873f46aSAzael Avalos 11976873f46aSAzael Avalos return out[0] == TOS_SUCCESS ? 0 : -EIO; 11986873f46aSAzael Avalos } 11996873f46aSAzael Avalos 1200763ff32fSAzael Avalos /* Cooling Method */ 1201763ff32fSAzael Avalos static void toshiba_cooling_method_available(struct toshiba_acpi_dev *dev) 1202763ff32fSAzael Avalos { 1203763ff32fSAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_COOLING_METHOD, 0, 0, 0, 0 }; 1204763ff32fSAzael Avalos u32 out[TCI_WORDS]; 1205763ff32fSAzael Avalos acpi_status status; 1206763ff32fSAzael Avalos 1207763ff32fSAzael Avalos dev->cooling_method_supported = 0; 1208763ff32fSAzael Avalos dev->max_cooling_method = 0; 1209763ff32fSAzael Avalos 1210763ff32fSAzael Avalos status = tci_raw(dev, in, out); 1211763ff32fSAzael Avalos if (ACPI_FAILURE(status)) 1212763ff32fSAzael Avalos pr_err("ACPI call to get Cooling Method failed\n"); 1213763ff32fSAzael Avalos 1214763ff32fSAzael Avalos if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2) 1215763ff32fSAzael Avalos return; 1216763ff32fSAzael Avalos 1217763ff32fSAzael Avalos dev->cooling_method_supported = 1; 1218763ff32fSAzael Avalos dev->max_cooling_method = out[3]; 1219763ff32fSAzael Avalos } 1220763ff32fSAzael Avalos 1221763ff32fSAzael Avalos static int toshiba_cooling_method_get(struct toshiba_acpi_dev *dev, u32 *state) 1222763ff32fSAzael Avalos { 1223763ff32fSAzael Avalos u32 result = hci_read(dev, HCI_COOLING_METHOD, state); 1224763ff32fSAzael Avalos 1225763ff32fSAzael Avalos if (result == TOS_FAILURE) 1226763ff32fSAzael Avalos pr_err("ACPI call to get Cooling Method failed\n"); 1227763ff32fSAzael Avalos 1228763ff32fSAzael Avalos if (result == TOS_NOT_SUPPORTED) 1229763ff32fSAzael Avalos return -ENODEV; 1230763ff32fSAzael Avalos 1231763ff32fSAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 1232763ff32fSAzael Avalos } 1233763ff32fSAzael Avalos 1234763ff32fSAzael Avalos static int toshiba_cooling_method_set(struct toshiba_acpi_dev *dev, u32 state) 1235763ff32fSAzael Avalos { 1236763ff32fSAzael Avalos u32 result = hci_write(dev, HCI_COOLING_METHOD, state); 1237763ff32fSAzael Avalos 1238763ff32fSAzael Avalos if (result == TOS_FAILURE) 1239763ff32fSAzael Avalos pr_err("ACPI call to get Cooling Method failed\n"); 1240763ff32fSAzael Avalos 1241763ff32fSAzael Avalos if (result == TOS_NOT_SUPPORTED) 1242763ff32fSAzael Avalos return -ENODEV; 1243763ff32fSAzael Avalos 1244763ff32fSAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 1245763ff32fSAzael Avalos } 1246763ff32fSAzael Avalos 12473f75bbe9SAzael Avalos /* Transflective Backlight */ 1248695f6060SAzael Avalos static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status) 1249121b7b0dSAkio Idehara { 1250e1a949c1SAzael Avalos u32 result = hci_read(dev, HCI_TR_BACKLIGHT, status); 1251121b7b0dSAkio Idehara 1252e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1253e1a949c1SAzael Avalos pr_err("ACPI call to get Transflective Backlight failed\n"); 1254e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1255e1a949c1SAzael Avalos return -ENODEV; 1256e1a949c1SAzael Avalos 1257e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1258121b7b0dSAkio Idehara } 1259121b7b0dSAkio Idehara 1260695f6060SAzael Avalos static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 status) 1261121b7b0dSAkio Idehara { 1262e1a949c1SAzael Avalos u32 result = hci_write(dev, HCI_TR_BACKLIGHT, !status); 1263121b7b0dSAkio Idehara 1264e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1265e1a949c1SAzael Avalos pr_err("ACPI call to set Transflective Backlight failed\n"); 1266e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1267e1a949c1SAzael Avalos return -ENODEV; 1268e1a949c1SAzael Avalos 1269e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1270121b7b0dSAkio Idehara } 1271121b7b0dSAkio Idehara 12723f75bbe9SAzael Avalos static struct proc_dir_entry *toshiba_proc_dir; 1273b4f9fe12SLen Brown 12743f75bbe9SAzael Avalos /* LCD Brightness */ 127562cce752SSeth Forshee static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) 1276b4f9fe12SLen Brown { 1277e1a949c1SAzael Avalos u32 result; 1278b4f9fe12SLen Brown u32 value; 1279121b7b0dSAkio Idehara int brightness = 0; 1280121b7b0dSAkio Idehara 1281121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1282695f6060SAzael Avalos int ret = get_tr_backlight_status(dev, &value); 1283b5163992SAzael Avalos 1284121b7b0dSAkio Idehara if (ret) 1285121b7b0dSAkio Idehara return ret; 1286695f6060SAzael Avalos if (value) 1287121b7b0dSAkio Idehara return 0; 1288121b7b0dSAkio Idehara brightness++; 1289121b7b0dSAkio Idehara } 1290b4f9fe12SLen Brown 1291e1a949c1SAzael Avalos result = hci_read(dev, HCI_LCD_BRIGHTNESS, &value); 1292e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1293e1a949c1SAzael Avalos pr_err("ACPI call to get LCD Brightness failed\n"); 1294e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1295e1a949c1SAzael Avalos return -ENODEV; 1296e1a949c1SAzael Avalos if (result == TOS_SUCCESS) 1297121b7b0dSAkio Idehara return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT); 129832bcd5cbSSeth Forshee 129932bcd5cbSSeth Forshee return -EIO; 1300b4f9fe12SLen Brown } 1301b4f9fe12SLen Brown 130262cce752SSeth Forshee static int get_lcd_brightness(struct backlight_device *bd) 130362cce752SSeth Forshee { 130462cce752SSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 1305b5163992SAzael Avalos 130662cce752SSeth Forshee return __get_lcd_brightness(dev); 130762cce752SSeth Forshee } 130862cce752SSeth Forshee 1309936c8bcdSAlexey Dobriyan static int lcd_proc_show(struct seq_file *m, void *v) 1310b4f9fe12SLen Brown { 1311135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1312121b7b0dSAkio Idehara int levels; 1313e1a949c1SAzael Avalos int value; 1314b4f9fe12SLen Brown 1315135740deSSeth Forshee if (!dev->backlight_dev) 1316135740deSSeth Forshee return -ENODEV; 1317135740deSSeth Forshee 1318121b7b0dSAkio Idehara levels = dev->backlight_dev->props.max_brightness + 1; 131962cce752SSeth Forshee value = get_lcd_brightness(dev->backlight_dev); 1320b4f9fe12SLen Brown if (value >= 0) { 1321936c8bcdSAlexey Dobriyan seq_printf(m, "brightness: %d\n", value); 1322121b7b0dSAkio Idehara seq_printf(m, "brightness_levels: %d\n", levels); 132332bcd5cbSSeth Forshee return 0; 1324b4f9fe12SLen Brown } 1325b4f9fe12SLen Brown 132632bcd5cbSSeth Forshee pr_err("Error reading LCD brightness\n"); 1327e1a949c1SAzael Avalos 132832bcd5cbSSeth Forshee return -EIO; 1329936c8bcdSAlexey Dobriyan } 1330936c8bcdSAlexey Dobriyan 1331936c8bcdSAlexey Dobriyan static int lcd_proc_open(struct inode *inode, struct file *file) 1332936c8bcdSAlexey Dobriyan { 1333d9dda78bSAl Viro return single_open(file, lcd_proc_show, PDE_DATA(inode)); 1334b4f9fe12SLen Brown } 1335b4f9fe12SLen Brown 133662cce752SSeth Forshee static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) 1337b4f9fe12SLen Brown { 1338e1a949c1SAzael Avalos u32 result; 1339b4f9fe12SLen Brown 1340121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1341695f6060SAzael Avalos int ret = set_tr_backlight_status(dev, !value); 1342b5163992SAzael Avalos 1343121b7b0dSAkio Idehara if (ret) 1344121b7b0dSAkio Idehara return ret; 1345121b7b0dSAkio Idehara if (value) 1346121b7b0dSAkio Idehara value--; 1347121b7b0dSAkio Idehara } 1348121b7b0dSAkio Idehara 1349a39f46dfSAzael Avalos value = value << HCI_LCD_BRIGHTNESS_SHIFT; 1350e1a949c1SAzael Avalos result = hci_write(dev, HCI_LCD_BRIGHTNESS, value); 1351e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1352e1a949c1SAzael Avalos pr_err("ACPI call to set LCD Brightness failed\n"); 1353e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1354e1a949c1SAzael Avalos return -ENODEV; 1355e1a949c1SAzael Avalos 1356e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1357b4f9fe12SLen Brown } 1358b4f9fe12SLen Brown 1359b4f9fe12SLen Brown static int set_lcd_status(struct backlight_device *bd) 1360b4f9fe12SLen Brown { 1361135740deSSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 1362b5163992SAzael Avalos 136362cce752SSeth Forshee return set_lcd_brightness(dev, bd->props.brightness); 1364b4f9fe12SLen Brown } 1365b4f9fe12SLen Brown 1366936c8bcdSAlexey Dobriyan static ssize_t lcd_proc_write(struct file *file, const char __user *buf, 1367936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1368b4f9fe12SLen Brown { 1369d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1370936c8bcdSAlexey Dobriyan char cmd[42]; 1371936c8bcdSAlexey Dobriyan size_t len; 1372121b7b0dSAkio Idehara int levels = dev->backlight_dev->props.max_brightness + 1; 1373e1a949c1SAzael Avalos int value; 1374b4f9fe12SLen Brown 1375936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1376936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1377936c8bcdSAlexey Dobriyan return -EFAULT; 1378936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1379936c8bcdSAlexey Dobriyan 1380e1a949c1SAzael Avalos if (sscanf(cmd, " brightness : %i", &value) != 1 && 1381e1a949c1SAzael Avalos value < 0 && value > levels) 1382e1a949c1SAzael Avalos return -EINVAL; 1383e1a949c1SAzael Avalos 1384e1a949c1SAzael Avalos if (set_lcd_brightness(dev, value)) 1385e1a949c1SAzael Avalos return -EIO; 1386e1a949c1SAzael Avalos 1387e1a949c1SAzael Avalos return count; 1388b4f9fe12SLen Brown } 1389b4f9fe12SLen Brown 1390936c8bcdSAlexey Dobriyan static const struct file_operations lcd_proc_fops = { 1391936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1392936c8bcdSAlexey Dobriyan .open = lcd_proc_open, 1393936c8bcdSAlexey Dobriyan .read = seq_read, 1394936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1395936c8bcdSAlexey Dobriyan .release = single_release, 1396936c8bcdSAlexey Dobriyan .write = lcd_proc_write, 1397936c8bcdSAlexey Dobriyan }; 1398936c8bcdSAlexey Dobriyan 1399e1a949c1SAzael Avalos /* Video-Out */ 140036d03f93SSeth Forshee static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status) 140136d03f93SSeth Forshee { 1402e1a949c1SAzael Avalos u32 result = hci_read(dev, HCI_VIDEO_OUT, status); 140336d03f93SSeth Forshee 1404e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1405e1a949c1SAzael Avalos pr_err("ACPI call to get Video-Out failed\n"); 1406e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1407e1a949c1SAzael Avalos return -ENODEV; 1408e1a949c1SAzael Avalos 1409e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 141036d03f93SSeth Forshee } 141136d03f93SSeth Forshee 1412936c8bcdSAlexey Dobriyan static int video_proc_show(struct seq_file *m, void *v) 1413b4f9fe12SLen Brown { 1414135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1415b4f9fe12SLen Brown u32 value; 1416b4f9fe12SLen Brown 1417e1a949c1SAzael Avalos if (!get_video_status(dev, &value)) { 1418b4f9fe12SLen Brown int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; 1419b4f9fe12SLen Brown int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; 1420b4f9fe12SLen Brown int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; 1421b5163992SAzael Avalos 1422936c8bcdSAlexey Dobriyan seq_printf(m, "lcd_out: %d\n", is_lcd); 1423936c8bcdSAlexey Dobriyan seq_printf(m, "crt_out: %d\n", is_crt); 1424936c8bcdSAlexey Dobriyan seq_printf(m, "tv_out: %d\n", is_tv); 1425e1a949c1SAzael Avalos return 0; 1426b4f9fe12SLen Brown } 1427b4f9fe12SLen Brown 1428e1a949c1SAzael Avalos return -EIO; 1429b4f9fe12SLen Brown } 1430b4f9fe12SLen Brown 1431936c8bcdSAlexey Dobriyan static int video_proc_open(struct inode *inode, struct file *file) 1432b4f9fe12SLen Brown { 1433d9dda78bSAl Viro return single_open(file, video_proc_show, PDE_DATA(inode)); 1434936c8bcdSAlexey Dobriyan } 1435936c8bcdSAlexey Dobriyan 1436936c8bcdSAlexey Dobriyan static ssize_t video_proc_write(struct file *file, const char __user *buf, 1437936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1438936c8bcdSAlexey Dobriyan { 1439d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1440e1a949c1SAzael Avalos char *buffer; 1441e1a949c1SAzael Avalos char *cmd; 1442b4f9fe12SLen Brown int remain = count; 1443b4f9fe12SLen Brown int lcd_out = -1; 1444b4f9fe12SLen Brown int crt_out = -1; 1445b4f9fe12SLen Brown int tv_out = -1; 1446e1a949c1SAzael Avalos int value; 1447e1a949c1SAzael Avalos int ret; 1448b4f9fe12SLen Brown u32 video_out; 1449b4f9fe12SLen Brown 1450936c8bcdSAlexey Dobriyan cmd = kmalloc(count + 1, GFP_KERNEL); 1451936c8bcdSAlexey Dobriyan if (!cmd) 1452936c8bcdSAlexey Dobriyan return -ENOMEM; 1453936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, count)) { 1454936c8bcdSAlexey Dobriyan kfree(cmd); 1455936c8bcdSAlexey Dobriyan return -EFAULT; 1456936c8bcdSAlexey Dobriyan } 1457936c8bcdSAlexey Dobriyan cmd[count] = '\0'; 1458936c8bcdSAlexey Dobriyan 1459936c8bcdSAlexey Dobriyan buffer = cmd; 1460936c8bcdSAlexey Dobriyan 1461e0769fe6SDarren Hart /* 1462e0769fe6SDarren Hart * Scan expression. Multiple expressions may be delimited with ; 1463e0769fe6SDarren Hart * NOTE: To keep scanning simple, invalid fields are ignored. 1464b4f9fe12SLen Brown */ 1465b4f9fe12SLen Brown while (remain) { 1466b4f9fe12SLen Brown if (sscanf(buffer, " lcd_out : %i", &value) == 1) 1467b4f9fe12SLen Brown lcd_out = value & 1; 1468b4f9fe12SLen Brown else if (sscanf(buffer, " crt_out : %i", &value) == 1) 1469b4f9fe12SLen Brown crt_out = value & 1; 1470b4f9fe12SLen Brown else if (sscanf(buffer, " tv_out : %i", &value) == 1) 1471b4f9fe12SLen Brown tv_out = value & 1; 1472e0769fe6SDarren Hart /* Advance to one character past the next ; */ 1473b4f9fe12SLen Brown do { 1474b4f9fe12SLen Brown ++buffer; 1475b4f9fe12SLen Brown --remain; 1476b5163992SAzael Avalos } while (remain && *(buffer - 1) != ';'); 1477b4f9fe12SLen Brown } 1478b4f9fe12SLen Brown 1479936c8bcdSAlexey Dobriyan kfree(cmd); 1480936c8bcdSAlexey Dobriyan 148136d03f93SSeth Forshee ret = get_video_status(dev, &video_out); 148236d03f93SSeth Forshee if (!ret) { 1483b4f9fe12SLen Brown unsigned int new_video_out = video_out; 1484b5163992SAzael Avalos 1485b4f9fe12SLen Brown if (lcd_out != -1) 1486b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out); 1487b4f9fe12SLen Brown if (crt_out != -1) 1488b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out); 1489b4f9fe12SLen Brown if (tv_out != -1) 1490b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out); 1491e0769fe6SDarren Hart /* 1492e0769fe6SDarren Hart * To avoid unnecessary video disruption, only write the new 14933f75bbe9SAzael Avalos * video setting if something changed. 14943f75bbe9SAzael Avalos */ 1495b4f9fe12SLen Brown if (new_video_out != video_out) 149632bcd5cbSSeth Forshee ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out); 1497b4f9fe12SLen Brown } 1498b4f9fe12SLen Brown 1499e1a949c1SAzael Avalos return ret ? -EIO : count; 1500b4f9fe12SLen Brown } 1501b4f9fe12SLen Brown 1502936c8bcdSAlexey Dobriyan static const struct file_operations video_proc_fops = { 1503936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1504936c8bcdSAlexey Dobriyan .open = video_proc_open, 1505936c8bcdSAlexey Dobriyan .read = seq_read, 1506936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1507936c8bcdSAlexey Dobriyan .release = single_release, 1508936c8bcdSAlexey Dobriyan .write = video_proc_write, 1509936c8bcdSAlexey Dobriyan }; 1510936c8bcdSAlexey Dobriyan 15113e07e5baSAzael Avalos /* Fan status */ 151236d03f93SSeth Forshee static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status) 151336d03f93SSeth Forshee { 15143e07e5baSAzael Avalos u32 result = hci_read(dev, HCI_FAN, status); 151536d03f93SSeth Forshee 15163e07e5baSAzael Avalos if (result == TOS_FAILURE) 15173e07e5baSAzael Avalos pr_err("ACPI call to get Fan status failed\n"); 15183e07e5baSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 15193e07e5baSAzael Avalos return -ENODEV; 15203e07e5baSAzael Avalos 1521e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 15223e07e5baSAzael Avalos } 15233e07e5baSAzael Avalos 15243e07e5baSAzael Avalos static int set_fan_status(struct toshiba_acpi_dev *dev, u32 status) 15253e07e5baSAzael Avalos { 15263e07e5baSAzael Avalos u32 result = hci_write(dev, HCI_FAN, status); 15273e07e5baSAzael Avalos 15283e07e5baSAzael Avalos if (result == TOS_FAILURE) 15293e07e5baSAzael Avalos pr_err("ACPI call to set Fan status failed\n"); 15303e07e5baSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 15313e07e5baSAzael Avalos return -ENODEV; 15323e07e5baSAzael Avalos 1533e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 153436d03f93SSeth Forshee } 153536d03f93SSeth Forshee 1536936c8bcdSAlexey Dobriyan static int fan_proc_show(struct seq_file *m, void *v) 1537b4f9fe12SLen Brown { 1538135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1539b4f9fe12SLen Brown u32 value; 1540b4f9fe12SLen Brown 15413e07e5baSAzael Avalos if (get_fan_status(dev, &value)) 15423e07e5baSAzael Avalos return -EIO; 15433e07e5baSAzael Avalos 1544936c8bcdSAlexey Dobriyan seq_printf(m, "running: %d\n", (value > 0)); 1545135740deSSeth Forshee seq_printf(m, "force_on: %d\n", dev->force_fan); 1546b4f9fe12SLen Brown 15473e07e5baSAzael Avalos return 0; 1548b4f9fe12SLen Brown } 1549b4f9fe12SLen Brown 1550936c8bcdSAlexey Dobriyan static int fan_proc_open(struct inode *inode, struct file *file) 1551b4f9fe12SLen Brown { 1552d9dda78bSAl Viro return single_open(file, fan_proc_show, PDE_DATA(inode)); 1553936c8bcdSAlexey Dobriyan } 1554936c8bcdSAlexey Dobriyan 1555936c8bcdSAlexey Dobriyan static ssize_t fan_proc_write(struct file *file, const char __user *buf, 1556936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1557936c8bcdSAlexey Dobriyan { 1558d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1559936c8bcdSAlexey Dobriyan char cmd[42]; 1560936c8bcdSAlexey Dobriyan size_t len; 1561b4f9fe12SLen Brown int value; 1562b4f9fe12SLen Brown 1563936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1564936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1565936c8bcdSAlexey Dobriyan return -EFAULT; 1566936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1567936c8bcdSAlexey Dobriyan 15683e07e5baSAzael Avalos if (sscanf(cmd, " force_on : %i", &value) != 1 && 15693e07e5baSAzael Avalos value != 0 && value != 1) 1570b4f9fe12SLen Brown return -EINVAL; 15713e07e5baSAzael Avalos 15723e07e5baSAzael Avalos if (set_fan_status(dev, value)) 15733e07e5baSAzael Avalos return -EIO; 15743e07e5baSAzael Avalos 15753e07e5baSAzael Avalos dev->force_fan = value; 1576b4f9fe12SLen Brown 1577b4f9fe12SLen Brown return count; 1578b4f9fe12SLen Brown } 1579b4f9fe12SLen Brown 1580936c8bcdSAlexey Dobriyan static const struct file_operations fan_proc_fops = { 1581936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1582936c8bcdSAlexey Dobriyan .open = fan_proc_open, 1583936c8bcdSAlexey Dobriyan .read = seq_read, 1584936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1585936c8bcdSAlexey Dobriyan .release = single_release, 1586936c8bcdSAlexey Dobriyan .write = fan_proc_write, 1587936c8bcdSAlexey Dobriyan }; 1588936c8bcdSAlexey Dobriyan 1589936c8bcdSAlexey Dobriyan static int keys_proc_show(struct seq_file *m, void *v) 1590b4f9fe12SLen Brown { 1591135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1592b4f9fe12SLen Brown 1593135740deSSeth Forshee seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid); 1594135740deSSeth Forshee seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event); 15957deef550SAzael Avalos 1596936c8bcdSAlexey Dobriyan return 0; 1597b4f9fe12SLen Brown } 1598b4f9fe12SLen Brown 1599936c8bcdSAlexey Dobriyan static int keys_proc_open(struct inode *inode, struct file *file) 1600b4f9fe12SLen Brown { 1601d9dda78bSAl Viro return single_open(file, keys_proc_show, PDE_DATA(inode)); 1602936c8bcdSAlexey Dobriyan } 1603936c8bcdSAlexey Dobriyan 1604936c8bcdSAlexey Dobriyan static ssize_t keys_proc_write(struct file *file, const char __user *buf, 1605936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1606936c8bcdSAlexey Dobriyan { 1607d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1608936c8bcdSAlexey Dobriyan char cmd[42]; 1609936c8bcdSAlexey Dobriyan size_t len; 1610b4f9fe12SLen Brown int value; 1611b4f9fe12SLen Brown 1612936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1613936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1614936c8bcdSAlexey Dobriyan return -EFAULT; 1615936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1616936c8bcdSAlexey Dobriyan 1617b5163992SAzael Avalos if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) 1618135740deSSeth Forshee dev->key_event_valid = 0; 1619b5163992SAzael Avalos else 1620b4f9fe12SLen Brown return -EINVAL; 1621b4f9fe12SLen Brown 1622b4f9fe12SLen Brown return count; 1623b4f9fe12SLen Brown } 1624b4f9fe12SLen Brown 1625936c8bcdSAlexey Dobriyan static const struct file_operations keys_proc_fops = { 1626936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1627936c8bcdSAlexey Dobriyan .open = keys_proc_open, 1628936c8bcdSAlexey Dobriyan .read = seq_read, 1629936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1630936c8bcdSAlexey Dobriyan .release = single_release, 1631936c8bcdSAlexey Dobriyan .write = keys_proc_write, 1632936c8bcdSAlexey Dobriyan }; 1633936c8bcdSAlexey Dobriyan 1634936c8bcdSAlexey Dobriyan static int version_proc_show(struct seq_file *m, void *v) 1635b4f9fe12SLen Brown { 1636936c8bcdSAlexey Dobriyan seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION); 1637936c8bcdSAlexey Dobriyan seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION); 1638936c8bcdSAlexey Dobriyan return 0; 1639b4f9fe12SLen Brown } 1640b4f9fe12SLen Brown 1641936c8bcdSAlexey Dobriyan static int version_proc_open(struct inode *inode, struct file *file) 1642936c8bcdSAlexey Dobriyan { 1643d9dda78bSAl Viro return single_open(file, version_proc_show, PDE_DATA(inode)); 1644936c8bcdSAlexey Dobriyan } 1645936c8bcdSAlexey Dobriyan 1646936c8bcdSAlexey Dobriyan static const struct file_operations version_proc_fops = { 1647936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1648936c8bcdSAlexey Dobriyan .open = version_proc_open, 1649936c8bcdSAlexey Dobriyan .read = seq_read, 1650936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1651936c8bcdSAlexey Dobriyan .release = single_release, 1652936c8bcdSAlexey Dobriyan }; 1653936c8bcdSAlexey Dobriyan 1654e0769fe6SDarren Hart /* 1655e0769fe6SDarren Hart * Proc and module init 1656b4f9fe12SLen Brown */ 1657b4f9fe12SLen Brown 1658b4f9fe12SLen Brown #define PROC_TOSHIBA "toshiba" 1659b4f9fe12SLen Brown 1660b859f159SGreg Kroah-Hartman static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1661b4f9fe12SLen Brown { 166236d03f93SSeth Forshee if (dev->backlight_dev) 1663135740deSSeth Forshee proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1664135740deSSeth Forshee &lcd_proc_fops, dev); 166536d03f93SSeth Forshee if (dev->video_supported) 1666135740deSSeth Forshee proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1667135740deSSeth Forshee &video_proc_fops, dev); 166836d03f93SSeth Forshee if (dev->fan_supported) 1669135740deSSeth Forshee proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1670135740deSSeth Forshee &fan_proc_fops, dev); 167136d03f93SSeth Forshee if (dev->hotkey_dev) 1672135740deSSeth Forshee proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1673135740deSSeth Forshee &keys_proc_fops, dev); 1674135740deSSeth Forshee proc_create_data("version", S_IRUGO, toshiba_proc_dir, 1675135740deSSeth Forshee &version_proc_fops, dev); 1676b4f9fe12SLen Brown } 1677b4f9fe12SLen Brown 167836d03f93SSeth Forshee static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1679b4f9fe12SLen Brown { 168036d03f93SSeth Forshee if (dev->backlight_dev) 1681936c8bcdSAlexey Dobriyan remove_proc_entry("lcd", toshiba_proc_dir); 168236d03f93SSeth Forshee if (dev->video_supported) 1683936c8bcdSAlexey Dobriyan remove_proc_entry("video", toshiba_proc_dir); 168436d03f93SSeth Forshee if (dev->fan_supported) 1685936c8bcdSAlexey Dobriyan remove_proc_entry("fan", toshiba_proc_dir); 168636d03f93SSeth Forshee if (dev->hotkey_dev) 1687936c8bcdSAlexey Dobriyan remove_proc_entry("keys", toshiba_proc_dir); 1688936c8bcdSAlexey Dobriyan remove_proc_entry("version", toshiba_proc_dir); 1689b4f9fe12SLen Brown } 1690b4f9fe12SLen Brown 1691acc2472eSLionel Debroux static const struct backlight_ops toshiba_backlight_data = { 1692121b7b0dSAkio Idehara .options = BL_CORE_SUSPENDRESUME, 169362cce752SSeth Forshee .get_brightness = get_lcd_brightness, 1694b4f9fe12SLen Brown .update_status = set_lcd_status, 1695b4f9fe12SLen Brown }; 1696b4f9fe12SLen Brown 169765e3cf9cSAzael Avalos /* Keyboard backlight work */ 169865e3cf9cSAzael Avalos static void toshiba_acpi_kbd_bl_work(struct work_struct *work); 169965e3cf9cSAzael Avalos 170065e3cf9cSAzael Avalos static DECLARE_WORK(kbd_bl_work, toshiba_acpi_kbd_bl_work); 170165e3cf9cSAzael Avalos 1702360f0f39SAzael Avalos /* 1703360f0f39SAzael Avalos * Sysfs files 1704360f0f39SAzael Avalos */ 17059d309848SAzael Avalos static ssize_t version_show(struct device *dev, 1706c6c68ff8SAzael Avalos struct device_attribute *attr, char *buf) 1707c6c68ff8SAzael Avalos { 1708c6c68ff8SAzael Avalos return sprintf(buf, "%s\n", TOSHIBA_ACPI_VERSION); 1709c6c68ff8SAzael Avalos } 17100c3c0f10SAzael Avalos static DEVICE_ATTR_RO(version); 1711c6c68ff8SAzael Avalos 17129d309848SAzael Avalos static ssize_t fan_store(struct device *dev, 171394477d4cSAzael Avalos struct device_attribute *attr, 171494477d4cSAzael Avalos const char *buf, size_t count) 171594477d4cSAzael Avalos { 171694477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 171794477d4cSAzael Avalos int state; 171894477d4cSAzael Avalos int ret; 171994477d4cSAzael Avalos 172094477d4cSAzael Avalos ret = kstrtoint(buf, 0, &state); 172194477d4cSAzael Avalos if (ret) 172294477d4cSAzael Avalos return ret; 172394477d4cSAzael Avalos 172494477d4cSAzael Avalos if (state != 0 && state != 1) 172594477d4cSAzael Avalos return -EINVAL; 172694477d4cSAzael Avalos 17273e07e5baSAzael Avalos ret = set_fan_status(toshiba, state); 17283e07e5baSAzael Avalos if (ret) 17293e07e5baSAzael Avalos return ret; 173094477d4cSAzael Avalos 173194477d4cSAzael Avalos return count; 173294477d4cSAzael Avalos } 173394477d4cSAzael Avalos 17349d309848SAzael Avalos static ssize_t fan_show(struct device *dev, 173594477d4cSAzael Avalos struct device_attribute *attr, char *buf) 173694477d4cSAzael Avalos { 173794477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 173894477d4cSAzael Avalos u32 value; 173994477d4cSAzael Avalos int ret; 174094477d4cSAzael Avalos 174194477d4cSAzael Avalos ret = get_fan_status(toshiba, &value); 174294477d4cSAzael Avalos if (ret) 174394477d4cSAzael Avalos return ret; 174494477d4cSAzael Avalos 174594477d4cSAzael Avalos return sprintf(buf, "%d\n", value); 174694477d4cSAzael Avalos } 17470c3c0f10SAzael Avalos static DEVICE_ATTR_RW(fan); 174894477d4cSAzael Avalos 17499d309848SAzael Avalos static ssize_t kbd_backlight_mode_store(struct device *dev, 1750360f0f39SAzael Avalos struct device_attribute *attr, 1751360f0f39SAzael Avalos const char *buf, size_t count) 1752360f0f39SAzael Avalos { 1753360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1754aeaac098SDan Carpenter int mode; 1755aeaac098SDan Carpenter int ret; 1756360f0f39SAzael Avalos 1757aeaac098SDan Carpenter 1758aeaac098SDan Carpenter ret = kstrtoint(buf, 0, &mode); 1759aeaac098SDan Carpenter if (ret) 1760aeaac098SDan Carpenter return ret; 176193f8c16dSAzael Avalos 176293f8c16dSAzael Avalos /* Check for supported modes depending on keyboard backlight type */ 176393f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 176493f8c16dSAzael Avalos /* Type 1 supports SCI_KBD_MODE_FNZ and SCI_KBD_MODE_AUTO */ 1765aeaac098SDan Carpenter if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO) 1766360f0f39SAzael Avalos return -EINVAL; 176793f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 176893f8c16dSAzael Avalos /* Type 2 doesn't support SCI_KBD_MODE_FNZ */ 176993f8c16dSAzael Avalos if (mode != SCI_KBD_MODE_AUTO && mode != SCI_KBD_MODE_ON && 177093f8c16dSAzael Avalos mode != SCI_KBD_MODE_OFF) 177193f8c16dSAzael Avalos return -EINVAL; 177293f8c16dSAzael Avalos } 1773360f0f39SAzael Avalos 1774e0769fe6SDarren Hart /* 1775e0769fe6SDarren Hart * Set the Keyboard Backlight Mode where: 1776360f0f39SAzael Avalos * Auto - KBD backlight turns off automatically in given time 1777360f0f39SAzael Avalos * FN-Z - KBD backlight "toggles" when hotkey pressed 177893f8c16dSAzael Avalos * ON - KBD backlight is always on 177993f8c16dSAzael Avalos * OFF - KBD backlight is always off 1780360f0f39SAzael Avalos */ 178193f8c16dSAzael Avalos 178293f8c16dSAzael Avalos /* Only make a change if the actual mode has changed */ 1783aeaac098SDan Carpenter if (toshiba->kbd_mode != mode) { 178493f8c16dSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 17851e574dbfSAzael Avalos int time = toshiba->kbd_time << HCI_MISC_SHIFT; 178693f8c16dSAzael Avalos 178793f8c16dSAzael Avalos /* OR the "base time" to the actual method format */ 178893f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 178993f8c16dSAzael Avalos /* Type 1 requires the current mode */ 179093f8c16dSAzael Avalos time |= toshiba->kbd_mode; 179193f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 179293f8c16dSAzael Avalos /* Type 2 requires the desired mode */ 179393f8c16dSAzael Avalos time |= mode; 179493f8c16dSAzael Avalos } 179593f8c16dSAzael Avalos 1796aeaac098SDan Carpenter ret = toshiba_kbd_illum_status_set(toshiba, time); 1797aeaac098SDan Carpenter if (ret) 1798aeaac098SDan Carpenter return ret; 179993f8c16dSAzael Avalos 1800360f0f39SAzael Avalos toshiba->kbd_mode = mode; 180165e3cf9cSAzael Avalos 180265e3cf9cSAzael Avalos /* 180365e3cf9cSAzael Avalos * Some laptop models with the second generation backlit 180465e3cf9cSAzael Avalos * keyboard (type 2) do not generate the keyboard backlight 180565e3cf9cSAzael Avalos * changed event (0x92), and thus, the driver will never update 180665e3cf9cSAzael Avalos * the sysfs entries. 180765e3cf9cSAzael Avalos * 180865e3cf9cSAzael Avalos * The event is generated right when changing the keyboard 180965e3cf9cSAzael Avalos * backlight mode and the *notify function will set the 181065e3cf9cSAzael Avalos * kbd_event_generated to true. 181165e3cf9cSAzael Avalos * 181265e3cf9cSAzael Avalos * In case the event is not generated, schedule the keyboard 181365e3cf9cSAzael Avalos * backlight work to update the sysfs entries and emulate the 181465e3cf9cSAzael Avalos * event via genetlink. 181565e3cf9cSAzael Avalos */ 181665e3cf9cSAzael Avalos if (toshiba->kbd_type == 2 && 181765e3cf9cSAzael Avalos !toshiba_acpi->kbd_event_generated) 181865e3cf9cSAzael Avalos schedule_work(&kbd_bl_work); 1819360f0f39SAzael Avalos } 1820360f0f39SAzael Avalos 1821360f0f39SAzael Avalos return count; 1822360f0f39SAzael Avalos } 1823360f0f39SAzael Avalos 18249d309848SAzael Avalos static ssize_t kbd_backlight_mode_show(struct device *dev, 1825360f0f39SAzael Avalos struct device_attribute *attr, 1826360f0f39SAzael Avalos char *buf) 1827360f0f39SAzael Avalos { 1828360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1829360f0f39SAzael Avalos u32 time; 1830360f0f39SAzael Avalos 1831360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1832360f0f39SAzael Avalos return -EIO; 1833360f0f39SAzael Avalos 183493f8c16dSAzael Avalos return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK); 183593f8c16dSAzael Avalos } 18360c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_mode); 183793f8c16dSAzael Avalos 18389d309848SAzael Avalos static ssize_t kbd_type_show(struct device *dev, 18399d309848SAzael Avalos struct device_attribute *attr, char *buf) 184093f8c16dSAzael Avalos { 184193f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 184293f8c16dSAzael Avalos 184393f8c16dSAzael Avalos return sprintf(buf, "%d\n", toshiba->kbd_type); 184493f8c16dSAzael Avalos } 18450c3c0f10SAzael Avalos static DEVICE_ATTR_RO(kbd_type); 184693f8c16dSAzael Avalos 18479d309848SAzael Avalos static ssize_t available_kbd_modes_show(struct device *dev, 184893f8c16dSAzael Avalos struct device_attribute *attr, 184993f8c16dSAzael Avalos char *buf) 185093f8c16dSAzael Avalos { 185193f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 185293f8c16dSAzael Avalos 185393f8c16dSAzael Avalos if (toshiba->kbd_type == 1) 18540b498201SAzael Avalos return sprintf(buf, "0x%x 0x%x\n", 185593f8c16dSAzael Avalos SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO); 185693f8c16dSAzael Avalos 18570b498201SAzael Avalos return sprintf(buf, "0x%x 0x%x 0x%x\n", 185893f8c16dSAzael Avalos SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF); 1859360f0f39SAzael Avalos } 18600c3c0f10SAzael Avalos static DEVICE_ATTR_RO(available_kbd_modes); 1861360f0f39SAzael Avalos 18629d309848SAzael Avalos static ssize_t kbd_backlight_timeout_store(struct device *dev, 1863360f0f39SAzael Avalos struct device_attribute *attr, 1864360f0f39SAzael Avalos const char *buf, size_t count) 1865360f0f39SAzael Avalos { 1866360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1867eabde0faSAzael Avalos int time; 1868eabde0faSAzael Avalos int ret; 1869360f0f39SAzael Avalos 1870eabde0faSAzael Avalos ret = kstrtoint(buf, 0, &time); 1871eabde0faSAzael Avalos if (ret) 1872eabde0faSAzael Avalos return ret; 1873eabde0faSAzael Avalos 1874eabde0faSAzael Avalos /* Check for supported values depending on kbd_type */ 1875eabde0faSAzael Avalos if (toshiba->kbd_type == 1) { 1876eabde0faSAzael Avalos if (time < 0 || time > 60) 1877360f0f39SAzael Avalos return -EINVAL; 1878eabde0faSAzael Avalos } else if (toshiba->kbd_type == 2) { 1879eabde0faSAzael Avalos if (time < 1 || time > 60) 1880eabde0faSAzael Avalos return -EINVAL; 1881eabde0faSAzael Avalos } 1882360f0f39SAzael Avalos 1883eabde0faSAzael Avalos /* Set the Keyboard Backlight Timeout */ 1884eabde0faSAzael Avalos 1885eabde0faSAzael Avalos /* Only make a change if the actual timeout has changed */ 1886eabde0faSAzael Avalos if (toshiba->kbd_time != time) { 1887eabde0faSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 1888360f0f39SAzael Avalos time = time << HCI_MISC_SHIFT; 1889eabde0faSAzael Avalos /* OR the "base time" to the actual method format */ 1890eabde0faSAzael Avalos if (toshiba->kbd_type == 1) 1891eabde0faSAzael Avalos time |= SCI_KBD_MODE_FNZ; 1892eabde0faSAzael Avalos else if (toshiba->kbd_type == 2) 1893eabde0faSAzael Avalos time |= SCI_KBD_MODE_AUTO; 1894eabde0faSAzael Avalos 1895eabde0faSAzael Avalos ret = toshiba_kbd_illum_status_set(toshiba, time); 1896eabde0faSAzael Avalos if (ret) 1897eabde0faSAzael Avalos return ret; 1898eabde0faSAzael Avalos 1899360f0f39SAzael Avalos toshiba->kbd_time = time >> HCI_MISC_SHIFT; 1900360f0f39SAzael Avalos } 1901360f0f39SAzael Avalos 1902360f0f39SAzael Avalos return count; 1903360f0f39SAzael Avalos } 1904360f0f39SAzael Avalos 19059d309848SAzael Avalos static ssize_t kbd_backlight_timeout_show(struct device *dev, 1906360f0f39SAzael Avalos struct device_attribute *attr, 1907360f0f39SAzael Avalos char *buf) 1908360f0f39SAzael Avalos { 1909360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1910360f0f39SAzael Avalos u32 time; 1911360f0f39SAzael Avalos 1912360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1913360f0f39SAzael Avalos return -EIO; 1914360f0f39SAzael Avalos 1915360f0f39SAzael Avalos return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT); 1916360f0f39SAzael Avalos } 19170c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_timeout); 1918360f0f39SAzael Avalos 19199d309848SAzael Avalos static ssize_t touchpad_store(struct device *dev, 19209d8658acSAzael Avalos struct device_attribute *attr, 19219d8658acSAzael Avalos const char *buf, size_t count) 19229d8658acSAzael Avalos { 19239d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 19249d8658acSAzael Avalos int state; 1925c8a41669SAzael Avalos int ret; 19269d8658acSAzael Avalos 19279d8658acSAzael Avalos /* Set the TouchPad on/off, 0 - Disable | 1 - Enable */ 1928c8a41669SAzael Avalos ret = kstrtoint(buf, 0, &state); 1929c8a41669SAzael Avalos if (ret) 1930c8a41669SAzael Avalos return ret; 1931c8a41669SAzael Avalos if (state != 0 && state != 1) 1932c8a41669SAzael Avalos return -EINVAL; 1933c8a41669SAzael Avalos 1934c8a41669SAzael Avalos ret = toshiba_touchpad_set(toshiba, state); 1935c8a41669SAzael Avalos if (ret) 1936c8a41669SAzael Avalos return ret; 19379d8658acSAzael Avalos 19389d8658acSAzael Avalos return count; 19399d8658acSAzael Avalos } 19409d8658acSAzael Avalos 19419d309848SAzael Avalos static ssize_t touchpad_show(struct device *dev, 19429d8658acSAzael Avalos struct device_attribute *attr, char *buf) 19439d8658acSAzael Avalos { 19449d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 19459d8658acSAzael Avalos u32 state; 19469d8658acSAzael Avalos int ret; 19479d8658acSAzael Avalos 19489d8658acSAzael Avalos ret = toshiba_touchpad_get(toshiba, &state); 19499d8658acSAzael Avalos if (ret < 0) 19509d8658acSAzael Avalos return ret; 19519d8658acSAzael Avalos 19529d8658acSAzael Avalos return sprintf(buf, "%i\n", state); 19539d8658acSAzael Avalos } 19540c3c0f10SAzael Avalos static DEVICE_ATTR_RW(touchpad); 19559d8658acSAzael Avalos 19569d309848SAzael Avalos static ssize_t position_show(struct device *dev, 19575a2813e9SAzael Avalos struct device_attribute *attr, char *buf) 19585a2813e9SAzael Avalos { 19595a2813e9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 19605a2813e9SAzael Avalos u32 xyval, zval, tmp; 19615a2813e9SAzael Avalos u16 x, y, z; 19625a2813e9SAzael Avalos int ret; 19635a2813e9SAzael Avalos 19645a2813e9SAzael Avalos xyval = zval = 0; 19655a2813e9SAzael Avalos ret = toshiba_accelerometer_get(toshiba, &xyval, &zval); 19665a2813e9SAzael Avalos if (ret < 0) 19675a2813e9SAzael Avalos return ret; 19685a2813e9SAzael Avalos 19695a2813e9SAzael Avalos x = xyval & HCI_ACCEL_MASK; 19705a2813e9SAzael Avalos tmp = xyval >> HCI_MISC_SHIFT; 19715a2813e9SAzael Avalos y = tmp & HCI_ACCEL_MASK; 19725a2813e9SAzael Avalos z = zval & HCI_ACCEL_MASK; 19735a2813e9SAzael Avalos 19745a2813e9SAzael Avalos return sprintf(buf, "%d %d %d\n", x, y, z); 19755a2813e9SAzael Avalos } 19760c3c0f10SAzael Avalos static DEVICE_ATTR_RO(position); 19775a2813e9SAzael Avalos 19789d309848SAzael Avalos static ssize_t usb_sleep_charge_show(struct device *dev, 19799d309848SAzael Avalos struct device_attribute *attr, char *buf) 1980e26ffe51SAzael Avalos { 1981e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1982e26ffe51SAzael Avalos u32 mode; 1983e26ffe51SAzael Avalos int ret; 1984e26ffe51SAzael Avalos 1985e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_get(toshiba, &mode); 1986e26ffe51SAzael Avalos if (ret < 0) 1987e26ffe51SAzael Avalos return ret; 1988e26ffe51SAzael Avalos 1989e26ffe51SAzael Avalos return sprintf(buf, "%x\n", mode & SCI_USB_CHARGE_MODE_MASK); 1990e26ffe51SAzael Avalos } 1991e26ffe51SAzael Avalos 19929d309848SAzael Avalos static ssize_t usb_sleep_charge_store(struct device *dev, 1993e26ffe51SAzael Avalos struct device_attribute *attr, 1994e26ffe51SAzael Avalos const char *buf, size_t count) 1995e26ffe51SAzael Avalos { 1996e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1997e26ffe51SAzael Avalos u32 mode; 1998e26ffe51SAzael Avalos int state; 1999e26ffe51SAzael Avalos int ret; 2000e26ffe51SAzael Avalos 2001e26ffe51SAzael Avalos ret = kstrtoint(buf, 0, &state); 2002e26ffe51SAzael Avalos if (ret) 2003e26ffe51SAzael Avalos return ret; 2004e0769fe6SDarren Hart /* 2005e0769fe6SDarren Hart * Check for supported values, where: 2006e26ffe51SAzael Avalos * 0 - Disabled 2007e26ffe51SAzael Avalos * 1 - Alternate (Non USB conformant devices that require more power) 2008e26ffe51SAzael Avalos * 2 - Auto (USB conformant devices) 2009c8c91842SAzael Avalos * 3 - Typical 2010e26ffe51SAzael Avalos */ 2011c8c91842SAzael Avalos if (state != 0 && state != 1 && state != 2 && state != 3) 2012e26ffe51SAzael Avalos return -EINVAL; 2013e26ffe51SAzael Avalos 2014e26ffe51SAzael Avalos /* Set the USB charging mode to internal value */ 2015c8c91842SAzael Avalos mode = toshiba->usbsc_mode_base; 2016e26ffe51SAzael Avalos if (state == 0) 2017c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_DISABLED; 2018e26ffe51SAzael Avalos else if (state == 1) 2019c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_ALTERNATE; 2020e26ffe51SAzael Avalos else if (state == 2) 2021c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_AUTO; 2022c8c91842SAzael Avalos else if (state == 3) 2023c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_TYPICAL; 2024e26ffe51SAzael Avalos 2025e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_set(toshiba, mode); 2026e26ffe51SAzael Avalos if (ret) 2027e26ffe51SAzael Avalos return ret; 2028e26ffe51SAzael Avalos 2029e26ffe51SAzael Avalos return count; 2030e26ffe51SAzael Avalos } 20310c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_charge); 2032e26ffe51SAzael Avalos 2033182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_show(struct device *dev, 2034182bcaa5SAzael Avalos struct device_attribute *attr, 2035182bcaa5SAzael Avalos char *buf) 2036182bcaa5SAzael Avalos { 2037182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2038182bcaa5SAzael Avalos u32 state; 2039182bcaa5SAzael Avalos int bat_lvl; 2040182bcaa5SAzael Avalos int status; 2041182bcaa5SAzael Avalos int ret; 2042182bcaa5SAzael Avalos int tmp; 2043182bcaa5SAzael Avalos 2044182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_get(toshiba, &state); 2045182bcaa5SAzael Avalos if (ret < 0) 2046182bcaa5SAzael Avalos return ret; 2047182bcaa5SAzael Avalos 2048182bcaa5SAzael Avalos /* Determine the status: 0x4 - Enabled | 0x1 - Disabled */ 2049182bcaa5SAzael Avalos tmp = state & SCI_USB_CHARGE_BAT_MASK; 2050182bcaa5SAzael Avalos status = (tmp == 0x4) ? 1 : 0; 2051182bcaa5SAzael Avalos /* Determine the battery level set */ 2052182bcaa5SAzael Avalos bat_lvl = state >> HCI_MISC_SHIFT; 2053182bcaa5SAzael Avalos 2054182bcaa5SAzael Avalos return sprintf(buf, "%d %d\n", status, bat_lvl); 2055182bcaa5SAzael Avalos } 2056182bcaa5SAzael Avalos 2057182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_store(struct device *dev, 2058182bcaa5SAzael Avalos struct device_attribute *attr, 2059182bcaa5SAzael Avalos const char *buf, size_t count) 2060182bcaa5SAzael Avalos { 2061182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2062182bcaa5SAzael Avalos u32 status; 2063182bcaa5SAzael Avalos int value; 2064182bcaa5SAzael Avalos int ret; 2065182bcaa5SAzael Avalos int tmp; 2066182bcaa5SAzael Avalos 2067182bcaa5SAzael Avalos ret = kstrtoint(buf, 0, &value); 2068182bcaa5SAzael Avalos if (ret) 2069182bcaa5SAzael Avalos return ret; 2070182bcaa5SAzael Avalos 2071e0769fe6SDarren Hart /* 2072e0769fe6SDarren Hart * Set the status of the function: 2073182bcaa5SAzael Avalos * 0 - Disabled 2074182bcaa5SAzael Avalos * 1-100 - Enabled 2075182bcaa5SAzael Avalos */ 2076182bcaa5SAzael Avalos if (value < 0 || value > 100) 2077182bcaa5SAzael Avalos return -EINVAL; 2078182bcaa5SAzael Avalos 2079182bcaa5SAzael Avalos if (value == 0) { 2080182bcaa5SAzael Avalos tmp = toshiba->usbsc_bat_level << HCI_MISC_SHIFT; 2081182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_OFF; 2082182bcaa5SAzael Avalos } else { 2083182bcaa5SAzael Avalos tmp = value << HCI_MISC_SHIFT; 2084182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_ON; 2085182bcaa5SAzael Avalos } 2086182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_set(toshiba, status); 2087182bcaa5SAzael Avalos if (ret < 0) 2088182bcaa5SAzael Avalos return ret; 2089182bcaa5SAzael Avalos 2090182bcaa5SAzael Avalos toshiba->usbsc_bat_level = status >> HCI_MISC_SHIFT; 2091182bcaa5SAzael Avalos 2092182bcaa5SAzael Avalos return count; 2093182bcaa5SAzael Avalos } 20940c3c0f10SAzael Avalos static DEVICE_ATTR_RW(sleep_functions_on_battery); 2095182bcaa5SAzael Avalos 20969d309848SAzael Avalos static ssize_t usb_rapid_charge_show(struct device *dev, 20979d309848SAzael Avalos struct device_attribute *attr, char *buf) 2098bb3fe01fSAzael Avalos { 2099bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2100bb3fe01fSAzael Avalos u32 state; 2101bb3fe01fSAzael Avalos int ret; 2102bb3fe01fSAzael Avalos 2103bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(toshiba, &state); 2104bb3fe01fSAzael Avalos if (ret < 0) 2105bb3fe01fSAzael Avalos return ret; 2106bb3fe01fSAzael Avalos 2107bb3fe01fSAzael Avalos return sprintf(buf, "%d\n", state); 2108bb3fe01fSAzael Avalos } 2109bb3fe01fSAzael Avalos 21109d309848SAzael Avalos static ssize_t usb_rapid_charge_store(struct device *dev, 2111bb3fe01fSAzael Avalos struct device_attribute *attr, 2112bb3fe01fSAzael Avalos const char *buf, size_t count) 2113bb3fe01fSAzael Avalos { 2114bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2115bb3fe01fSAzael Avalos int state; 2116bb3fe01fSAzael Avalos int ret; 2117bb3fe01fSAzael Avalos 2118bb3fe01fSAzael Avalos ret = kstrtoint(buf, 0, &state); 2119bb3fe01fSAzael Avalos if (ret) 2120bb3fe01fSAzael Avalos return ret; 2121bb3fe01fSAzael Avalos if (state != 0 && state != 1) 2122bb3fe01fSAzael Avalos return -EINVAL; 2123bb3fe01fSAzael Avalos 2124bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_set(toshiba, state); 2125bb3fe01fSAzael Avalos if (ret) 2126bb3fe01fSAzael Avalos return ret; 2127bb3fe01fSAzael Avalos 2128bb3fe01fSAzael Avalos return count; 2129bb3fe01fSAzael Avalos } 21300c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_rapid_charge); 2131bb3fe01fSAzael Avalos 21329d309848SAzael Avalos static ssize_t usb_sleep_music_show(struct device *dev, 21339d309848SAzael Avalos struct device_attribute *attr, char *buf) 2134172ce0a9SAzael Avalos { 2135172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2136172ce0a9SAzael Avalos u32 state; 2137172ce0a9SAzael Avalos int ret; 2138172ce0a9SAzael Avalos 2139172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(toshiba, &state); 2140172ce0a9SAzael Avalos if (ret < 0) 2141172ce0a9SAzael Avalos return ret; 2142172ce0a9SAzael Avalos 2143172ce0a9SAzael Avalos return sprintf(buf, "%d\n", state); 2144172ce0a9SAzael Avalos } 2145172ce0a9SAzael Avalos 21469d309848SAzael Avalos static ssize_t usb_sleep_music_store(struct device *dev, 2147172ce0a9SAzael Avalos struct device_attribute *attr, 2148172ce0a9SAzael Avalos const char *buf, size_t count) 2149172ce0a9SAzael Avalos { 2150172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2151172ce0a9SAzael Avalos int state; 2152172ce0a9SAzael Avalos int ret; 2153172ce0a9SAzael Avalos 2154172ce0a9SAzael Avalos ret = kstrtoint(buf, 0, &state); 2155172ce0a9SAzael Avalos if (ret) 2156172ce0a9SAzael Avalos return ret; 2157172ce0a9SAzael Avalos if (state != 0 && state != 1) 2158172ce0a9SAzael Avalos return -EINVAL; 2159172ce0a9SAzael Avalos 2160172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_set(toshiba, state); 2161172ce0a9SAzael Avalos if (ret) 2162172ce0a9SAzael Avalos return ret; 2163172ce0a9SAzael Avalos 2164172ce0a9SAzael Avalos return count; 2165172ce0a9SAzael Avalos } 21660c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_music); 2167172ce0a9SAzael Avalos 21689d309848SAzael Avalos static ssize_t kbd_function_keys_show(struct device *dev, 21699d309848SAzael Avalos struct device_attribute *attr, char *buf) 2170bae84195SAzael Avalos { 2171bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2172bae84195SAzael Avalos int mode; 2173bae84195SAzael Avalos int ret; 2174bae84195SAzael Avalos 2175bae84195SAzael Avalos ret = toshiba_function_keys_get(toshiba, &mode); 2176bae84195SAzael Avalos if (ret < 0) 2177bae84195SAzael Avalos return ret; 2178bae84195SAzael Avalos 2179bae84195SAzael Avalos return sprintf(buf, "%d\n", mode); 2180bae84195SAzael Avalos } 2181bae84195SAzael Avalos 21829d309848SAzael Avalos static ssize_t kbd_function_keys_store(struct device *dev, 2183bae84195SAzael Avalos struct device_attribute *attr, 2184bae84195SAzael Avalos const char *buf, size_t count) 2185bae84195SAzael Avalos { 2186bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2187bae84195SAzael Avalos int mode; 2188bae84195SAzael Avalos int ret; 2189bae84195SAzael Avalos 2190bae84195SAzael Avalos ret = kstrtoint(buf, 0, &mode); 2191bae84195SAzael Avalos if (ret) 2192bae84195SAzael Avalos return ret; 2193e0769fe6SDarren Hart /* 2194e0769fe6SDarren Hart * Check for the function keys mode where: 2195bae84195SAzael Avalos * 0 - Normal operation (F{1-12} as usual and hotkeys via FN-F{1-12}) 2196bae84195SAzael Avalos * 1 - Special functions (Opposite of the above setting) 2197bae84195SAzael Avalos */ 2198bae84195SAzael Avalos if (mode != 0 && mode != 1) 2199bae84195SAzael Avalos return -EINVAL; 2200bae84195SAzael Avalos 2201bae84195SAzael Avalos ret = toshiba_function_keys_set(toshiba, mode); 2202bae84195SAzael Avalos if (ret) 2203bae84195SAzael Avalos return ret; 2204bae84195SAzael Avalos 2205bae84195SAzael Avalos pr_info("Reboot for changes to KBD Function Keys to take effect"); 2206bae84195SAzael Avalos 2207bae84195SAzael Avalos return count; 2208bae84195SAzael Avalos } 22090c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_function_keys); 2210bae84195SAzael Avalos 22119d309848SAzael Avalos static ssize_t panel_power_on_show(struct device *dev, 22129d309848SAzael Avalos struct device_attribute *attr, char *buf) 221335d53ceaSAzael Avalos { 221435d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 221535d53ceaSAzael Avalos u32 state; 221635d53ceaSAzael Avalos int ret; 221735d53ceaSAzael Avalos 221835d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(toshiba, &state); 221935d53ceaSAzael Avalos if (ret < 0) 222035d53ceaSAzael Avalos return ret; 222135d53ceaSAzael Avalos 222235d53ceaSAzael Avalos return sprintf(buf, "%d\n", state); 222335d53ceaSAzael Avalos } 222435d53ceaSAzael Avalos 22259d309848SAzael Avalos static ssize_t panel_power_on_store(struct device *dev, 222635d53ceaSAzael Avalos struct device_attribute *attr, 222735d53ceaSAzael Avalos const char *buf, size_t count) 222835d53ceaSAzael Avalos { 222935d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 223035d53ceaSAzael Avalos int state; 223135d53ceaSAzael Avalos int ret; 223235d53ceaSAzael Avalos 223335d53ceaSAzael Avalos ret = kstrtoint(buf, 0, &state); 223435d53ceaSAzael Avalos if (ret) 223535d53ceaSAzael Avalos return ret; 223635d53ceaSAzael Avalos if (state != 0 && state != 1) 223735d53ceaSAzael Avalos return -EINVAL; 223835d53ceaSAzael Avalos 223935d53ceaSAzael Avalos ret = toshiba_panel_power_on_set(toshiba, state); 224035d53ceaSAzael Avalos if (ret) 224135d53ceaSAzael Avalos return ret; 224235d53ceaSAzael Avalos 224335d53ceaSAzael Avalos pr_info("Reboot for changes to Panel Power ON to take effect"); 224435d53ceaSAzael Avalos 224535d53ceaSAzael Avalos return count; 224635d53ceaSAzael Avalos } 22470c3c0f10SAzael Avalos static DEVICE_ATTR_RW(panel_power_on); 224835d53ceaSAzael Avalos 22499d309848SAzael Avalos static ssize_t usb_three_show(struct device *dev, 22509d309848SAzael Avalos struct device_attribute *attr, char *buf) 225117fe4b3dSAzael Avalos { 225217fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 225317fe4b3dSAzael Avalos u32 state; 225417fe4b3dSAzael Avalos int ret; 225517fe4b3dSAzael Avalos 225617fe4b3dSAzael Avalos ret = toshiba_usb_three_get(toshiba, &state); 225717fe4b3dSAzael Avalos if (ret < 0) 225817fe4b3dSAzael Avalos return ret; 225917fe4b3dSAzael Avalos 226017fe4b3dSAzael Avalos return sprintf(buf, "%d\n", state); 226117fe4b3dSAzael Avalos } 226217fe4b3dSAzael Avalos 22639d309848SAzael Avalos static ssize_t usb_three_store(struct device *dev, 226417fe4b3dSAzael Avalos struct device_attribute *attr, 226517fe4b3dSAzael Avalos const char *buf, size_t count) 226617fe4b3dSAzael Avalos { 226717fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 226817fe4b3dSAzael Avalos int state; 226917fe4b3dSAzael Avalos int ret; 227017fe4b3dSAzael Avalos 227117fe4b3dSAzael Avalos ret = kstrtoint(buf, 0, &state); 227217fe4b3dSAzael Avalos if (ret) 227317fe4b3dSAzael Avalos return ret; 2274e0769fe6SDarren Hart /* 2275e0769fe6SDarren Hart * Check for USB 3 mode where: 227617fe4b3dSAzael Avalos * 0 - Disabled (Acts like a USB 2 port, saving power) 227717fe4b3dSAzael Avalos * 1 - Enabled 227817fe4b3dSAzael Avalos */ 227917fe4b3dSAzael Avalos if (state != 0 && state != 1) 228017fe4b3dSAzael Avalos return -EINVAL; 228117fe4b3dSAzael Avalos 228217fe4b3dSAzael Avalos ret = toshiba_usb_three_set(toshiba, state); 228317fe4b3dSAzael Avalos if (ret) 228417fe4b3dSAzael Avalos return ret; 228517fe4b3dSAzael Avalos 228617fe4b3dSAzael Avalos pr_info("Reboot for changes to USB 3 to take effect"); 228717fe4b3dSAzael Avalos 228817fe4b3dSAzael Avalos return count; 228917fe4b3dSAzael Avalos } 22900c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_three); 22919bd1213bSAzael Avalos 2292*b1009b91SAzael Avalos static ssize_t cooling_method_show(struct device *dev, 2293*b1009b91SAzael Avalos struct device_attribute *attr, char *buf) 2294*b1009b91SAzael Avalos { 2295*b1009b91SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2296*b1009b91SAzael Avalos int state; 2297*b1009b91SAzael Avalos int ret; 2298*b1009b91SAzael Avalos 2299*b1009b91SAzael Avalos ret = toshiba_cooling_method_get(toshiba, &state); 2300*b1009b91SAzael Avalos if (ret < 0) 2301*b1009b91SAzael Avalos return ret; 2302*b1009b91SAzael Avalos 2303*b1009b91SAzael Avalos return sprintf(buf, "%d %d\n", state, toshiba->max_cooling_method); 2304*b1009b91SAzael Avalos } 2305*b1009b91SAzael Avalos 2306*b1009b91SAzael Avalos static ssize_t cooling_method_store(struct device *dev, 2307*b1009b91SAzael Avalos struct device_attribute *attr, 2308*b1009b91SAzael Avalos const char *buf, size_t count) 2309*b1009b91SAzael Avalos { 2310*b1009b91SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2311*b1009b91SAzael Avalos int state; 2312*b1009b91SAzael Avalos int ret; 2313*b1009b91SAzael Avalos 2314*b1009b91SAzael Avalos ret = kstrtoint(buf, 0, &state); 2315*b1009b91SAzael Avalos if (ret) 2316*b1009b91SAzael Avalos return ret; 2317*b1009b91SAzael Avalos 2318*b1009b91SAzael Avalos /* 2319*b1009b91SAzael Avalos * Check for supported values 2320*b1009b91SAzael Avalos * Depending on the laptop model, some only support these two: 2321*b1009b91SAzael Avalos * 0 - Maximum Performance 2322*b1009b91SAzael Avalos * 1 - Battery Optimized 2323*b1009b91SAzael Avalos * 2324*b1009b91SAzael Avalos * While some others support all three methods: 2325*b1009b91SAzael Avalos * 0 - Maximum Performance 2326*b1009b91SAzael Avalos * 1 - Performance 2327*b1009b91SAzael Avalos * 2 - Battery Optimized 2328*b1009b91SAzael Avalos */ 2329*b1009b91SAzael Avalos if (state < 0 || state > toshiba->max_cooling_method) 2330*b1009b91SAzael Avalos return -EINVAL; 2331*b1009b91SAzael Avalos 2332*b1009b91SAzael Avalos ret = toshiba_cooling_method_set(toshiba, state); 2333*b1009b91SAzael Avalos if (ret) 2334*b1009b91SAzael Avalos return ret; 2335*b1009b91SAzael Avalos 2336*b1009b91SAzael Avalos return count; 2337*b1009b91SAzael Avalos } 2338*b1009b91SAzael Avalos static DEVICE_ATTR_RW(cooling_method); 2339*b1009b91SAzael Avalos 23409bd1213bSAzael Avalos static struct attribute *toshiba_attributes[] = { 23419bd1213bSAzael Avalos &dev_attr_version.attr, 23429bd1213bSAzael Avalos &dev_attr_fan.attr, 23439bd1213bSAzael Avalos &dev_attr_kbd_backlight_mode.attr, 23449bd1213bSAzael Avalos &dev_attr_kbd_type.attr, 23459bd1213bSAzael Avalos &dev_attr_available_kbd_modes.attr, 23469bd1213bSAzael Avalos &dev_attr_kbd_backlight_timeout.attr, 23479bd1213bSAzael Avalos &dev_attr_touchpad.attr, 23489bd1213bSAzael Avalos &dev_attr_position.attr, 23499bd1213bSAzael Avalos &dev_attr_usb_sleep_charge.attr, 23509bd1213bSAzael Avalos &dev_attr_sleep_functions_on_battery.attr, 23519bd1213bSAzael Avalos &dev_attr_usb_rapid_charge.attr, 23529bd1213bSAzael Avalos &dev_attr_usb_sleep_music.attr, 23539bd1213bSAzael Avalos &dev_attr_kbd_function_keys.attr, 23549bd1213bSAzael Avalos &dev_attr_panel_power_on.attr, 23559bd1213bSAzael Avalos &dev_attr_usb_three.attr, 2356*b1009b91SAzael Avalos &dev_attr_cooling_method.attr, 23579bd1213bSAzael Avalos NULL, 23589bd1213bSAzael Avalos }; 23599bd1213bSAzael Avalos 2360360f0f39SAzael Avalos static umode_t toshiba_sysfs_is_visible(struct kobject *kobj, 2361360f0f39SAzael Avalos struct attribute *attr, int idx) 2362360f0f39SAzael Avalos { 2363360f0f39SAzael Avalos struct device *dev = container_of(kobj, struct device, kobj); 2364360f0f39SAzael Avalos struct toshiba_acpi_dev *drv = dev_get_drvdata(dev); 2365360f0f39SAzael Avalos bool exists = true; 2366360f0f39SAzael Avalos 236794477d4cSAzael Avalos if (attr == &dev_attr_fan.attr) 236894477d4cSAzael Avalos exists = (drv->fan_supported) ? true : false; 236994477d4cSAzael Avalos else if (attr == &dev_attr_kbd_backlight_mode.attr) 2370360f0f39SAzael Avalos exists = (drv->kbd_illum_supported) ? true : false; 2371360f0f39SAzael Avalos else if (attr == &dev_attr_kbd_backlight_timeout.attr) 2372360f0f39SAzael Avalos exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false; 23739d8658acSAzael Avalos else if (attr == &dev_attr_touchpad.attr) 23749d8658acSAzael Avalos exists = (drv->touchpad_supported) ? true : false; 23755a2813e9SAzael Avalos else if (attr == &dev_attr_position.attr) 23765a2813e9SAzael Avalos exists = (drv->accelerometer_supported) ? true : false; 2377e26ffe51SAzael Avalos else if (attr == &dev_attr_usb_sleep_charge.attr) 2378e26ffe51SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2379182bcaa5SAzael Avalos else if (attr == &dev_attr_sleep_functions_on_battery.attr) 2380182bcaa5SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2381bb3fe01fSAzael Avalos else if (attr == &dev_attr_usb_rapid_charge.attr) 2382bb3fe01fSAzael Avalos exists = (drv->usb_rapid_charge_supported) ? true : false; 2383172ce0a9SAzael Avalos else if (attr == &dev_attr_usb_sleep_music.attr) 2384172ce0a9SAzael Avalos exists = (drv->usb_sleep_music_supported) ? true : false; 2385bae84195SAzael Avalos else if (attr == &dev_attr_kbd_function_keys.attr) 2386bae84195SAzael Avalos exists = (drv->kbd_function_keys_supported) ? true : false; 238735d53ceaSAzael Avalos else if (attr == &dev_attr_panel_power_on.attr) 238835d53ceaSAzael Avalos exists = (drv->panel_power_on_supported) ? true : false; 238917fe4b3dSAzael Avalos else if (attr == &dev_attr_usb_three.attr) 239017fe4b3dSAzael Avalos exists = (drv->usb_three_supported) ? true : false; 2391*b1009b91SAzael Avalos else if (attr == &dev_attr_cooling_method.attr) 2392*b1009b91SAzael Avalos exists = (drv->cooling_method_supported) ? true : false; 2393360f0f39SAzael Avalos 2394360f0f39SAzael Avalos return exists ? attr->mode : 0; 2395360f0f39SAzael Avalos } 2396360f0f39SAzael Avalos 23979bd1213bSAzael Avalos static struct attribute_group toshiba_attr_group = { 23989bd1213bSAzael Avalos .is_visible = toshiba_sysfs_is_visible, 23999bd1213bSAzael Avalos .attrs = toshiba_attributes, 24009bd1213bSAzael Avalos }; 24019bd1213bSAzael Avalos 240265e3cf9cSAzael Avalos static void toshiba_acpi_kbd_bl_work(struct work_struct *work) 240365e3cf9cSAzael Avalos { 240465e3cf9cSAzael Avalos struct acpi_device *acpi_dev = toshiba_acpi->acpi_dev; 240565e3cf9cSAzael Avalos 240665e3cf9cSAzael Avalos /* Update the sysfs entries */ 240765e3cf9cSAzael Avalos if (sysfs_update_group(&acpi_dev->dev.kobj, 240865e3cf9cSAzael Avalos &toshiba_attr_group)) 240965e3cf9cSAzael Avalos pr_err("Unable to update sysfs entries\n"); 241065e3cf9cSAzael Avalos 241165e3cf9cSAzael Avalos /* Emulate the keyboard backlight event */ 241265e3cf9cSAzael Avalos acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class, 241365e3cf9cSAzael Avalos dev_name(&acpi_dev->dev), 241465e3cf9cSAzael Avalos 0x92, 0); 241565e3cf9cSAzael Avalos } 241665e3cf9cSAzael Avalos 24171f28f290SAzael Avalos /* 2418fc5462f8SAzael Avalos * Misc device 2419fc5462f8SAzael Avalos */ 2420fc5462f8SAzael Avalos static int toshiba_acpi_smm_bridge(SMMRegisters *regs) 2421fc5462f8SAzael Avalos { 2422fc5462f8SAzael Avalos u32 in[TCI_WORDS] = { regs->eax, regs->ebx, regs->ecx, 2423fc5462f8SAzael Avalos regs->edx, regs->esi, regs->edi }; 2424fc5462f8SAzael Avalos u32 out[TCI_WORDS]; 2425fc5462f8SAzael Avalos acpi_status status; 2426fc5462f8SAzael Avalos 2427fc5462f8SAzael Avalos status = tci_raw(toshiba_acpi, in, out); 2428fc5462f8SAzael Avalos if (ACPI_FAILURE(status)) { 2429fc5462f8SAzael Avalos pr_err("ACPI call to query SMM registers failed\n"); 2430fc5462f8SAzael Avalos return -EIO; 2431fc5462f8SAzael Avalos } 2432fc5462f8SAzael Avalos 2433fc5462f8SAzael Avalos /* Fillout the SMM struct with the TCI call results */ 2434fc5462f8SAzael Avalos regs->eax = out[0]; 2435fc5462f8SAzael Avalos regs->ebx = out[1]; 2436fc5462f8SAzael Avalos regs->ecx = out[2]; 2437fc5462f8SAzael Avalos regs->edx = out[3]; 2438fc5462f8SAzael Avalos regs->esi = out[4]; 2439fc5462f8SAzael Avalos regs->edi = out[5]; 2440fc5462f8SAzael Avalos 2441fc5462f8SAzael Avalos return 0; 2442fc5462f8SAzael Avalos } 2443fc5462f8SAzael Avalos 2444fc5462f8SAzael Avalos static long toshiba_acpi_ioctl(struct file *fp, unsigned int cmd, 2445fc5462f8SAzael Avalos unsigned long arg) 2446fc5462f8SAzael Avalos { 2447fc5462f8SAzael Avalos SMMRegisters __user *argp = (SMMRegisters __user *)arg; 2448fc5462f8SAzael Avalos SMMRegisters regs; 2449fc5462f8SAzael Avalos int ret; 2450fc5462f8SAzael Avalos 2451fc5462f8SAzael Avalos if (!argp) 2452fc5462f8SAzael Avalos return -EINVAL; 2453fc5462f8SAzael Avalos 2454fc5462f8SAzael Avalos switch (cmd) { 2455fc5462f8SAzael Avalos case TOSH_SMM: 2456fc5462f8SAzael Avalos if (copy_from_user(®s, argp, sizeof(SMMRegisters))) 2457fc5462f8SAzael Avalos return -EFAULT; 2458fc5462f8SAzael Avalos ret = toshiba_acpi_smm_bridge(®s); 2459fc5462f8SAzael Avalos if (ret) 2460fc5462f8SAzael Avalos return ret; 2461fc5462f8SAzael Avalos if (copy_to_user(argp, ®s, sizeof(SMMRegisters))) 2462fc5462f8SAzael Avalos return -EFAULT; 2463fc5462f8SAzael Avalos break; 2464fc5462f8SAzael Avalos case TOSHIBA_ACPI_SCI: 2465fc5462f8SAzael Avalos if (copy_from_user(®s, argp, sizeof(SMMRegisters))) 2466fc5462f8SAzael Avalos return -EFAULT; 2467fc5462f8SAzael Avalos /* Ensure we are being called with a SCI_{GET, SET} register */ 2468fc5462f8SAzael Avalos if (regs.eax != SCI_GET && regs.eax != SCI_SET) 2469fc5462f8SAzael Avalos return -EINVAL; 2470fc5462f8SAzael Avalos if (!sci_open(toshiba_acpi)) 2471fc5462f8SAzael Avalos return -EIO; 2472fc5462f8SAzael Avalos ret = toshiba_acpi_smm_bridge(®s); 2473fc5462f8SAzael Avalos sci_close(toshiba_acpi); 2474fc5462f8SAzael Avalos if (ret) 2475fc5462f8SAzael Avalos return ret; 2476fc5462f8SAzael Avalos if (copy_to_user(argp, ®s, sizeof(SMMRegisters))) 2477fc5462f8SAzael Avalos return -EFAULT; 2478fc5462f8SAzael Avalos break; 2479fc5462f8SAzael Avalos default: 2480fc5462f8SAzael Avalos return -EINVAL; 2481fc5462f8SAzael Avalos } 2482fc5462f8SAzael Avalos 2483fc5462f8SAzael Avalos return 0; 2484fc5462f8SAzael Avalos } 2485fc5462f8SAzael Avalos 2486fc5462f8SAzael Avalos static const struct file_operations toshiba_acpi_fops = { 2487fc5462f8SAzael Avalos .owner = THIS_MODULE, 2488fc5462f8SAzael Avalos .unlocked_ioctl = toshiba_acpi_ioctl, 2489fc5462f8SAzael Avalos .llseek = noop_llseek, 2490fc5462f8SAzael Avalos }; 2491fc5462f8SAzael Avalos 2492fc5462f8SAzael Avalos /* 24932fdde834SAzael Avalos * WWAN RFKill handlers 24942fdde834SAzael Avalos */ 24952fdde834SAzael Avalos static int toshiba_acpi_wwan_set_block(void *data, bool blocked) 24962fdde834SAzael Avalos { 24972fdde834SAzael Avalos struct toshiba_acpi_dev *dev = data; 24982fdde834SAzael Avalos int ret; 24992fdde834SAzael Avalos 25002fdde834SAzael Avalos ret = toshiba_wireless_status(dev); 25012fdde834SAzael Avalos if (ret) 25022fdde834SAzael Avalos return ret; 25032fdde834SAzael Avalos 25042fdde834SAzael Avalos if (!dev->killswitch) 25052fdde834SAzael Avalos return 0; 25062fdde834SAzael Avalos 25072fdde834SAzael Avalos return toshiba_wwan_set(dev, !blocked); 25082fdde834SAzael Avalos } 25092fdde834SAzael Avalos 25102fdde834SAzael Avalos static void toshiba_acpi_wwan_poll(struct rfkill *rfkill, void *data) 25112fdde834SAzael Avalos { 25122fdde834SAzael Avalos struct toshiba_acpi_dev *dev = data; 25132fdde834SAzael Avalos 25142fdde834SAzael Avalos if (toshiba_wireless_status(dev)) 25152fdde834SAzael Avalos return; 25162fdde834SAzael Avalos 25172fdde834SAzael Avalos rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch); 25182fdde834SAzael Avalos } 25192fdde834SAzael Avalos 25202fdde834SAzael Avalos static const struct rfkill_ops wwan_rfk_ops = { 25212fdde834SAzael Avalos .set_block = toshiba_acpi_wwan_set_block, 25222fdde834SAzael Avalos .poll = toshiba_acpi_wwan_poll, 25232fdde834SAzael Avalos }; 25242fdde834SAzael Avalos 25252fdde834SAzael Avalos static int toshiba_acpi_setup_wwan_rfkill(struct toshiba_acpi_dev *dev) 25262fdde834SAzael Avalos { 25272fdde834SAzael Avalos int ret = toshiba_wireless_status(dev); 25282fdde834SAzael Avalos 25292fdde834SAzael Avalos if (ret) 25302fdde834SAzael Avalos return ret; 25312fdde834SAzael Avalos 25322fdde834SAzael Avalos dev->wwan_rfk = rfkill_alloc("Toshiba WWAN", 25332fdde834SAzael Avalos &dev->acpi_dev->dev, 25342fdde834SAzael Avalos RFKILL_TYPE_WWAN, 25352fdde834SAzael Avalos &wwan_rfk_ops, 25362fdde834SAzael Avalos dev); 25372fdde834SAzael Avalos if (!dev->wwan_rfk) { 25382fdde834SAzael Avalos pr_err("Unable to allocate WWAN rfkill device\n"); 25392fdde834SAzael Avalos return -ENOMEM; 25402fdde834SAzael Avalos } 25412fdde834SAzael Avalos 25422fdde834SAzael Avalos rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch); 25432fdde834SAzael Avalos 25442fdde834SAzael Avalos ret = rfkill_register(dev->wwan_rfk); 25452fdde834SAzael Avalos if (ret) { 25462fdde834SAzael Avalos pr_err("Unable to register WWAN rfkill device\n"); 25472fdde834SAzael Avalos rfkill_destroy(dev->wwan_rfk); 25482fdde834SAzael Avalos } 25492fdde834SAzael Avalos 25502fdde834SAzael Avalos return ret; 25512fdde834SAzael Avalos } 25522fdde834SAzael Avalos 25532fdde834SAzael Avalos /* 25541f28f290SAzael Avalos * Hotkeys 25551f28f290SAzael Avalos */ 25561f28f290SAzael Avalos static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev) 25571f28f290SAzael Avalos { 25581f28f290SAzael Avalos acpi_status status; 25591f28f290SAzael Avalos u32 result; 25601f28f290SAzael Avalos 25611f28f290SAzael Avalos status = acpi_evaluate_object(dev->acpi_dev->handle, 25621f28f290SAzael Avalos "ENAB", NULL, NULL); 25631f28f290SAzael Avalos if (ACPI_FAILURE(status)) 25641f28f290SAzael Avalos return -ENODEV; 25651f28f290SAzael Avalos 2566b116fd00SAzael Avalos /* 2567b116fd00SAzael Avalos * Enable the "Special Functions" mode only if they are 2568b116fd00SAzael Avalos * supported and if they are activated. 2569b116fd00SAzael Avalos */ 2570b116fd00SAzael Avalos if (dev->kbd_function_keys_supported && dev->special_functions) 2571b116fd00SAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, 2572b116fd00SAzael Avalos HCI_HOTKEY_SPECIAL_FUNCTIONS); 2573b116fd00SAzael Avalos else 2574d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE); 2575b116fd00SAzael Avalos 25761f28f290SAzael Avalos if (result == TOS_FAILURE) 25771f28f290SAzael Avalos return -EIO; 25781f28f290SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 25791f28f290SAzael Avalos return -ENODEV; 25801f28f290SAzael Avalos 25811f28f290SAzael Avalos return 0; 25821f28f290SAzael Avalos } 25831f28f290SAzael Avalos 258429cd293fSSeth Forshee static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, 258529cd293fSSeth Forshee struct serio *port) 258629cd293fSSeth Forshee { 258798280374SGiedrius Statkevičius if (str & I8042_STR_AUXDATA) 258829cd293fSSeth Forshee return false; 258929cd293fSSeth Forshee 259029cd293fSSeth Forshee if (unlikely(data == 0xe0)) 259129cd293fSSeth Forshee return false; 259229cd293fSSeth Forshee 259329cd293fSSeth Forshee if ((data & 0x7f) == TOS1900_FN_SCAN) { 259429cd293fSSeth Forshee schedule_work(&toshiba_acpi->hotkey_work); 259529cd293fSSeth Forshee return true; 259629cd293fSSeth Forshee } 259729cd293fSSeth Forshee 259829cd293fSSeth Forshee return false; 259929cd293fSSeth Forshee } 260029cd293fSSeth Forshee 260129cd293fSSeth Forshee static void toshiba_acpi_hotkey_work(struct work_struct *work) 260229cd293fSSeth Forshee { 260329cd293fSSeth Forshee acpi_handle ec_handle = ec_get_handle(); 260429cd293fSSeth Forshee acpi_status status; 260529cd293fSSeth Forshee 260629cd293fSSeth Forshee if (!ec_handle) 260729cd293fSSeth Forshee return; 260829cd293fSSeth Forshee 260929cd293fSSeth Forshee status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL); 261029cd293fSSeth Forshee if (ACPI_FAILURE(status)) 261129cd293fSSeth Forshee pr_err("ACPI NTFY method execution failed\n"); 261229cd293fSSeth Forshee } 261329cd293fSSeth Forshee 261429cd293fSSeth Forshee /* 261529cd293fSSeth Forshee * Returns hotkey scancode, or < 0 on failure. 261629cd293fSSeth Forshee */ 261729cd293fSSeth Forshee static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev) 261829cd293fSSeth Forshee { 261974facaf7SZhang Rui unsigned long long value; 262029cd293fSSeth Forshee acpi_status status; 262129cd293fSSeth Forshee 262274facaf7SZhang Rui status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO", 262374facaf7SZhang Rui NULL, &value); 262474facaf7SZhang Rui if (ACPI_FAILURE(status)) { 262529cd293fSSeth Forshee pr_err("ACPI INFO method execution failed\n"); 262629cd293fSSeth Forshee return -EIO; 262729cd293fSSeth Forshee } 262829cd293fSSeth Forshee 262974facaf7SZhang Rui return value; 263029cd293fSSeth Forshee } 263129cd293fSSeth Forshee 263229cd293fSSeth Forshee static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev, 263329cd293fSSeth Forshee int scancode) 263429cd293fSSeth Forshee { 263529cd293fSSeth Forshee if (scancode == 0x100) 263629cd293fSSeth Forshee return; 263729cd293fSSeth Forshee 2638e0769fe6SDarren Hart /* Act on key press; ignore key release */ 263929cd293fSSeth Forshee if (scancode & 0x80) 264029cd293fSSeth Forshee return; 264129cd293fSSeth Forshee 264229cd293fSSeth Forshee if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true)) 264329cd293fSSeth Forshee pr_info("Unknown key %x\n", scancode); 264429cd293fSSeth Forshee } 264529cd293fSSeth Forshee 264671454d78SAzael Avalos static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) 264771454d78SAzael Avalos { 264871454d78SAzael Avalos if (dev->info_supported) { 26497deef550SAzael Avalos int scancode = toshiba_acpi_query_hotkey(dev); 26507deef550SAzael Avalos 26517deef550SAzael Avalos if (scancode < 0) { 265271454d78SAzael Avalos pr_err("Failed to query hotkey event\n"); 26537deef550SAzael Avalos } else if (scancode != 0) { 265471454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, scancode); 26557deef550SAzael Avalos dev->key_event_valid = 1; 26567deef550SAzael Avalos dev->last_key_event = scancode; 26577deef550SAzael Avalos } 265871454d78SAzael Avalos } else if (dev->system_event_supported) { 26597deef550SAzael Avalos u32 result; 26607deef550SAzael Avalos u32 value; 26617deef550SAzael Avalos int retries = 3; 26627deef550SAzael Avalos 266371454d78SAzael Avalos do { 26647deef550SAzael Avalos result = hci_read(dev, HCI_SYSTEM_EVENT, &value); 26657deef550SAzael Avalos switch (result) { 266671454d78SAzael Avalos case TOS_SUCCESS: 266771454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, (int)value); 26687deef550SAzael Avalos dev->key_event_valid = 1; 26697deef550SAzael Avalos dev->last_key_event = value; 267071454d78SAzael Avalos break; 267171454d78SAzael Avalos case TOS_NOT_SUPPORTED: 267271454d78SAzael Avalos /* 267371454d78SAzael Avalos * This is a workaround for an unresolved 267471454d78SAzael Avalos * issue on some machines where system events 267571454d78SAzael Avalos * sporadically become disabled. 267671454d78SAzael Avalos */ 26777deef550SAzael Avalos result = hci_write(dev, HCI_SYSTEM_EVENT, 1); 26787deef550SAzael Avalos if (result == TOS_SUCCESS) 267971454d78SAzael Avalos pr_notice("Re-enabled hotkeys\n"); 2680e0769fe6SDarren Hart /* Fall through */ 268171454d78SAzael Avalos default: 268271454d78SAzael Avalos retries--; 268371454d78SAzael Avalos break; 268471454d78SAzael Avalos } 26857deef550SAzael Avalos } while (retries && result != TOS_FIFO_EMPTY); 268671454d78SAzael Avalos } 268771454d78SAzael Avalos } 268871454d78SAzael Avalos 2689b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) 26906335e4d5SMatthew Garrett { 2691fe808bfbSTakashi Iwai const struct key_entry *keymap = toshiba_acpi_keymap; 2692a2b3471bSAzael Avalos acpi_handle ec_handle; 2693a2b3471bSAzael Avalos int error; 2694a2b3471bSAzael Avalos 2695a88bc06eSAzael Avalos if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) { 2696a88bc06eSAzael Avalos pr_info("WMI event detected, hotkeys will not be monitored\n"); 2697a88bc06eSAzael Avalos return 0; 2698a88bc06eSAzael Avalos } 2699a88bc06eSAzael Avalos 2700a2b3471bSAzael Avalos error = toshiba_acpi_enable_hotkeys(dev); 2701a2b3471bSAzael Avalos if (error) 2702a2b3471bSAzael Avalos return error; 2703a2b3471bSAzael Avalos 270410e6aaabSAzael Avalos if (toshiba_hotkey_event_type_get(dev, &dev->hotkey_event_type)) 270553147b6cSAzael Avalos pr_notice("Unable to query Hotkey Event Type\n"); 270653147b6cSAzael Avalos 2707135740deSSeth Forshee dev->hotkey_dev = input_allocate_device(); 2708b222cca6SJoe Perches if (!dev->hotkey_dev) 2709135740deSSeth Forshee return -ENOMEM; 2710135740deSSeth Forshee 2711135740deSSeth Forshee dev->hotkey_dev->name = "Toshiba input device"; 27126e02cc7eSSeth Forshee dev->hotkey_dev->phys = "toshiba_acpi/input0"; 2713135740deSSeth Forshee dev->hotkey_dev->id.bustype = BUS_HOST; 2714135740deSSeth Forshee 271510e6aaabSAzael Avalos if (dev->hotkey_event_type == HCI_SYSTEM_TYPE1 || 2716a2b3471bSAzael Avalos !dev->kbd_function_keys_supported) 2717a2b3471bSAzael Avalos keymap = toshiba_acpi_keymap; 271810e6aaabSAzael Avalos else if (dev->hotkey_event_type == HCI_SYSTEM_TYPE2 || 2719a2b3471bSAzael Avalos dev->kbd_function_keys_supported) 2720fe808bfbSTakashi Iwai keymap = toshiba_acpi_alt_keymap; 2721a2b3471bSAzael Avalos else 272210e6aaabSAzael Avalos pr_info("Unknown event type received %x\n", 272310e6aaabSAzael Avalos dev->hotkey_event_type); 2724fe808bfbSTakashi Iwai error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL); 2725135740deSSeth Forshee if (error) 2726135740deSSeth Forshee goto err_free_dev; 2727135740deSSeth Forshee 272829cd293fSSeth Forshee /* 272929cd293fSSeth Forshee * For some machines the SCI responsible for providing hotkey 273029cd293fSSeth Forshee * notification doesn't fire. We can trigger the notification 273129cd293fSSeth Forshee * whenever the Fn key is pressed using the NTFY method, if 273229cd293fSSeth Forshee * supported, so if it's present set up an i8042 key filter 273329cd293fSSeth Forshee * for this purpose. 273429cd293fSSeth Forshee */ 273529cd293fSSeth Forshee ec_handle = ec_get_handle(); 2736e2e19606SZhang Rui if (ec_handle && acpi_has_method(ec_handle, "NTFY")) { 273729cd293fSSeth Forshee INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work); 273829cd293fSSeth Forshee 273929cd293fSSeth Forshee error = i8042_install_filter(toshiba_acpi_i8042_filter); 274029cd293fSSeth Forshee if (error) { 274129cd293fSSeth Forshee pr_err("Error installing key filter\n"); 274229cd293fSSeth Forshee goto err_free_keymap; 274329cd293fSSeth Forshee } 274429cd293fSSeth Forshee 274529cd293fSSeth Forshee dev->ntfy_supported = 1; 274629cd293fSSeth Forshee } 274729cd293fSSeth Forshee 274829cd293fSSeth Forshee /* 274929cd293fSSeth Forshee * Determine hotkey query interface. Prefer using the INFO 275029cd293fSSeth Forshee * method when it is available. 275129cd293fSSeth Forshee */ 2752e2e19606SZhang Rui if (acpi_has_method(dev->acpi_dev->handle, "INFO")) 275329cd293fSSeth Forshee dev->info_supported = 1; 275410e6aaabSAzael Avalos else if (hci_write(dev, HCI_SYSTEM_EVENT, 1) == TOS_SUCCESS) 275529cd293fSSeth Forshee dev->system_event_supported = 1; 275629cd293fSSeth Forshee 275729cd293fSSeth Forshee if (!dev->info_supported && !dev->system_event_supported) { 275829cd293fSSeth Forshee pr_warn("No hotkey query interface found\n"); 275929cd293fSSeth Forshee goto err_remove_filter; 276029cd293fSSeth Forshee } 276129cd293fSSeth Forshee 2762135740deSSeth Forshee error = input_register_device(dev->hotkey_dev); 2763135740deSSeth Forshee if (error) { 2764135740deSSeth Forshee pr_info("Unable to register input device\n"); 276529cd293fSSeth Forshee goto err_remove_filter; 2766135740deSSeth Forshee } 2767135740deSSeth Forshee 2768135740deSSeth Forshee return 0; 2769135740deSSeth Forshee 277029cd293fSSeth Forshee err_remove_filter: 277129cd293fSSeth Forshee if (dev->ntfy_supported) 277229cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 2773135740deSSeth Forshee err_free_keymap: 2774135740deSSeth Forshee sparse_keymap_free(dev->hotkey_dev); 2775135740deSSeth Forshee err_free_dev: 2776135740deSSeth Forshee input_free_device(dev->hotkey_dev); 2777135740deSSeth Forshee dev->hotkey_dev = NULL; 2778135740deSSeth Forshee return error; 2779135740deSSeth Forshee } 2780135740deSSeth Forshee 2781b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) 278262cce752SSeth Forshee { 278362cce752SSeth Forshee struct backlight_properties props; 278462cce752SSeth Forshee int brightness; 278562cce752SSeth Forshee int ret; 278662cce752SSeth Forshee 278762cce752SSeth Forshee /* 278862cce752SSeth Forshee * Some machines don't support the backlight methods at all, and 278962cce752SSeth Forshee * others support it read-only. Either of these is pretty useless, 279062cce752SSeth Forshee * so only register the backlight device if the backlight method 279162cce752SSeth Forshee * supports both reads and writes. 279262cce752SSeth Forshee */ 279362cce752SSeth Forshee brightness = __get_lcd_brightness(dev); 279462cce752SSeth Forshee if (brightness < 0) 279562cce752SSeth Forshee return 0; 2796bae5336fSAzael Avalos /* 2797bae5336fSAzael Avalos * If transflective backlight is supported and the brightness is zero 2798bae5336fSAzael Avalos * (lowest brightness level), the set_lcd_brightness function will 2799bae5336fSAzael Avalos * activate the transflective backlight, making the LCD appear to be 2800bae5336fSAzael Avalos * turned off, simply increment the brightness level to avoid that. 2801bae5336fSAzael Avalos */ 2802bae5336fSAzael Avalos if (dev->tr_backlight_supported && brightness == 0) 2803bae5336fSAzael Avalos brightness++; 280462cce752SSeth Forshee ret = set_lcd_brightness(dev, brightness); 280562cce752SSeth Forshee if (ret) { 280662cce752SSeth Forshee pr_debug("Backlight method is read-only, disabling backlight support\n"); 280762cce752SSeth Forshee return 0; 280862cce752SSeth Forshee } 280962cce752SSeth Forshee 2810358d6a2cSHans de Goede /* 2811358d6a2cSHans de Goede * Tell acpi-video-detect code to prefer vendor backlight on all 2812358d6a2cSHans de Goede * systems with transflective backlight and on dmi matched systems. 2813358d6a2cSHans de Goede */ 2814358d6a2cSHans de Goede if (dev->tr_backlight_supported || 2815358d6a2cSHans de Goede dmi_check_system(toshiba_vendor_backlight_dmi)) 2816234b7cf8SHans de Goede acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); 2817358d6a2cSHans de Goede 2818234b7cf8SHans de Goede if (acpi_video_get_backlight_type() != acpi_backlight_vendor) 2819358d6a2cSHans de Goede return 0; 2820358d6a2cSHans de Goede 282153039f22SMatthew Garrett memset(&props, 0, sizeof(props)); 282262cce752SSeth Forshee props.type = BACKLIGHT_PLATFORM; 282362cce752SSeth Forshee props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; 282462cce752SSeth Forshee 2825e0769fe6SDarren Hart /* Adding an extra level and having 0 change to transflective mode */ 2826121b7b0dSAkio Idehara if (dev->tr_backlight_supported) 2827121b7b0dSAkio Idehara props.max_brightness++; 2828121b7b0dSAkio Idehara 282962cce752SSeth Forshee dev->backlight_dev = backlight_device_register("toshiba", 283062cce752SSeth Forshee &dev->acpi_dev->dev, 283162cce752SSeth Forshee dev, 283262cce752SSeth Forshee &toshiba_backlight_data, 283362cce752SSeth Forshee &props); 283462cce752SSeth Forshee if (IS_ERR(dev->backlight_dev)) { 283562cce752SSeth Forshee ret = PTR_ERR(dev->backlight_dev); 283662cce752SSeth Forshee pr_err("Could not register toshiba backlight device\n"); 283762cce752SSeth Forshee dev->backlight_dev = NULL; 283862cce752SSeth Forshee return ret; 283962cce752SSeth Forshee } 284062cce752SSeth Forshee 284162cce752SSeth Forshee dev->backlight_dev->props.brightness = brightness; 284262cce752SSeth Forshee return 0; 284362cce752SSeth Forshee } 284462cce752SSeth Forshee 28450409cbceSAzael Avalos static void print_supported_features(struct toshiba_acpi_dev *dev) 28460409cbceSAzael Avalos { 28470409cbceSAzael Avalos pr_info("Supported laptop features:"); 28480409cbceSAzael Avalos 28490409cbceSAzael Avalos if (dev->hotkey_dev) 28500409cbceSAzael Avalos pr_cont(" hotkeys"); 28510409cbceSAzael Avalos if (dev->backlight_dev) 28520409cbceSAzael Avalos pr_cont(" backlight"); 28530409cbceSAzael Avalos if (dev->video_supported) 28540409cbceSAzael Avalos pr_cont(" video-out"); 28550409cbceSAzael Avalos if (dev->fan_supported) 28560409cbceSAzael Avalos pr_cont(" fan"); 28570409cbceSAzael Avalos if (dev->tr_backlight_supported) 28580409cbceSAzael Avalos pr_cont(" transflective-backlight"); 28590409cbceSAzael Avalos if (dev->illumination_supported) 28600409cbceSAzael Avalos pr_cont(" illumination"); 28610409cbceSAzael Avalos if (dev->kbd_illum_supported) 28620409cbceSAzael Avalos pr_cont(" keyboard-backlight"); 28630409cbceSAzael Avalos if (dev->touchpad_supported) 28640409cbceSAzael Avalos pr_cont(" touchpad"); 28650409cbceSAzael Avalos if (dev->eco_supported) 28660409cbceSAzael Avalos pr_cont(" eco-led"); 28670409cbceSAzael Avalos if (dev->accelerometer_supported) 28680409cbceSAzael Avalos pr_cont(" accelerometer-axes"); 28690409cbceSAzael Avalos if (dev->usb_sleep_charge_supported) 28700409cbceSAzael Avalos pr_cont(" usb-sleep-charge"); 28710409cbceSAzael Avalos if (dev->usb_rapid_charge_supported) 28720409cbceSAzael Avalos pr_cont(" usb-rapid-charge"); 28730409cbceSAzael Avalos if (dev->usb_sleep_music_supported) 28740409cbceSAzael Avalos pr_cont(" usb-sleep-music"); 28750409cbceSAzael Avalos if (dev->kbd_function_keys_supported) 28760409cbceSAzael Avalos pr_cont(" special-function-keys"); 28770409cbceSAzael Avalos if (dev->panel_power_on_supported) 28780409cbceSAzael Avalos pr_cont(" panel-power-on"); 28790409cbceSAzael Avalos if (dev->usb_three_supported) 28800409cbceSAzael Avalos pr_cont(" usb3"); 28816873f46aSAzael Avalos if (dev->wwan_supported) 28826873f46aSAzael Avalos pr_cont(" wwan"); 2883763ff32fSAzael Avalos if (dev->cooling_method_supported) 2884763ff32fSAzael Avalos pr_cont(" cooling-method"); 28850409cbceSAzael Avalos 28860409cbceSAzael Avalos pr_cont("\n"); 28870409cbceSAzael Avalos } 28880409cbceSAzael Avalos 288951fac838SRafael J. Wysocki static int toshiba_acpi_remove(struct acpi_device *acpi_dev) 2890135740deSSeth Forshee { 2891135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 2892135740deSSeth Forshee 2893fc5462f8SAzael Avalos misc_deregister(&dev->miscdev); 2894fc5462f8SAzael Avalos 289536d03f93SSeth Forshee remove_toshiba_proc_entries(dev); 2896135740deSSeth Forshee 2897360f0f39SAzael Avalos if (dev->sysfs_created) 2898360f0f39SAzael Avalos sysfs_remove_group(&dev->acpi_dev->dev.kobj, 2899360f0f39SAzael Avalos &toshiba_attr_group); 2900360f0f39SAzael Avalos 290129cd293fSSeth Forshee if (dev->ntfy_supported) { 290229cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 290329cd293fSSeth Forshee cancel_work_sync(&dev->hotkey_work); 290429cd293fSSeth Forshee } 290529cd293fSSeth Forshee 2906135740deSSeth Forshee if (dev->hotkey_dev) { 2907135740deSSeth Forshee input_unregister_device(dev->hotkey_dev); 2908135740deSSeth Forshee sparse_keymap_free(dev->hotkey_dev); 2909135740deSSeth Forshee } 2910135740deSSeth Forshee 2911135740deSSeth Forshee backlight_device_unregister(dev->backlight_dev); 2912135740deSSeth Forshee 2913ea215a3fSAzael Avalos if (dev->illumination_led_registered) 2914135740deSSeth Forshee led_classdev_unregister(&dev->led_dev); 2915135740deSSeth Forshee 2916360f0f39SAzael Avalos if (dev->kbd_led_registered) 2917360f0f39SAzael Avalos led_classdev_unregister(&dev->kbd_led); 2918360f0f39SAzael Avalos 2919ea215a3fSAzael Avalos if (dev->eco_led_registered) 2920def6c4e2SAzael Avalos led_classdev_unregister(&dev->eco_led); 2921def6c4e2SAzael Avalos 29222fdde834SAzael Avalos if (dev->wwan_rfk) { 29232fdde834SAzael Avalos rfkill_unregister(dev->wwan_rfk); 29242fdde834SAzael Avalos rfkill_destroy(dev->wwan_rfk); 29252fdde834SAzael Avalos } 29262fdde834SAzael Avalos 292729cd293fSSeth Forshee if (toshiba_acpi) 292829cd293fSSeth Forshee toshiba_acpi = NULL; 292929cd293fSSeth Forshee 2930135740deSSeth Forshee kfree(dev); 2931135740deSSeth Forshee 2932135740deSSeth Forshee return 0; 2933135740deSSeth Forshee } 2934135740deSSeth Forshee 2935b859f159SGreg Kroah-Hartman static const char *find_hci_method(acpi_handle handle) 2936a540d6b5SSeth Forshee { 2937e2e19606SZhang Rui if (acpi_has_method(handle, "GHCI")) 2938a540d6b5SSeth Forshee return "GHCI"; 2939a540d6b5SSeth Forshee 2940e2e19606SZhang Rui if (acpi_has_method(handle, "SPFC")) 2941a540d6b5SSeth Forshee return "SPFC"; 2942a540d6b5SSeth Forshee 2943a540d6b5SSeth Forshee return NULL; 2944a540d6b5SSeth Forshee } 2945a540d6b5SSeth Forshee 2946b859f159SGreg Kroah-Hartman static int toshiba_acpi_add(struct acpi_device *acpi_dev) 2947135740deSSeth Forshee { 2948135740deSSeth Forshee struct toshiba_acpi_dev *dev; 2949a540d6b5SSeth Forshee const char *hci_method; 295036d03f93SSeth Forshee u32 dummy; 2951135740deSSeth Forshee int ret = 0; 2952135740deSSeth Forshee 295329cd293fSSeth Forshee if (toshiba_acpi) 295429cd293fSSeth Forshee return -EBUSY; 295529cd293fSSeth Forshee 2956135740deSSeth Forshee pr_info("Toshiba Laptop ACPI Extras version %s\n", 2957135740deSSeth Forshee TOSHIBA_ACPI_VERSION); 2958135740deSSeth Forshee 2959a540d6b5SSeth Forshee hci_method = find_hci_method(acpi_dev->handle); 2960a540d6b5SSeth Forshee if (!hci_method) { 2961a540d6b5SSeth Forshee pr_err("HCI interface not found\n"); 29626e02cc7eSSeth Forshee return -ENODEV; 2963a540d6b5SSeth Forshee } 29646e02cc7eSSeth Forshee 2965135740deSSeth Forshee dev = kzalloc(sizeof(*dev), GFP_KERNEL); 2966135740deSSeth Forshee if (!dev) 2967135740deSSeth Forshee return -ENOMEM; 2968135740deSSeth Forshee dev->acpi_dev = acpi_dev; 2969a540d6b5SSeth Forshee dev->method_hci = hci_method; 2970fc5462f8SAzael Avalos dev->miscdev.minor = MISC_DYNAMIC_MINOR; 2971fc5462f8SAzael Avalos dev->miscdev.name = "toshiba_acpi"; 2972fc5462f8SAzael Avalos dev->miscdev.fops = &toshiba_acpi_fops; 2973fc5462f8SAzael Avalos 2974fc5462f8SAzael Avalos ret = misc_register(&dev->miscdev); 2975fc5462f8SAzael Avalos if (ret) { 2976fc5462f8SAzael Avalos pr_err("Failed to register miscdevice\n"); 2977fc5462f8SAzael Avalos kfree(dev); 2978fc5462f8SAzael Avalos return ret; 2979fc5462f8SAzael Avalos } 2980fc5462f8SAzael Avalos 2981135740deSSeth Forshee acpi_dev->driver_data = dev; 2982360f0f39SAzael Avalos dev_set_drvdata(&acpi_dev->dev, dev); 2983135740deSSeth Forshee 2984a2b3471bSAzael Avalos /* Query the BIOS for supported features */ 2985a2b3471bSAzael Avalos 2986a2b3471bSAzael Avalos /* 2987a2b3471bSAzael Avalos * The "Special Functions" are always supported by the laptops 2988a2b3471bSAzael Avalos * with the new keyboard layout, query for its presence to help 2989a2b3471bSAzael Avalos * determine the keymap layout to use. 2990a2b3471bSAzael Avalos */ 2991b116fd00SAzael Avalos ret = toshiba_function_keys_get(dev, &dev->special_functions); 2992a2b3471bSAzael Avalos dev->kbd_function_keys_supported = !ret; 2993a2b3471bSAzael Avalos 2994d2f20619SAzael Avalos dev->hotkey_event_type = 0; 29956e02cc7eSSeth Forshee if (toshiba_acpi_setup_keyboard(dev)) 2996135740deSSeth Forshee pr_info("Unable to activate hotkeys\n"); 2997135740deSSeth Forshee 2998695f6060SAzael Avalos /* Determine whether or not BIOS supports transflective backlight */ 2999695f6060SAzael Avalos ret = get_tr_backlight_status(dev, &dummy); 3000695f6060SAzael Avalos dev->tr_backlight_supported = !ret; 3001695f6060SAzael Avalos 300262cce752SSeth Forshee ret = toshiba_acpi_setup_backlight(dev); 300362cce752SSeth Forshee if (ret) 3004135740deSSeth Forshee goto error; 3005135740deSSeth Forshee 3006ea215a3fSAzael Avalos toshiba_illumination_available(dev); 3007ea215a3fSAzael Avalos if (dev->illumination_supported) { 3008135740deSSeth Forshee dev->led_dev.name = "toshiba::illumination"; 3009135740deSSeth Forshee dev->led_dev.max_brightness = 1; 3010135740deSSeth Forshee dev->led_dev.brightness_set = toshiba_illumination_set; 3011135740deSSeth Forshee dev->led_dev.brightness_get = toshiba_illumination_get; 3012135740deSSeth Forshee if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev)) 3013ea215a3fSAzael Avalos dev->illumination_led_registered = true; 3014135740deSSeth Forshee } 3015135740deSSeth Forshee 3016ea215a3fSAzael Avalos toshiba_eco_mode_available(dev); 3017ea215a3fSAzael Avalos if (dev->eco_supported) { 3018def6c4e2SAzael Avalos dev->eco_led.name = "toshiba::eco_mode"; 3019def6c4e2SAzael Avalos dev->eco_led.max_brightness = 1; 3020def6c4e2SAzael Avalos dev->eco_led.brightness_set = toshiba_eco_mode_set_status; 3021def6c4e2SAzael Avalos dev->eco_led.brightness_get = toshiba_eco_mode_get_status; 3022def6c4e2SAzael Avalos if (!led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led)) 3023ea215a3fSAzael Avalos dev->eco_led_registered = true; 3024def6c4e2SAzael Avalos } 3025def6c4e2SAzael Avalos 3026ea215a3fSAzael Avalos toshiba_kbd_illum_available(dev); 3027360f0f39SAzael Avalos /* 3028360f0f39SAzael Avalos * Only register the LED if KBD illumination is supported 3029360f0f39SAzael Avalos * and the keyboard backlight operation mode is set to FN-Z 3030360f0f39SAzael Avalos */ 3031360f0f39SAzael Avalos if (dev->kbd_illum_supported && dev->kbd_mode == SCI_KBD_MODE_FNZ) { 3032360f0f39SAzael Avalos dev->kbd_led.name = "toshiba::kbd_backlight"; 3033360f0f39SAzael Avalos dev->kbd_led.max_brightness = 1; 3034360f0f39SAzael Avalos dev->kbd_led.brightness_set = toshiba_kbd_backlight_set; 3035360f0f39SAzael Avalos dev->kbd_led.brightness_get = toshiba_kbd_backlight_get; 3036360f0f39SAzael Avalos if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led)) 3037ea215a3fSAzael Avalos dev->kbd_led_registered = true; 3038360f0f39SAzael Avalos } 3039360f0f39SAzael Avalos 30409d8658acSAzael Avalos ret = toshiba_touchpad_get(dev, &dummy); 30419d8658acSAzael Avalos dev->touchpad_supported = !ret; 30429d8658acSAzael Avalos 3043ea215a3fSAzael Avalos toshiba_accelerometer_available(dev); 30445a2813e9SAzael Avalos 3045c8c91842SAzael Avalos toshiba_usb_sleep_charge_available(dev); 3046e26ffe51SAzael Avalos 3047bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(dev, &dummy); 3048bb3fe01fSAzael Avalos dev->usb_rapid_charge_supported = !ret; 3049bb3fe01fSAzael Avalos 3050172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(dev, &dummy); 3051172ce0a9SAzael Avalos dev->usb_sleep_music_supported = !ret; 3052172ce0a9SAzael Avalos 305335d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(dev, &dummy); 305435d53ceaSAzael Avalos dev->panel_power_on_supported = !ret; 305535d53ceaSAzael Avalos 305617fe4b3dSAzael Avalos ret = toshiba_usb_three_get(dev, &dummy); 305717fe4b3dSAzael Avalos dev->usb_three_supported = !ret; 305817fe4b3dSAzael Avalos 305936d03f93SSeth Forshee ret = get_video_status(dev, &dummy); 306036d03f93SSeth Forshee dev->video_supported = !ret; 306136d03f93SSeth Forshee 306236d03f93SSeth Forshee ret = get_fan_status(dev, &dummy); 306336d03f93SSeth Forshee dev->fan_supported = !ret; 306436d03f93SSeth Forshee 30656873f46aSAzael Avalos toshiba_wwan_available(dev); 30662fdde834SAzael Avalos if (dev->wwan_supported) 30672fdde834SAzael Avalos toshiba_acpi_setup_wwan_rfkill(dev); 30686873f46aSAzael Avalos 3069763ff32fSAzael Avalos toshiba_cooling_method_available(dev); 3070763ff32fSAzael Avalos 30710409cbceSAzael Avalos print_supported_features(dev); 30720409cbceSAzael Avalos 3073360f0f39SAzael Avalos ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, 3074360f0f39SAzael Avalos &toshiba_attr_group); 3075360f0f39SAzael Avalos if (ret) { 3076360f0f39SAzael Avalos dev->sysfs_created = 0; 3077360f0f39SAzael Avalos goto error; 3078360f0f39SAzael Avalos } 3079360f0f39SAzael Avalos dev->sysfs_created = !ret; 3080360f0f39SAzael Avalos 308136d03f93SSeth Forshee create_toshiba_proc_entries(dev); 308236d03f93SSeth Forshee 308329cd293fSSeth Forshee toshiba_acpi = dev; 308429cd293fSSeth Forshee 3085135740deSSeth Forshee return 0; 3086135740deSSeth Forshee 3087135740deSSeth Forshee error: 308851fac838SRafael J. Wysocki toshiba_acpi_remove(acpi_dev); 3089135740deSSeth Forshee return ret; 3090135740deSSeth Forshee } 3091135740deSSeth Forshee 3092135740deSSeth Forshee static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) 3093135740deSSeth Forshee { 3094135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 30956335e4d5SMatthew Garrett 309671454d78SAzael Avalos switch (event) { 309771454d78SAzael Avalos case 0x80: /* Hotkeys and some system events */ 3098a88bc06eSAzael Avalos /* 3099a88bc06eSAzael Avalos * Machines with this WMI GUID aren't supported due to bugs in 3100a88bc06eSAzael Avalos * their AML. 3101a88bc06eSAzael Avalos * 3102a88bc06eSAzael Avalos * Return silently to avoid triggering a netlink event. 3103a88bc06eSAzael Avalos */ 3104a88bc06eSAzael Avalos if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) 3105a88bc06eSAzael Avalos return; 310671454d78SAzael Avalos toshiba_acpi_process_hotkeys(dev); 310711948b93SSeth Forshee break; 3108bab09e23SAzael Avalos case 0x81: /* Dock events */ 3109bab09e23SAzael Avalos case 0x82: 3110bab09e23SAzael Avalos case 0x83: 3111bab09e23SAzael Avalos pr_info("Dock event received %x\n", event); 3112bab09e23SAzael Avalos break; 3113bab09e23SAzael Avalos case 0x88: /* Thermal events */ 3114bab09e23SAzael Avalos pr_info("Thermal event received\n"); 3115bab09e23SAzael Avalos break; 3116bab09e23SAzael Avalos case 0x8f: /* LID closed */ 3117bab09e23SAzael Avalos case 0x90: /* LID is closed and Dock has been ejected */ 3118bab09e23SAzael Avalos break; 3119bab09e23SAzael Avalos case 0x8c: /* SATA power events */ 3120bab09e23SAzael Avalos case 0x8b: 3121bab09e23SAzael Avalos pr_info("SATA power event received %x\n", event); 3122bab09e23SAzael Avalos break; 312380546905SAzael Avalos case 0x92: /* Keyboard backlight mode changed */ 312465e3cf9cSAzael Avalos toshiba_acpi->kbd_event_generated = true; 312580546905SAzael Avalos /* Update sysfs entries */ 312665e3cf9cSAzael Avalos if (sysfs_update_group(&acpi_dev->dev.kobj, 312765e3cf9cSAzael Avalos &toshiba_attr_group)) 312880546905SAzael Avalos pr_err("Unable to update sysfs entries\n"); 312980546905SAzael Avalos break; 3130bab09e23SAzael Avalos case 0x85: /* Unknown */ 3131bab09e23SAzael Avalos case 0x8d: /* Unknown */ 313271454d78SAzael Avalos case 0x8e: /* Unknown */ 3133bab09e23SAzael Avalos case 0x94: /* Unknown */ 3134bab09e23SAzael Avalos case 0x95: /* Unknown */ 313511948b93SSeth Forshee default: 313671454d78SAzael Avalos pr_info("Unknown event received %x\n", event); 313711948b93SSeth Forshee break; 31386335e4d5SMatthew Garrett } 3139bab09e23SAzael Avalos 3140bab09e23SAzael Avalos acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class, 3141bab09e23SAzael Avalos dev_name(&acpi_dev->dev), 314213ae84f9SAzael Avalos event, (event == 0x80) ? 314313ae84f9SAzael Avalos dev->last_key_event : 0); 314429cd293fSSeth Forshee } 31456335e4d5SMatthew Garrett 31463567a4e2SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 314743d2fd3bSRafael J. Wysocki static int toshiba_acpi_suspend(struct device *device) 314829cd293fSSeth Forshee { 314943d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 31501e574dbfSAzael Avalos 31511e574dbfSAzael Avalos if (dev->hotkey_dev) { 315229cd293fSSeth Forshee u32 result; 315329cd293fSSeth Forshee 3154d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE); 31551e574dbfSAzael Avalos if (result != TOS_SUCCESS) 31561e574dbfSAzael Avalos pr_info("Unable to disable hotkeys\n"); 31571e574dbfSAzael Avalos } 315829cd293fSSeth Forshee 315929cd293fSSeth Forshee return 0; 316029cd293fSSeth Forshee } 316129cd293fSSeth Forshee 316243d2fd3bSRafael J. Wysocki static int toshiba_acpi_resume(struct device *device) 316329cd293fSSeth Forshee { 316443d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 316529cd293fSSeth Forshee 3166e7fdb762SBenjamin Tissoires if (dev->hotkey_dev) { 31672fdde834SAzael Avalos if (toshiba_acpi_enable_hotkeys(dev)) 3168e7fdb762SBenjamin Tissoires pr_info("Unable to re-enable hotkeys\n"); 3169e7fdb762SBenjamin Tissoires } 317029cd293fSSeth Forshee 31712fdde834SAzael Avalos if (dev->wwan_rfk) { 31722fdde834SAzael Avalos if (!toshiba_wireless_status(dev)) 31732fdde834SAzael Avalos rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch); 31742fdde834SAzael Avalos } 31752fdde834SAzael Avalos 317629cd293fSSeth Forshee return 0; 317729cd293fSSeth Forshee } 31783567a4e2SRafael J. Wysocki #endif 31796335e4d5SMatthew Garrett 318043d2fd3bSRafael J. Wysocki static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm, 318143d2fd3bSRafael J. Wysocki toshiba_acpi_suspend, toshiba_acpi_resume); 318243d2fd3bSRafael J. Wysocki 3183135740deSSeth Forshee static struct acpi_driver toshiba_acpi_driver = { 3184135740deSSeth Forshee .name = "Toshiba ACPI driver", 3185135740deSSeth Forshee .owner = THIS_MODULE, 3186135740deSSeth Forshee .ids = toshiba_device_ids, 3187135740deSSeth Forshee .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, 3188135740deSSeth Forshee .ops = { 3189135740deSSeth Forshee .add = toshiba_acpi_add, 3190135740deSSeth Forshee .remove = toshiba_acpi_remove, 3191135740deSSeth Forshee .notify = toshiba_acpi_notify, 3192135740deSSeth Forshee }, 319343d2fd3bSRafael J. Wysocki .drv.pm = &toshiba_acpi_pm, 3194135740deSSeth Forshee }; 3195b4f9fe12SLen Brown 3196b4f9fe12SLen Brown static int __init toshiba_acpi_init(void) 3197b4f9fe12SLen Brown { 3198135740deSSeth Forshee int ret; 3199b4f9fe12SLen Brown 3200b4f9fe12SLen Brown toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); 3201b4f9fe12SLen Brown if (!toshiba_proc_dir) { 3202135740deSSeth Forshee pr_err("Unable to create proc dir " PROC_TOSHIBA "\n"); 3203b4f9fe12SLen Brown return -ENODEV; 3204b4f9fe12SLen Brown } 3205b4f9fe12SLen Brown 3206135740deSSeth Forshee ret = acpi_bus_register_driver(&toshiba_acpi_driver); 3207b4f9fe12SLen Brown if (ret) { 3208135740deSSeth Forshee pr_err("Failed to register ACPI driver: %d\n", ret); 3209135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 3210135740deSSeth Forshee } 3211135740deSSeth Forshee 3212b4f9fe12SLen Brown return ret; 3213b4f9fe12SLen Brown } 3214b4f9fe12SLen Brown 3215135740deSSeth Forshee static void __exit toshiba_acpi_exit(void) 3216135740deSSeth Forshee { 3217135740deSSeth Forshee acpi_bus_unregister_driver(&toshiba_acpi_driver); 3218135740deSSeth Forshee if (toshiba_proc_dir) 3219135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 3220b4f9fe12SLen Brown } 3221b4f9fe12SLen Brown 3222b4f9fe12SLen Brown module_init(toshiba_acpi_init); 3223b4f9fe12SLen Brown module_exit(toshiba_acpi_exit); 3224