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 347216d702SAzael Avalos #define TOSHIBA_ACPI_VERSION "0.21" 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> 53358d6a2cSHans de Goede #include <acpi/video.h> 54b4f9fe12SLen Brown 55b4f9fe12SLen Brown MODULE_AUTHOR("John Belmonte"); 56b4f9fe12SLen Brown MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); 57b4f9fe12SLen Brown MODULE_LICENSE("GPL"); 58b4f9fe12SLen Brown 59f11f999eSSeth Forshee #define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100" 60f11f999eSSeth Forshee 6129cd293fSSeth Forshee /* Scan code for Fn key on TOS1900 models */ 6229cd293fSSeth Forshee #define TOS1900_FN_SCAN 0x6e 6329cd293fSSeth Forshee 64b4f9fe12SLen Brown /* Toshiba ACPI method paths */ 65b4f9fe12SLen Brown #define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX" 66b4f9fe12SLen Brown 67e0769fe6SDarren Hart /* 68e0769fe6SDarren Hart * The Toshiba configuration interface is composed of the HCI and the SCI, 69258c5903SAzael Avalos * which are defined as follows: 70b4f9fe12SLen Brown * 71b4f9fe12SLen Brown * HCI is Toshiba's "Hardware Control Interface" which is supposed to 72b4f9fe12SLen Brown * be uniform across all their models. Ideally we would just call 73b4f9fe12SLen Brown * dedicated ACPI methods instead of using this primitive interface. 74b4f9fe12SLen Brown * However the ACPI methods seem to be incomplete in some areas (for 75b4f9fe12SLen Brown * example they allow setting, but not reading, the LCD brightness value), 76b4f9fe12SLen Brown * so this is still useful. 7784a6273fSAzael Avalos * 7884a6273fSAzael Avalos * SCI stands for "System Configuration Interface" which aim is to 7984a6273fSAzael Avalos * conceal differences in hardware between different models. 80b4f9fe12SLen Brown */ 81b4f9fe12SLen Brown 82258c5903SAzael Avalos #define TCI_WORDS 6 83b4f9fe12SLen Brown 843f75bbe9SAzael Avalos /* Operations */ 85b4f9fe12SLen Brown #define HCI_SET 0xff00 86b4f9fe12SLen Brown #define HCI_GET 0xfe00 8784a6273fSAzael Avalos #define SCI_OPEN 0xf100 8884a6273fSAzael Avalos #define SCI_CLOSE 0xf200 8984a6273fSAzael Avalos #define SCI_GET 0xf300 9084a6273fSAzael Avalos #define SCI_SET 0xf400 91b4f9fe12SLen Brown 923f75bbe9SAzael Avalos /* Return codes */ 931864bbc2SAzael Avalos #define TOS_SUCCESS 0x0000 941864bbc2SAzael Avalos #define TOS_OPEN_CLOSE_OK 0x0044 951864bbc2SAzael Avalos #define TOS_FAILURE 0x1000 961864bbc2SAzael Avalos #define TOS_NOT_SUPPORTED 0x8000 971864bbc2SAzael Avalos #define TOS_ALREADY_OPEN 0x8100 981864bbc2SAzael Avalos #define TOS_NOT_OPENED 0x8200 991864bbc2SAzael Avalos #define TOS_INPUT_DATA_ERROR 0x8300 1001864bbc2SAzael Avalos #define TOS_WRITE_PROTECTED 0x8400 1011864bbc2SAzael Avalos #define TOS_NOT_PRESENT 0x8600 1021864bbc2SAzael Avalos #define TOS_FIFO_EMPTY 0x8c00 1031864bbc2SAzael Avalos #define TOS_DATA_NOT_AVAILABLE 0x8d20 1041864bbc2SAzael Avalos #define TOS_NOT_INITIALIZED 0x8d50 10598fc4ec6SAzael Avalos #define TOS_NOT_INSTALLED 0x8e00 106b4f9fe12SLen Brown 1073f75bbe9SAzael Avalos /* Registers */ 108b4f9fe12SLen Brown #define HCI_FAN 0x0004 109121b7b0dSAkio Idehara #define HCI_TR_BACKLIGHT 0x0005 110b4f9fe12SLen Brown #define HCI_SYSTEM_EVENT 0x0016 111b4f9fe12SLen Brown #define HCI_VIDEO_OUT 0x001c 112b4f9fe12SLen Brown #define HCI_HOTKEY_EVENT 0x001e 113b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS 0x002a 114b4f9fe12SLen Brown #define HCI_WIRELESS 0x0056 1155a2813e9SAzael Avalos #define HCI_ACCELEROMETER 0x006d 116360f0f39SAzael Avalos #define HCI_KBD_ILLUMINATION 0x0095 117def6c4e2SAzael Avalos #define HCI_ECO_MODE 0x0097 1185a2813e9SAzael Avalos #define HCI_ACCELEROMETER2 0x00a6 11956e6b353SAzael Avalos #define HCI_SYSTEM_INFO 0xc000 12035d53ceaSAzael Avalos #define SCI_PANEL_POWER_ON 0x010d 121fdb79081SAzael Avalos #define SCI_ILLUMINATION 0x014e 122e26ffe51SAzael Avalos #define SCI_USB_SLEEP_CHARGE 0x0150 123360f0f39SAzael Avalos #define SCI_KBD_ILLUM_STATUS 0x015c 124172ce0a9SAzael Avalos #define SCI_USB_SLEEP_MUSIC 0x015e 12517fe4b3dSAzael Avalos #define SCI_USB_THREE 0x0169 1269d8658acSAzael Avalos #define SCI_TOUCHPAD 0x050e 127bae84195SAzael Avalos #define SCI_KBD_FUNCTION_KEYS 0x0522 128b4f9fe12SLen Brown 1293f75bbe9SAzael Avalos /* Field definitions */ 1305a2813e9SAzael Avalos #define HCI_ACCEL_MASK 0x7fff 13129cd293fSSeth Forshee #define HCI_HOTKEY_DISABLE 0x0b 13229cd293fSSeth Forshee #define HCI_HOTKEY_ENABLE 0x09 133fb42d1f4SAzael Avalos #define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10 134b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_BITS 3 135b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) 136b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS) 137360f0f39SAzael Avalos #define HCI_MISC_SHIFT 0x10 13856e6b353SAzael Avalos #define HCI_SYSTEM_TYPE1 0x10 13956e6b353SAzael Avalos #define HCI_SYSTEM_TYPE2 0x11 140b4f9fe12SLen Brown #define HCI_VIDEO_OUT_LCD 0x1 141b4f9fe12SLen Brown #define HCI_VIDEO_OUT_CRT 0x2 142b4f9fe12SLen Brown #define HCI_VIDEO_OUT_TV 0x4 143b4f9fe12SLen Brown #define HCI_WIRELESS_KILL_SWITCH 0x01 144b4f9fe12SLen Brown #define HCI_WIRELESS_BT_PRESENT 0x0f 145b4f9fe12SLen Brown #define HCI_WIRELESS_BT_ATTACH 0x40 146b4f9fe12SLen Brown #define HCI_WIRELESS_BT_POWER 0x80 14793f8c16dSAzael Avalos #define SCI_KBD_MODE_MASK 0x1f 148360f0f39SAzael Avalos #define SCI_KBD_MODE_FNZ 0x1 149360f0f39SAzael Avalos #define SCI_KBD_MODE_AUTO 0x2 15093f8c16dSAzael Avalos #define SCI_KBD_MODE_ON 0x8 15193f8c16dSAzael Avalos #define SCI_KBD_MODE_OFF 0x10 15293f8c16dSAzael Avalos #define SCI_KBD_TIME_MAX 0x3c001a 153e26ffe51SAzael Avalos #define SCI_USB_CHARGE_MODE_MASK 0xff 154c8c91842SAzael Avalos #define SCI_USB_CHARGE_DISABLED 0x00 155c8c91842SAzael Avalos #define SCI_USB_CHARGE_ALTERNATE 0x09 156c8c91842SAzael Avalos #define SCI_USB_CHARGE_TYPICAL 0x11 157c8c91842SAzael Avalos #define SCI_USB_CHARGE_AUTO 0x21 158182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_MASK 0x7 159182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_OFF 0x1 160182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_ON 0x4 161182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL 0x0200 162bb3fe01fSAzael Avalos #define SCI_USB_CHARGE_RAPID_DSP 0x0300 163b4f9fe12SLen Brown 164135740deSSeth Forshee struct toshiba_acpi_dev { 165135740deSSeth Forshee struct acpi_device *acpi_dev; 166135740deSSeth Forshee const char *method_hci; 167135740deSSeth Forshee struct input_dev *hotkey_dev; 16829cd293fSSeth Forshee struct work_struct hotkey_work; 169135740deSSeth Forshee struct backlight_device *backlight_dev; 170135740deSSeth Forshee struct led_classdev led_dev; 171360f0f39SAzael Avalos struct led_classdev kbd_led; 172def6c4e2SAzael Avalos struct led_classdev eco_led; 17336d03f93SSeth Forshee 174135740deSSeth Forshee int force_fan; 175135740deSSeth Forshee int last_key_event; 176135740deSSeth Forshee int key_event_valid; 17793f8c16dSAzael Avalos int kbd_type; 178360f0f39SAzael Avalos int kbd_mode; 179360f0f39SAzael Avalos int kbd_time; 180182bcaa5SAzael Avalos int usbsc_bat_level; 181c8c91842SAzael Avalos int usbsc_mode_base; 182a2b3471bSAzael Avalos int hotkey_event_type; 183135740deSSeth Forshee 184592b746cSDan Carpenter unsigned int illumination_supported:1; 185592b746cSDan Carpenter unsigned int video_supported:1; 186592b746cSDan Carpenter unsigned int fan_supported:1; 187592b746cSDan Carpenter unsigned int system_event_supported:1; 18829cd293fSSeth Forshee unsigned int ntfy_supported:1; 18929cd293fSSeth Forshee unsigned int info_supported:1; 190121b7b0dSAkio Idehara unsigned int tr_backlight_supported:1; 191360f0f39SAzael Avalos unsigned int kbd_illum_supported:1; 192360f0f39SAzael Avalos unsigned int kbd_led_registered:1; 1939d8658acSAzael Avalos unsigned int touchpad_supported:1; 194def6c4e2SAzael Avalos unsigned int eco_supported:1; 1955a2813e9SAzael Avalos unsigned int accelerometer_supported:1; 196e26ffe51SAzael Avalos unsigned int usb_sleep_charge_supported:1; 197bb3fe01fSAzael Avalos unsigned int usb_rapid_charge_supported:1; 198172ce0a9SAzael Avalos unsigned int usb_sleep_music_supported:1; 199bae84195SAzael Avalos unsigned int kbd_function_keys_supported:1; 20035d53ceaSAzael Avalos unsigned int panel_power_on_supported:1; 20117fe4b3dSAzael Avalos unsigned int usb_three_supported:1; 202360f0f39SAzael Avalos unsigned int sysfs_created:1; 203135740deSSeth Forshee }; 204135740deSSeth Forshee 20529cd293fSSeth Forshee static struct toshiba_acpi_dev *toshiba_acpi; 20629cd293fSSeth Forshee 207b4f9fe12SLen Brown static const struct acpi_device_id toshiba_device_ids[] = { 208b4f9fe12SLen Brown {"TOS6200", 0}, 20963a9e016SOndrej Zary {"TOS6207", 0}, 210b4f9fe12SLen Brown {"TOS6208", 0}, 211b4f9fe12SLen Brown {"TOS1900", 0}, 212b4f9fe12SLen Brown {"", 0}, 213b4f9fe12SLen Brown }; 214b4f9fe12SLen Brown MODULE_DEVICE_TABLE(acpi, toshiba_device_ids); 215b4f9fe12SLen Brown 216b859f159SGreg Kroah-Hartman static const struct key_entry toshiba_acpi_keymap[] = { 217fec278a1SUnai Uribarri { KE_KEY, 0x9e, { KEY_RFKILL } }, 218384a7cd9SDmitry Torokhov { KE_KEY, 0x101, { KEY_MUTE } }, 219384a7cd9SDmitry Torokhov { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 220384a7cd9SDmitry Torokhov { KE_KEY, 0x103, { KEY_ZOOMIN } }, 221408a5d13SAzael Avalos { KE_KEY, 0x10f, { KEY_TAB } }, 222af502837SAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 223af502837SAzael Avalos { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 224384a7cd9SDmitry Torokhov { KE_KEY, 0x13b, { KEY_COFFEE } }, 225384a7cd9SDmitry Torokhov { KE_KEY, 0x13c, { KEY_BATTERY } }, 226384a7cd9SDmitry Torokhov { KE_KEY, 0x13d, { KEY_SLEEP } }, 227384a7cd9SDmitry Torokhov { KE_KEY, 0x13e, { KEY_SUSPEND } }, 228384a7cd9SDmitry Torokhov { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } }, 229384a7cd9SDmitry Torokhov { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } }, 230384a7cd9SDmitry Torokhov { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } }, 231384a7cd9SDmitry Torokhov { KE_KEY, 0x142, { KEY_WLAN } }, 232af502837SAzael Avalos { KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } }, 233a49010f5SJon Dowland { KE_KEY, 0x17f, { KEY_FN } }, 234384a7cd9SDmitry Torokhov { KE_KEY, 0xb05, { KEY_PROG2 } }, 235384a7cd9SDmitry Torokhov { KE_KEY, 0xb06, { KEY_WWW } }, 236384a7cd9SDmitry Torokhov { KE_KEY, 0xb07, { KEY_MAIL } }, 237384a7cd9SDmitry Torokhov { KE_KEY, 0xb30, { KEY_STOP } }, 238384a7cd9SDmitry Torokhov { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } }, 239384a7cd9SDmitry Torokhov { KE_KEY, 0xb32, { KEY_NEXTSONG } }, 240384a7cd9SDmitry Torokhov { KE_KEY, 0xb33, { KEY_PLAYPAUSE } }, 241384a7cd9SDmitry Torokhov { KE_KEY, 0xb5a, { KEY_MEDIA } }, 242408a5d13SAzael Avalos { KE_IGNORE, 0x1430, { KEY_RESERVED } }, /* Wake from sleep */ 243408a5d13SAzael Avalos { KE_IGNORE, 0x1501, { KEY_RESERVED } }, /* Output changed */ 244408a5d13SAzael Avalos { KE_IGNORE, 0x1502, { KEY_RESERVED } }, /* HDMI plugged/unplugged */ 245408a5d13SAzael Avalos { KE_IGNORE, 0x1ABE, { KEY_RESERVED } }, /* Protection level set */ 246408a5d13SAzael Avalos { KE_IGNORE, 0x1ABF, { KEY_RESERVED } }, /* Protection level off */ 247384a7cd9SDmitry Torokhov { KE_END, 0 }, 2486335e4d5SMatthew Garrett }; 2496335e4d5SMatthew Garrett 250fe808bfbSTakashi Iwai static const struct key_entry toshiba_acpi_alt_keymap[] = { 251fe808bfbSTakashi Iwai { KE_KEY, 0x157, { KEY_MUTE } }, 252fe808bfbSTakashi Iwai { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 253fe808bfbSTakashi Iwai { KE_KEY, 0x103, { KEY_ZOOMIN } }, 254e6efad7fSAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 255fe808bfbSTakashi Iwai { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 256fe808bfbSTakashi Iwai { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } }, 257fe808bfbSTakashi Iwai { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } }, 258fe808bfbSTakashi Iwai { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } }, 259fe808bfbSTakashi Iwai { KE_KEY, 0x158, { KEY_WLAN } }, 260fe808bfbSTakashi Iwai { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } }, 261fe808bfbSTakashi Iwai { KE_END, 0 }, 262fe808bfbSTakashi Iwai }; 263fe808bfbSTakashi Iwai 264e0769fe6SDarren Hart /* 265358d6a2cSHans de Goede * List of models which have a broken acpi-video backlight interface and thus 266358d6a2cSHans de Goede * need to use the toshiba (vendor) interface instead. 267358d6a2cSHans de Goede */ 268358d6a2cSHans de Goede static const struct dmi_system_id toshiba_vendor_backlight_dmi[] = { 269358d6a2cSHans de Goede {} 270358d6a2cSHans de Goede }; 271358d6a2cSHans de Goede 272358d6a2cSHans de Goede /* 273e0769fe6SDarren Hart * Utility 274b4f9fe12SLen Brown */ 275b4f9fe12SLen Brown 276b5163992SAzael Avalos static inline void _set_bit(u32 *word, u32 mask, int value) 277b4f9fe12SLen Brown { 278b4f9fe12SLen Brown *word = (*word & ~mask) | (mask * value); 279b4f9fe12SLen Brown } 280b4f9fe12SLen Brown 281e0769fe6SDarren Hart /* 282e0769fe6SDarren Hart * ACPI interface wrappers 283b4f9fe12SLen Brown */ 284b4f9fe12SLen Brown 285b4f9fe12SLen Brown static int write_acpi_int(const char *methodName, int val) 286b4f9fe12SLen Brown { 287b4f9fe12SLen Brown acpi_status status; 288b4f9fe12SLen Brown 289619400daSZhang Rui status = acpi_execute_simple_method(NULL, (char *)methodName, val); 29032bcd5cbSSeth Forshee return (status == AE_OK) ? 0 : -EIO; 291b4f9fe12SLen Brown } 292b4f9fe12SLen Brown 293e0769fe6SDarren Hart /* 294e0769fe6SDarren Hart * Perform a raw configuration call. Here we don't care about input or output 295258c5903SAzael Avalos * buffer format. 296b4f9fe12SLen Brown */ 297258c5903SAzael Avalos static acpi_status tci_raw(struct toshiba_acpi_dev *dev, 298258c5903SAzael Avalos const u32 in[TCI_WORDS], u32 out[TCI_WORDS]) 299b4f9fe12SLen Brown { 300b4f9fe12SLen Brown struct acpi_object_list params; 301258c5903SAzael Avalos union acpi_object in_objs[TCI_WORDS]; 302b4f9fe12SLen Brown struct acpi_buffer results; 303258c5903SAzael Avalos union acpi_object out_objs[TCI_WORDS + 1]; 304b4f9fe12SLen Brown acpi_status status; 305b4f9fe12SLen Brown int i; 306b4f9fe12SLen Brown 307258c5903SAzael Avalos params.count = TCI_WORDS; 308b4f9fe12SLen Brown params.pointer = in_objs; 309258c5903SAzael Avalos for (i = 0; i < TCI_WORDS; ++i) { 310b4f9fe12SLen Brown in_objs[i].type = ACPI_TYPE_INTEGER; 311b4f9fe12SLen Brown in_objs[i].integer.value = in[i]; 312b4f9fe12SLen Brown } 313b4f9fe12SLen Brown 314b4f9fe12SLen Brown results.length = sizeof(out_objs); 315b4f9fe12SLen Brown results.pointer = out_objs; 316b4f9fe12SLen Brown 3176e02cc7eSSeth Forshee status = acpi_evaluate_object(dev->acpi_dev->handle, 3186e02cc7eSSeth Forshee (char *)dev->method_hci, ¶ms, 319b4f9fe12SLen Brown &results); 320258c5903SAzael Avalos if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) { 321b5163992SAzael Avalos for (i = 0; i < out_objs->package.count; ++i) 322b4f9fe12SLen Brown out[i] = out_objs->package.elements[i].integer.value; 323b4f9fe12SLen Brown } 324b4f9fe12SLen Brown 325b4f9fe12SLen Brown return status; 326b4f9fe12SLen Brown } 327b4f9fe12SLen Brown 328e0769fe6SDarren Hart /* 329d37782bdSAzael Avalos * Common hci tasks 330b4f9fe12SLen Brown * 331b4f9fe12SLen Brown * In addition to the ACPI status, the HCI system returns a result which 332b4f9fe12SLen Brown * may be useful (such as "not supported"). 333b4f9fe12SLen Brown */ 334b4f9fe12SLen Brown 335d37782bdSAzael Avalos static u32 hci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 336b4f9fe12SLen Brown { 337258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 }; 338258c5903SAzael Avalos u32 out[TCI_WORDS]; 339258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 340893f3f62SAzael Avalos 341893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 342b4f9fe12SLen Brown } 343b4f9fe12SLen Brown 344d37782bdSAzael Avalos static u32 hci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 345b4f9fe12SLen Brown { 346258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 }; 347258c5903SAzael Avalos u32 out[TCI_WORDS]; 348258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 349b5163992SAzael Avalos 350893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 351893f3f62SAzael Avalos return TOS_FAILURE; 352893f3f62SAzael Avalos 353b4f9fe12SLen Brown *out1 = out[2]; 354893f3f62SAzael Avalos 355893f3f62SAzael Avalos return out[0]; 356b4f9fe12SLen Brown } 357b4f9fe12SLen Brown 358e0769fe6SDarren Hart /* 359e0769fe6SDarren Hart * Common sci tasks 36084a6273fSAzael Avalos */ 36184a6273fSAzael Avalos 36284a6273fSAzael Avalos static int sci_open(struct toshiba_acpi_dev *dev) 36384a6273fSAzael Avalos { 364258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 }; 365258c5903SAzael Avalos u32 out[TCI_WORDS]; 36684a6273fSAzael Avalos acpi_status status; 36784a6273fSAzael Avalos 368258c5903SAzael Avalos status = tci_raw(dev, in, out); 369*8baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 37084a6273fSAzael Avalos pr_err("ACPI call to open SCI failed\n"); 37184a6273fSAzael Avalos return 0; 37284a6273fSAzael Avalos } 37384a6273fSAzael Avalos 3741864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) { 37584a6273fSAzael Avalos return 1; 3761864bbc2SAzael Avalos } else if (out[0] == TOS_ALREADY_OPEN) { 37784a6273fSAzael Avalos pr_info("Toshiba SCI already opened\n"); 37884a6273fSAzael Avalos return 1; 379fa465739SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 380e0769fe6SDarren Hart /* 381e0769fe6SDarren Hart * Some BIOSes do not have the SCI open/close functions 382fa465739SAzael Avalos * implemented and return 0x8000 (Not Supported), failing to 383fa465739SAzael Avalos * register some supported features. 384fa465739SAzael Avalos * 385fa465739SAzael Avalos * Simply return 1 if we hit those affected laptops to make the 386fa465739SAzael Avalos * supported features work. 387fa465739SAzael Avalos * 388fa465739SAzael Avalos * In the case that some laptops really do not support the SCI, 389fa465739SAzael Avalos * all the SCI dependent functions check for TOS_NOT_SUPPORTED, 390fa465739SAzael Avalos * and thus, not registering support for the queried feature. 391fa465739SAzael Avalos */ 392fa465739SAzael Avalos return 1; 3931864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_PRESENT) { 39484a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 39584a6273fSAzael Avalos } 39684a6273fSAzael Avalos 39784a6273fSAzael Avalos return 0; 39884a6273fSAzael Avalos } 39984a6273fSAzael Avalos 40084a6273fSAzael Avalos static void sci_close(struct toshiba_acpi_dev *dev) 40184a6273fSAzael Avalos { 402258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 }; 403258c5903SAzael Avalos u32 out[TCI_WORDS]; 40484a6273fSAzael Avalos acpi_status status; 40584a6273fSAzael Avalos 406258c5903SAzael Avalos status = tci_raw(dev, in, out); 407*8baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 40884a6273fSAzael Avalos pr_err("ACPI call to close SCI failed\n"); 40984a6273fSAzael Avalos return; 41084a6273fSAzael Avalos } 41184a6273fSAzael Avalos 4121864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) 41384a6273fSAzael Avalos return; 4141864bbc2SAzael Avalos else if (out[0] == TOS_NOT_OPENED) 41584a6273fSAzael Avalos pr_info("Toshiba SCI not opened\n"); 4161864bbc2SAzael Avalos else if (out[0] == TOS_NOT_PRESENT) 41784a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 41884a6273fSAzael Avalos } 41984a6273fSAzael Avalos 420893f3f62SAzael Avalos static u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 42184a6273fSAzael Avalos { 422258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 }; 423258c5903SAzael Avalos u32 out[TCI_WORDS]; 424258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 425b5163992SAzael Avalos 426893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 427893f3f62SAzael Avalos return TOS_FAILURE; 428893f3f62SAzael Avalos 42984a6273fSAzael Avalos *out1 = out[2]; 430893f3f62SAzael Avalos 431893f3f62SAzael Avalos return out[0]; 43284a6273fSAzael Avalos } 43384a6273fSAzael Avalos 434893f3f62SAzael Avalos static u32 sci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 43584a6273fSAzael Avalos { 436258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 }; 437258c5903SAzael Avalos u32 out[TCI_WORDS]; 438258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 439893f3f62SAzael Avalos 440893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 44184a6273fSAzael Avalos } 44284a6273fSAzael Avalos 4436c3f6e6cSPierre Ducroquet /* Illumination support */ 444135740deSSeth Forshee static int toshiba_illumination_available(struct toshiba_acpi_dev *dev) 4456c3f6e6cSPierre Ducroquet { 446258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 }; 447258c5903SAzael Avalos u32 out[TCI_WORDS]; 4486c3f6e6cSPierre Ducroquet acpi_status status; 4496c3f6e6cSPierre Ducroquet 450fdb79081SAzael Avalos if (!sci_open(dev)) 451fdb79081SAzael Avalos return 0; 452fdb79081SAzael Avalos 453258c5903SAzael Avalos status = tci_raw(dev, in, out); 454fdb79081SAzael Avalos sci_close(dev); 455*8baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 456fdb79081SAzael Avalos pr_err("ACPI call to query Illumination support failed\n"); 457fdb79081SAzael Avalos return 0; 4581864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 4597e33460dSJoe Perches pr_info("Illumination device not available\n"); 4606c3f6e6cSPierre Ducroquet return 0; 4616c3f6e6cSPierre Ducroquet } 462fdb79081SAzael Avalos 4636c3f6e6cSPierre Ducroquet return 1; 4646c3f6e6cSPierre Ducroquet } 4656c3f6e6cSPierre Ducroquet 4666c3f6e6cSPierre Ducroquet static void toshiba_illumination_set(struct led_classdev *cdev, 4676c3f6e6cSPierre Ducroquet enum led_brightness brightness) 4686c3f6e6cSPierre Ducroquet { 469135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 470135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 471fdb79081SAzael Avalos u32 state, result; 4726c3f6e6cSPierre Ducroquet 4736c3f6e6cSPierre Ducroquet /* First request : initialize communication. */ 474fdb79081SAzael Avalos if (!sci_open(dev)) 4756c3f6e6cSPierre Ducroquet return; 4766c3f6e6cSPierre Ducroquet 477fdb79081SAzael Avalos /* Switch the illumination on/off */ 478fdb79081SAzael Avalos state = brightness ? 1 : 0; 479893f3f62SAzael Avalos result = sci_write(dev, SCI_ILLUMINATION, state); 480fdb79081SAzael Avalos sci_close(dev); 481893f3f62SAzael Avalos if (result == TOS_FAILURE) { 482fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 483fdb79081SAzael Avalos return; 4841864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 485fdb79081SAzael Avalos pr_info("Illumination not supported\n"); 4866c3f6e6cSPierre Ducroquet return; 4876c3f6e6cSPierre Ducroquet } 4886c3f6e6cSPierre Ducroquet } 4896c3f6e6cSPierre Ducroquet 4906c3f6e6cSPierre Ducroquet static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) 4916c3f6e6cSPierre Ducroquet { 492135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 493135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 494fdb79081SAzael Avalos u32 state, result; 4956c3f6e6cSPierre Ducroquet 4963f75bbe9SAzael Avalos /* First request : initialize communication. */ 497fdb79081SAzael Avalos if (!sci_open(dev)) 4986c3f6e6cSPierre Ducroquet return LED_OFF; 4996c3f6e6cSPierre Ducroquet 5006c3f6e6cSPierre Ducroquet /* Check the illumination */ 501893f3f62SAzael Avalos result = sci_read(dev, SCI_ILLUMINATION, &state); 502fdb79081SAzael Avalos sci_close(dev); 503893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 504fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 505fdb79081SAzael Avalos return LED_OFF; 5061864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 507fdb79081SAzael Avalos pr_info("Illumination not supported\n"); 5086c3f6e6cSPierre Ducroquet return LED_OFF; 5096c3f6e6cSPierre Ducroquet } 5106c3f6e6cSPierre Ducroquet 511fdb79081SAzael Avalos return state ? LED_FULL : LED_OFF; 5126c3f6e6cSPierre Ducroquet } 5136c3f6e6cSPierre Ducroquet 514360f0f39SAzael Avalos /* KBD Illumination */ 51593f8c16dSAzael Avalos static int toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev) 51693f8c16dSAzael Avalos { 517258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 }; 518258c5903SAzael Avalos u32 out[TCI_WORDS]; 51993f8c16dSAzael Avalos acpi_status status; 52093f8c16dSAzael Avalos 52193f8c16dSAzael Avalos if (!sci_open(dev)) 52293f8c16dSAzael Avalos return 0; 52393f8c16dSAzael Avalos 524258c5903SAzael Avalos status = tci_raw(dev, in, out); 52593f8c16dSAzael Avalos sci_close(dev); 5261864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 52793f8c16dSAzael Avalos pr_err("ACPI call to query kbd illumination support failed\n"); 52893f8c16dSAzael Avalos return 0; 5291864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 53093f8c16dSAzael Avalos pr_info("Keyboard illumination not available\n"); 53193f8c16dSAzael Avalos return 0; 53293f8c16dSAzael Avalos } 53393f8c16dSAzael Avalos 534e0769fe6SDarren Hart /* 535e0769fe6SDarren Hart * Check for keyboard backlight timeout max value, 53693f8c16dSAzael Avalos * previous kbd backlight implementation set this to 53793f8c16dSAzael Avalos * 0x3c0003, and now the new implementation set this 538e0769fe6SDarren Hart * to 0x3c001a, use this to distinguish between them. 53993f8c16dSAzael Avalos */ 54093f8c16dSAzael Avalos if (out[3] == SCI_KBD_TIME_MAX) 54193f8c16dSAzael Avalos dev->kbd_type = 2; 54293f8c16dSAzael Avalos else 54393f8c16dSAzael Avalos dev->kbd_type = 1; 54493f8c16dSAzael Avalos /* Get the current keyboard backlight mode */ 54593f8c16dSAzael Avalos dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK; 54693f8c16dSAzael Avalos /* Get the current time (1-60 seconds) */ 54793f8c16dSAzael Avalos dev->kbd_time = out[2] >> HCI_MISC_SHIFT; 54893f8c16dSAzael Avalos 54993f8c16dSAzael Avalos return 1; 55093f8c16dSAzael Avalos } 55193f8c16dSAzael Avalos 552360f0f39SAzael Avalos static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time) 553360f0f39SAzael Avalos { 554360f0f39SAzael Avalos u32 result; 555360f0f39SAzael Avalos 556360f0f39SAzael Avalos if (!sci_open(dev)) 557360f0f39SAzael Avalos return -EIO; 558360f0f39SAzael Avalos 559893f3f62SAzael Avalos result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time); 560360f0f39SAzael Avalos sci_close(dev); 561893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 562360f0f39SAzael Avalos pr_err("ACPI call to set KBD backlight status failed\n"); 563360f0f39SAzael Avalos return -EIO; 5641864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 565360f0f39SAzael Avalos pr_info("Keyboard backlight status not supported\n"); 566360f0f39SAzael Avalos return -ENODEV; 567360f0f39SAzael Avalos } 568360f0f39SAzael Avalos 569360f0f39SAzael Avalos return 0; 570360f0f39SAzael Avalos } 571360f0f39SAzael Avalos 572360f0f39SAzael Avalos static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time) 573360f0f39SAzael Avalos { 574360f0f39SAzael Avalos u32 result; 575360f0f39SAzael Avalos 576360f0f39SAzael Avalos if (!sci_open(dev)) 577360f0f39SAzael Avalos return -EIO; 578360f0f39SAzael Avalos 579893f3f62SAzael Avalos result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time); 580360f0f39SAzael Avalos sci_close(dev); 581893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 582360f0f39SAzael Avalos pr_err("ACPI call to get KBD backlight status failed\n"); 583360f0f39SAzael Avalos return -EIO; 5841864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 585360f0f39SAzael Avalos pr_info("Keyboard backlight status not supported\n"); 586360f0f39SAzael Avalos return -ENODEV; 587360f0f39SAzael Avalos } 588360f0f39SAzael Avalos 589360f0f39SAzael Avalos return 0; 590360f0f39SAzael Avalos } 591360f0f39SAzael Avalos 592360f0f39SAzael Avalos static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev) 593360f0f39SAzael Avalos { 594360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 595360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 596360f0f39SAzael Avalos u32 state, result; 597360f0f39SAzael Avalos 598360f0f39SAzael Avalos /* Check the keyboard backlight state */ 599d37782bdSAzael Avalos result = hci_read(dev, HCI_KBD_ILLUMINATION, &state); 600893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 601360f0f39SAzael Avalos pr_err("ACPI call to get the keyboard backlight failed\n"); 602360f0f39SAzael Avalos return LED_OFF; 6031864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 604360f0f39SAzael Avalos pr_info("Keyboard backlight not supported\n"); 605360f0f39SAzael Avalos return LED_OFF; 606360f0f39SAzael Avalos } 607360f0f39SAzael Avalos 608360f0f39SAzael Avalos return state ? LED_FULL : LED_OFF; 609360f0f39SAzael Avalos } 610360f0f39SAzael Avalos 611360f0f39SAzael Avalos static void toshiba_kbd_backlight_set(struct led_classdev *cdev, 612360f0f39SAzael Avalos enum led_brightness brightness) 613360f0f39SAzael Avalos { 614360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 615360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 616360f0f39SAzael Avalos u32 state, result; 617360f0f39SAzael Avalos 618360f0f39SAzael Avalos /* Set the keyboard backlight state */ 619360f0f39SAzael Avalos state = brightness ? 1 : 0; 620d37782bdSAzael Avalos result = hci_write(dev, HCI_KBD_ILLUMINATION, state); 621893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 622360f0f39SAzael Avalos pr_err("ACPI call to set KBD Illumination mode failed\n"); 623360f0f39SAzael Avalos return; 6241864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 625360f0f39SAzael Avalos pr_info("Keyboard backlight not supported\n"); 626360f0f39SAzael Avalos return; 627360f0f39SAzael Avalos } 628360f0f39SAzael Avalos } 629360f0f39SAzael Avalos 6309d8658acSAzael Avalos /* TouchPad support */ 6319d8658acSAzael Avalos static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state) 6329d8658acSAzael Avalos { 6339d8658acSAzael Avalos u32 result; 6349d8658acSAzael Avalos 6359d8658acSAzael Avalos if (!sci_open(dev)) 6369d8658acSAzael Avalos return -EIO; 6379d8658acSAzael Avalos 638893f3f62SAzael Avalos result = sci_write(dev, SCI_TOUCHPAD, state); 6399d8658acSAzael Avalos sci_close(dev); 640893f3f62SAzael Avalos if (result == TOS_FAILURE) { 6419d8658acSAzael Avalos pr_err("ACPI call to set the touchpad failed\n"); 6429d8658acSAzael Avalos return -EIO; 6431864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 6449d8658acSAzael Avalos return -ENODEV; 6459d8658acSAzael Avalos } 6469d8658acSAzael Avalos 6479d8658acSAzael Avalos return 0; 6489d8658acSAzael Avalos } 6499d8658acSAzael Avalos 6509d8658acSAzael Avalos static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) 6519d8658acSAzael Avalos { 6529d8658acSAzael Avalos u32 result; 6539d8658acSAzael Avalos 6549d8658acSAzael Avalos if (!sci_open(dev)) 6559d8658acSAzael Avalos return -EIO; 6569d8658acSAzael Avalos 657893f3f62SAzael Avalos result = sci_read(dev, SCI_TOUCHPAD, state); 6589d8658acSAzael Avalos sci_close(dev); 659893f3f62SAzael Avalos if (result == TOS_FAILURE) { 6609d8658acSAzael Avalos pr_err("ACPI call to query the touchpad failed\n"); 6619d8658acSAzael Avalos return -EIO; 6621864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 6639d8658acSAzael Avalos return -ENODEV; 6649d8658acSAzael Avalos } 6659d8658acSAzael Avalos 6669d8658acSAzael Avalos return 0; 6679d8658acSAzael Avalos } 6689d8658acSAzael Avalos 669def6c4e2SAzael Avalos /* Eco Mode support */ 670def6c4e2SAzael Avalos static int toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) 671def6c4e2SAzael Avalos { 672def6c4e2SAzael Avalos acpi_status status; 67398fc4ec6SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 }; 674258c5903SAzael Avalos u32 out[TCI_WORDS]; 675def6c4e2SAzael Avalos 676258c5903SAzael Avalos status = tci_raw(dev, in, out); 677*8baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 67898fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 67998fc4ec6SAzael Avalos } else if (out[0] == TOS_NOT_INSTALLED) { 68098fc4ec6SAzael Avalos pr_info("ECO led not installed"); 68198fc4ec6SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 682e0769fe6SDarren Hart /* 683e0769fe6SDarren Hart * If we receive 0x8300 (Input Data Error), it means that the 68498fc4ec6SAzael Avalos * LED device is present, but that we just screwed the input 68598fc4ec6SAzael Avalos * parameters. 68698fc4ec6SAzael Avalos * 68798fc4ec6SAzael Avalos * Let's query the status of the LED to see if we really have a 68898fc4ec6SAzael Avalos * success response, indicating the actual presense of the LED, 68998fc4ec6SAzael Avalos * bail out otherwise. 69098fc4ec6SAzael Avalos */ 69198fc4ec6SAzael Avalos in[3] = 1; 69298fc4ec6SAzael Avalos status = tci_raw(dev, in, out); 69398fc4ec6SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) 69498fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 69598fc4ec6SAzael Avalos else if (out[0] == TOS_SUCCESS) 69698fc4ec6SAzael Avalos return 1; 697def6c4e2SAzael Avalos } 698def6c4e2SAzael Avalos 69998fc4ec6SAzael Avalos return 0; 700def6c4e2SAzael Avalos } 701def6c4e2SAzael Avalos 702b5163992SAzael Avalos static enum led_brightness 703b5163992SAzael Avalos toshiba_eco_mode_get_status(struct led_classdev *cdev) 704def6c4e2SAzael Avalos { 705def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 706def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 707258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 }; 708258c5903SAzael Avalos u32 out[TCI_WORDS]; 709def6c4e2SAzael Avalos acpi_status status; 710def6c4e2SAzael Avalos 711258c5903SAzael Avalos status = tci_raw(dev, in, out); 7121864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 713def6c4e2SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 714def6c4e2SAzael Avalos return LED_OFF; 715def6c4e2SAzael Avalos } 716def6c4e2SAzael Avalos 717def6c4e2SAzael Avalos return out[2] ? LED_FULL : LED_OFF; 718def6c4e2SAzael Avalos } 719def6c4e2SAzael Avalos 720def6c4e2SAzael Avalos static void toshiba_eco_mode_set_status(struct led_classdev *cdev, 721def6c4e2SAzael Avalos enum led_brightness brightness) 722def6c4e2SAzael Avalos { 723def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 724def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 725258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 }; 726258c5903SAzael Avalos u32 out[TCI_WORDS]; 727def6c4e2SAzael Avalos acpi_status status; 728def6c4e2SAzael Avalos 729def6c4e2SAzael Avalos /* Switch the Eco Mode led on/off */ 730def6c4e2SAzael Avalos in[2] = (brightness) ? 1 : 0; 731258c5903SAzael Avalos status = tci_raw(dev, in, out); 7321864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 733def6c4e2SAzael Avalos pr_err("ACPI call to set ECO led failed\n"); 734def6c4e2SAzael Avalos return; 735def6c4e2SAzael Avalos } 736def6c4e2SAzael Avalos } 737def6c4e2SAzael Avalos 7385a2813e9SAzael Avalos /* Accelerometer support */ 7395a2813e9SAzael Avalos static int toshiba_accelerometer_supported(struct toshiba_acpi_dev *dev) 7405a2813e9SAzael Avalos { 741258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 }; 742258c5903SAzael Avalos u32 out[TCI_WORDS]; 7435a2813e9SAzael Avalos acpi_status status; 7445a2813e9SAzael Avalos 745e0769fe6SDarren Hart /* 746e0769fe6SDarren Hart * Check if the accelerometer call exists, 7475a2813e9SAzael Avalos * this call also serves as initialization 7485a2813e9SAzael Avalos */ 749258c5903SAzael Avalos status = tci_raw(dev, in, out); 7501864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 7515a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 7525a2813e9SAzael Avalos return -EIO; 7531864bbc2SAzael Avalos } else if (out[0] == TOS_DATA_NOT_AVAILABLE || 7541864bbc2SAzael Avalos out[0] == TOS_NOT_INITIALIZED) { 7555a2813e9SAzael Avalos pr_err("Accelerometer not initialized\n"); 7565a2813e9SAzael Avalos return -EIO; 7571864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 7585a2813e9SAzael Avalos pr_info("Accelerometer not supported\n"); 7595a2813e9SAzael Avalos return -ENODEV; 7605a2813e9SAzael Avalos } 7615a2813e9SAzael Avalos 7625a2813e9SAzael Avalos return 0; 7635a2813e9SAzael Avalos } 7645a2813e9SAzael Avalos 7655a2813e9SAzael Avalos static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, 7665a2813e9SAzael Avalos u32 *xy, u32 *z) 7675a2813e9SAzael Avalos { 768258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 }; 769258c5903SAzael Avalos u32 out[TCI_WORDS]; 7705a2813e9SAzael Avalos acpi_status status; 7715a2813e9SAzael Avalos 7725a2813e9SAzael Avalos /* Check the Accelerometer status */ 773258c5903SAzael Avalos status = tci_raw(dev, in, out); 7741864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 7755a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 7765a2813e9SAzael Avalos return -EIO; 7775a2813e9SAzael Avalos } 7785a2813e9SAzael Avalos 7795a2813e9SAzael Avalos *xy = out[2]; 7805a2813e9SAzael Avalos *z = out[4]; 7815a2813e9SAzael Avalos 7825a2813e9SAzael Avalos return 0; 7835a2813e9SAzael Avalos } 7845a2813e9SAzael Avalos 785e26ffe51SAzael Avalos /* Sleep (Charge and Music) utilities support */ 786c8c91842SAzael Avalos static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev) 787c8c91842SAzael Avalos { 788c8c91842SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 789c8c91842SAzael Avalos u32 out[TCI_WORDS]; 790c8c91842SAzael Avalos acpi_status status; 791c8c91842SAzael Avalos 792c8c91842SAzael Avalos /* Set the feature to "not supported" in case of error */ 793c8c91842SAzael Avalos dev->usb_sleep_charge_supported = 0; 794c8c91842SAzael Avalos 795c8c91842SAzael Avalos if (!sci_open(dev)) 796c8c91842SAzael Avalos return; 797c8c91842SAzael Avalos 798c8c91842SAzael Avalos status = tci_raw(dev, in, out); 799*8baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 800c8c91842SAzael Avalos pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); 801c8c91842SAzael Avalos sci_close(dev); 802c8c91842SAzael Avalos return; 803c8c91842SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 804c8c91842SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 805c8c91842SAzael Avalos sci_close(dev); 806c8c91842SAzael Avalos return; 807c8c91842SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 808c8c91842SAzael Avalos dev->usbsc_mode_base = out[4]; 809c8c91842SAzael Avalos } 810c8c91842SAzael Avalos 811c8c91842SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 812c8c91842SAzael Avalos status = tci_raw(dev, in, out); 813*8baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 814c8c91842SAzael Avalos pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); 815c8c91842SAzael Avalos sci_close(dev); 816c8c91842SAzael Avalos return; 817c8c91842SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 818c8c91842SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 819c8c91842SAzael Avalos sci_close(dev); 820c8c91842SAzael Avalos return; 821c8c91842SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 822c8c91842SAzael Avalos dev->usbsc_bat_level = out[2]; 823c8c91842SAzael Avalos /* 824c8c91842SAzael Avalos * If we reach this point, it means that the laptop has support 825c8c91842SAzael Avalos * for this feature and all values are initialized. 826c8c91842SAzael Avalos * Set it as supported. 827c8c91842SAzael Avalos */ 828c8c91842SAzael Avalos dev->usb_sleep_charge_supported = 1; 829c8c91842SAzael Avalos } 830c8c91842SAzael Avalos 831c8c91842SAzael Avalos sci_close(dev); 832c8c91842SAzael Avalos } 833c8c91842SAzael Avalos 834e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, 835e26ffe51SAzael Avalos u32 *mode) 836e26ffe51SAzael Avalos { 837e26ffe51SAzael Avalos u32 result; 838e26ffe51SAzael Avalos 839e26ffe51SAzael Avalos if (!sci_open(dev)) 840e26ffe51SAzael Avalos return -EIO; 841e26ffe51SAzael Avalos 842e26ffe51SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode); 843e26ffe51SAzael Avalos sci_close(dev); 844e26ffe51SAzael Avalos if (result == TOS_FAILURE) { 845e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 846e26ffe51SAzael Avalos return -EIO; 847e26ffe51SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 848e26ffe51SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 849e26ffe51SAzael Avalos return -ENODEV; 850e26ffe51SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 851e26ffe51SAzael Avalos return -EIO; 852e26ffe51SAzael Avalos } 853e26ffe51SAzael Avalos 854e26ffe51SAzael Avalos return 0; 855e26ffe51SAzael Avalos } 856e26ffe51SAzael Avalos 857e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev, 858e26ffe51SAzael Avalos u32 mode) 859e26ffe51SAzael Avalos { 860e26ffe51SAzael Avalos u32 result; 861e26ffe51SAzael Avalos 862e26ffe51SAzael Avalos if (!sci_open(dev)) 863e26ffe51SAzael Avalos return -EIO; 864e26ffe51SAzael Avalos 865e26ffe51SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode); 866e26ffe51SAzael Avalos sci_close(dev); 867e26ffe51SAzael Avalos if (result == TOS_FAILURE) { 868e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 869e26ffe51SAzael Avalos return -EIO; 870e26ffe51SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 871e26ffe51SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 872e26ffe51SAzael Avalos return -ENODEV; 873e26ffe51SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 874e26ffe51SAzael Avalos return -EIO; 875e26ffe51SAzael Avalos } 876e26ffe51SAzael Avalos 877e26ffe51SAzael Avalos return 0; 878e26ffe51SAzael Avalos } 879e26ffe51SAzael Avalos 880182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev, 881182bcaa5SAzael Avalos u32 *mode) 882182bcaa5SAzael Avalos { 883182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 884182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 885182bcaa5SAzael Avalos acpi_status status; 886182bcaa5SAzael Avalos 887182bcaa5SAzael Avalos if (!sci_open(dev)) 888182bcaa5SAzael Avalos return -EIO; 889182bcaa5SAzael Avalos 890182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 891182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 892182bcaa5SAzael Avalos sci_close(dev); 893*8baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 894182bcaa5SAzael Avalos pr_err("ACPI call to get USB S&C battery level failed\n"); 895182bcaa5SAzael Avalos return -EIO; 896182bcaa5SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 897182bcaa5SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 898182bcaa5SAzael Avalos return -ENODEV; 899182bcaa5SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 900182bcaa5SAzael Avalos return -EIO; 901182bcaa5SAzael Avalos } 902182bcaa5SAzael Avalos 903182bcaa5SAzael Avalos *mode = out[2]; 904182bcaa5SAzael Avalos 905182bcaa5SAzael Avalos return 0; 906182bcaa5SAzael Avalos } 907182bcaa5SAzael Avalos 908182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, 909182bcaa5SAzael Avalos u32 mode) 910182bcaa5SAzael Avalos { 911182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 912182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 913182bcaa5SAzael Avalos acpi_status status; 914182bcaa5SAzael Avalos 915182bcaa5SAzael Avalos if (!sci_open(dev)) 916182bcaa5SAzael Avalos return -EIO; 917182bcaa5SAzael Avalos 918182bcaa5SAzael Avalos in[2] = mode; 919182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 920182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 921182bcaa5SAzael Avalos sci_close(dev); 922*8baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 923182bcaa5SAzael Avalos pr_err("ACPI call to set USB S&C battery level failed\n"); 924182bcaa5SAzael Avalos return -EIO; 925182bcaa5SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 926182bcaa5SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 927182bcaa5SAzael Avalos return -ENODEV; 928182bcaa5SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 929182bcaa5SAzael Avalos return -EIO; 930182bcaa5SAzael Avalos } 931182bcaa5SAzael Avalos 932182bcaa5SAzael Avalos return 0; 933182bcaa5SAzael Avalos } 934182bcaa5SAzael Avalos 935bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, 936bb3fe01fSAzael Avalos u32 *state) 937bb3fe01fSAzael Avalos { 938bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 939bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 940bb3fe01fSAzael Avalos acpi_status status; 941bb3fe01fSAzael Avalos 942bb3fe01fSAzael Avalos if (!sci_open(dev)) 943bb3fe01fSAzael Avalos return -EIO; 944bb3fe01fSAzael Avalos 945bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 946bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 947bb3fe01fSAzael Avalos sci_close(dev); 948*8baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 949bb26f189SAzael Avalos pr_err("ACPI call to get USB Rapid Charge failed\n"); 950bb3fe01fSAzael Avalos return -EIO; 951bb3fe01fSAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED || 952bb3fe01fSAzael Avalos out[0] == TOS_INPUT_DATA_ERROR) { 953bb26f189SAzael Avalos pr_info("USB Rapid Charge not supported\n"); 954bb3fe01fSAzael Avalos return -ENODEV; 955bb3fe01fSAzael Avalos } 956bb3fe01fSAzael Avalos 957bb3fe01fSAzael Avalos *state = out[2]; 958bb3fe01fSAzael Avalos 959bb3fe01fSAzael Avalos return 0; 960bb3fe01fSAzael Avalos } 961bb3fe01fSAzael Avalos 962bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, 963bb3fe01fSAzael Avalos u32 state) 964bb3fe01fSAzael Avalos { 965bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 966bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 967bb3fe01fSAzael Avalos acpi_status status; 968bb3fe01fSAzael Avalos 969bb3fe01fSAzael Avalos if (!sci_open(dev)) 970bb3fe01fSAzael Avalos return -EIO; 971bb3fe01fSAzael Avalos 972bb3fe01fSAzael Avalos in[2] = state; 973bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 974bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 975bb3fe01fSAzael Avalos sci_close(dev); 976*8baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 977bb26f189SAzael Avalos pr_err("ACPI call to set USB Rapid Charge failed\n"); 978bb3fe01fSAzael Avalos return -EIO; 979bb3fe01fSAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 980bb26f189SAzael Avalos pr_info("USB Rapid Charge not supported\n"); 981bb3fe01fSAzael Avalos return -ENODEV; 982bb3fe01fSAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 983bb3fe01fSAzael Avalos return -EIO; 984bb3fe01fSAzael Avalos } 985bb3fe01fSAzael Avalos 986bb3fe01fSAzael Avalos return 0; 987bb3fe01fSAzael Avalos } 988bb3fe01fSAzael Avalos 989172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state) 990172ce0a9SAzael Avalos { 991172ce0a9SAzael Avalos u32 result; 992172ce0a9SAzael Avalos 993172ce0a9SAzael Avalos if (!sci_open(dev)) 994172ce0a9SAzael Avalos return -EIO; 995172ce0a9SAzael Avalos 996172ce0a9SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state); 997172ce0a9SAzael Avalos sci_close(dev); 998172ce0a9SAzael Avalos if (result == TOS_FAILURE) { 999bb26f189SAzael Avalos pr_err("ACPI call to get Sleep and Music failed\n"); 1000172ce0a9SAzael Avalos return -EIO; 1001172ce0a9SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1002bb26f189SAzael Avalos pr_info("Sleep and Music not supported\n"); 1003172ce0a9SAzael Avalos return -ENODEV; 1004172ce0a9SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 1005172ce0a9SAzael Avalos return -EIO; 1006172ce0a9SAzael Avalos } 1007172ce0a9SAzael Avalos 1008172ce0a9SAzael Avalos return 0; 1009172ce0a9SAzael Avalos } 1010172ce0a9SAzael Avalos 1011172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state) 1012172ce0a9SAzael Avalos { 1013172ce0a9SAzael Avalos u32 result; 1014172ce0a9SAzael Avalos 1015172ce0a9SAzael Avalos if (!sci_open(dev)) 1016172ce0a9SAzael Avalos return -EIO; 1017172ce0a9SAzael Avalos 1018172ce0a9SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state); 1019172ce0a9SAzael Avalos sci_close(dev); 1020172ce0a9SAzael Avalos if (result == TOS_FAILURE) { 1021bb26f189SAzael Avalos pr_err("ACPI call to set Sleep and Music failed\n"); 1022172ce0a9SAzael Avalos return -EIO; 1023172ce0a9SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1024bb26f189SAzael Avalos pr_info("Sleep and Music not supported\n"); 1025172ce0a9SAzael Avalos return -ENODEV; 1026172ce0a9SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 1027172ce0a9SAzael Avalos return -EIO; 1028172ce0a9SAzael Avalos } 1029172ce0a9SAzael Avalos 1030172ce0a9SAzael Avalos return 0; 1031172ce0a9SAzael Avalos } 1032172ce0a9SAzael Avalos 1033bae84195SAzael Avalos /* Keyboard function keys */ 1034bae84195SAzael Avalos static int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode) 1035bae84195SAzael Avalos { 1036bae84195SAzael Avalos u32 result; 1037bae84195SAzael Avalos 1038bae84195SAzael Avalos if (!sci_open(dev)) 1039bae84195SAzael Avalos return -EIO; 1040bae84195SAzael Avalos 1041bae84195SAzael Avalos result = sci_read(dev, SCI_KBD_FUNCTION_KEYS, mode); 1042bae84195SAzael Avalos sci_close(dev); 1043bae84195SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 1044bae84195SAzael Avalos pr_err("ACPI call to get KBD function keys failed\n"); 1045bae84195SAzael Avalos return -EIO; 1046bae84195SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1047bae84195SAzael Avalos pr_info("KBD function keys not supported\n"); 1048bae84195SAzael Avalos return -ENODEV; 1049bae84195SAzael Avalos } 1050bae84195SAzael Avalos 1051bae84195SAzael Avalos return 0; 1052bae84195SAzael Avalos } 1053bae84195SAzael Avalos 1054bae84195SAzael Avalos static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode) 1055bae84195SAzael Avalos { 1056bae84195SAzael Avalos u32 result; 1057bae84195SAzael Avalos 1058bae84195SAzael Avalos if (!sci_open(dev)) 1059bae84195SAzael Avalos return -EIO; 1060bae84195SAzael Avalos 1061bae84195SAzael Avalos result = sci_write(dev, SCI_KBD_FUNCTION_KEYS, mode); 1062bae84195SAzael Avalos sci_close(dev); 1063bae84195SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 1064bae84195SAzael Avalos pr_err("ACPI call to set KBD function keys failed\n"); 1065bae84195SAzael Avalos return -EIO; 1066bae84195SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1067bae84195SAzael Avalos pr_info("KBD function keys not supported\n"); 1068bae84195SAzael Avalos return -ENODEV; 1069bae84195SAzael Avalos } 1070bae84195SAzael Avalos 1071bae84195SAzael Avalos return 0; 1072bae84195SAzael Avalos } 1073bae84195SAzael Avalos 107435d53ceaSAzael Avalos /* Panel Power ON */ 107535d53ceaSAzael Avalos static int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state) 107635d53ceaSAzael Avalos { 107735d53ceaSAzael Avalos u32 result; 107835d53ceaSAzael Avalos 107935d53ceaSAzael Avalos if (!sci_open(dev)) 108035d53ceaSAzael Avalos return -EIO; 108135d53ceaSAzael Avalos 108235d53ceaSAzael Avalos result = sci_read(dev, SCI_PANEL_POWER_ON, state); 108335d53ceaSAzael Avalos sci_close(dev); 108435d53ceaSAzael Avalos if (result == TOS_FAILURE) { 108535d53ceaSAzael Avalos pr_err("ACPI call to get Panel Power ON failed\n"); 108635d53ceaSAzael Avalos return -EIO; 108735d53ceaSAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 108835d53ceaSAzael Avalos pr_info("Panel Power on not supported\n"); 108935d53ceaSAzael Avalos return -ENODEV; 109035d53ceaSAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 109135d53ceaSAzael Avalos return -EIO; 109235d53ceaSAzael Avalos } 109335d53ceaSAzael Avalos 109435d53ceaSAzael Avalos return 0; 109535d53ceaSAzael Avalos } 109635d53ceaSAzael Avalos 109735d53ceaSAzael Avalos static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state) 109835d53ceaSAzael Avalos { 109935d53ceaSAzael Avalos u32 result; 110035d53ceaSAzael Avalos 110135d53ceaSAzael Avalos if (!sci_open(dev)) 110235d53ceaSAzael Avalos return -EIO; 110335d53ceaSAzael Avalos 110435d53ceaSAzael Avalos result = sci_write(dev, SCI_PANEL_POWER_ON, state); 110535d53ceaSAzael Avalos sci_close(dev); 110635d53ceaSAzael Avalos if (result == TOS_FAILURE) { 110735d53ceaSAzael Avalos pr_err("ACPI call to set Panel Power ON failed\n"); 110835d53ceaSAzael Avalos return -EIO; 110935d53ceaSAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 111035d53ceaSAzael Avalos pr_info("Panel Power ON not supported\n"); 111135d53ceaSAzael Avalos return -ENODEV; 111235d53ceaSAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 111335d53ceaSAzael Avalos return -EIO; 111435d53ceaSAzael Avalos } 111535d53ceaSAzael Avalos 111635d53ceaSAzael Avalos return 0; 111735d53ceaSAzael Avalos } 111835d53ceaSAzael Avalos 111917fe4b3dSAzael Avalos /* USB Three */ 112017fe4b3dSAzael Avalos static int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state) 112117fe4b3dSAzael Avalos { 112217fe4b3dSAzael Avalos u32 result; 112317fe4b3dSAzael Avalos 112417fe4b3dSAzael Avalos if (!sci_open(dev)) 112517fe4b3dSAzael Avalos return -EIO; 112617fe4b3dSAzael Avalos 112717fe4b3dSAzael Avalos result = sci_read(dev, SCI_USB_THREE, state); 112817fe4b3dSAzael Avalos sci_close(dev); 112917fe4b3dSAzael Avalos if (result == TOS_FAILURE) { 113017fe4b3dSAzael Avalos pr_err("ACPI call to get USB 3 failed\n"); 113117fe4b3dSAzael Avalos return -EIO; 113217fe4b3dSAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 113317fe4b3dSAzael Avalos pr_info("USB 3 not supported\n"); 113417fe4b3dSAzael Avalos return -ENODEV; 113517fe4b3dSAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 113617fe4b3dSAzael Avalos return -EIO; 113717fe4b3dSAzael Avalos } 113817fe4b3dSAzael Avalos 113917fe4b3dSAzael Avalos return 0; 114017fe4b3dSAzael Avalos } 114117fe4b3dSAzael Avalos 114217fe4b3dSAzael Avalos static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state) 114317fe4b3dSAzael Avalos { 114417fe4b3dSAzael Avalos u32 result; 114517fe4b3dSAzael Avalos 114617fe4b3dSAzael Avalos if (!sci_open(dev)) 114717fe4b3dSAzael Avalos return -EIO; 114817fe4b3dSAzael Avalos 114917fe4b3dSAzael Avalos result = sci_write(dev, SCI_USB_THREE, state); 115017fe4b3dSAzael Avalos sci_close(dev); 115117fe4b3dSAzael Avalos if (result == TOS_FAILURE) { 115217fe4b3dSAzael Avalos pr_err("ACPI call to set USB 3 failed\n"); 115317fe4b3dSAzael Avalos return -EIO; 115417fe4b3dSAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 115517fe4b3dSAzael Avalos pr_info("USB 3 not supported\n"); 115617fe4b3dSAzael Avalos return -ENODEV; 115717fe4b3dSAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 115817fe4b3dSAzael Avalos return -EIO; 115917fe4b3dSAzael Avalos } 116017fe4b3dSAzael Avalos 116117fe4b3dSAzael Avalos return 0; 116217fe4b3dSAzael Avalos } 116317fe4b3dSAzael Avalos 116456e6b353SAzael Avalos /* Hotkey Event type */ 116556e6b353SAzael Avalos static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev, 116656e6b353SAzael Avalos u32 *type) 116756e6b353SAzael Avalos { 11683b876000SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_SYSTEM_INFO, 0x03, 0, 0, 0 }; 11693b876000SAzael Avalos u32 out[TCI_WORDS]; 11703b876000SAzael Avalos acpi_status status; 117156e6b353SAzael Avalos 11723b876000SAzael Avalos status = tci_raw(dev, in, out); 11733b876000SAzael Avalos if (ACPI_FAILURE(status)) { 117456e6b353SAzael Avalos pr_err("ACPI call to get System type failed\n"); 117556e6b353SAzael Avalos return -EIO; 11763b876000SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 117756e6b353SAzael Avalos pr_info("System type not supported\n"); 117856e6b353SAzael Avalos return -ENODEV; 117956e6b353SAzael Avalos } 118056e6b353SAzael Avalos 11813b876000SAzael Avalos *type = out[3]; 118256e6b353SAzael Avalos 118356e6b353SAzael Avalos return 0; 118456e6b353SAzael Avalos } 118556e6b353SAzael Avalos 11863f75bbe9SAzael Avalos /* Transflective Backlight */ 1187121b7b0dSAkio Idehara static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled) 1188121b7b0dSAkio Idehara { 1189121b7b0dSAkio Idehara u32 hci_result; 1190121b7b0dSAkio Idehara u32 status; 1191121b7b0dSAkio Idehara 1192d37782bdSAzael Avalos hci_result = hci_read(dev, HCI_TR_BACKLIGHT, &status); 1193121b7b0dSAkio Idehara *enabled = !status; 11941864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 1195121b7b0dSAkio Idehara } 1196121b7b0dSAkio Idehara 1197121b7b0dSAkio Idehara static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable) 1198121b7b0dSAkio Idehara { 1199121b7b0dSAkio Idehara u32 hci_result; 1200121b7b0dSAkio Idehara u32 value = !enable; 1201121b7b0dSAkio Idehara 1202d37782bdSAzael Avalos hci_result = hci_write(dev, HCI_TR_BACKLIGHT, value); 12031864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 1204121b7b0dSAkio Idehara } 1205121b7b0dSAkio Idehara 12063f75bbe9SAzael Avalos static struct proc_dir_entry *toshiba_proc_dir; 1207b4f9fe12SLen Brown 12083f75bbe9SAzael Avalos /* LCD Brightness */ 120962cce752SSeth Forshee static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) 1210b4f9fe12SLen Brown { 1211b4f9fe12SLen Brown u32 hci_result; 1212b4f9fe12SLen Brown u32 value; 1213121b7b0dSAkio Idehara int brightness = 0; 1214121b7b0dSAkio Idehara 1215121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1216121b7b0dSAkio Idehara bool enabled; 1217121b7b0dSAkio Idehara int ret = get_tr_backlight_status(dev, &enabled); 1218b5163992SAzael Avalos 1219121b7b0dSAkio Idehara if (ret) 1220121b7b0dSAkio Idehara return ret; 1221121b7b0dSAkio Idehara if (enabled) 1222121b7b0dSAkio Idehara return 0; 1223121b7b0dSAkio Idehara brightness++; 1224121b7b0dSAkio Idehara } 1225b4f9fe12SLen Brown 1226d37782bdSAzael Avalos hci_result = hci_read(dev, HCI_LCD_BRIGHTNESS, &value); 12271864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) 1228121b7b0dSAkio Idehara return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT); 122932bcd5cbSSeth Forshee 123032bcd5cbSSeth Forshee return -EIO; 1231b4f9fe12SLen Brown } 1232b4f9fe12SLen Brown 123362cce752SSeth Forshee static int get_lcd_brightness(struct backlight_device *bd) 123462cce752SSeth Forshee { 123562cce752SSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 1236b5163992SAzael Avalos 123762cce752SSeth Forshee return __get_lcd_brightness(dev); 123862cce752SSeth Forshee } 123962cce752SSeth Forshee 1240936c8bcdSAlexey Dobriyan static int lcd_proc_show(struct seq_file *m, void *v) 1241b4f9fe12SLen Brown { 1242135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1243135740deSSeth Forshee int value; 1244121b7b0dSAkio Idehara int levels; 1245b4f9fe12SLen Brown 1246135740deSSeth Forshee if (!dev->backlight_dev) 1247135740deSSeth Forshee return -ENODEV; 1248135740deSSeth Forshee 1249121b7b0dSAkio Idehara levels = dev->backlight_dev->props.max_brightness + 1; 125062cce752SSeth Forshee value = get_lcd_brightness(dev->backlight_dev); 1251b4f9fe12SLen Brown if (value >= 0) { 1252936c8bcdSAlexey Dobriyan seq_printf(m, "brightness: %d\n", value); 1253121b7b0dSAkio Idehara seq_printf(m, "brightness_levels: %d\n", levels); 125432bcd5cbSSeth Forshee return 0; 1255b4f9fe12SLen Brown } 1256b4f9fe12SLen Brown 125732bcd5cbSSeth Forshee pr_err("Error reading LCD brightness\n"); 125832bcd5cbSSeth Forshee return -EIO; 1259936c8bcdSAlexey Dobriyan } 1260936c8bcdSAlexey Dobriyan 1261936c8bcdSAlexey Dobriyan static int lcd_proc_open(struct inode *inode, struct file *file) 1262936c8bcdSAlexey Dobriyan { 1263d9dda78bSAl Viro return single_open(file, lcd_proc_show, PDE_DATA(inode)); 1264b4f9fe12SLen Brown } 1265b4f9fe12SLen Brown 126662cce752SSeth Forshee static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) 1267b4f9fe12SLen Brown { 1268a39f46dfSAzael Avalos u32 hci_result; 1269b4f9fe12SLen Brown 1270121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1271121b7b0dSAkio Idehara bool enable = !value; 1272121b7b0dSAkio Idehara int ret = set_tr_backlight_status(dev, enable); 1273b5163992SAzael Avalos 1274121b7b0dSAkio Idehara if (ret) 1275121b7b0dSAkio Idehara return ret; 1276121b7b0dSAkio Idehara if (value) 1277121b7b0dSAkio Idehara value--; 1278121b7b0dSAkio Idehara } 1279121b7b0dSAkio Idehara 1280a39f46dfSAzael Avalos value = value << HCI_LCD_BRIGHTNESS_SHIFT; 1281d37782bdSAzael Avalos hci_result = hci_write(dev, HCI_LCD_BRIGHTNESS, value); 1282a39f46dfSAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 1283b4f9fe12SLen Brown } 1284b4f9fe12SLen Brown 1285b4f9fe12SLen Brown static int set_lcd_status(struct backlight_device *bd) 1286b4f9fe12SLen Brown { 1287135740deSSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 1288b5163992SAzael Avalos 128962cce752SSeth Forshee return set_lcd_brightness(dev, bd->props.brightness); 1290b4f9fe12SLen Brown } 1291b4f9fe12SLen Brown 1292936c8bcdSAlexey Dobriyan static ssize_t lcd_proc_write(struct file *file, const char __user *buf, 1293936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1294b4f9fe12SLen Brown { 1295d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1296936c8bcdSAlexey Dobriyan char cmd[42]; 1297936c8bcdSAlexey Dobriyan size_t len; 1298b4f9fe12SLen Brown int value; 1299b4f9fe12SLen Brown int ret; 1300121b7b0dSAkio Idehara int levels = dev->backlight_dev->props.max_brightness + 1; 1301b4f9fe12SLen Brown 1302936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1303936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1304936c8bcdSAlexey Dobriyan return -EFAULT; 1305936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1306936c8bcdSAlexey Dobriyan 1307936c8bcdSAlexey Dobriyan if (sscanf(cmd, " brightness : %i", &value) == 1 && 1308121b7b0dSAkio Idehara value >= 0 && value < levels) { 130962cce752SSeth Forshee ret = set_lcd_brightness(dev, value); 1310b4f9fe12SLen Brown if (ret == 0) 1311b4f9fe12SLen Brown ret = count; 1312b4f9fe12SLen Brown } else { 1313b4f9fe12SLen Brown ret = -EINVAL; 1314b4f9fe12SLen Brown } 1315b4f9fe12SLen Brown return ret; 1316b4f9fe12SLen Brown } 1317b4f9fe12SLen Brown 1318936c8bcdSAlexey Dobriyan static const struct file_operations lcd_proc_fops = { 1319936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1320936c8bcdSAlexey Dobriyan .open = lcd_proc_open, 1321936c8bcdSAlexey Dobriyan .read = seq_read, 1322936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1323936c8bcdSAlexey Dobriyan .release = single_release, 1324936c8bcdSAlexey Dobriyan .write = lcd_proc_write, 1325936c8bcdSAlexey Dobriyan }; 1326936c8bcdSAlexey Dobriyan 132736d03f93SSeth Forshee static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status) 132836d03f93SSeth Forshee { 132936d03f93SSeth Forshee u32 hci_result; 133036d03f93SSeth Forshee 1331d37782bdSAzael Avalos hci_result = hci_read(dev, HCI_VIDEO_OUT, status); 13321864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 133336d03f93SSeth Forshee } 133436d03f93SSeth Forshee 1335936c8bcdSAlexey Dobriyan static int video_proc_show(struct seq_file *m, void *v) 1336b4f9fe12SLen Brown { 1337135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1338b4f9fe12SLen Brown u32 value; 133936d03f93SSeth Forshee int ret; 1340b4f9fe12SLen Brown 134136d03f93SSeth Forshee ret = get_video_status(dev, &value); 134236d03f93SSeth Forshee if (!ret) { 1343b4f9fe12SLen Brown int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; 1344b4f9fe12SLen Brown int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; 1345b4f9fe12SLen Brown int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; 1346b5163992SAzael Avalos 1347936c8bcdSAlexey Dobriyan seq_printf(m, "lcd_out: %d\n", is_lcd); 1348936c8bcdSAlexey Dobriyan seq_printf(m, "crt_out: %d\n", is_crt); 1349936c8bcdSAlexey Dobriyan seq_printf(m, "tv_out: %d\n", is_tv); 1350b4f9fe12SLen Brown } 1351b4f9fe12SLen Brown 135236d03f93SSeth Forshee return ret; 1353b4f9fe12SLen Brown } 1354b4f9fe12SLen Brown 1355936c8bcdSAlexey Dobriyan static int video_proc_open(struct inode *inode, struct file *file) 1356b4f9fe12SLen Brown { 1357d9dda78bSAl Viro return single_open(file, video_proc_show, PDE_DATA(inode)); 1358936c8bcdSAlexey Dobriyan } 1359936c8bcdSAlexey Dobriyan 1360936c8bcdSAlexey Dobriyan static ssize_t video_proc_write(struct file *file, const char __user *buf, 1361936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1362936c8bcdSAlexey Dobriyan { 1363d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1364936c8bcdSAlexey Dobriyan char *cmd, *buffer; 136536d03f93SSeth Forshee int ret; 1366b4f9fe12SLen Brown int value; 1367b4f9fe12SLen Brown int remain = count; 1368b4f9fe12SLen Brown int lcd_out = -1; 1369b4f9fe12SLen Brown int crt_out = -1; 1370b4f9fe12SLen Brown int tv_out = -1; 1371b4f9fe12SLen Brown u32 video_out; 1372b4f9fe12SLen Brown 1373936c8bcdSAlexey Dobriyan cmd = kmalloc(count + 1, GFP_KERNEL); 1374936c8bcdSAlexey Dobriyan if (!cmd) 1375936c8bcdSAlexey Dobriyan return -ENOMEM; 1376936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, count)) { 1377936c8bcdSAlexey Dobriyan kfree(cmd); 1378936c8bcdSAlexey Dobriyan return -EFAULT; 1379936c8bcdSAlexey Dobriyan } 1380936c8bcdSAlexey Dobriyan cmd[count] = '\0'; 1381936c8bcdSAlexey Dobriyan 1382936c8bcdSAlexey Dobriyan buffer = cmd; 1383936c8bcdSAlexey Dobriyan 1384e0769fe6SDarren Hart /* 1385e0769fe6SDarren Hart * Scan expression. Multiple expressions may be delimited with ; 1386e0769fe6SDarren Hart * NOTE: To keep scanning simple, invalid fields are ignored. 1387b4f9fe12SLen Brown */ 1388b4f9fe12SLen Brown while (remain) { 1389b4f9fe12SLen Brown if (sscanf(buffer, " lcd_out : %i", &value) == 1) 1390b4f9fe12SLen Brown lcd_out = value & 1; 1391b4f9fe12SLen Brown else if (sscanf(buffer, " crt_out : %i", &value) == 1) 1392b4f9fe12SLen Brown crt_out = value & 1; 1393b4f9fe12SLen Brown else if (sscanf(buffer, " tv_out : %i", &value) == 1) 1394b4f9fe12SLen Brown tv_out = value & 1; 1395e0769fe6SDarren Hart /* Advance to one character past the next ; */ 1396b4f9fe12SLen Brown do { 1397b4f9fe12SLen Brown ++buffer; 1398b4f9fe12SLen Brown --remain; 1399b5163992SAzael Avalos } while (remain && *(buffer - 1) != ';'); 1400b4f9fe12SLen Brown } 1401b4f9fe12SLen Brown 1402936c8bcdSAlexey Dobriyan kfree(cmd); 1403936c8bcdSAlexey Dobriyan 140436d03f93SSeth Forshee ret = get_video_status(dev, &video_out); 140536d03f93SSeth Forshee if (!ret) { 1406b4f9fe12SLen Brown unsigned int new_video_out = video_out; 1407b5163992SAzael Avalos 1408b4f9fe12SLen Brown if (lcd_out != -1) 1409b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out); 1410b4f9fe12SLen Brown if (crt_out != -1) 1411b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out); 1412b4f9fe12SLen Brown if (tv_out != -1) 1413b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out); 1414e0769fe6SDarren Hart /* 1415e0769fe6SDarren Hart * To avoid unnecessary video disruption, only write the new 14163f75bbe9SAzael Avalos * video setting if something changed. 14173f75bbe9SAzael Avalos */ 1418b4f9fe12SLen Brown if (new_video_out != video_out) 141932bcd5cbSSeth Forshee ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out); 1420b4f9fe12SLen Brown } 1421b4f9fe12SLen Brown 142232bcd5cbSSeth Forshee return ret ? ret : count; 1423b4f9fe12SLen Brown } 1424b4f9fe12SLen Brown 1425936c8bcdSAlexey Dobriyan static const struct file_operations video_proc_fops = { 1426936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1427936c8bcdSAlexey Dobriyan .open = video_proc_open, 1428936c8bcdSAlexey Dobriyan .read = seq_read, 1429936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1430936c8bcdSAlexey Dobriyan .release = single_release, 1431936c8bcdSAlexey Dobriyan .write = video_proc_write, 1432936c8bcdSAlexey Dobriyan }; 1433936c8bcdSAlexey Dobriyan 143436d03f93SSeth Forshee static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status) 143536d03f93SSeth Forshee { 143636d03f93SSeth Forshee u32 hci_result; 143736d03f93SSeth Forshee 1438d37782bdSAzael Avalos hci_result = hci_read(dev, HCI_FAN, status); 14391864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 144036d03f93SSeth Forshee } 144136d03f93SSeth Forshee 1442936c8bcdSAlexey Dobriyan static int fan_proc_show(struct seq_file *m, void *v) 1443b4f9fe12SLen Brown { 1444135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 144536d03f93SSeth Forshee int ret; 1446b4f9fe12SLen Brown u32 value; 1447b4f9fe12SLen Brown 144836d03f93SSeth Forshee ret = get_fan_status(dev, &value); 144936d03f93SSeth Forshee if (!ret) { 1450936c8bcdSAlexey Dobriyan seq_printf(m, "running: %d\n", (value > 0)); 1451135740deSSeth Forshee seq_printf(m, "force_on: %d\n", dev->force_fan); 1452b4f9fe12SLen Brown } 1453b4f9fe12SLen Brown 145436d03f93SSeth Forshee return ret; 1455b4f9fe12SLen Brown } 1456b4f9fe12SLen Brown 1457936c8bcdSAlexey Dobriyan static int fan_proc_open(struct inode *inode, struct file *file) 1458b4f9fe12SLen Brown { 1459d9dda78bSAl Viro return single_open(file, fan_proc_show, PDE_DATA(inode)); 1460936c8bcdSAlexey Dobriyan } 1461936c8bcdSAlexey Dobriyan 1462936c8bcdSAlexey Dobriyan static ssize_t fan_proc_write(struct file *file, const char __user *buf, 1463936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1464936c8bcdSAlexey Dobriyan { 1465d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1466936c8bcdSAlexey Dobriyan char cmd[42]; 1467936c8bcdSAlexey Dobriyan size_t len; 1468b4f9fe12SLen Brown int value; 1469b4f9fe12SLen Brown u32 hci_result; 1470b4f9fe12SLen Brown 1471936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1472936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1473936c8bcdSAlexey Dobriyan return -EFAULT; 1474936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1475936c8bcdSAlexey Dobriyan 1476936c8bcdSAlexey Dobriyan if (sscanf(cmd, " force_on : %i", &value) == 1 && 1477b4f9fe12SLen Brown value >= 0 && value <= 1) { 1478d37782bdSAzael Avalos hci_result = hci_write(dev, HCI_FAN, value); 1479b5163992SAzael Avalos if (hci_result == TOS_SUCCESS) 1480135740deSSeth Forshee dev->force_fan = value; 1481b5163992SAzael Avalos else 1482b5163992SAzael Avalos return -EIO; 1483b4f9fe12SLen Brown } else { 1484b4f9fe12SLen Brown return -EINVAL; 1485b4f9fe12SLen Brown } 1486b4f9fe12SLen Brown 1487b4f9fe12SLen Brown return count; 1488b4f9fe12SLen Brown } 1489b4f9fe12SLen Brown 1490936c8bcdSAlexey Dobriyan static const struct file_operations fan_proc_fops = { 1491936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1492936c8bcdSAlexey Dobriyan .open = fan_proc_open, 1493936c8bcdSAlexey Dobriyan .read = seq_read, 1494936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1495936c8bcdSAlexey Dobriyan .release = single_release, 1496936c8bcdSAlexey Dobriyan .write = fan_proc_write, 1497936c8bcdSAlexey Dobriyan }; 1498936c8bcdSAlexey Dobriyan 1499936c8bcdSAlexey Dobriyan static int keys_proc_show(struct seq_file *m, void *v) 1500b4f9fe12SLen Brown { 1501135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1502b4f9fe12SLen Brown u32 hci_result; 1503b4f9fe12SLen Brown u32 value; 1504b4f9fe12SLen Brown 150511948b93SSeth Forshee if (!dev->key_event_valid && dev->system_event_supported) { 1506d37782bdSAzael Avalos hci_result = hci_read(dev, HCI_SYSTEM_EVENT, &value); 15071864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) { 1508135740deSSeth Forshee dev->key_event_valid = 1; 1509135740deSSeth Forshee dev->last_key_event = value; 15101864bbc2SAzael Avalos } else if (hci_result == TOS_FIFO_EMPTY) { 1511e0769fe6SDarren Hart /* Better luck next time */ 15121864bbc2SAzael Avalos } else if (hci_result == TOS_NOT_SUPPORTED) { 1513e0769fe6SDarren Hart /* 1514e0769fe6SDarren Hart * This is a workaround for an unresolved issue on 1515b4f9fe12SLen Brown * some machines where system events sporadically 1516e0769fe6SDarren Hart * become disabled. 1517e0769fe6SDarren Hart */ 1518d37782bdSAzael Avalos hci_result = hci_write(dev, HCI_SYSTEM_EVENT, 1); 15197e33460dSJoe Perches pr_notice("Re-enabled hotkeys\n"); 1520b4f9fe12SLen Brown } else { 15217e33460dSJoe Perches pr_err("Error reading hotkey status\n"); 152232bcd5cbSSeth Forshee return -EIO; 1523b4f9fe12SLen Brown } 1524b4f9fe12SLen Brown } 1525b4f9fe12SLen Brown 1526135740deSSeth Forshee seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid); 1527135740deSSeth Forshee seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event); 1528936c8bcdSAlexey Dobriyan return 0; 1529b4f9fe12SLen Brown } 1530b4f9fe12SLen Brown 1531936c8bcdSAlexey Dobriyan static int keys_proc_open(struct inode *inode, struct file *file) 1532b4f9fe12SLen Brown { 1533d9dda78bSAl Viro return single_open(file, keys_proc_show, PDE_DATA(inode)); 1534936c8bcdSAlexey Dobriyan } 1535936c8bcdSAlexey Dobriyan 1536936c8bcdSAlexey Dobriyan static ssize_t keys_proc_write(struct file *file, const char __user *buf, 1537936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1538936c8bcdSAlexey Dobriyan { 1539d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1540936c8bcdSAlexey Dobriyan char cmd[42]; 1541936c8bcdSAlexey Dobriyan size_t len; 1542b4f9fe12SLen Brown int value; 1543b4f9fe12SLen Brown 1544936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1545936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1546936c8bcdSAlexey Dobriyan return -EFAULT; 1547936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1548936c8bcdSAlexey Dobriyan 1549b5163992SAzael Avalos if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) 1550135740deSSeth Forshee dev->key_event_valid = 0; 1551b5163992SAzael Avalos else 1552b4f9fe12SLen Brown return -EINVAL; 1553b4f9fe12SLen Brown 1554b4f9fe12SLen Brown return count; 1555b4f9fe12SLen Brown } 1556b4f9fe12SLen Brown 1557936c8bcdSAlexey Dobriyan static const struct file_operations keys_proc_fops = { 1558936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1559936c8bcdSAlexey Dobriyan .open = keys_proc_open, 1560936c8bcdSAlexey Dobriyan .read = seq_read, 1561936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1562936c8bcdSAlexey Dobriyan .release = single_release, 1563936c8bcdSAlexey Dobriyan .write = keys_proc_write, 1564936c8bcdSAlexey Dobriyan }; 1565936c8bcdSAlexey Dobriyan 1566936c8bcdSAlexey Dobriyan static int version_proc_show(struct seq_file *m, void *v) 1567b4f9fe12SLen Brown { 1568936c8bcdSAlexey Dobriyan seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION); 1569936c8bcdSAlexey Dobriyan seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION); 1570936c8bcdSAlexey Dobriyan return 0; 1571b4f9fe12SLen Brown } 1572b4f9fe12SLen Brown 1573936c8bcdSAlexey Dobriyan static int version_proc_open(struct inode *inode, struct file *file) 1574936c8bcdSAlexey Dobriyan { 1575d9dda78bSAl Viro return single_open(file, version_proc_show, PDE_DATA(inode)); 1576936c8bcdSAlexey Dobriyan } 1577936c8bcdSAlexey Dobriyan 1578936c8bcdSAlexey Dobriyan static const struct file_operations version_proc_fops = { 1579936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1580936c8bcdSAlexey Dobriyan .open = version_proc_open, 1581936c8bcdSAlexey Dobriyan .read = seq_read, 1582936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1583936c8bcdSAlexey Dobriyan .release = single_release, 1584936c8bcdSAlexey Dobriyan }; 1585936c8bcdSAlexey Dobriyan 1586e0769fe6SDarren Hart /* 1587e0769fe6SDarren Hart * Proc and module init 1588b4f9fe12SLen Brown */ 1589b4f9fe12SLen Brown 1590b4f9fe12SLen Brown #define PROC_TOSHIBA "toshiba" 1591b4f9fe12SLen Brown 1592b859f159SGreg Kroah-Hartman static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1593b4f9fe12SLen Brown { 159436d03f93SSeth Forshee if (dev->backlight_dev) 1595135740deSSeth Forshee proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1596135740deSSeth Forshee &lcd_proc_fops, dev); 159736d03f93SSeth Forshee if (dev->video_supported) 1598135740deSSeth Forshee proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1599135740deSSeth Forshee &video_proc_fops, dev); 160036d03f93SSeth Forshee if (dev->fan_supported) 1601135740deSSeth Forshee proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1602135740deSSeth Forshee &fan_proc_fops, dev); 160336d03f93SSeth Forshee if (dev->hotkey_dev) 1604135740deSSeth Forshee proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1605135740deSSeth Forshee &keys_proc_fops, dev); 1606135740deSSeth Forshee proc_create_data("version", S_IRUGO, toshiba_proc_dir, 1607135740deSSeth Forshee &version_proc_fops, dev); 1608b4f9fe12SLen Brown } 1609b4f9fe12SLen Brown 161036d03f93SSeth Forshee static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1611b4f9fe12SLen Brown { 161236d03f93SSeth Forshee if (dev->backlight_dev) 1613936c8bcdSAlexey Dobriyan remove_proc_entry("lcd", toshiba_proc_dir); 161436d03f93SSeth Forshee if (dev->video_supported) 1615936c8bcdSAlexey Dobriyan remove_proc_entry("video", toshiba_proc_dir); 161636d03f93SSeth Forshee if (dev->fan_supported) 1617936c8bcdSAlexey Dobriyan remove_proc_entry("fan", toshiba_proc_dir); 161836d03f93SSeth Forshee if (dev->hotkey_dev) 1619936c8bcdSAlexey Dobriyan remove_proc_entry("keys", toshiba_proc_dir); 1620936c8bcdSAlexey Dobriyan remove_proc_entry("version", toshiba_proc_dir); 1621b4f9fe12SLen Brown } 1622b4f9fe12SLen Brown 1623acc2472eSLionel Debroux static const struct backlight_ops toshiba_backlight_data = { 1624121b7b0dSAkio Idehara .options = BL_CORE_SUSPENDRESUME, 162562cce752SSeth Forshee .get_brightness = get_lcd_brightness, 1626b4f9fe12SLen Brown .update_status = set_lcd_status, 1627b4f9fe12SLen Brown }; 1628b4f9fe12SLen Brown 1629360f0f39SAzael Avalos /* 1630360f0f39SAzael Avalos * Sysfs files 1631360f0f39SAzael Avalos */ 16329d309848SAzael Avalos static ssize_t version_show(struct device *dev, 1633c6c68ff8SAzael Avalos struct device_attribute *attr, char *buf) 1634c6c68ff8SAzael Avalos { 1635c6c68ff8SAzael Avalos return sprintf(buf, "%s\n", TOSHIBA_ACPI_VERSION); 1636c6c68ff8SAzael Avalos } 16370c3c0f10SAzael Avalos static DEVICE_ATTR_RO(version); 1638c6c68ff8SAzael Avalos 16399d309848SAzael Avalos static ssize_t fan_store(struct device *dev, 164094477d4cSAzael Avalos struct device_attribute *attr, 164194477d4cSAzael Avalos const char *buf, size_t count) 164294477d4cSAzael Avalos { 164394477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 164494477d4cSAzael Avalos u32 result; 164594477d4cSAzael Avalos int state; 164694477d4cSAzael Avalos int ret; 164794477d4cSAzael Avalos 164894477d4cSAzael Avalos ret = kstrtoint(buf, 0, &state); 164994477d4cSAzael Avalos if (ret) 165094477d4cSAzael Avalos return ret; 165194477d4cSAzael Avalos 165294477d4cSAzael Avalos if (state != 0 && state != 1) 165394477d4cSAzael Avalos return -EINVAL; 165494477d4cSAzael Avalos 1655d37782bdSAzael Avalos result = hci_write(toshiba, HCI_FAN, state); 165694477d4cSAzael Avalos if (result == TOS_FAILURE) 165794477d4cSAzael Avalos return -EIO; 165894477d4cSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 165994477d4cSAzael Avalos return -ENODEV; 166094477d4cSAzael Avalos 166194477d4cSAzael Avalos return count; 166294477d4cSAzael Avalos } 166394477d4cSAzael Avalos 16649d309848SAzael Avalos static ssize_t fan_show(struct device *dev, 166594477d4cSAzael Avalos struct device_attribute *attr, char *buf) 166694477d4cSAzael Avalos { 166794477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 166894477d4cSAzael Avalos u32 value; 166994477d4cSAzael Avalos int ret; 167094477d4cSAzael Avalos 167194477d4cSAzael Avalos ret = get_fan_status(toshiba, &value); 167294477d4cSAzael Avalos if (ret) 167394477d4cSAzael Avalos return ret; 167494477d4cSAzael Avalos 167594477d4cSAzael Avalos return sprintf(buf, "%d\n", value); 167694477d4cSAzael Avalos } 16770c3c0f10SAzael Avalos static DEVICE_ATTR_RW(fan); 167894477d4cSAzael Avalos 16799d309848SAzael Avalos static ssize_t kbd_backlight_mode_store(struct device *dev, 1680360f0f39SAzael Avalos struct device_attribute *attr, 1681360f0f39SAzael Avalos const char *buf, size_t count) 1682360f0f39SAzael Avalos { 1683360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1684aeaac098SDan Carpenter int mode; 1685aeaac098SDan Carpenter int time; 1686aeaac098SDan Carpenter int ret; 1687360f0f39SAzael Avalos 1688aeaac098SDan Carpenter 1689aeaac098SDan Carpenter ret = kstrtoint(buf, 0, &mode); 1690aeaac098SDan Carpenter if (ret) 1691aeaac098SDan Carpenter return ret; 169293f8c16dSAzael Avalos 169393f8c16dSAzael Avalos /* Check for supported modes depending on keyboard backlight type */ 169493f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 169593f8c16dSAzael Avalos /* Type 1 supports SCI_KBD_MODE_FNZ and SCI_KBD_MODE_AUTO */ 1696aeaac098SDan Carpenter if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO) 1697360f0f39SAzael Avalos return -EINVAL; 169893f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 169993f8c16dSAzael Avalos /* Type 2 doesn't support SCI_KBD_MODE_FNZ */ 170093f8c16dSAzael Avalos if (mode != SCI_KBD_MODE_AUTO && mode != SCI_KBD_MODE_ON && 170193f8c16dSAzael Avalos mode != SCI_KBD_MODE_OFF) 170293f8c16dSAzael Avalos return -EINVAL; 170393f8c16dSAzael Avalos } 1704360f0f39SAzael Avalos 1705e0769fe6SDarren Hart /* 1706e0769fe6SDarren Hart * Set the Keyboard Backlight Mode where: 1707360f0f39SAzael Avalos * Auto - KBD backlight turns off automatically in given time 1708360f0f39SAzael Avalos * FN-Z - KBD backlight "toggles" when hotkey pressed 170993f8c16dSAzael Avalos * ON - KBD backlight is always on 171093f8c16dSAzael Avalos * OFF - KBD backlight is always off 1711360f0f39SAzael Avalos */ 171293f8c16dSAzael Avalos 171393f8c16dSAzael Avalos /* Only make a change if the actual mode has changed */ 1714aeaac098SDan Carpenter if (toshiba->kbd_mode != mode) { 171593f8c16dSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 1716360f0f39SAzael Avalos time = toshiba->kbd_time << HCI_MISC_SHIFT; 171793f8c16dSAzael Avalos 171893f8c16dSAzael Avalos /* OR the "base time" to the actual method format */ 171993f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 172093f8c16dSAzael Avalos /* Type 1 requires the current mode */ 172193f8c16dSAzael Avalos time |= toshiba->kbd_mode; 172293f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 172393f8c16dSAzael Avalos /* Type 2 requires the desired mode */ 172493f8c16dSAzael Avalos time |= mode; 172593f8c16dSAzael Avalos } 172693f8c16dSAzael Avalos 1727aeaac098SDan Carpenter ret = toshiba_kbd_illum_status_set(toshiba, time); 1728aeaac098SDan Carpenter if (ret) 1729aeaac098SDan Carpenter return ret; 173093f8c16dSAzael Avalos 1731360f0f39SAzael Avalos toshiba->kbd_mode = mode; 1732360f0f39SAzael Avalos } 1733360f0f39SAzael Avalos 1734360f0f39SAzael Avalos return count; 1735360f0f39SAzael Avalos } 1736360f0f39SAzael Avalos 17379d309848SAzael Avalos static ssize_t kbd_backlight_mode_show(struct device *dev, 1738360f0f39SAzael Avalos struct device_attribute *attr, 1739360f0f39SAzael Avalos char *buf) 1740360f0f39SAzael Avalos { 1741360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1742360f0f39SAzael Avalos u32 time; 1743360f0f39SAzael Avalos 1744360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1745360f0f39SAzael Avalos return -EIO; 1746360f0f39SAzael Avalos 174793f8c16dSAzael Avalos return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK); 174893f8c16dSAzael Avalos } 17490c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_mode); 175093f8c16dSAzael Avalos 17519d309848SAzael Avalos static ssize_t kbd_type_show(struct device *dev, 17529d309848SAzael Avalos struct device_attribute *attr, char *buf) 175393f8c16dSAzael Avalos { 175493f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 175593f8c16dSAzael Avalos 175693f8c16dSAzael Avalos return sprintf(buf, "%d\n", toshiba->kbd_type); 175793f8c16dSAzael Avalos } 17580c3c0f10SAzael Avalos static DEVICE_ATTR_RO(kbd_type); 175993f8c16dSAzael Avalos 17609d309848SAzael Avalos static ssize_t available_kbd_modes_show(struct device *dev, 176193f8c16dSAzael Avalos struct device_attribute *attr, 176293f8c16dSAzael Avalos char *buf) 176393f8c16dSAzael Avalos { 176493f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 176593f8c16dSAzael Avalos 176693f8c16dSAzael Avalos if (toshiba->kbd_type == 1) 176793f8c16dSAzael Avalos return sprintf(buf, "%x %x\n", 176893f8c16dSAzael Avalos SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO); 176993f8c16dSAzael Avalos 177093f8c16dSAzael Avalos return sprintf(buf, "%x %x %x\n", 177193f8c16dSAzael Avalos SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF); 1772360f0f39SAzael Avalos } 17730c3c0f10SAzael Avalos static DEVICE_ATTR_RO(available_kbd_modes); 1774360f0f39SAzael Avalos 17759d309848SAzael Avalos static ssize_t kbd_backlight_timeout_store(struct device *dev, 1776360f0f39SAzael Avalos struct device_attribute *attr, 1777360f0f39SAzael Avalos const char *buf, size_t count) 1778360f0f39SAzael Avalos { 1779360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1780eabde0faSAzael Avalos int time; 1781eabde0faSAzael Avalos int ret; 1782360f0f39SAzael Avalos 1783eabde0faSAzael Avalos ret = kstrtoint(buf, 0, &time); 1784eabde0faSAzael Avalos if (ret) 1785eabde0faSAzael Avalos return ret; 1786eabde0faSAzael Avalos 1787eabde0faSAzael Avalos /* Check for supported values depending on kbd_type */ 1788eabde0faSAzael Avalos if (toshiba->kbd_type == 1) { 1789eabde0faSAzael Avalos if (time < 0 || time > 60) 1790360f0f39SAzael Avalos return -EINVAL; 1791eabde0faSAzael Avalos } else if (toshiba->kbd_type == 2) { 1792eabde0faSAzael Avalos if (time < 1 || time > 60) 1793eabde0faSAzael Avalos return -EINVAL; 1794eabde0faSAzael Avalos } 1795360f0f39SAzael Avalos 1796eabde0faSAzael Avalos /* Set the Keyboard Backlight Timeout */ 1797eabde0faSAzael Avalos 1798eabde0faSAzael Avalos /* Only make a change if the actual timeout has changed */ 1799eabde0faSAzael Avalos if (toshiba->kbd_time != time) { 1800eabde0faSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 1801360f0f39SAzael Avalos time = time << HCI_MISC_SHIFT; 1802eabde0faSAzael Avalos /* OR the "base time" to the actual method format */ 1803eabde0faSAzael Avalos if (toshiba->kbd_type == 1) 1804eabde0faSAzael Avalos time |= SCI_KBD_MODE_FNZ; 1805eabde0faSAzael Avalos else if (toshiba->kbd_type == 2) 1806eabde0faSAzael Avalos time |= SCI_KBD_MODE_AUTO; 1807eabde0faSAzael Avalos 1808eabde0faSAzael Avalos ret = toshiba_kbd_illum_status_set(toshiba, time); 1809eabde0faSAzael Avalos if (ret) 1810eabde0faSAzael Avalos return ret; 1811eabde0faSAzael Avalos 1812360f0f39SAzael Avalos toshiba->kbd_time = time >> HCI_MISC_SHIFT; 1813360f0f39SAzael Avalos } 1814360f0f39SAzael Avalos 1815360f0f39SAzael Avalos return count; 1816360f0f39SAzael Avalos } 1817360f0f39SAzael Avalos 18189d309848SAzael Avalos static ssize_t kbd_backlight_timeout_show(struct device *dev, 1819360f0f39SAzael Avalos struct device_attribute *attr, 1820360f0f39SAzael Avalos char *buf) 1821360f0f39SAzael Avalos { 1822360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1823360f0f39SAzael Avalos u32 time; 1824360f0f39SAzael Avalos 1825360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1826360f0f39SAzael Avalos return -EIO; 1827360f0f39SAzael Avalos 1828360f0f39SAzael Avalos return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT); 1829360f0f39SAzael Avalos } 18300c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_timeout); 1831360f0f39SAzael Avalos 18329d309848SAzael Avalos static ssize_t touchpad_store(struct device *dev, 18339d8658acSAzael Avalos struct device_attribute *attr, 18349d8658acSAzael Avalos const char *buf, size_t count) 18359d8658acSAzael Avalos { 18369d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 18379d8658acSAzael Avalos int state; 1838c8a41669SAzael Avalos int ret; 18399d8658acSAzael Avalos 18409d8658acSAzael Avalos /* Set the TouchPad on/off, 0 - Disable | 1 - Enable */ 1841c8a41669SAzael Avalos ret = kstrtoint(buf, 0, &state); 1842c8a41669SAzael Avalos if (ret) 1843c8a41669SAzael Avalos return ret; 1844c8a41669SAzael Avalos if (state != 0 && state != 1) 1845c8a41669SAzael Avalos return -EINVAL; 1846c8a41669SAzael Avalos 1847c8a41669SAzael Avalos ret = toshiba_touchpad_set(toshiba, state); 1848c8a41669SAzael Avalos if (ret) 1849c8a41669SAzael Avalos return ret; 18509d8658acSAzael Avalos 18519d8658acSAzael Avalos return count; 18529d8658acSAzael Avalos } 18539d8658acSAzael Avalos 18549d309848SAzael Avalos static ssize_t touchpad_show(struct device *dev, 18559d8658acSAzael Avalos struct device_attribute *attr, char *buf) 18569d8658acSAzael Avalos { 18579d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 18589d8658acSAzael Avalos u32 state; 18599d8658acSAzael Avalos int ret; 18609d8658acSAzael Avalos 18619d8658acSAzael Avalos ret = toshiba_touchpad_get(toshiba, &state); 18629d8658acSAzael Avalos if (ret < 0) 18639d8658acSAzael Avalos return ret; 18649d8658acSAzael Avalos 18659d8658acSAzael Avalos return sprintf(buf, "%i\n", state); 18669d8658acSAzael Avalos } 18670c3c0f10SAzael Avalos static DEVICE_ATTR_RW(touchpad); 18689d8658acSAzael Avalos 18699d309848SAzael Avalos static ssize_t position_show(struct device *dev, 18705a2813e9SAzael Avalos struct device_attribute *attr, char *buf) 18715a2813e9SAzael Avalos { 18725a2813e9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 18735a2813e9SAzael Avalos u32 xyval, zval, tmp; 18745a2813e9SAzael Avalos u16 x, y, z; 18755a2813e9SAzael Avalos int ret; 18765a2813e9SAzael Avalos 18775a2813e9SAzael Avalos xyval = zval = 0; 18785a2813e9SAzael Avalos ret = toshiba_accelerometer_get(toshiba, &xyval, &zval); 18795a2813e9SAzael Avalos if (ret < 0) 18805a2813e9SAzael Avalos return ret; 18815a2813e9SAzael Avalos 18825a2813e9SAzael Avalos x = xyval & HCI_ACCEL_MASK; 18835a2813e9SAzael Avalos tmp = xyval >> HCI_MISC_SHIFT; 18845a2813e9SAzael Avalos y = tmp & HCI_ACCEL_MASK; 18855a2813e9SAzael Avalos z = zval & HCI_ACCEL_MASK; 18865a2813e9SAzael Avalos 18875a2813e9SAzael Avalos return sprintf(buf, "%d %d %d\n", x, y, z); 18885a2813e9SAzael Avalos } 18890c3c0f10SAzael Avalos static DEVICE_ATTR_RO(position); 18905a2813e9SAzael Avalos 18919d309848SAzael Avalos static ssize_t usb_sleep_charge_show(struct device *dev, 18929d309848SAzael Avalos struct device_attribute *attr, char *buf) 1893e26ffe51SAzael Avalos { 1894e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1895e26ffe51SAzael Avalos u32 mode; 1896e26ffe51SAzael Avalos int ret; 1897e26ffe51SAzael Avalos 1898e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_get(toshiba, &mode); 1899e26ffe51SAzael Avalos if (ret < 0) 1900e26ffe51SAzael Avalos return ret; 1901e26ffe51SAzael Avalos 1902e26ffe51SAzael Avalos return sprintf(buf, "%x\n", mode & SCI_USB_CHARGE_MODE_MASK); 1903e26ffe51SAzael Avalos } 1904e26ffe51SAzael Avalos 19059d309848SAzael Avalos static ssize_t usb_sleep_charge_store(struct device *dev, 1906e26ffe51SAzael Avalos struct device_attribute *attr, 1907e26ffe51SAzael Avalos const char *buf, size_t count) 1908e26ffe51SAzael Avalos { 1909e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1910e26ffe51SAzael Avalos u32 mode; 1911e26ffe51SAzael Avalos int state; 1912e26ffe51SAzael Avalos int ret; 1913e26ffe51SAzael Avalos 1914e26ffe51SAzael Avalos ret = kstrtoint(buf, 0, &state); 1915e26ffe51SAzael Avalos if (ret) 1916e26ffe51SAzael Avalos return ret; 1917e0769fe6SDarren Hart /* 1918e0769fe6SDarren Hart * Check for supported values, where: 1919e26ffe51SAzael Avalos * 0 - Disabled 1920e26ffe51SAzael Avalos * 1 - Alternate (Non USB conformant devices that require more power) 1921e26ffe51SAzael Avalos * 2 - Auto (USB conformant devices) 1922c8c91842SAzael Avalos * 3 - Typical 1923e26ffe51SAzael Avalos */ 1924c8c91842SAzael Avalos if (state != 0 && state != 1 && state != 2 && state != 3) 1925e26ffe51SAzael Avalos return -EINVAL; 1926e26ffe51SAzael Avalos 1927e26ffe51SAzael Avalos /* Set the USB charging mode to internal value */ 1928c8c91842SAzael Avalos mode = toshiba->usbsc_mode_base; 1929e26ffe51SAzael Avalos if (state == 0) 1930c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_DISABLED; 1931e26ffe51SAzael Avalos else if (state == 1) 1932c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_ALTERNATE; 1933e26ffe51SAzael Avalos else if (state == 2) 1934c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_AUTO; 1935c8c91842SAzael Avalos else if (state == 3) 1936c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_TYPICAL; 1937e26ffe51SAzael Avalos 1938e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_set(toshiba, mode); 1939e26ffe51SAzael Avalos if (ret) 1940e26ffe51SAzael Avalos return ret; 1941e26ffe51SAzael Avalos 1942e26ffe51SAzael Avalos return count; 1943e26ffe51SAzael Avalos } 19440c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_charge); 1945e26ffe51SAzael Avalos 1946182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_show(struct device *dev, 1947182bcaa5SAzael Avalos struct device_attribute *attr, 1948182bcaa5SAzael Avalos char *buf) 1949182bcaa5SAzael Avalos { 1950182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1951182bcaa5SAzael Avalos u32 state; 1952182bcaa5SAzael Avalos int bat_lvl; 1953182bcaa5SAzael Avalos int status; 1954182bcaa5SAzael Avalos int ret; 1955182bcaa5SAzael Avalos int tmp; 1956182bcaa5SAzael Avalos 1957182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_get(toshiba, &state); 1958182bcaa5SAzael Avalos if (ret < 0) 1959182bcaa5SAzael Avalos return ret; 1960182bcaa5SAzael Avalos 1961182bcaa5SAzael Avalos /* Determine the status: 0x4 - Enabled | 0x1 - Disabled */ 1962182bcaa5SAzael Avalos tmp = state & SCI_USB_CHARGE_BAT_MASK; 1963182bcaa5SAzael Avalos status = (tmp == 0x4) ? 1 : 0; 1964182bcaa5SAzael Avalos /* Determine the battery level set */ 1965182bcaa5SAzael Avalos bat_lvl = state >> HCI_MISC_SHIFT; 1966182bcaa5SAzael Avalos 1967182bcaa5SAzael Avalos return sprintf(buf, "%d %d\n", status, bat_lvl); 1968182bcaa5SAzael Avalos } 1969182bcaa5SAzael Avalos 1970182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_store(struct device *dev, 1971182bcaa5SAzael Avalos struct device_attribute *attr, 1972182bcaa5SAzael Avalos const char *buf, size_t count) 1973182bcaa5SAzael Avalos { 1974182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1975182bcaa5SAzael Avalos u32 status; 1976182bcaa5SAzael Avalos int value; 1977182bcaa5SAzael Avalos int ret; 1978182bcaa5SAzael Avalos int tmp; 1979182bcaa5SAzael Avalos 1980182bcaa5SAzael Avalos ret = kstrtoint(buf, 0, &value); 1981182bcaa5SAzael Avalos if (ret) 1982182bcaa5SAzael Avalos return ret; 1983182bcaa5SAzael Avalos 1984e0769fe6SDarren Hart /* 1985e0769fe6SDarren Hart * Set the status of the function: 1986182bcaa5SAzael Avalos * 0 - Disabled 1987182bcaa5SAzael Avalos * 1-100 - Enabled 1988182bcaa5SAzael Avalos */ 1989182bcaa5SAzael Avalos if (value < 0 || value > 100) 1990182bcaa5SAzael Avalos return -EINVAL; 1991182bcaa5SAzael Avalos 1992182bcaa5SAzael Avalos if (value == 0) { 1993182bcaa5SAzael Avalos tmp = toshiba->usbsc_bat_level << HCI_MISC_SHIFT; 1994182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_OFF; 1995182bcaa5SAzael Avalos } else { 1996182bcaa5SAzael Avalos tmp = value << HCI_MISC_SHIFT; 1997182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_ON; 1998182bcaa5SAzael Avalos } 1999182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_set(toshiba, status); 2000182bcaa5SAzael Avalos if (ret < 0) 2001182bcaa5SAzael Avalos return ret; 2002182bcaa5SAzael Avalos 2003182bcaa5SAzael Avalos toshiba->usbsc_bat_level = status >> HCI_MISC_SHIFT; 2004182bcaa5SAzael Avalos 2005182bcaa5SAzael Avalos return count; 2006182bcaa5SAzael Avalos } 20070c3c0f10SAzael Avalos static DEVICE_ATTR_RW(sleep_functions_on_battery); 2008182bcaa5SAzael Avalos 20099d309848SAzael Avalos static ssize_t usb_rapid_charge_show(struct device *dev, 20109d309848SAzael Avalos struct device_attribute *attr, char *buf) 2011bb3fe01fSAzael Avalos { 2012bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2013bb3fe01fSAzael Avalos u32 state; 2014bb3fe01fSAzael Avalos int ret; 2015bb3fe01fSAzael Avalos 2016bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(toshiba, &state); 2017bb3fe01fSAzael Avalos if (ret < 0) 2018bb3fe01fSAzael Avalos return ret; 2019bb3fe01fSAzael Avalos 2020bb3fe01fSAzael Avalos return sprintf(buf, "%d\n", state); 2021bb3fe01fSAzael Avalos } 2022bb3fe01fSAzael Avalos 20239d309848SAzael Avalos static ssize_t usb_rapid_charge_store(struct device *dev, 2024bb3fe01fSAzael Avalos struct device_attribute *attr, 2025bb3fe01fSAzael Avalos const char *buf, size_t count) 2026bb3fe01fSAzael Avalos { 2027bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2028bb3fe01fSAzael Avalos int state; 2029bb3fe01fSAzael Avalos int ret; 2030bb3fe01fSAzael Avalos 2031bb3fe01fSAzael Avalos ret = kstrtoint(buf, 0, &state); 2032bb3fe01fSAzael Avalos if (ret) 2033bb3fe01fSAzael Avalos return ret; 2034bb3fe01fSAzael Avalos if (state != 0 && state != 1) 2035bb3fe01fSAzael Avalos return -EINVAL; 2036bb3fe01fSAzael Avalos 2037bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_set(toshiba, state); 2038bb3fe01fSAzael Avalos if (ret) 2039bb3fe01fSAzael Avalos return ret; 2040bb3fe01fSAzael Avalos 2041bb3fe01fSAzael Avalos return count; 2042bb3fe01fSAzael Avalos } 20430c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_rapid_charge); 2044bb3fe01fSAzael Avalos 20459d309848SAzael Avalos static ssize_t usb_sleep_music_show(struct device *dev, 20469d309848SAzael Avalos struct device_attribute *attr, char *buf) 2047172ce0a9SAzael Avalos { 2048172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2049172ce0a9SAzael Avalos u32 state; 2050172ce0a9SAzael Avalos int ret; 2051172ce0a9SAzael Avalos 2052172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(toshiba, &state); 2053172ce0a9SAzael Avalos if (ret < 0) 2054172ce0a9SAzael Avalos return ret; 2055172ce0a9SAzael Avalos 2056172ce0a9SAzael Avalos return sprintf(buf, "%d\n", state); 2057172ce0a9SAzael Avalos } 2058172ce0a9SAzael Avalos 20599d309848SAzael Avalos static ssize_t usb_sleep_music_store(struct device *dev, 2060172ce0a9SAzael Avalos struct device_attribute *attr, 2061172ce0a9SAzael Avalos const char *buf, size_t count) 2062172ce0a9SAzael Avalos { 2063172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2064172ce0a9SAzael Avalos int state; 2065172ce0a9SAzael Avalos int ret; 2066172ce0a9SAzael Avalos 2067172ce0a9SAzael Avalos ret = kstrtoint(buf, 0, &state); 2068172ce0a9SAzael Avalos if (ret) 2069172ce0a9SAzael Avalos return ret; 2070172ce0a9SAzael Avalos if (state != 0 && state != 1) 2071172ce0a9SAzael Avalos return -EINVAL; 2072172ce0a9SAzael Avalos 2073172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_set(toshiba, state); 2074172ce0a9SAzael Avalos if (ret) 2075172ce0a9SAzael Avalos return ret; 2076172ce0a9SAzael Avalos 2077172ce0a9SAzael Avalos return count; 2078172ce0a9SAzael Avalos } 20790c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_music); 2080172ce0a9SAzael Avalos 20819d309848SAzael Avalos static ssize_t kbd_function_keys_show(struct device *dev, 20829d309848SAzael Avalos struct device_attribute *attr, char *buf) 2083bae84195SAzael Avalos { 2084bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2085bae84195SAzael Avalos int mode; 2086bae84195SAzael Avalos int ret; 2087bae84195SAzael Avalos 2088bae84195SAzael Avalos ret = toshiba_function_keys_get(toshiba, &mode); 2089bae84195SAzael Avalos if (ret < 0) 2090bae84195SAzael Avalos return ret; 2091bae84195SAzael Avalos 2092bae84195SAzael Avalos return sprintf(buf, "%d\n", mode); 2093bae84195SAzael Avalos } 2094bae84195SAzael Avalos 20959d309848SAzael Avalos static ssize_t kbd_function_keys_store(struct device *dev, 2096bae84195SAzael Avalos struct device_attribute *attr, 2097bae84195SAzael Avalos const char *buf, size_t count) 2098bae84195SAzael Avalos { 2099bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2100bae84195SAzael Avalos int mode; 2101bae84195SAzael Avalos int ret; 2102bae84195SAzael Avalos 2103bae84195SAzael Avalos ret = kstrtoint(buf, 0, &mode); 2104bae84195SAzael Avalos if (ret) 2105bae84195SAzael Avalos return ret; 2106e0769fe6SDarren Hart /* 2107e0769fe6SDarren Hart * Check for the function keys mode where: 2108bae84195SAzael Avalos * 0 - Normal operation (F{1-12} as usual and hotkeys via FN-F{1-12}) 2109bae84195SAzael Avalos * 1 - Special functions (Opposite of the above setting) 2110bae84195SAzael Avalos */ 2111bae84195SAzael Avalos if (mode != 0 && mode != 1) 2112bae84195SAzael Avalos return -EINVAL; 2113bae84195SAzael Avalos 2114bae84195SAzael Avalos ret = toshiba_function_keys_set(toshiba, mode); 2115bae84195SAzael Avalos if (ret) 2116bae84195SAzael Avalos return ret; 2117bae84195SAzael Avalos 2118bae84195SAzael Avalos pr_info("Reboot for changes to KBD Function Keys to take effect"); 2119bae84195SAzael Avalos 2120bae84195SAzael Avalos return count; 2121bae84195SAzael Avalos } 21220c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_function_keys); 2123bae84195SAzael Avalos 21249d309848SAzael Avalos static ssize_t panel_power_on_show(struct device *dev, 21259d309848SAzael Avalos struct device_attribute *attr, char *buf) 212635d53ceaSAzael Avalos { 212735d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 212835d53ceaSAzael Avalos u32 state; 212935d53ceaSAzael Avalos int ret; 213035d53ceaSAzael Avalos 213135d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(toshiba, &state); 213235d53ceaSAzael Avalos if (ret < 0) 213335d53ceaSAzael Avalos return ret; 213435d53ceaSAzael Avalos 213535d53ceaSAzael Avalos return sprintf(buf, "%d\n", state); 213635d53ceaSAzael Avalos } 213735d53ceaSAzael Avalos 21389d309848SAzael Avalos static ssize_t panel_power_on_store(struct device *dev, 213935d53ceaSAzael Avalos struct device_attribute *attr, 214035d53ceaSAzael Avalos const char *buf, size_t count) 214135d53ceaSAzael Avalos { 214235d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 214335d53ceaSAzael Avalos int state; 214435d53ceaSAzael Avalos int ret; 214535d53ceaSAzael Avalos 214635d53ceaSAzael Avalos ret = kstrtoint(buf, 0, &state); 214735d53ceaSAzael Avalos if (ret) 214835d53ceaSAzael Avalos return ret; 214935d53ceaSAzael Avalos if (state != 0 && state != 1) 215035d53ceaSAzael Avalos return -EINVAL; 215135d53ceaSAzael Avalos 215235d53ceaSAzael Avalos ret = toshiba_panel_power_on_set(toshiba, state); 215335d53ceaSAzael Avalos if (ret) 215435d53ceaSAzael Avalos return ret; 215535d53ceaSAzael Avalos 215635d53ceaSAzael Avalos pr_info("Reboot for changes to Panel Power ON to take effect"); 215735d53ceaSAzael Avalos 215835d53ceaSAzael Avalos return count; 215935d53ceaSAzael Avalos } 21600c3c0f10SAzael Avalos static DEVICE_ATTR_RW(panel_power_on); 216135d53ceaSAzael Avalos 21629d309848SAzael Avalos static ssize_t usb_three_show(struct device *dev, 21639d309848SAzael Avalos struct device_attribute *attr, char *buf) 216417fe4b3dSAzael Avalos { 216517fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 216617fe4b3dSAzael Avalos u32 state; 216717fe4b3dSAzael Avalos int ret; 216817fe4b3dSAzael Avalos 216917fe4b3dSAzael Avalos ret = toshiba_usb_three_get(toshiba, &state); 217017fe4b3dSAzael Avalos if (ret < 0) 217117fe4b3dSAzael Avalos return ret; 217217fe4b3dSAzael Avalos 217317fe4b3dSAzael Avalos return sprintf(buf, "%d\n", state); 217417fe4b3dSAzael Avalos } 217517fe4b3dSAzael Avalos 21769d309848SAzael Avalos static ssize_t usb_three_store(struct device *dev, 217717fe4b3dSAzael Avalos struct device_attribute *attr, 217817fe4b3dSAzael Avalos const char *buf, size_t count) 217917fe4b3dSAzael Avalos { 218017fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 218117fe4b3dSAzael Avalos int state; 218217fe4b3dSAzael Avalos int ret; 218317fe4b3dSAzael Avalos 218417fe4b3dSAzael Avalos ret = kstrtoint(buf, 0, &state); 218517fe4b3dSAzael Avalos if (ret) 218617fe4b3dSAzael Avalos return ret; 2187e0769fe6SDarren Hart /* 2188e0769fe6SDarren Hart * Check for USB 3 mode where: 218917fe4b3dSAzael Avalos * 0 - Disabled (Acts like a USB 2 port, saving power) 219017fe4b3dSAzael Avalos * 1 - Enabled 219117fe4b3dSAzael Avalos */ 219217fe4b3dSAzael Avalos if (state != 0 && state != 1) 219317fe4b3dSAzael Avalos return -EINVAL; 219417fe4b3dSAzael Avalos 219517fe4b3dSAzael Avalos ret = toshiba_usb_three_set(toshiba, state); 219617fe4b3dSAzael Avalos if (ret) 219717fe4b3dSAzael Avalos return ret; 219817fe4b3dSAzael Avalos 219917fe4b3dSAzael Avalos pr_info("Reboot for changes to USB 3 to take effect"); 220017fe4b3dSAzael Avalos 220117fe4b3dSAzael Avalos return count; 220217fe4b3dSAzael Avalos } 22030c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_three); 22049bd1213bSAzael Avalos 22059bd1213bSAzael Avalos static struct attribute *toshiba_attributes[] = { 22069bd1213bSAzael Avalos &dev_attr_version.attr, 22079bd1213bSAzael Avalos &dev_attr_fan.attr, 22089bd1213bSAzael Avalos &dev_attr_kbd_backlight_mode.attr, 22099bd1213bSAzael Avalos &dev_attr_kbd_type.attr, 22109bd1213bSAzael Avalos &dev_attr_available_kbd_modes.attr, 22119bd1213bSAzael Avalos &dev_attr_kbd_backlight_timeout.attr, 22129bd1213bSAzael Avalos &dev_attr_touchpad.attr, 22139bd1213bSAzael Avalos &dev_attr_position.attr, 22149bd1213bSAzael Avalos &dev_attr_usb_sleep_charge.attr, 22159bd1213bSAzael Avalos &dev_attr_sleep_functions_on_battery.attr, 22169bd1213bSAzael Avalos &dev_attr_usb_rapid_charge.attr, 22179bd1213bSAzael Avalos &dev_attr_usb_sleep_music.attr, 22189bd1213bSAzael Avalos &dev_attr_kbd_function_keys.attr, 22199bd1213bSAzael Avalos &dev_attr_panel_power_on.attr, 22209bd1213bSAzael Avalos &dev_attr_usb_three.attr, 22219bd1213bSAzael Avalos NULL, 22229bd1213bSAzael Avalos }; 22239bd1213bSAzael Avalos 2224360f0f39SAzael Avalos static umode_t toshiba_sysfs_is_visible(struct kobject *kobj, 2225360f0f39SAzael Avalos struct attribute *attr, int idx) 2226360f0f39SAzael Avalos { 2227360f0f39SAzael Avalos struct device *dev = container_of(kobj, struct device, kobj); 2228360f0f39SAzael Avalos struct toshiba_acpi_dev *drv = dev_get_drvdata(dev); 2229360f0f39SAzael Avalos bool exists = true; 2230360f0f39SAzael Avalos 223194477d4cSAzael Avalos if (attr == &dev_attr_fan.attr) 223294477d4cSAzael Avalos exists = (drv->fan_supported) ? true : false; 223394477d4cSAzael Avalos else if (attr == &dev_attr_kbd_backlight_mode.attr) 2234360f0f39SAzael Avalos exists = (drv->kbd_illum_supported) ? true : false; 2235360f0f39SAzael Avalos else if (attr == &dev_attr_kbd_backlight_timeout.attr) 2236360f0f39SAzael Avalos exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false; 22379d8658acSAzael Avalos else if (attr == &dev_attr_touchpad.attr) 22389d8658acSAzael Avalos exists = (drv->touchpad_supported) ? true : false; 22395a2813e9SAzael Avalos else if (attr == &dev_attr_position.attr) 22405a2813e9SAzael Avalos exists = (drv->accelerometer_supported) ? true : false; 2241e26ffe51SAzael Avalos else if (attr == &dev_attr_usb_sleep_charge.attr) 2242e26ffe51SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2243182bcaa5SAzael Avalos else if (attr == &dev_attr_sleep_functions_on_battery.attr) 2244182bcaa5SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2245bb3fe01fSAzael Avalos else if (attr == &dev_attr_usb_rapid_charge.attr) 2246bb3fe01fSAzael Avalos exists = (drv->usb_rapid_charge_supported) ? true : false; 2247172ce0a9SAzael Avalos else if (attr == &dev_attr_usb_sleep_music.attr) 2248172ce0a9SAzael Avalos exists = (drv->usb_sleep_music_supported) ? true : false; 2249bae84195SAzael Avalos else if (attr == &dev_attr_kbd_function_keys.attr) 2250bae84195SAzael Avalos exists = (drv->kbd_function_keys_supported) ? true : false; 225135d53ceaSAzael Avalos else if (attr == &dev_attr_panel_power_on.attr) 225235d53ceaSAzael Avalos exists = (drv->panel_power_on_supported) ? true : false; 225317fe4b3dSAzael Avalos else if (attr == &dev_attr_usb_three.attr) 225417fe4b3dSAzael Avalos exists = (drv->usb_three_supported) ? true : false; 2255360f0f39SAzael Avalos 2256360f0f39SAzael Avalos return exists ? attr->mode : 0; 2257360f0f39SAzael Avalos } 2258360f0f39SAzael Avalos 22599bd1213bSAzael Avalos static struct attribute_group toshiba_attr_group = { 22609bd1213bSAzael Avalos .is_visible = toshiba_sysfs_is_visible, 22619bd1213bSAzael Avalos .attrs = toshiba_attributes, 22629bd1213bSAzael Avalos }; 22639bd1213bSAzael Avalos 22641f28f290SAzael Avalos /* 22651f28f290SAzael Avalos * Hotkeys 22661f28f290SAzael Avalos */ 22671f28f290SAzael Avalos static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev) 22681f28f290SAzael Avalos { 22691f28f290SAzael Avalos acpi_status status; 22701f28f290SAzael Avalos u32 result; 22711f28f290SAzael Avalos 22721f28f290SAzael Avalos status = acpi_evaluate_object(dev->acpi_dev->handle, 22731f28f290SAzael Avalos "ENAB", NULL, NULL); 22741f28f290SAzael Avalos if (ACPI_FAILURE(status)) 22751f28f290SAzael Avalos return -ENODEV; 22761f28f290SAzael Avalos 2277d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE); 22781f28f290SAzael Avalos if (result == TOS_FAILURE) 22791f28f290SAzael Avalos return -EIO; 22801f28f290SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 22811f28f290SAzael Avalos return -ENODEV; 22821f28f290SAzael Avalos 22831f28f290SAzael Avalos return 0; 22841f28f290SAzael Avalos } 22851f28f290SAzael Avalos 2286fb42d1f4SAzael Avalos static void toshiba_acpi_enable_special_functions(struct toshiba_acpi_dev *dev) 2287fb42d1f4SAzael Avalos { 2288fb42d1f4SAzael Avalos u32 result; 2289fb42d1f4SAzael Avalos 2290fb42d1f4SAzael Avalos /* 2291fb42d1f4SAzael Avalos * Re-activate the hotkeys, but this time, we are using the 2292fb42d1f4SAzael Avalos * "Special Functions" mode. 2293fb42d1f4SAzael Avalos */ 2294d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, 2295fb42d1f4SAzael Avalos HCI_HOTKEY_SPECIAL_FUNCTIONS); 2296fb42d1f4SAzael Avalos if (result != TOS_SUCCESS) 2297fb42d1f4SAzael Avalos pr_err("Could not enable the Special Function mode\n"); 2298fb42d1f4SAzael Avalos } 2299fb42d1f4SAzael Avalos 230029cd293fSSeth Forshee static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, 230129cd293fSSeth Forshee struct serio *port) 230229cd293fSSeth Forshee { 230398280374SGiedrius Statkevičius if (str & I8042_STR_AUXDATA) 230429cd293fSSeth Forshee return false; 230529cd293fSSeth Forshee 230629cd293fSSeth Forshee if (unlikely(data == 0xe0)) 230729cd293fSSeth Forshee return false; 230829cd293fSSeth Forshee 230929cd293fSSeth Forshee if ((data & 0x7f) == TOS1900_FN_SCAN) { 231029cd293fSSeth Forshee schedule_work(&toshiba_acpi->hotkey_work); 231129cd293fSSeth Forshee return true; 231229cd293fSSeth Forshee } 231329cd293fSSeth Forshee 231429cd293fSSeth Forshee return false; 231529cd293fSSeth Forshee } 231629cd293fSSeth Forshee 231729cd293fSSeth Forshee static void toshiba_acpi_hotkey_work(struct work_struct *work) 231829cd293fSSeth Forshee { 231929cd293fSSeth Forshee acpi_handle ec_handle = ec_get_handle(); 232029cd293fSSeth Forshee acpi_status status; 232129cd293fSSeth Forshee 232229cd293fSSeth Forshee if (!ec_handle) 232329cd293fSSeth Forshee return; 232429cd293fSSeth Forshee 232529cd293fSSeth Forshee status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL); 232629cd293fSSeth Forshee if (ACPI_FAILURE(status)) 232729cd293fSSeth Forshee pr_err("ACPI NTFY method execution failed\n"); 232829cd293fSSeth Forshee } 232929cd293fSSeth Forshee 233029cd293fSSeth Forshee /* 233129cd293fSSeth Forshee * Returns hotkey scancode, or < 0 on failure. 233229cd293fSSeth Forshee */ 233329cd293fSSeth Forshee static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev) 233429cd293fSSeth Forshee { 233574facaf7SZhang Rui unsigned long long value; 233629cd293fSSeth Forshee acpi_status status; 233729cd293fSSeth Forshee 233874facaf7SZhang Rui status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO", 233974facaf7SZhang Rui NULL, &value); 234074facaf7SZhang Rui if (ACPI_FAILURE(status)) { 234129cd293fSSeth Forshee pr_err("ACPI INFO method execution failed\n"); 234229cd293fSSeth Forshee return -EIO; 234329cd293fSSeth Forshee } 234429cd293fSSeth Forshee 234574facaf7SZhang Rui return value; 234629cd293fSSeth Forshee } 234729cd293fSSeth Forshee 234829cd293fSSeth Forshee static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev, 234929cd293fSSeth Forshee int scancode) 235029cd293fSSeth Forshee { 235129cd293fSSeth Forshee if (scancode == 0x100) 235229cd293fSSeth Forshee return; 235329cd293fSSeth Forshee 2354e0769fe6SDarren Hart /* Act on key press; ignore key release */ 235529cd293fSSeth Forshee if (scancode & 0x80) 235629cd293fSSeth Forshee return; 235729cd293fSSeth Forshee 235829cd293fSSeth Forshee if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true)) 235929cd293fSSeth Forshee pr_info("Unknown key %x\n", scancode); 236029cd293fSSeth Forshee } 236129cd293fSSeth Forshee 236271454d78SAzael Avalos static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) 236371454d78SAzael Avalos { 236471454d78SAzael Avalos u32 hci_result, value; 236571454d78SAzael Avalos int retries = 3; 236671454d78SAzael Avalos int scancode; 236771454d78SAzael Avalos 236871454d78SAzael Avalos if (dev->info_supported) { 236971454d78SAzael Avalos scancode = toshiba_acpi_query_hotkey(dev); 237071454d78SAzael Avalos if (scancode < 0) 237171454d78SAzael Avalos pr_err("Failed to query hotkey event\n"); 237271454d78SAzael Avalos else if (scancode != 0) 237371454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, scancode); 237471454d78SAzael Avalos } else if (dev->system_event_supported) { 237571454d78SAzael Avalos do { 2376d37782bdSAzael Avalos hci_result = hci_read(dev, HCI_SYSTEM_EVENT, &value); 237771454d78SAzael Avalos switch (hci_result) { 237871454d78SAzael Avalos case TOS_SUCCESS: 237971454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, (int)value); 238071454d78SAzael Avalos break; 238171454d78SAzael Avalos case TOS_NOT_SUPPORTED: 238271454d78SAzael Avalos /* 238371454d78SAzael Avalos * This is a workaround for an unresolved 238471454d78SAzael Avalos * issue on some machines where system events 238571454d78SAzael Avalos * sporadically become disabled. 238671454d78SAzael Avalos */ 238771454d78SAzael Avalos hci_result = 2388d37782bdSAzael Avalos hci_write(dev, HCI_SYSTEM_EVENT, 1); 238971454d78SAzael Avalos pr_notice("Re-enabled hotkeys\n"); 2390e0769fe6SDarren Hart /* Fall through */ 239171454d78SAzael Avalos default: 239271454d78SAzael Avalos retries--; 239371454d78SAzael Avalos break; 239471454d78SAzael Avalos } 239571454d78SAzael Avalos } while (retries && hci_result != TOS_FIFO_EMPTY); 239671454d78SAzael Avalos } 239771454d78SAzael Avalos } 239871454d78SAzael Avalos 2399b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) 24006335e4d5SMatthew Garrett { 2401fe808bfbSTakashi Iwai const struct key_entry *keymap = toshiba_acpi_keymap; 2402a2b3471bSAzael Avalos acpi_handle ec_handle; 2403a2b3471bSAzael Avalos u32 events_type; 2404a2b3471bSAzael Avalos u32 hci_result; 2405a2b3471bSAzael Avalos int error; 2406a2b3471bSAzael Avalos 2407a2b3471bSAzael Avalos error = toshiba_acpi_enable_hotkeys(dev); 2408a2b3471bSAzael Avalos if (error) 2409a2b3471bSAzael Avalos return error; 2410a2b3471bSAzael Avalos 2411a2b3471bSAzael Avalos error = toshiba_hotkey_event_type_get(dev, &events_type); 2412a2b3471bSAzael Avalos if (error) { 2413a2b3471bSAzael Avalos pr_err("Unable to query Hotkey Event Type\n"); 2414a2b3471bSAzael Avalos return error; 2415a2b3471bSAzael Avalos } 2416a2b3471bSAzael Avalos dev->hotkey_event_type = events_type; 2417135740deSSeth Forshee 2418135740deSSeth Forshee dev->hotkey_dev = input_allocate_device(); 2419b222cca6SJoe Perches if (!dev->hotkey_dev) 2420135740deSSeth Forshee return -ENOMEM; 2421135740deSSeth Forshee 2422135740deSSeth Forshee dev->hotkey_dev->name = "Toshiba input device"; 24236e02cc7eSSeth Forshee dev->hotkey_dev->phys = "toshiba_acpi/input0"; 2424135740deSSeth Forshee dev->hotkey_dev->id.bustype = BUS_HOST; 2425135740deSSeth Forshee 2426a2b3471bSAzael Avalos if (events_type == HCI_SYSTEM_TYPE1 || 2427a2b3471bSAzael Avalos !dev->kbd_function_keys_supported) 2428a2b3471bSAzael Avalos keymap = toshiba_acpi_keymap; 2429a2b3471bSAzael Avalos else if (events_type == HCI_SYSTEM_TYPE2 || 2430a2b3471bSAzael Avalos dev->kbd_function_keys_supported) 2431fe808bfbSTakashi Iwai keymap = toshiba_acpi_alt_keymap; 2432a2b3471bSAzael Avalos else 2433a2b3471bSAzael Avalos pr_info("Unknown event type received %x\n", events_type); 2434fe808bfbSTakashi Iwai error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL); 2435135740deSSeth Forshee if (error) 2436135740deSSeth Forshee goto err_free_dev; 2437135740deSSeth Forshee 243829cd293fSSeth Forshee /* 243929cd293fSSeth Forshee * For some machines the SCI responsible for providing hotkey 244029cd293fSSeth Forshee * notification doesn't fire. We can trigger the notification 244129cd293fSSeth Forshee * whenever the Fn key is pressed using the NTFY method, if 244229cd293fSSeth Forshee * supported, so if it's present set up an i8042 key filter 244329cd293fSSeth Forshee * for this purpose. 244429cd293fSSeth Forshee */ 244529cd293fSSeth Forshee ec_handle = ec_get_handle(); 2446e2e19606SZhang Rui if (ec_handle && acpi_has_method(ec_handle, "NTFY")) { 244729cd293fSSeth Forshee INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work); 244829cd293fSSeth Forshee 244929cd293fSSeth Forshee error = i8042_install_filter(toshiba_acpi_i8042_filter); 245029cd293fSSeth Forshee if (error) { 245129cd293fSSeth Forshee pr_err("Error installing key filter\n"); 245229cd293fSSeth Forshee goto err_free_keymap; 245329cd293fSSeth Forshee } 245429cd293fSSeth Forshee 245529cd293fSSeth Forshee dev->ntfy_supported = 1; 245629cd293fSSeth Forshee } 245729cd293fSSeth Forshee 245829cd293fSSeth Forshee /* 245929cd293fSSeth Forshee * Determine hotkey query interface. Prefer using the INFO 246029cd293fSSeth Forshee * method when it is available. 246129cd293fSSeth Forshee */ 2462e2e19606SZhang Rui if (acpi_has_method(dev->acpi_dev->handle, "INFO")) 246329cd293fSSeth Forshee dev->info_supported = 1; 2464e2e19606SZhang Rui else { 2465d37782bdSAzael Avalos hci_result = hci_write(dev, HCI_SYSTEM_EVENT, 1); 24661864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) 246729cd293fSSeth Forshee dev->system_event_supported = 1; 246829cd293fSSeth Forshee } 246929cd293fSSeth Forshee 247029cd293fSSeth Forshee if (!dev->info_supported && !dev->system_event_supported) { 247129cd293fSSeth Forshee pr_warn("No hotkey query interface found\n"); 247229cd293fSSeth Forshee goto err_remove_filter; 247329cd293fSSeth Forshee } 247429cd293fSSeth Forshee 2475135740deSSeth Forshee error = input_register_device(dev->hotkey_dev); 2476135740deSSeth Forshee if (error) { 2477135740deSSeth Forshee pr_info("Unable to register input device\n"); 247829cd293fSSeth Forshee goto err_remove_filter; 2479135740deSSeth Forshee } 2480135740deSSeth Forshee 2481135740deSSeth Forshee return 0; 2482135740deSSeth Forshee 248329cd293fSSeth Forshee err_remove_filter: 248429cd293fSSeth Forshee if (dev->ntfy_supported) 248529cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 2486135740deSSeth Forshee err_free_keymap: 2487135740deSSeth Forshee sparse_keymap_free(dev->hotkey_dev); 2488135740deSSeth Forshee err_free_dev: 2489135740deSSeth Forshee input_free_device(dev->hotkey_dev); 2490135740deSSeth Forshee dev->hotkey_dev = NULL; 2491135740deSSeth Forshee return error; 2492135740deSSeth Forshee } 2493135740deSSeth Forshee 2494b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) 249562cce752SSeth Forshee { 249662cce752SSeth Forshee struct backlight_properties props; 249762cce752SSeth Forshee int brightness; 249862cce752SSeth Forshee int ret; 2499121b7b0dSAkio Idehara bool enabled; 250062cce752SSeth Forshee 250162cce752SSeth Forshee /* 250262cce752SSeth Forshee * Some machines don't support the backlight methods at all, and 250362cce752SSeth Forshee * others support it read-only. Either of these is pretty useless, 250462cce752SSeth Forshee * so only register the backlight device if the backlight method 250562cce752SSeth Forshee * supports both reads and writes. 250662cce752SSeth Forshee */ 250762cce752SSeth Forshee brightness = __get_lcd_brightness(dev); 250862cce752SSeth Forshee if (brightness < 0) 250962cce752SSeth Forshee return 0; 251062cce752SSeth Forshee ret = set_lcd_brightness(dev, brightness); 251162cce752SSeth Forshee if (ret) { 251262cce752SSeth Forshee pr_debug("Backlight method is read-only, disabling backlight support\n"); 251362cce752SSeth Forshee return 0; 251462cce752SSeth Forshee } 251562cce752SSeth Forshee 2516121b7b0dSAkio Idehara /* Determine whether or not BIOS supports transflective backlight */ 2517121b7b0dSAkio Idehara ret = get_tr_backlight_status(dev, &enabled); 2518121b7b0dSAkio Idehara dev->tr_backlight_supported = !ret; 2519121b7b0dSAkio Idehara 2520358d6a2cSHans de Goede /* 2521358d6a2cSHans de Goede * Tell acpi-video-detect code to prefer vendor backlight on all 2522358d6a2cSHans de Goede * systems with transflective backlight and on dmi matched systems. 2523358d6a2cSHans de Goede */ 2524358d6a2cSHans de Goede if (dev->tr_backlight_supported || 2525358d6a2cSHans de Goede dmi_check_system(toshiba_vendor_backlight_dmi)) 2526358d6a2cSHans de Goede acpi_video_dmi_promote_vendor(); 2527358d6a2cSHans de Goede 2528358d6a2cSHans de Goede if (acpi_video_backlight_support()) 2529358d6a2cSHans de Goede return 0; 2530358d6a2cSHans de Goede 2531358d6a2cSHans de Goede /* acpi-video may have loaded before we called dmi_promote_vendor() */ 2532358d6a2cSHans de Goede acpi_video_unregister_backlight(); 2533358d6a2cSHans de Goede 253453039f22SMatthew Garrett memset(&props, 0, sizeof(props)); 253562cce752SSeth Forshee props.type = BACKLIGHT_PLATFORM; 253662cce752SSeth Forshee props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; 253762cce752SSeth Forshee 2538e0769fe6SDarren Hart /* Adding an extra level and having 0 change to transflective mode */ 2539121b7b0dSAkio Idehara if (dev->tr_backlight_supported) 2540121b7b0dSAkio Idehara props.max_brightness++; 2541121b7b0dSAkio Idehara 254262cce752SSeth Forshee dev->backlight_dev = backlight_device_register("toshiba", 254362cce752SSeth Forshee &dev->acpi_dev->dev, 254462cce752SSeth Forshee dev, 254562cce752SSeth Forshee &toshiba_backlight_data, 254662cce752SSeth Forshee &props); 254762cce752SSeth Forshee if (IS_ERR(dev->backlight_dev)) { 254862cce752SSeth Forshee ret = PTR_ERR(dev->backlight_dev); 254962cce752SSeth Forshee pr_err("Could not register toshiba backlight device\n"); 255062cce752SSeth Forshee dev->backlight_dev = NULL; 255162cce752SSeth Forshee return ret; 255262cce752SSeth Forshee } 255362cce752SSeth Forshee 255462cce752SSeth Forshee dev->backlight_dev->props.brightness = brightness; 255562cce752SSeth Forshee return 0; 255662cce752SSeth Forshee } 255762cce752SSeth Forshee 255851fac838SRafael J. Wysocki static int toshiba_acpi_remove(struct acpi_device *acpi_dev) 2559135740deSSeth Forshee { 2560135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 2561135740deSSeth Forshee 256236d03f93SSeth Forshee remove_toshiba_proc_entries(dev); 2563135740deSSeth Forshee 2564360f0f39SAzael Avalos if (dev->sysfs_created) 2565360f0f39SAzael Avalos sysfs_remove_group(&dev->acpi_dev->dev.kobj, 2566360f0f39SAzael Avalos &toshiba_attr_group); 2567360f0f39SAzael Avalos 256829cd293fSSeth Forshee if (dev->ntfy_supported) { 256929cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 257029cd293fSSeth Forshee cancel_work_sync(&dev->hotkey_work); 257129cd293fSSeth Forshee } 257229cd293fSSeth Forshee 2573135740deSSeth Forshee if (dev->hotkey_dev) { 2574135740deSSeth Forshee input_unregister_device(dev->hotkey_dev); 2575135740deSSeth Forshee sparse_keymap_free(dev->hotkey_dev); 2576135740deSSeth Forshee } 2577135740deSSeth Forshee 2578135740deSSeth Forshee backlight_device_unregister(dev->backlight_dev); 2579135740deSSeth Forshee 258036d03f93SSeth Forshee if (dev->illumination_supported) 2581135740deSSeth Forshee led_classdev_unregister(&dev->led_dev); 2582135740deSSeth Forshee 2583360f0f39SAzael Avalos if (dev->kbd_led_registered) 2584360f0f39SAzael Avalos led_classdev_unregister(&dev->kbd_led); 2585360f0f39SAzael Avalos 2586def6c4e2SAzael Avalos if (dev->eco_supported) 2587def6c4e2SAzael Avalos led_classdev_unregister(&dev->eco_led); 2588def6c4e2SAzael Avalos 258929cd293fSSeth Forshee if (toshiba_acpi) 259029cd293fSSeth Forshee toshiba_acpi = NULL; 259129cd293fSSeth Forshee 2592135740deSSeth Forshee kfree(dev); 2593135740deSSeth Forshee 2594135740deSSeth Forshee return 0; 2595135740deSSeth Forshee } 2596135740deSSeth Forshee 2597b859f159SGreg Kroah-Hartman static const char *find_hci_method(acpi_handle handle) 2598a540d6b5SSeth Forshee { 2599e2e19606SZhang Rui if (acpi_has_method(handle, "GHCI")) 2600a540d6b5SSeth Forshee return "GHCI"; 2601a540d6b5SSeth Forshee 2602e2e19606SZhang Rui if (acpi_has_method(handle, "SPFC")) 2603a540d6b5SSeth Forshee return "SPFC"; 2604a540d6b5SSeth Forshee 2605a540d6b5SSeth Forshee return NULL; 2606a540d6b5SSeth Forshee } 2607a540d6b5SSeth Forshee 2608b859f159SGreg Kroah-Hartman static int toshiba_acpi_add(struct acpi_device *acpi_dev) 2609135740deSSeth Forshee { 2610135740deSSeth Forshee struct toshiba_acpi_dev *dev; 2611a540d6b5SSeth Forshee const char *hci_method; 2612fb42d1f4SAzael Avalos u32 special_functions; 261336d03f93SSeth Forshee u32 dummy; 2614135740deSSeth Forshee int ret = 0; 2615135740deSSeth Forshee 261629cd293fSSeth Forshee if (toshiba_acpi) 261729cd293fSSeth Forshee return -EBUSY; 261829cd293fSSeth Forshee 2619135740deSSeth Forshee pr_info("Toshiba Laptop ACPI Extras version %s\n", 2620135740deSSeth Forshee TOSHIBA_ACPI_VERSION); 2621135740deSSeth Forshee 2622a540d6b5SSeth Forshee hci_method = find_hci_method(acpi_dev->handle); 2623a540d6b5SSeth Forshee if (!hci_method) { 2624a540d6b5SSeth Forshee pr_err("HCI interface not found\n"); 26256e02cc7eSSeth Forshee return -ENODEV; 2626a540d6b5SSeth Forshee } 26276e02cc7eSSeth Forshee 2628135740deSSeth Forshee dev = kzalloc(sizeof(*dev), GFP_KERNEL); 2629135740deSSeth Forshee if (!dev) 2630135740deSSeth Forshee return -ENOMEM; 2631135740deSSeth Forshee dev->acpi_dev = acpi_dev; 2632a540d6b5SSeth Forshee dev->method_hci = hci_method; 2633135740deSSeth Forshee acpi_dev->driver_data = dev; 2634360f0f39SAzael Avalos dev_set_drvdata(&acpi_dev->dev, dev); 2635135740deSSeth Forshee 2636a2b3471bSAzael Avalos /* Query the BIOS for supported features */ 2637a2b3471bSAzael Avalos 2638a2b3471bSAzael Avalos /* 2639a2b3471bSAzael Avalos * The "Special Functions" are always supported by the laptops 2640a2b3471bSAzael Avalos * with the new keyboard layout, query for its presence to help 2641a2b3471bSAzael Avalos * determine the keymap layout to use. 2642a2b3471bSAzael Avalos */ 2643fb42d1f4SAzael Avalos ret = toshiba_function_keys_get(dev, &special_functions); 2644a2b3471bSAzael Avalos dev->kbd_function_keys_supported = !ret; 2645a2b3471bSAzael Avalos 26466e02cc7eSSeth Forshee if (toshiba_acpi_setup_keyboard(dev)) 2647135740deSSeth Forshee pr_info("Unable to activate hotkeys\n"); 2648135740deSSeth Forshee 264962cce752SSeth Forshee ret = toshiba_acpi_setup_backlight(dev); 265062cce752SSeth Forshee if (ret) 2651135740deSSeth Forshee goto error; 2652135740deSSeth Forshee 2653135740deSSeth Forshee if (toshiba_illumination_available(dev)) { 2654135740deSSeth Forshee dev->led_dev.name = "toshiba::illumination"; 2655135740deSSeth Forshee dev->led_dev.max_brightness = 1; 2656135740deSSeth Forshee dev->led_dev.brightness_set = toshiba_illumination_set; 2657135740deSSeth Forshee dev->led_dev.brightness_get = toshiba_illumination_get; 2658135740deSSeth Forshee if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev)) 265936d03f93SSeth Forshee dev->illumination_supported = 1; 2660135740deSSeth Forshee } 2661135740deSSeth Forshee 2662def6c4e2SAzael Avalos if (toshiba_eco_mode_available(dev)) { 2663def6c4e2SAzael Avalos dev->eco_led.name = "toshiba::eco_mode"; 2664def6c4e2SAzael Avalos dev->eco_led.max_brightness = 1; 2665def6c4e2SAzael Avalos dev->eco_led.brightness_set = toshiba_eco_mode_set_status; 2666def6c4e2SAzael Avalos dev->eco_led.brightness_get = toshiba_eco_mode_get_status; 2667def6c4e2SAzael Avalos if (!led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led)) 2668def6c4e2SAzael Avalos dev->eco_supported = 1; 2669def6c4e2SAzael Avalos } 2670def6c4e2SAzael Avalos 267193f8c16dSAzael Avalos dev->kbd_illum_supported = toshiba_kbd_illum_available(dev); 2672360f0f39SAzael Avalos /* 2673360f0f39SAzael Avalos * Only register the LED if KBD illumination is supported 2674360f0f39SAzael Avalos * and the keyboard backlight operation mode is set to FN-Z 2675360f0f39SAzael Avalos */ 2676360f0f39SAzael Avalos if (dev->kbd_illum_supported && dev->kbd_mode == SCI_KBD_MODE_FNZ) { 2677360f0f39SAzael Avalos dev->kbd_led.name = "toshiba::kbd_backlight"; 2678360f0f39SAzael Avalos dev->kbd_led.max_brightness = 1; 2679360f0f39SAzael Avalos dev->kbd_led.brightness_set = toshiba_kbd_backlight_set; 2680360f0f39SAzael Avalos dev->kbd_led.brightness_get = toshiba_kbd_backlight_get; 2681360f0f39SAzael Avalos if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led)) 2682360f0f39SAzael Avalos dev->kbd_led_registered = 1; 2683360f0f39SAzael Avalos } 2684360f0f39SAzael Avalos 26859d8658acSAzael Avalos ret = toshiba_touchpad_get(dev, &dummy); 26869d8658acSAzael Avalos dev->touchpad_supported = !ret; 26879d8658acSAzael Avalos 26885a2813e9SAzael Avalos ret = toshiba_accelerometer_supported(dev); 26895a2813e9SAzael Avalos dev->accelerometer_supported = !ret; 26905a2813e9SAzael Avalos 2691c8c91842SAzael Avalos toshiba_usb_sleep_charge_available(dev); 2692e26ffe51SAzael Avalos 2693bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(dev, &dummy); 2694bb3fe01fSAzael Avalos dev->usb_rapid_charge_supported = !ret; 2695bb3fe01fSAzael Avalos 2696172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(dev, &dummy); 2697172ce0a9SAzael Avalos dev->usb_sleep_music_supported = !ret; 2698172ce0a9SAzael Avalos 269935d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(dev, &dummy); 270035d53ceaSAzael Avalos dev->panel_power_on_supported = !ret; 270135d53ceaSAzael Avalos 270217fe4b3dSAzael Avalos ret = toshiba_usb_three_get(dev, &dummy); 270317fe4b3dSAzael Avalos dev->usb_three_supported = !ret; 270417fe4b3dSAzael Avalos 270536d03f93SSeth Forshee ret = get_video_status(dev, &dummy); 270636d03f93SSeth Forshee dev->video_supported = !ret; 270736d03f93SSeth Forshee 270836d03f93SSeth Forshee ret = get_fan_status(dev, &dummy); 270936d03f93SSeth Forshee dev->fan_supported = !ret; 271036d03f93SSeth Forshee 2711fb42d1f4SAzael Avalos /* 2712fb42d1f4SAzael Avalos * Enable the "Special Functions" mode only if they are 2713fb42d1f4SAzael Avalos * supported and if they are activated. 2714fb42d1f4SAzael Avalos */ 2715fb42d1f4SAzael Avalos if (dev->kbd_function_keys_supported && special_functions) 2716fb42d1f4SAzael Avalos toshiba_acpi_enable_special_functions(dev); 2717fb42d1f4SAzael Avalos 2718360f0f39SAzael Avalos ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, 2719360f0f39SAzael Avalos &toshiba_attr_group); 2720360f0f39SAzael Avalos if (ret) { 2721360f0f39SAzael Avalos dev->sysfs_created = 0; 2722360f0f39SAzael Avalos goto error; 2723360f0f39SAzael Avalos } 2724360f0f39SAzael Avalos dev->sysfs_created = !ret; 2725360f0f39SAzael Avalos 272636d03f93SSeth Forshee create_toshiba_proc_entries(dev); 272736d03f93SSeth Forshee 272829cd293fSSeth Forshee toshiba_acpi = dev; 272929cd293fSSeth Forshee 2730135740deSSeth Forshee return 0; 2731135740deSSeth Forshee 2732135740deSSeth Forshee error: 273351fac838SRafael J. Wysocki toshiba_acpi_remove(acpi_dev); 2734135740deSSeth Forshee return ret; 2735135740deSSeth Forshee } 2736135740deSSeth Forshee 2737135740deSSeth Forshee static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) 2738135740deSSeth Forshee { 2739135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 274080546905SAzael Avalos int ret; 27416335e4d5SMatthew Garrett 274271454d78SAzael Avalos switch (event) { 274371454d78SAzael Avalos case 0x80: /* Hotkeys and some system events */ 274471454d78SAzael Avalos toshiba_acpi_process_hotkeys(dev); 274511948b93SSeth Forshee break; 2746bab09e23SAzael Avalos case 0x81: /* Dock events */ 2747bab09e23SAzael Avalos case 0x82: 2748bab09e23SAzael Avalos case 0x83: 2749bab09e23SAzael Avalos pr_info("Dock event received %x\n", event); 2750bab09e23SAzael Avalos break; 2751bab09e23SAzael Avalos case 0x88: /* Thermal events */ 2752bab09e23SAzael Avalos pr_info("Thermal event received\n"); 2753bab09e23SAzael Avalos break; 2754bab09e23SAzael Avalos case 0x8f: /* LID closed */ 2755bab09e23SAzael Avalos case 0x90: /* LID is closed and Dock has been ejected */ 2756bab09e23SAzael Avalos break; 2757bab09e23SAzael Avalos case 0x8c: /* SATA power events */ 2758bab09e23SAzael Avalos case 0x8b: 2759bab09e23SAzael Avalos pr_info("SATA power event received %x\n", event); 2760bab09e23SAzael Avalos break; 276180546905SAzael Avalos case 0x92: /* Keyboard backlight mode changed */ 276280546905SAzael Avalos /* Update sysfs entries */ 276380546905SAzael Avalos ret = sysfs_update_group(&acpi_dev->dev.kobj, 276480546905SAzael Avalos &toshiba_attr_group); 276580546905SAzael Avalos if (ret) 276680546905SAzael Avalos pr_err("Unable to update sysfs entries\n"); 276780546905SAzael Avalos break; 2768bab09e23SAzael Avalos case 0x85: /* Unknown */ 2769bab09e23SAzael Avalos case 0x8d: /* Unknown */ 277071454d78SAzael Avalos case 0x8e: /* Unknown */ 2771bab09e23SAzael Avalos case 0x94: /* Unknown */ 2772bab09e23SAzael Avalos case 0x95: /* Unknown */ 277311948b93SSeth Forshee default: 277471454d78SAzael Avalos pr_info("Unknown event received %x\n", event); 277511948b93SSeth Forshee break; 27766335e4d5SMatthew Garrett } 2777bab09e23SAzael Avalos 2778bab09e23SAzael Avalos acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class, 2779bab09e23SAzael Avalos dev_name(&acpi_dev->dev), 2780bab09e23SAzael Avalos event, 0); 278129cd293fSSeth Forshee } 27826335e4d5SMatthew Garrett 27833567a4e2SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 278443d2fd3bSRafael J. Wysocki static int toshiba_acpi_suspend(struct device *device) 278529cd293fSSeth Forshee { 278643d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 278729cd293fSSeth Forshee u32 result; 278829cd293fSSeth Forshee 278929cd293fSSeth Forshee if (dev->hotkey_dev) 2790d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE); 279129cd293fSSeth Forshee 279229cd293fSSeth Forshee return 0; 279329cd293fSSeth Forshee } 279429cd293fSSeth Forshee 279543d2fd3bSRafael J. Wysocki static int toshiba_acpi_resume(struct device *device) 279629cd293fSSeth Forshee { 279743d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 27981f28f290SAzael Avalos int error; 279929cd293fSSeth Forshee 2800e7fdb762SBenjamin Tissoires if (dev->hotkey_dev) { 28011f28f290SAzael Avalos error = toshiba_acpi_enable_hotkeys(dev); 28021f28f290SAzael Avalos if (error) 2803e7fdb762SBenjamin Tissoires pr_info("Unable to re-enable hotkeys\n"); 2804e7fdb762SBenjamin Tissoires } 280529cd293fSSeth Forshee 280629cd293fSSeth Forshee return 0; 280729cd293fSSeth Forshee } 28083567a4e2SRafael J. Wysocki #endif 28096335e4d5SMatthew Garrett 281043d2fd3bSRafael J. Wysocki static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm, 281143d2fd3bSRafael J. Wysocki toshiba_acpi_suspend, toshiba_acpi_resume); 281243d2fd3bSRafael J. Wysocki 2813135740deSSeth Forshee static struct acpi_driver toshiba_acpi_driver = { 2814135740deSSeth Forshee .name = "Toshiba ACPI driver", 2815135740deSSeth Forshee .owner = THIS_MODULE, 2816135740deSSeth Forshee .ids = toshiba_device_ids, 2817135740deSSeth Forshee .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, 2818135740deSSeth Forshee .ops = { 2819135740deSSeth Forshee .add = toshiba_acpi_add, 2820135740deSSeth Forshee .remove = toshiba_acpi_remove, 2821135740deSSeth Forshee .notify = toshiba_acpi_notify, 2822135740deSSeth Forshee }, 282343d2fd3bSRafael J. Wysocki .drv.pm = &toshiba_acpi_pm, 2824135740deSSeth Forshee }; 2825b4f9fe12SLen Brown 2826b4f9fe12SLen Brown static int __init toshiba_acpi_init(void) 2827b4f9fe12SLen Brown { 2828135740deSSeth Forshee int ret; 2829b4f9fe12SLen Brown 2830f11f999eSSeth Forshee /* 2831f11f999eSSeth Forshee * Machines with this WMI guid aren't supported due to bugs in 2832f11f999eSSeth Forshee * their AML. This check relies on wmi initializing before 2833f11f999eSSeth Forshee * toshiba_acpi to guarantee guids have been identified. 2834f11f999eSSeth Forshee */ 2835f11f999eSSeth Forshee if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) 2836f11f999eSSeth Forshee return -ENODEV; 2837f11f999eSSeth Forshee 2838b4f9fe12SLen Brown toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); 2839b4f9fe12SLen Brown if (!toshiba_proc_dir) { 2840135740deSSeth Forshee pr_err("Unable to create proc dir " PROC_TOSHIBA "\n"); 2841b4f9fe12SLen Brown return -ENODEV; 2842b4f9fe12SLen Brown } 2843b4f9fe12SLen Brown 2844135740deSSeth Forshee ret = acpi_bus_register_driver(&toshiba_acpi_driver); 2845b4f9fe12SLen Brown if (ret) { 2846135740deSSeth Forshee pr_err("Failed to register ACPI driver: %d\n", ret); 2847135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 2848135740deSSeth Forshee } 2849135740deSSeth Forshee 2850b4f9fe12SLen Brown return ret; 2851b4f9fe12SLen Brown } 2852b4f9fe12SLen Brown 2853135740deSSeth Forshee static void __exit toshiba_acpi_exit(void) 2854135740deSSeth Forshee { 2855135740deSSeth Forshee acpi_bus_unregister_driver(&toshiba_acpi_driver); 2856135740deSSeth Forshee if (toshiba_proc_dir) 2857135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 2858b4f9fe12SLen Brown } 2859b4f9fe12SLen Brown 2860b4f9fe12SLen Brown module_init(toshiba_acpi_init); 2861b4f9fe12SLen Brown module_exit(toshiba_acpi_exit); 2862