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> 44b4f9fe12SLen Brown #include <linux/rfkill.h> 456335e4d5SMatthew Garrett #include <linux/input.h> 46384a7cd9SDmitry Torokhov #include <linux/input/sparse-keymap.h> 476c3f6e6cSPierre Ducroquet #include <linux/leds.h> 485a0e3ad6STejun Heo #include <linux/slab.h> 4929cd293fSSeth Forshee #include <linux/workqueue.h> 5029cd293fSSeth Forshee #include <linux/i8042.h> 518b48463fSLv Zheng #include <linux/acpi.h> 52fe808bfbSTakashi Iwai #include <linux/dmi.h> 53b5163992SAzael Avalos #include <linux/uaccess.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 84b4f9fe12SLen Brown /* 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 92b4f9fe12SLen Brown /* 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 107b4f9fe12SLen Brown /* 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 119*56e6b353SAzael 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 129b4f9fe12SLen Brown /* field definitions */ 1305a2813e9SAzael Avalos #define HCI_ACCEL_MASK 0x7fff 13129cd293fSSeth Forshee #define HCI_HOTKEY_DISABLE 0x0b 13229cd293fSSeth Forshee #define HCI_HOTKEY_ENABLE 0x09 133b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_BITS 3 134b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) 135b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS) 136360f0f39SAzael Avalos #define HCI_MISC_SHIFT 0x10 137*56e6b353SAzael Avalos #define HCI_SYSTEM_TYPE1 0x10 138*56e6b353SAzael Avalos #define HCI_SYSTEM_TYPE2 0x11 139b4f9fe12SLen Brown #define HCI_VIDEO_OUT_LCD 0x1 140b4f9fe12SLen Brown #define HCI_VIDEO_OUT_CRT 0x2 141b4f9fe12SLen Brown #define HCI_VIDEO_OUT_TV 0x4 142b4f9fe12SLen Brown #define HCI_WIRELESS_KILL_SWITCH 0x01 143b4f9fe12SLen Brown #define HCI_WIRELESS_BT_PRESENT 0x0f 144b4f9fe12SLen Brown #define HCI_WIRELESS_BT_ATTACH 0x40 145b4f9fe12SLen Brown #define HCI_WIRELESS_BT_POWER 0x80 14693f8c16dSAzael Avalos #define SCI_KBD_MODE_MASK 0x1f 147360f0f39SAzael Avalos #define SCI_KBD_MODE_FNZ 0x1 148360f0f39SAzael Avalos #define SCI_KBD_MODE_AUTO 0x2 14993f8c16dSAzael Avalos #define SCI_KBD_MODE_ON 0x8 15093f8c16dSAzael Avalos #define SCI_KBD_MODE_OFF 0x10 15193f8c16dSAzael Avalos #define SCI_KBD_TIME_MAX 0x3c001a 152e26ffe51SAzael Avalos #define SCI_USB_CHARGE_MODE_MASK 0xff 153e26ffe51SAzael Avalos #define SCI_USB_CHARGE_DISABLED 0x30000 154e26ffe51SAzael Avalos #define SCI_USB_CHARGE_ALTERNATE 0x30009 155e26ffe51SAzael Avalos #define SCI_USB_CHARGE_AUTO 0x30021 156182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_MASK 0x7 157182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_OFF 0x1 158182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_ON 0x4 159182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL 0x0200 160bb3fe01fSAzael Avalos #define SCI_USB_CHARGE_RAPID_DSP 0x0300 161b4f9fe12SLen Brown 162135740deSSeth Forshee struct toshiba_acpi_dev { 163135740deSSeth Forshee struct acpi_device *acpi_dev; 164135740deSSeth Forshee const char *method_hci; 165135740deSSeth Forshee struct rfkill *bt_rfk; 166135740deSSeth Forshee struct input_dev *hotkey_dev; 16729cd293fSSeth Forshee struct work_struct hotkey_work; 168135740deSSeth Forshee struct backlight_device *backlight_dev; 169135740deSSeth Forshee struct led_classdev led_dev; 170360f0f39SAzael Avalos struct led_classdev kbd_led; 171def6c4e2SAzael Avalos struct led_classdev eco_led; 17236d03f93SSeth Forshee 173135740deSSeth Forshee int force_fan; 174135740deSSeth Forshee int last_key_event; 175135740deSSeth Forshee int key_event_valid; 17693f8c16dSAzael Avalos int kbd_type; 177360f0f39SAzael Avalos int kbd_mode; 178360f0f39SAzael Avalos int kbd_time; 179182bcaa5SAzael Avalos int usbsc_bat_level; 180135740deSSeth Forshee 181592b746cSDan Carpenter unsigned int illumination_supported:1; 182592b746cSDan Carpenter unsigned int video_supported:1; 183592b746cSDan Carpenter unsigned int fan_supported:1; 184592b746cSDan Carpenter unsigned int system_event_supported:1; 18529cd293fSSeth Forshee unsigned int ntfy_supported:1; 18629cd293fSSeth Forshee unsigned int info_supported:1; 187121b7b0dSAkio Idehara unsigned int tr_backlight_supported:1; 188360f0f39SAzael Avalos unsigned int kbd_illum_supported:1; 189360f0f39SAzael Avalos unsigned int kbd_led_registered:1; 1909d8658acSAzael Avalos unsigned int touchpad_supported:1; 191def6c4e2SAzael Avalos unsigned int eco_supported:1; 1925a2813e9SAzael Avalos unsigned int accelerometer_supported:1; 193e26ffe51SAzael Avalos unsigned int usb_sleep_charge_supported:1; 194bb3fe01fSAzael Avalos unsigned int usb_rapid_charge_supported:1; 195172ce0a9SAzael Avalos unsigned int usb_sleep_music_supported:1; 196bae84195SAzael Avalos unsigned int kbd_function_keys_supported:1; 19735d53ceaSAzael Avalos unsigned int panel_power_on_supported:1; 19817fe4b3dSAzael Avalos unsigned int usb_three_supported:1; 199360f0f39SAzael Avalos unsigned int sysfs_created:1; 20036d03f93SSeth Forshee 201135740deSSeth Forshee struct mutex mutex; 202135740deSSeth Forshee }; 203135740deSSeth Forshee 20429cd293fSSeth Forshee static struct toshiba_acpi_dev *toshiba_acpi; 20529cd293fSSeth Forshee 206b4f9fe12SLen Brown static const struct acpi_device_id toshiba_device_ids[] = { 207b4f9fe12SLen Brown {"TOS6200", 0}, 20863a9e016SOndrej Zary {"TOS6207", 0}, 209b4f9fe12SLen Brown {"TOS6208", 0}, 210b4f9fe12SLen Brown {"TOS1900", 0}, 211b4f9fe12SLen Brown {"", 0}, 212b4f9fe12SLen Brown }; 213b4f9fe12SLen Brown MODULE_DEVICE_TABLE(acpi, toshiba_device_ids); 214b4f9fe12SLen Brown 215b859f159SGreg Kroah-Hartman static const struct key_entry toshiba_acpi_keymap[] = { 216fec278a1SUnai Uribarri { KE_KEY, 0x9e, { KEY_RFKILL } }, 217384a7cd9SDmitry Torokhov { KE_KEY, 0x101, { KEY_MUTE } }, 218384a7cd9SDmitry Torokhov { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 219384a7cd9SDmitry Torokhov { KE_KEY, 0x103, { KEY_ZOOMIN } }, 220408a5d13SAzael Avalos { KE_KEY, 0x10f, { KEY_TAB } }, 221af502837SAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 222af502837SAzael Avalos { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 223384a7cd9SDmitry Torokhov { KE_KEY, 0x13b, { KEY_COFFEE } }, 224384a7cd9SDmitry Torokhov { KE_KEY, 0x13c, { KEY_BATTERY } }, 225384a7cd9SDmitry Torokhov { KE_KEY, 0x13d, { KEY_SLEEP } }, 226384a7cd9SDmitry Torokhov { KE_KEY, 0x13e, { KEY_SUSPEND } }, 227384a7cd9SDmitry Torokhov { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } }, 228384a7cd9SDmitry Torokhov { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } }, 229384a7cd9SDmitry Torokhov { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } }, 230384a7cd9SDmitry Torokhov { KE_KEY, 0x142, { KEY_WLAN } }, 231af502837SAzael Avalos { KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } }, 232a49010f5SJon Dowland { KE_KEY, 0x17f, { KEY_FN } }, 233384a7cd9SDmitry Torokhov { KE_KEY, 0xb05, { KEY_PROG2 } }, 234384a7cd9SDmitry Torokhov { KE_KEY, 0xb06, { KEY_WWW } }, 235384a7cd9SDmitry Torokhov { KE_KEY, 0xb07, { KEY_MAIL } }, 236384a7cd9SDmitry Torokhov { KE_KEY, 0xb30, { KEY_STOP } }, 237384a7cd9SDmitry Torokhov { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } }, 238384a7cd9SDmitry Torokhov { KE_KEY, 0xb32, { KEY_NEXTSONG } }, 239384a7cd9SDmitry Torokhov { KE_KEY, 0xb33, { KEY_PLAYPAUSE } }, 240384a7cd9SDmitry Torokhov { KE_KEY, 0xb5a, { KEY_MEDIA } }, 241408a5d13SAzael Avalos { KE_IGNORE, 0x1430, { KEY_RESERVED } }, /* Wake from sleep */ 242408a5d13SAzael Avalos { KE_IGNORE, 0x1501, { KEY_RESERVED } }, /* Output changed */ 243408a5d13SAzael Avalos { KE_IGNORE, 0x1502, { KEY_RESERVED } }, /* HDMI plugged/unplugged */ 244408a5d13SAzael Avalos { KE_IGNORE, 0x1ABE, { KEY_RESERVED } }, /* Protection level set */ 245408a5d13SAzael Avalos { KE_IGNORE, 0x1ABF, { KEY_RESERVED } }, /* Protection level off */ 246384a7cd9SDmitry Torokhov { KE_END, 0 }, 2476335e4d5SMatthew Garrett }; 2486335e4d5SMatthew Garrett 249fe808bfbSTakashi Iwai /* alternative keymap */ 250fe808bfbSTakashi Iwai static const struct dmi_system_id toshiba_alt_keymap_dmi[] = { 251fe808bfbSTakashi Iwai { 252fe808bfbSTakashi Iwai .matches = { 253fe808bfbSTakashi Iwai DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 254fe808bfbSTakashi Iwai DMI_MATCH(DMI_PRODUCT_NAME, "Satellite M840"), 255fe808bfbSTakashi Iwai }, 256fe808bfbSTakashi Iwai }, 257e6efad7fSAzael Avalos { 258e6efad7fSAzael Avalos .matches = { 259e6efad7fSAzael Avalos DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 260e6efad7fSAzael Avalos DMI_MATCH(DMI_PRODUCT_NAME, "Qosmio X75-A"), 261e6efad7fSAzael Avalos }, 262e6efad7fSAzael Avalos }, 263b1bde689SAaron Lu { 264b1bde689SAaron Lu .matches = { 265b1bde689SAaron Lu DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 266b1bde689SAaron Lu DMI_MATCH(DMI_PRODUCT_NAME, "TECRA A50-A"), 267b1bde689SAaron Lu }, 268b1bde689SAaron Lu }, 269fe808bfbSTakashi Iwai {} 270fe808bfbSTakashi Iwai }; 271fe808bfbSTakashi Iwai 272fe808bfbSTakashi Iwai static const struct key_entry toshiba_acpi_alt_keymap[] = { 273fe808bfbSTakashi Iwai { KE_KEY, 0x157, { KEY_MUTE } }, 274fe808bfbSTakashi Iwai { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 275fe808bfbSTakashi Iwai { KE_KEY, 0x103, { KEY_ZOOMIN } }, 276e6efad7fSAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 277fe808bfbSTakashi Iwai { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 278fe808bfbSTakashi Iwai { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } }, 279fe808bfbSTakashi Iwai { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } }, 280fe808bfbSTakashi Iwai { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } }, 281fe808bfbSTakashi Iwai { KE_KEY, 0x158, { KEY_WLAN } }, 282fe808bfbSTakashi Iwai { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } }, 283fe808bfbSTakashi Iwai { KE_END, 0 }, 284fe808bfbSTakashi Iwai }; 285fe808bfbSTakashi Iwai 286e0769fe6SDarren Hart /* 287e0769fe6SDarren Hart * Utility 288b4f9fe12SLen Brown */ 289b4f9fe12SLen Brown 290b5163992SAzael Avalos static inline void _set_bit(u32 *word, u32 mask, int value) 291b4f9fe12SLen Brown { 292b4f9fe12SLen Brown *word = (*word & ~mask) | (mask * value); 293b4f9fe12SLen Brown } 294b4f9fe12SLen Brown 295e0769fe6SDarren Hart /* 296e0769fe6SDarren Hart * ACPI interface wrappers 297b4f9fe12SLen Brown */ 298b4f9fe12SLen Brown 299b4f9fe12SLen Brown static int write_acpi_int(const char *methodName, int val) 300b4f9fe12SLen Brown { 301b4f9fe12SLen Brown acpi_status status; 302b4f9fe12SLen Brown 303619400daSZhang Rui status = acpi_execute_simple_method(NULL, (char *)methodName, val); 30432bcd5cbSSeth Forshee return (status == AE_OK) ? 0 : -EIO; 305b4f9fe12SLen Brown } 306b4f9fe12SLen Brown 307e0769fe6SDarren Hart /* 308e0769fe6SDarren Hart * Perform a raw configuration call. Here we don't care about input or output 309258c5903SAzael Avalos * buffer format. 310b4f9fe12SLen Brown */ 311258c5903SAzael Avalos static acpi_status tci_raw(struct toshiba_acpi_dev *dev, 312258c5903SAzael Avalos const u32 in[TCI_WORDS], u32 out[TCI_WORDS]) 313b4f9fe12SLen Brown { 314b4f9fe12SLen Brown struct acpi_object_list params; 315258c5903SAzael Avalos union acpi_object in_objs[TCI_WORDS]; 316b4f9fe12SLen Brown struct acpi_buffer results; 317258c5903SAzael Avalos union acpi_object out_objs[TCI_WORDS + 1]; 318b4f9fe12SLen Brown acpi_status status; 319b4f9fe12SLen Brown int i; 320b4f9fe12SLen Brown 321258c5903SAzael Avalos params.count = TCI_WORDS; 322b4f9fe12SLen Brown params.pointer = in_objs; 323258c5903SAzael Avalos for (i = 0; i < TCI_WORDS; ++i) { 324b4f9fe12SLen Brown in_objs[i].type = ACPI_TYPE_INTEGER; 325b4f9fe12SLen Brown in_objs[i].integer.value = in[i]; 326b4f9fe12SLen Brown } 327b4f9fe12SLen Brown 328b4f9fe12SLen Brown results.length = sizeof(out_objs); 329b4f9fe12SLen Brown results.pointer = out_objs; 330b4f9fe12SLen Brown 3316e02cc7eSSeth Forshee status = acpi_evaluate_object(dev->acpi_dev->handle, 3326e02cc7eSSeth Forshee (char *)dev->method_hci, ¶ms, 333b4f9fe12SLen Brown &results); 334258c5903SAzael Avalos if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) { 335b5163992SAzael Avalos for (i = 0; i < out_objs->package.count; ++i) 336b4f9fe12SLen Brown out[i] = out_objs->package.elements[i].integer.value; 337b4f9fe12SLen Brown } 338b4f9fe12SLen Brown 339b4f9fe12SLen Brown return status; 340b4f9fe12SLen Brown } 341b4f9fe12SLen Brown 342e0769fe6SDarren Hart /* 343e0769fe6SDarren Hart * Common hci tasks (get or set one or two value) 344b4f9fe12SLen Brown * 345b4f9fe12SLen Brown * In addition to the ACPI status, the HCI system returns a result which 346b4f9fe12SLen Brown * may be useful (such as "not supported"). 347b4f9fe12SLen Brown */ 348b4f9fe12SLen Brown 349893f3f62SAzael Avalos static u32 hci_write1(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 350b4f9fe12SLen Brown { 351258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 }; 352258c5903SAzael Avalos u32 out[TCI_WORDS]; 353258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 354893f3f62SAzael Avalos 355893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 356b4f9fe12SLen Brown } 357b4f9fe12SLen Brown 358893f3f62SAzael Avalos static u32 hci_read1(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 359b4f9fe12SLen Brown { 360258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 }; 361258c5903SAzael Avalos u32 out[TCI_WORDS]; 362258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 363b5163992SAzael Avalos 364893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 365893f3f62SAzael Avalos return TOS_FAILURE; 366893f3f62SAzael Avalos 367b4f9fe12SLen Brown *out1 = out[2]; 368893f3f62SAzael Avalos 369893f3f62SAzael Avalos return out[0]; 370b4f9fe12SLen Brown } 371b4f9fe12SLen Brown 372893f3f62SAzael Avalos static u32 hci_write2(struct toshiba_acpi_dev *dev, u32 reg, u32 in1, u32 in2) 373b4f9fe12SLen Brown { 374258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, reg, in1, in2, 0, 0 }; 375258c5903SAzael Avalos u32 out[TCI_WORDS]; 376258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 377893f3f62SAzael Avalos 378893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 379b4f9fe12SLen Brown } 380b4f9fe12SLen Brown 381b5163992SAzael Avalos static u32 hci_read2(struct toshiba_acpi_dev *dev, 382b5163992SAzael Avalos u32 reg, u32 *out1, u32 *out2) 383b4f9fe12SLen Brown { 384258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 }; 385258c5903SAzael Avalos u32 out[TCI_WORDS]; 386258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 387b5163992SAzael Avalos 388893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 389893f3f62SAzael Avalos return TOS_FAILURE; 390893f3f62SAzael Avalos 391b4f9fe12SLen Brown *out1 = out[2]; 392b4f9fe12SLen Brown *out2 = out[3]; 393893f3f62SAzael Avalos 394893f3f62SAzael Avalos return out[0]; 395b4f9fe12SLen Brown } 396b4f9fe12SLen Brown 397e0769fe6SDarren Hart /* 398e0769fe6SDarren Hart * Common sci tasks 39984a6273fSAzael Avalos */ 40084a6273fSAzael Avalos 40184a6273fSAzael Avalos static int sci_open(struct toshiba_acpi_dev *dev) 40284a6273fSAzael Avalos { 403258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 }; 404258c5903SAzael Avalos u32 out[TCI_WORDS]; 40584a6273fSAzael Avalos acpi_status status; 40684a6273fSAzael Avalos 407258c5903SAzael Avalos status = tci_raw(dev, in, out); 4081864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 40984a6273fSAzael Avalos pr_err("ACPI call to open SCI failed\n"); 41084a6273fSAzael Avalos return 0; 41184a6273fSAzael Avalos } 41284a6273fSAzael Avalos 4131864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) { 41484a6273fSAzael Avalos return 1; 4151864bbc2SAzael Avalos } else if (out[0] == TOS_ALREADY_OPEN) { 41684a6273fSAzael Avalos pr_info("Toshiba SCI already opened\n"); 41784a6273fSAzael Avalos return 1; 418fa465739SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 419e0769fe6SDarren Hart /* 420e0769fe6SDarren Hart * Some BIOSes do not have the SCI open/close functions 421fa465739SAzael Avalos * implemented and return 0x8000 (Not Supported), failing to 422fa465739SAzael Avalos * register some supported features. 423fa465739SAzael Avalos * 424fa465739SAzael Avalos * Simply return 1 if we hit those affected laptops to make the 425fa465739SAzael Avalos * supported features work. 426fa465739SAzael Avalos * 427fa465739SAzael Avalos * In the case that some laptops really do not support the SCI, 428fa465739SAzael Avalos * all the SCI dependent functions check for TOS_NOT_SUPPORTED, 429fa465739SAzael Avalos * and thus, not registering support for the queried feature. 430fa465739SAzael Avalos */ 431fa465739SAzael Avalos return 1; 4321864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_PRESENT) { 43384a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 43484a6273fSAzael Avalos } 43584a6273fSAzael Avalos 43684a6273fSAzael Avalos return 0; 43784a6273fSAzael Avalos } 43884a6273fSAzael Avalos 43984a6273fSAzael Avalos static void sci_close(struct toshiba_acpi_dev *dev) 44084a6273fSAzael Avalos { 441258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 }; 442258c5903SAzael Avalos u32 out[TCI_WORDS]; 44384a6273fSAzael Avalos acpi_status status; 44484a6273fSAzael Avalos 445258c5903SAzael Avalos status = tci_raw(dev, in, out); 4461864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 44784a6273fSAzael Avalos pr_err("ACPI call to close SCI failed\n"); 44884a6273fSAzael Avalos return; 44984a6273fSAzael Avalos } 45084a6273fSAzael Avalos 4511864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) 45284a6273fSAzael Avalos return; 4531864bbc2SAzael Avalos else if (out[0] == TOS_NOT_OPENED) 45484a6273fSAzael Avalos pr_info("Toshiba SCI not opened\n"); 4551864bbc2SAzael Avalos else if (out[0] == TOS_NOT_PRESENT) 45684a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 45784a6273fSAzael Avalos } 45884a6273fSAzael Avalos 459893f3f62SAzael Avalos static u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 46084a6273fSAzael Avalos { 461258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 }; 462258c5903SAzael Avalos u32 out[TCI_WORDS]; 463258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 464b5163992SAzael Avalos 465893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 466893f3f62SAzael Avalos return TOS_FAILURE; 467893f3f62SAzael Avalos 46884a6273fSAzael Avalos *out1 = out[2]; 469893f3f62SAzael Avalos 470893f3f62SAzael Avalos return out[0]; 47184a6273fSAzael Avalos } 47284a6273fSAzael Avalos 473893f3f62SAzael Avalos static u32 sci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 47484a6273fSAzael Avalos { 475258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 }; 476258c5903SAzael Avalos u32 out[TCI_WORDS]; 477258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 478893f3f62SAzael Avalos 479893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 48084a6273fSAzael Avalos } 48184a6273fSAzael Avalos 4826c3f6e6cSPierre Ducroquet /* Illumination support */ 483135740deSSeth Forshee static int toshiba_illumination_available(struct toshiba_acpi_dev *dev) 4846c3f6e6cSPierre Ducroquet { 485258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 }; 486258c5903SAzael Avalos u32 out[TCI_WORDS]; 4876c3f6e6cSPierre Ducroquet acpi_status status; 4886c3f6e6cSPierre Ducroquet 489fdb79081SAzael Avalos if (!sci_open(dev)) 490fdb79081SAzael Avalos return 0; 491fdb79081SAzael Avalos 492258c5903SAzael Avalos status = tci_raw(dev, in, out); 493fdb79081SAzael Avalos sci_close(dev); 4941864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 495fdb79081SAzael Avalos pr_err("ACPI call to query Illumination support failed\n"); 496fdb79081SAzael Avalos return 0; 4971864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 4987e33460dSJoe Perches pr_info("Illumination device not available\n"); 4996c3f6e6cSPierre Ducroquet return 0; 5006c3f6e6cSPierre Ducroquet } 501fdb79081SAzael Avalos 5026c3f6e6cSPierre Ducroquet return 1; 5036c3f6e6cSPierre Ducroquet } 5046c3f6e6cSPierre Ducroquet 5056c3f6e6cSPierre Ducroquet static void toshiba_illumination_set(struct led_classdev *cdev, 5066c3f6e6cSPierre Ducroquet enum led_brightness brightness) 5076c3f6e6cSPierre Ducroquet { 508135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 509135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 510fdb79081SAzael Avalos u32 state, result; 5116c3f6e6cSPierre Ducroquet 5126c3f6e6cSPierre Ducroquet /* First request : initialize communication. */ 513fdb79081SAzael Avalos if (!sci_open(dev)) 5146c3f6e6cSPierre Ducroquet return; 5156c3f6e6cSPierre Ducroquet 516fdb79081SAzael Avalos /* Switch the illumination on/off */ 517fdb79081SAzael Avalos state = brightness ? 1 : 0; 518893f3f62SAzael Avalos result = sci_write(dev, SCI_ILLUMINATION, state); 519fdb79081SAzael Avalos sci_close(dev); 520893f3f62SAzael Avalos if (result == TOS_FAILURE) { 521fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 522fdb79081SAzael Avalos return; 5231864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 524fdb79081SAzael Avalos pr_info("Illumination not supported\n"); 5256c3f6e6cSPierre Ducroquet return; 5266c3f6e6cSPierre Ducroquet } 5276c3f6e6cSPierre Ducroquet } 5286c3f6e6cSPierre Ducroquet 5296c3f6e6cSPierre Ducroquet static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) 5306c3f6e6cSPierre Ducroquet { 531135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 532135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 533fdb79081SAzael Avalos u32 state, result; 5346c3f6e6cSPierre Ducroquet 5356c3f6e6cSPierre Ducroquet /* First request : initialize communication. */ 536fdb79081SAzael Avalos if (!sci_open(dev)) 5376c3f6e6cSPierre Ducroquet return LED_OFF; 5386c3f6e6cSPierre Ducroquet 5396c3f6e6cSPierre Ducroquet /* Check the illumination */ 540893f3f62SAzael Avalos result = sci_read(dev, SCI_ILLUMINATION, &state); 541fdb79081SAzael Avalos sci_close(dev); 542893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 543fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 544fdb79081SAzael Avalos return LED_OFF; 5451864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 546fdb79081SAzael Avalos pr_info("Illumination not supported\n"); 5476c3f6e6cSPierre Ducroquet return LED_OFF; 5486c3f6e6cSPierre Ducroquet } 5496c3f6e6cSPierre Ducroquet 550fdb79081SAzael Avalos return state ? LED_FULL : LED_OFF; 5516c3f6e6cSPierre Ducroquet } 5526c3f6e6cSPierre Ducroquet 553360f0f39SAzael Avalos /* KBD Illumination */ 55493f8c16dSAzael Avalos static int toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev) 55593f8c16dSAzael Avalos { 556258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 }; 557258c5903SAzael Avalos u32 out[TCI_WORDS]; 55893f8c16dSAzael Avalos acpi_status status; 55993f8c16dSAzael Avalos 56093f8c16dSAzael Avalos if (!sci_open(dev)) 56193f8c16dSAzael Avalos return 0; 56293f8c16dSAzael Avalos 563258c5903SAzael Avalos status = tci_raw(dev, in, out); 56493f8c16dSAzael Avalos sci_close(dev); 5651864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 56693f8c16dSAzael Avalos pr_err("ACPI call to query kbd illumination support failed\n"); 56793f8c16dSAzael Avalos return 0; 5681864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 56993f8c16dSAzael Avalos pr_info("Keyboard illumination not available\n"); 57093f8c16dSAzael Avalos return 0; 57193f8c16dSAzael Avalos } 57293f8c16dSAzael Avalos 573e0769fe6SDarren Hart /* 574e0769fe6SDarren Hart * Check for keyboard backlight timeout max value, 57593f8c16dSAzael Avalos * previous kbd backlight implementation set this to 57693f8c16dSAzael Avalos * 0x3c0003, and now the new implementation set this 577e0769fe6SDarren Hart * to 0x3c001a, use this to distinguish between them. 57893f8c16dSAzael Avalos */ 57993f8c16dSAzael Avalos if (out[3] == SCI_KBD_TIME_MAX) 58093f8c16dSAzael Avalos dev->kbd_type = 2; 58193f8c16dSAzael Avalos else 58293f8c16dSAzael Avalos dev->kbd_type = 1; 58393f8c16dSAzael Avalos /* Get the current keyboard backlight mode */ 58493f8c16dSAzael Avalos dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK; 58593f8c16dSAzael Avalos /* Get the current time (1-60 seconds) */ 58693f8c16dSAzael Avalos dev->kbd_time = out[2] >> HCI_MISC_SHIFT; 58793f8c16dSAzael Avalos 58893f8c16dSAzael Avalos return 1; 58993f8c16dSAzael Avalos } 59093f8c16dSAzael Avalos 591360f0f39SAzael Avalos static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time) 592360f0f39SAzael Avalos { 593360f0f39SAzael Avalos u32 result; 594360f0f39SAzael Avalos 595360f0f39SAzael Avalos if (!sci_open(dev)) 596360f0f39SAzael Avalos return -EIO; 597360f0f39SAzael Avalos 598893f3f62SAzael Avalos result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time); 599360f0f39SAzael Avalos sci_close(dev); 600893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 601360f0f39SAzael Avalos pr_err("ACPI call to set KBD backlight status failed\n"); 602360f0f39SAzael Avalos return -EIO; 6031864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 604360f0f39SAzael Avalos pr_info("Keyboard backlight status not supported\n"); 605360f0f39SAzael Avalos return -ENODEV; 606360f0f39SAzael Avalos } 607360f0f39SAzael Avalos 608360f0f39SAzael Avalos return 0; 609360f0f39SAzael Avalos } 610360f0f39SAzael Avalos 611360f0f39SAzael Avalos static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time) 612360f0f39SAzael Avalos { 613360f0f39SAzael Avalos u32 result; 614360f0f39SAzael Avalos 615360f0f39SAzael Avalos if (!sci_open(dev)) 616360f0f39SAzael Avalos return -EIO; 617360f0f39SAzael Avalos 618893f3f62SAzael Avalos result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time); 619360f0f39SAzael Avalos sci_close(dev); 620893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 621360f0f39SAzael Avalos pr_err("ACPI call to get KBD backlight status failed\n"); 622360f0f39SAzael Avalos return -EIO; 6231864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 624360f0f39SAzael Avalos pr_info("Keyboard backlight status not supported\n"); 625360f0f39SAzael Avalos return -ENODEV; 626360f0f39SAzael Avalos } 627360f0f39SAzael Avalos 628360f0f39SAzael Avalos return 0; 629360f0f39SAzael Avalos } 630360f0f39SAzael Avalos 631360f0f39SAzael Avalos static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev) 632360f0f39SAzael Avalos { 633360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 634360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 635360f0f39SAzael Avalos u32 state, result; 636360f0f39SAzael Avalos 637360f0f39SAzael Avalos /* Check the keyboard backlight state */ 638893f3f62SAzael Avalos result = hci_read1(dev, HCI_KBD_ILLUMINATION, &state); 639893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 640360f0f39SAzael Avalos pr_err("ACPI call to get the keyboard backlight failed\n"); 641360f0f39SAzael Avalos return LED_OFF; 6421864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 643360f0f39SAzael Avalos pr_info("Keyboard backlight not supported\n"); 644360f0f39SAzael Avalos return LED_OFF; 645360f0f39SAzael Avalos } 646360f0f39SAzael Avalos 647360f0f39SAzael Avalos return state ? LED_FULL : LED_OFF; 648360f0f39SAzael Avalos } 649360f0f39SAzael Avalos 650360f0f39SAzael Avalos static void toshiba_kbd_backlight_set(struct led_classdev *cdev, 651360f0f39SAzael Avalos enum led_brightness brightness) 652360f0f39SAzael Avalos { 653360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 654360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 655360f0f39SAzael Avalos u32 state, result; 656360f0f39SAzael Avalos 657360f0f39SAzael Avalos /* Set the keyboard backlight state */ 658360f0f39SAzael Avalos state = brightness ? 1 : 0; 659893f3f62SAzael Avalos result = hci_write1(dev, HCI_KBD_ILLUMINATION, state); 660893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 661360f0f39SAzael Avalos pr_err("ACPI call to set KBD Illumination mode failed\n"); 662360f0f39SAzael Avalos return; 6631864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 664360f0f39SAzael Avalos pr_info("Keyboard backlight not supported\n"); 665360f0f39SAzael Avalos return; 666360f0f39SAzael Avalos } 667360f0f39SAzael Avalos } 668360f0f39SAzael Avalos 6699d8658acSAzael Avalos /* TouchPad support */ 6709d8658acSAzael Avalos static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state) 6719d8658acSAzael Avalos { 6729d8658acSAzael Avalos u32 result; 6739d8658acSAzael Avalos 6749d8658acSAzael Avalos if (!sci_open(dev)) 6759d8658acSAzael Avalos return -EIO; 6769d8658acSAzael Avalos 677893f3f62SAzael Avalos result = sci_write(dev, SCI_TOUCHPAD, state); 6789d8658acSAzael Avalos sci_close(dev); 679893f3f62SAzael Avalos if (result == TOS_FAILURE) { 6809d8658acSAzael Avalos pr_err("ACPI call to set the touchpad failed\n"); 6819d8658acSAzael Avalos return -EIO; 6821864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 6839d8658acSAzael Avalos return -ENODEV; 6849d8658acSAzael Avalos } 6859d8658acSAzael Avalos 6869d8658acSAzael Avalos return 0; 6879d8658acSAzael Avalos } 6889d8658acSAzael Avalos 6899d8658acSAzael Avalos static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) 6909d8658acSAzael Avalos { 6919d8658acSAzael Avalos u32 result; 6929d8658acSAzael Avalos 6939d8658acSAzael Avalos if (!sci_open(dev)) 6949d8658acSAzael Avalos return -EIO; 6959d8658acSAzael Avalos 696893f3f62SAzael Avalos result = sci_read(dev, SCI_TOUCHPAD, state); 6979d8658acSAzael Avalos sci_close(dev); 698893f3f62SAzael Avalos if (result == TOS_FAILURE) { 6999d8658acSAzael Avalos pr_err("ACPI call to query the touchpad failed\n"); 7009d8658acSAzael Avalos return -EIO; 7011864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 7029d8658acSAzael Avalos return -ENODEV; 7039d8658acSAzael Avalos } 7049d8658acSAzael Avalos 7059d8658acSAzael Avalos return 0; 7069d8658acSAzael Avalos } 7079d8658acSAzael Avalos 708def6c4e2SAzael Avalos /* Eco Mode support */ 709def6c4e2SAzael Avalos static int toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) 710def6c4e2SAzael Avalos { 711def6c4e2SAzael Avalos acpi_status status; 71298fc4ec6SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 }; 713258c5903SAzael Avalos u32 out[TCI_WORDS]; 714def6c4e2SAzael Avalos 715258c5903SAzael Avalos status = tci_raw(dev, in, out); 71698fc4ec6SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 71798fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 71898fc4ec6SAzael Avalos } else if (out[0] == TOS_NOT_INSTALLED) { 71998fc4ec6SAzael Avalos pr_info("ECO led not installed"); 72098fc4ec6SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 721e0769fe6SDarren Hart /* 722e0769fe6SDarren Hart * If we receive 0x8300 (Input Data Error), it means that the 72398fc4ec6SAzael Avalos * LED device is present, but that we just screwed the input 72498fc4ec6SAzael Avalos * parameters. 72598fc4ec6SAzael Avalos * 72698fc4ec6SAzael Avalos * Let's query the status of the LED to see if we really have a 72798fc4ec6SAzael Avalos * success response, indicating the actual presense of the LED, 72898fc4ec6SAzael Avalos * bail out otherwise. 72998fc4ec6SAzael Avalos */ 73098fc4ec6SAzael Avalos in[3] = 1; 73198fc4ec6SAzael Avalos status = tci_raw(dev, in, out); 73298fc4ec6SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) 73398fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 73498fc4ec6SAzael Avalos else if (out[0] == TOS_SUCCESS) 73598fc4ec6SAzael Avalos return 1; 736def6c4e2SAzael Avalos } 737def6c4e2SAzael Avalos 73898fc4ec6SAzael Avalos return 0; 739def6c4e2SAzael Avalos } 740def6c4e2SAzael Avalos 741b5163992SAzael Avalos static enum led_brightness 742b5163992SAzael Avalos toshiba_eco_mode_get_status(struct led_classdev *cdev) 743def6c4e2SAzael Avalos { 744def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 745def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 746258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 }; 747258c5903SAzael Avalos u32 out[TCI_WORDS]; 748def6c4e2SAzael Avalos acpi_status status; 749def6c4e2SAzael Avalos 750258c5903SAzael Avalos status = tci_raw(dev, in, out); 7511864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 752def6c4e2SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 753def6c4e2SAzael Avalos return LED_OFF; 754def6c4e2SAzael Avalos } 755def6c4e2SAzael Avalos 756def6c4e2SAzael Avalos return out[2] ? LED_FULL : LED_OFF; 757def6c4e2SAzael Avalos } 758def6c4e2SAzael Avalos 759def6c4e2SAzael Avalos static void toshiba_eco_mode_set_status(struct led_classdev *cdev, 760def6c4e2SAzael Avalos enum led_brightness brightness) 761def6c4e2SAzael Avalos { 762def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 763def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 764258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 }; 765258c5903SAzael Avalos u32 out[TCI_WORDS]; 766def6c4e2SAzael Avalos acpi_status status; 767def6c4e2SAzael Avalos 768def6c4e2SAzael Avalos /* Switch the Eco Mode led on/off */ 769def6c4e2SAzael Avalos in[2] = (brightness) ? 1 : 0; 770258c5903SAzael Avalos status = tci_raw(dev, in, out); 7711864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 772def6c4e2SAzael Avalos pr_err("ACPI call to set ECO led failed\n"); 773def6c4e2SAzael Avalos return; 774def6c4e2SAzael Avalos } 775def6c4e2SAzael Avalos } 776def6c4e2SAzael Avalos 7775a2813e9SAzael Avalos /* Accelerometer support */ 7785a2813e9SAzael Avalos static int toshiba_accelerometer_supported(struct toshiba_acpi_dev *dev) 7795a2813e9SAzael Avalos { 780258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 }; 781258c5903SAzael Avalos u32 out[TCI_WORDS]; 7825a2813e9SAzael Avalos acpi_status status; 7835a2813e9SAzael Avalos 784e0769fe6SDarren Hart /* 785e0769fe6SDarren Hart * Check if the accelerometer call exists, 7865a2813e9SAzael Avalos * this call also serves as initialization 7875a2813e9SAzael Avalos */ 788258c5903SAzael Avalos status = tci_raw(dev, in, out); 7891864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 7905a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 7915a2813e9SAzael Avalos return -EIO; 7921864bbc2SAzael Avalos } else if (out[0] == TOS_DATA_NOT_AVAILABLE || 7931864bbc2SAzael Avalos out[0] == TOS_NOT_INITIALIZED) { 7945a2813e9SAzael Avalos pr_err("Accelerometer not initialized\n"); 7955a2813e9SAzael Avalos return -EIO; 7961864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 7975a2813e9SAzael Avalos pr_info("Accelerometer not supported\n"); 7985a2813e9SAzael Avalos return -ENODEV; 7995a2813e9SAzael Avalos } 8005a2813e9SAzael Avalos 8015a2813e9SAzael Avalos return 0; 8025a2813e9SAzael Avalos } 8035a2813e9SAzael Avalos 8045a2813e9SAzael Avalos static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, 8055a2813e9SAzael Avalos u32 *xy, u32 *z) 8065a2813e9SAzael Avalos { 807258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 }; 808258c5903SAzael Avalos u32 out[TCI_WORDS]; 8095a2813e9SAzael Avalos acpi_status status; 8105a2813e9SAzael Avalos 8115a2813e9SAzael Avalos /* Check the Accelerometer status */ 812258c5903SAzael Avalos status = tci_raw(dev, in, out); 8131864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 8145a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 8155a2813e9SAzael Avalos return -EIO; 8165a2813e9SAzael Avalos } 8175a2813e9SAzael Avalos 8185a2813e9SAzael Avalos *xy = out[2]; 8195a2813e9SAzael Avalos *z = out[4]; 8205a2813e9SAzael Avalos 8215a2813e9SAzael Avalos return 0; 8225a2813e9SAzael Avalos } 8235a2813e9SAzael Avalos 824e26ffe51SAzael Avalos /* Sleep (Charge and Music) utilities support */ 825e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, 826e26ffe51SAzael Avalos u32 *mode) 827e26ffe51SAzael Avalos { 828e26ffe51SAzael Avalos u32 result; 829e26ffe51SAzael Avalos 830e26ffe51SAzael Avalos if (!sci_open(dev)) 831e26ffe51SAzael Avalos return -EIO; 832e26ffe51SAzael Avalos 833e26ffe51SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode); 834e26ffe51SAzael Avalos sci_close(dev); 835e26ffe51SAzael Avalos if (result == TOS_FAILURE) { 836e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 837e26ffe51SAzael Avalos return -EIO; 838e26ffe51SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 839e26ffe51SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 840e26ffe51SAzael Avalos return -ENODEV; 841e26ffe51SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 842e26ffe51SAzael Avalos return -EIO; 843e26ffe51SAzael Avalos } 844e26ffe51SAzael Avalos 845e26ffe51SAzael Avalos return 0; 846e26ffe51SAzael Avalos } 847e26ffe51SAzael Avalos 848e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev, 849e26ffe51SAzael Avalos u32 mode) 850e26ffe51SAzael Avalos { 851e26ffe51SAzael Avalos u32 result; 852e26ffe51SAzael Avalos 853e26ffe51SAzael Avalos if (!sci_open(dev)) 854e26ffe51SAzael Avalos return -EIO; 855e26ffe51SAzael Avalos 856e26ffe51SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode); 857e26ffe51SAzael Avalos sci_close(dev); 858e26ffe51SAzael Avalos if (result == TOS_FAILURE) { 859e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 860e26ffe51SAzael Avalos return -EIO; 861e26ffe51SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 862e26ffe51SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 863e26ffe51SAzael Avalos return -ENODEV; 864e26ffe51SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 865e26ffe51SAzael Avalos return -EIO; 866e26ffe51SAzael Avalos } 867e26ffe51SAzael Avalos 868e26ffe51SAzael Avalos return 0; 869e26ffe51SAzael Avalos } 870e26ffe51SAzael Avalos 871182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev, 872182bcaa5SAzael Avalos u32 *mode) 873182bcaa5SAzael Avalos { 874182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 875182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 876182bcaa5SAzael Avalos acpi_status status; 877182bcaa5SAzael Avalos 878182bcaa5SAzael Avalos if (!sci_open(dev)) 879182bcaa5SAzael Avalos return -EIO; 880182bcaa5SAzael Avalos 881182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 882182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 883182bcaa5SAzael Avalos sci_close(dev); 884182bcaa5SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 885182bcaa5SAzael Avalos pr_err("ACPI call to get USB S&C battery level failed\n"); 886182bcaa5SAzael Avalos return -EIO; 887182bcaa5SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 888182bcaa5SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 889182bcaa5SAzael Avalos return -ENODEV; 890182bcaa5SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 891182bcaa5SAzael Avalos return -EIO; 892182bcaa5SAzael Avalos } 893182bcaa5SAzael Avalos 894182bcaa5SAzael Avalos *mode = out[2]; 895182bcaa5SAzael Avalos 896182bcaa5SAzael Avalos return 0; 897182bcaa5SAzael Avalos } 898182bcaa5SAzael Avalos 899182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, 900182bcaa5SAzael Avalos u32 mode) 901182bcaa5SAzael Avalos { 902182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 903182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 904182bcaa5SAzael Avalos acpi_status status; 905182bcaa5SAzael Avalos 906182bcaa5SAzael Avalos if (!sci_open(dev)) 907182bcaa5SAzael Avalos return -EIO; 908182bcaa5SAzael Avalos 909182bcaa5SAzael Avalos in[2] = mode; 910182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 911182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 912182bcaa5SAzael Avalos sci_close(dev); 913182bcaa5SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 914182bcaa5SAzael Avalos pr_err("ACPI call to set USB S&C battery level failed\n"); 915182bcaa5SAzael Avalos return -EIO; 916182bcaa5SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 917182bcaa5SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 918182bcaa5SAzael Avalos return -ENODEV; 919182bcaa5SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 920182bcaa5SAzael Avalos return -EIO; 921182bcaa5SAzael Avalos } 922182bcaa5SAzael Avalos 923182bcaa5SAzael Avalos return 0; 924182bcaa5SAzael Avalos } 925182bcaa5SAzael Avalos 926bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, 927bb3fe01fSAzael Avalos u32 *state) 928bb3fe01fSAzael Avalos { 929bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 930bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 931bb3fe01fSAzael Avalos acpi_status status; 932bb3fe01fSAzael Avalos 933bb3fe01fSAzael Avalos if (!sci_open(dev)) 934bb3fe01fSAzael Avalos return -EIO; 935bb3fe01fSAzael Avalos 936bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 937bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 938bb3fe01fSAzael Avalos sci_close(dev); 939bb3fe01fSAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 940bb3fe01fSAzael Avalos pr_err("ACPI call to get USB S&C battery level failed\n"); 941bb3fe01fSAzael Avalos return -EIO; 942bb3fe01fSAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED || 943bb3fe01fSAzael Avalos out[0] == TOS_INPUT_DATA_ERROR) { 944bb3fe01fSAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 945bb3fe01fSAzael Avalos return -ENODEV; 946bb3fe01fSAzael Avalos } 947bb3fe01fSAzael Avalos 948bb3fe01fSAzael Avalos *state = out[2]; 949bb3fe01fSAzael Avalos 950bb3fe01fSAzael Avalos return 0; 951bb3fe01fSAzael Avalos } 952bb3fe01fSAzael Avalos 953bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, 954bb3fe01fSAzael Avalos u32 state) 955bb3fe01fSAzael Avalos { 956bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 957bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 958bb3fe01fSAzael Avalos acpi_status status; 959bb3fe01fSAzael Avalos 960bb3fe01fSAzael Avalos if (!sci_open(dev)) 961bb3fe01fSAzael Avalos return -EIO; 962bb3fe01fSAzael Avalos 963bb3fe01fSAzael Avalos in[2] = state; 964bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 965bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 966bb3fe01fSAzael Avalos sci_close(dev); 967bb3fe01fSAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 968bb3fe01fSAzael Avalos pr_err("ACPI call to set USB S&C battery level failed\n"); 969bb3fe01fSAzael Avalos return -EIO; 970bb3fe01fSAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 971bb3fe01fSAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 972bb3fe01fSAzael Avalos return -ENODEV; 973bb3fe01fSAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 974bb3fe01fSAzael Avalos return -EIO; 975bb3fe01fSAzael Avalos } 976bb3fe01fSAzael Avalos 977bb3fe01fSAzael Avalos return 0; 978bb3fe01fSAzael Avalos } 979bb3fe01fSAzael Avalos 980172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state) 981172ce0a9SAzael Avalos { 982172ce0a9SAzael Avalos u32 result; 983172ce0a9SAzael Avalos 984172ce0a9SAzael Avalos if (!sci_open(dev)) 985172ce0a9SAzael Avalos return -EIO; 986172ce0a9SAzael Avalos 987172ce0a9SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state); 988172ce0a9SAzael Avalos sci_close(dev); 989172ce0a9SAzael Avalos if (result == TOS_FAILURE) { 990172ce0a9SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 991172ce0a9SAzael Avalos return -EIO; 992172ce0a9SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 993172ce0a9SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 994172ce0a9SAzael Avalos return -ENODEV; 995172ce0a9SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 996172ce0a9SAzael Avalos return -EIO; 997172ce0a9SAzael Avalos } 998172ce0a9SAzael Avalos 999172ce0a9SAzael Avalos return 0; 1000172ce0a9SAzael Avalos } 1001172ce0a9SAzael Avalos 1002172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state) 1003172ce0a9SAzael Avalos { 1004172ce0a9SAzael Avalos u32 result; 1005172ce0a9SAzael Avalos 1006172ce0a9SAzael Avalos if (!sci_open(dev)) 1007172ce0a9SAzael Avalos return -EIO; 1008172ce0a9SAzael Avalos 1009172ce0a9SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state); 1010172ce0a9SAzael Avalos sci_close(dev); 1011172ce0a9SAzael Avalos if (result == TOS_FAILURE) { 1012172ce0a9SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 1013172ce0a9SAzael Avalos return -EIO; 1014172ce0a9SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1015172ce0a9SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 1016172ce0a9SAzael Avalos return -ENODEV; 1017172ce0a9SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 1018172ce0a9SAzael Avalos return -EIO; 1019172ce0a9SAzael Avalos } 1020172ce0a9SAzael Avalos 1021172ce0a9SAzael Avalos return 0; 1022172ce0a9SAzael Avalos } 1023172ce0a9SAzael Avalos 1024bae84195SAzael Avalos /* Keyboard function keys */ 1025bae84195SAzael Avalos static int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode) 1026bae84195SAzael Avalos { 1027bae84195SAzael Avalos u32 result; 1028bae84195SAzael Avalos 1029bae84195SAzael Avalos if (!sci_open(dev)) 1030bae84195SAzael Avalos return -EIO; 1031bae84195SAzael Avalos 1032bae84195SAzael Avalos result = sci_read(dev, SCI_KBD_FUNCTION_KEYS, mode); 1033bae84195SAzael Avalos sci_close(dev); 1034bae84195SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 1035bae84195SAzael Avalos pr_err("ACPI call to get KBD function keys failed\n"); 1036bae84195SAzael Avalos return -EIO; 1037bae84195SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1038bae84195SAzael Avalos pr_info("KBD function keys not supported\n"); 1039bae84195SAzael Avalos return -ENODEV; 1040bae84195SAzael Avalos } 1041bae84195SAzael Avalos 1042bae84195SAzael Avalos return 0; 1043bae84195SAzael Avalos } 1044bae84195SAzael Avalos 1045bae84195SAzael Avalos static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode) 1046bae84195SAzael Avalos { 1047bae84195SAzael Avalos u32 result; 1048bae84195SAzael Avalos 1049bae84195SAzael Avalos if (!sci_open(dev)) 1050bae84195SAzael Avalos return -EIO; 1051bae84195SAzael Avalos 1052bae84195SAzael Avalos result = sci_write(dev, SCI_KBD_FUNCTION_KEYS, mode); 1053bae84195SAzael Avalos sci_close(dev); 1054bae84195SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 1055bae84195SAzael Avalos pr_err("ACPI call to set KBD function keys failed\n"); 1056bae84195SAzael Avalos return -EIO; 1057bae84195SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1058bae84195SAzael Avalos pr_info("KBD function keys not supported\n"); 1059bae84195SAzael Avalos return -ENODEV; 1060bae84195SAzael Avalos } 1061bae84195SAzael Avalos 1062bae84195SAzael Avalos return 0; 1063bae84195SAzael Avalos } 1064bae84195SAzael Avalos 106535d53ceaSAzael Avalos /* Panel Power ON */ 106635d53ceaSAzael Avalos static int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state) 106735d53ceaSAzael Avalos { 106835d53ceaSAzael Avalos u32 result; 106935d53ceaSAzael Avalos 107035d53ceaSAzael Avalos if (!sci_open(dev)) 107135d53ceaSAzael Avalos return -EIO; 107235d53ceaSAzael Avalos 107335d53ceaSAzael Avalos result = sci_read(dev, SCI_PANEL_POWER_ON, state); 107435d53ceaSAzael Avalos sci_close(dev); 107535d53ceaSAzael Avalos if (result == TOS_FAILURE) { 107635d53ceaSAzael Avalos pr_err("ACPI call to get Panel Power ON failed\n"); 107735d53ceaSAzael Avalos return -EIO; 107835d53ceaSAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 107935d53ceaSAzael Avalos pr_info("Panel Power on not supported\n"); 108035d53ceaSAzael Avalos return -ENODEV; 108135d53ceaSAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 108235d53ceaSAzael Avalos return -EIO; 108335d53ceaSAzael Avalos } 108435d53ceaSAzael Avalos 108535d53ceaSAzael Avalos return 0; 108635d53ceaSAzael Avalos } 108735d53ceaSAzael Avalos 108835d53ceaSAzael Avalos static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state) 108935d53ceaSAzael Avalos { 109035d53ceaSAzael Avalos u32 result; 109135d53ceaSAzael Avalos 109235d53ceaSAzael Avalos if (!sci_open(dev)) 109335d53ceaSAzael Avalos return -EIO; 109435d53ceaSAzael Avalos 109535d53ceaSAzael Avalos result = sci_write(dev, SCI_PANEL_POWER_ON, state); 109635d53ceaSAzael Avalos sci_close(dev); 109735d53ceaSAzael Avalos if (result == TOS_FAILURE) { 109835d53ceaSAzael Avalos pr_err("ACPI call to set Panel Power ON failed\n"); 109935d53ceaSAzael Avalos return -EIO; 110035d53ceaSAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 110135d53ceaSAzael Avalos pr_info("Panel Power ON not supported\n"); 110235d53ceaSAzael Avalos return -ENODEV; 110335d53ceaSAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 110435d53ceaSAzael Avalos return -EIO; 110535d53ceaSAzael Avalos } 110635d53ceaSAzael Avalos 110735d53ceaSAzael Avalos return 0; 110835d53ceaSAzael Avalos } 110935d53ceaSAzael Avalos 111017fe4b3dSAzael Avalos /* USB Three */ 111117fe4b3dSAzael Avalos static int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state) 111217fe4b3dSAzael Avalos { 111317fe4b3dSAzael Avalos u32 result; 111417fe4b3dSAzael Avalos 111517fe4b3dSAzael Avalos if (!sci_open(dev)) 111617fe4b3dSAzael Avalos return -EIO; 111717fe4b3dSAzael Avalos 111817fe4b3dSAzael Avalos result = sci_read(dev, SCI_USB_THREE, state); 111917fe4b3dSAzael Avalos sci_close(dev); 112017fe4b3dSAzael Avalos if (result == TOS_FAILURE) { 112117fe4b3dSAzael Avalos pr_err("ACPI call to get USB 3 failed\n"); 112217fe4b3dSAzael Avalos return -EIO; 112317fe4b3dSAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 112417fe4b3dSAzael Avalos pr_info("USB 3 not supported\n"); 112517fe4b3dSAzael Avalos return -ENODEV; 112617fe4b3dSAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 112717fe4b3dSAzael Avalos return -EIO; 112817fe4b3dSAzael Avalos } 112917fe4b3dSAzael Avalos 113017fe4b3dSAzael Avalos return 0; 113117fe4b3dSAzael Avalos } 113217fe4b3dSAzael Avalos 113317fe4b3dSAzael Avalos static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state) 113417fe4b3dSAzael Avalos { 113517fe4b3dSAzael Avalos u32 result; 113617fe4b3dSAzael Avalos 113717fe4b3dSAzael Avalos if (!sci_open(dev)) 113817fe4b3dSAzael Avalos return -EIO; 113917fe4b3dSAzael Avalos 114017fe4b3dSAzael Avalos result = sci_write(dev, SCI_USB_THREE, state); 114117fe4b3dSAzael Avalos sci_close(dev); 114217fe4b3dSAzael Avalos if (result == TOS_FAILURE) { 114317fe4b3dSAzael Avalos pr_err("ACPI call to set USB 3 failed\n"); 114417fe4b3dSAzael Avalos return -EIO; 114517fe4b3dSAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 114617fe4b3dSAzael Avalos pr_info("USB 3 not supported\n"); 114717fe4b3dSAzael Avalos return -ENODEV; 114817fe4b3dSAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 114917fe4b3dSAzael Avalos return -EIO; 115017fe4b3dSAzael Avalos } 115117fe4b3dSAzael Avalos 115217fe4b3dSAzael Avalos return 0; 115317fe4b3dSAzael Avalos } 115417fe4b3dSAzael Avalos 1155*56e6b353SAzael Avalos /* Hotkey Event type */ 1156*56e6b353SAzael Avalos static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev, 1157*56e6b353SAzael Avalos u32 *type) 1158*56e6b353SAzael Avalos { 1159*56e6b353SAzael Avalos u32 val1 = 0x03; 1160*56e6b353SAzael Avalos u32 val2 = 0; 1161*56e6b353SAzael Avalos u32 result; 1162*56e6b353SAzael Avalos 1163*56e6b353SAzael Avalos result = hci_read2(dev, HCI_SYSTEM_INFO, &val1, &val2); 1164*56e6b353SAzael Avalos if (result == TOS_FAILURE) { 1165*56e6b353SAzael Avalos pr_err("ACPI call to get System type failed\n"); 1166*56e6b353SAzael Avalos return -EIO; 1167*56e6b353SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1168*56e6b353SAzael Avalos pr_info("System type not supported\n"); 1169*56e6b353SAzael Avalos return -ENODEV; 1170*56e6b353SAzael Avalos } 1171*56e6b353SAzael Avalos 1172*56e6b353SAzael Avalos *type = val2; 1173*56e6b353SAzael Avalos 1174*56e6b353SAzael Avalos return 0; 1175*56e6b353SAzael Avalos } 1176*56e6b353SAzael Avalos 1177b4f9fe12SLen Brown /* Bluetooth rfkill handlers */ 1178b4f9fe12SLen Brown 1179135740deSSeth Forshee static u32 hci_get_bt_present(struct toshiba_acpi_dev *dev, bool *present) 1180b4f9fe12SLen Brown { 1181b4f9fe12SLen Brown u32 hci_result; 1182b4f9fe12SLen Brown u32 value, value2; 1183b4f9fe12SLen Brown 1184b4f9fe12SLen Brown value = 0; 1185b4f9fe12SLen Brown value2 = 0; 1186893f3f62SAzael Avalos hci_result = hci_read2(dev, HCI_WIRELESS, &value, &value2); 11871864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) 1188b4f9fe12SLen Brown *present = (value & HCI_WIRELESS_BT_PRESENT) ? true : false; 1189b4f9fe12SLen Brown 1190b4f9fe12SLen Brown return hci_result; 1191b4f9fe12SLen Brown } 1192b4f9fe12SLen Brown 1193135740deSSeth Forshee static u32 hci_get_radio_state(struct toshiba_acpi_dev *dev, bool *radio_state) 1194b4f9fe12SLen Brown { 1195b4f9fe12SLen Brown u32 hci_result; 1196b4f9fe12SLen Brown u32 value, value2; 1197b4f9fe12SLen Brown 1198b4f9fe12SLen Brown value = 0; 1199b4f9fe12SLen Brown value2 = 0x0001; 1200893f3f62SAzael Avalos hci_result = hci_read2(dev, HCI_WIRELESS, &value, &value2); 1201b4f9fe12SLen Brown 1202b4f9fe12SLen Brown *radio_state = value & HCI_WIRELESS_KILL_SWITCH; 1203b4f9fe12SLen Brown return hci_result; 1204b4f9fe12SLen Brown } 1205b4f9fe12SLen Brown 120619d337dfSJohannes Berg static int bt_rfkill_set_block(void *data, bool blocked) 1207b4f9fe12SLen Brown { 120819d337dfSJohannes Berg struct toshiba_acpi_dev *dev = data; 1209b4f9fe12SLen Brown u32 result1, result2; 1210b4f9fe12SLen Brown u32 value; 121119d337dfSJohannes Berg int err; 1212b4f9fe12SLen Brown bool radio_state; 1213b4f9fe12SLen Brown 121419d337dfSJohannes Berg value = (blocked == false); 1215b4f9fe12SLen Brown 1216b4f9fe12SLen Brown mutex_lock(&dev->mutex); 12171864bbc2SAzael Avalos if (hci_get_radio_state(dev, &radio_state) != TOS_SUCCESS) { 121832bcd5cbSSeth Forshee err = -EIO; 121919d337dfSJohannes Berg goto out; 1220b4f9fe12SLen Brown } 1221b4f9fe12SLen Brown 122219d337dfSJohannes Berg if (!radio_state) { 122319d337dfSJohannes Berg err = 0; 122419d337dfSJohannes Berg goto out; 122519d337dfSJohannes Berg } 122619d337dfSJohannes Berg 1227893f3f62SAzael Avalos result1 = hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER); 1228893f3f62SAzael Avalos result2 = hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH); 122919d337dfSJohannes Berg 12301864bbc2SAzael Avalos if (result1 != TOS_SUCCESS || result2 != TOS_SUCCESS) 123132bcd5cbSSeth Forshee err = -EIO; 123219d337dfSJohannes Berg else 123319d337dfSJohannes Berg err = 0; 123419d337dfSJohannes Berg out: 123519d337dfSJohannes Berg mutex_unlock(&dev->mutex); 123619d337dfSJohannes Berg return err; 123719d337dfSJohannes Berg } 123819d337dfSJohannes Berg 123919d337dfSJohannes Berg static void bt_rfkill_poll(struct rfkill *rfkill, void *data) 1240b4f9fe12SLen Brown { 1241b4f9fe12SLen Brown bool new_rfk_state; 1242b4f9fe12SLen Brown bool value; 1243b4f9fe12SLen Brown u32 hci_result; 124419d337dfSJohannes Berg struct toshiba_acpi_dev *dev = data; 124519d337dfSJohannes Berg 124619d337dfSJohannes Berg mutex_lock(&dev->mutex); 1247b4f9fe12SLen Brown 1248135740deSSeth Forshee hci_result = hci_get_radio_state(dev, &value); 12491864bbc2SAzael Avalos if (hci_result != TOS_SUCCESS) { 125019d337dfSJohannes Berg /* Can't do anything useful */ 125119d337dfSJohannes Berg mutex_unlock(&dev->mutex); 125282e7784fSJiri Slaby return; 125319d337dfSJohannes Berg } 1254b4f9fe12SLen Brown 1255b4f9fe12SLen Brown new_rfk_state = value; 1256b4f9fe12SLen Brown 1257b4f9fe12SLen Brown mutex_unlock(&dev->mutex); 1258b4f9fe12SLen Brown 125919d337dfSJohannes Berg if (rfkill_set_hw_state(rfkill, !new_rfk_state)) 126019d337dfSJohannes Berg bt_rfkill_set_block(data, true); 1261b4f9fe12SLen Brown } 126219d337dfSJohannes Berg 126319d337dfSJohannes Berg static const struct rfkill_ops toshiba_rfk_ops = { 126419d337dfSJohannes Berg .set_block = bt_rfkill_set_block, 126519d337dfSJohannes Berg .poll = bt_rfkill_poll, 126619d337dfSJohannes Berg }; 1267b4f9fe12SLen Brown 1268121b7b0dSAkio Idehara static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled) 1269121b7b0dSAkio Idehara { 1270121b7b0dSAkio Idehara u32 hci_result; 1271121b7b0dSAkio Idehara u32 status; 1272121b7b0dSAkio Idehara 1273893f3f62SAzael Avalos hci_result = hci_read1(dev, HCI_TR_BACKLIGHT, &status); 1274121b7b0dSAkio Idehara *enabled = !status; 12751864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 1276121b7b0dSAkio Idehara } 1277121b7b0dSAkio Idehara 1278121b7b0dSAkio Idehara static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable) 1279121b7b0dSAkio Idehara { 1280121b7b0dSAkio Idehara u32 hci_result; 1281121b7b0dSAkio Idehara u32 value = !enable; 1282121b7b0dSAkio Idehara 1283893f3f62SAzael Avalos hci_result = hci_write1(dev, HCI_TR_BACKLIGHT, value); 12841864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 1285121b7b0dSAkio Idehara } 1286121b7b0dSAkio Idehara 1287b4f9fe12SLen Brown static struct proc_dir_entry *toshiba_proc_dir /*= 0*/; 1288b4f9fe12SLen Brown 128962cce752SSeth Forshee static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) 1290b4f9fe12SLen Brown { 1291b4f9fe12SLen Brown u32 hci_result; 1292b4f9fe12SLen Brown u32 value; 1293121b7b0dSAkio Idehara int brightness = 0; 1294121b7b0dSAkio Idehara 1295121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1296121b7b0dSAkio Idehara bool enabled; 1297121b7b0dSAkio Idehara int ret = get_tr_backlight_status(dev, &enabled); 1298b5163992SAzael Avalos 1299121b7b0dSAkio Idehara if (ret) 1300121b7b0dSAkio Idehara return ret; 1301121b7b0dSAkio Idehara if (enabled) 1302121b7b0dSAkio Idehara return 0; 1303121b7b0dSAkio Idehara brightness++; 1304121b7b0dSAkio Idehara } 1305b4f9fe12SLen Brown 1306893f3f62SAzael Avalos hci_result = hci_read1(dev, HCI_LCD_BRIGHTNESS, &value); 13071864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) 1308121b7b0dSAkio Idehara return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT); 130932bcd5cbSSeth Forshee 131032bcd5cbSSeth Forshee return -EIO; 1311b4f9fe12SLen Brown } 1312b4f9fe12SLen Brown 131362cce752SSeth Forshee static int get_lcd_brightness(struct backlight_device *bd) 131462cce752SSeth Forshee { 131562cce752SSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 1316b5163992SAzael Avalos 131762cce752SSeth Forshee return __get_lcd_brightness(dev); 131862cce752SSeth Forshee } 131962cce752SSeth Forshee 1320936c8bcdSAlexey Dobriyan static int lcd_proc_show(struct seq_file *m, void *v) 1321b4f9fe12SLen Brown { 1322135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1323135740deSSeth Forshee int value; 1324121b7b0dSAkio Idehara int levels; 1325b4f9fe12SLen Brown 1326135740deSSeth Forshee if (!dev->backlight_dev) 1327135740deSSeth Forshee return -ENODEV; 1328135740deSSeth Forshee 1329121b7b0dSAkio Idehara levels = dev->backlight_dev->props.max_brightness + 1; 133062cce752SSeth Forshee value = get_lcd_brightness(dev->backlight_dev); 1331b4f9fe12SLen Brown if (value >= 0) { 1332936c8bcdSAlexey Dobriyan seq_printf(m, "brightness: %d\n", value); 1333121b7b0dSAkio Idehara seq_printf(m, "brightness_levels: %d\n", levels); 133432bcd5cbSSeth Forshee return 0; 1335b4f9fe12SLen Brown } 1336b4f9fe12SLen Brown 133732bcd5cbSSeth Forshee pr_err("Error reading LCD brightness\n"); 133832bcd5cbSSeth Forshee return -EIO; 1339936c8bcdSAlexey Dobriyan } 1340936c8bcdSAlexey Dobriyan 1341936c8bcdSAlexey Dobriyan static int lcd_proc_open(struct inode *inode, struct file *file) 1342936c8bcdSAlexey Dobriyan { 1343d9dda78bSAl Viro return single_open(file, lcd_proc_show, PDE_DATA(inode)); 1344b4f9fe12SLen Brown } 1345b4f9fe12SLen Brown 134662cce752SSeth Forshee static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) 1347b4f9fe12SLen Brown { 1348a39f46dfSAzael Avalos u32 hci_result; 1349b4f9fe12SLen Brown 1350121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1351121b7b0dSAkio Idehara bool enable = !value; 1352121b7b0dSAkio Idehara int ret = set_tr_backlight_status(dev, enable); 1353b5163992SAzael Avalos 1354121b7b0dSAkio Idehara if (ret) 1355121b7b0dSAkio Idehara return ret; 1356121b7b0dSAkio Idehara if (value) 1357121b7b0dSAkio Idehara value--; 1358121b7b0dSAkio Idehara } 1359121b7b0dSAkio Idehara 1360a39f46dfSAzael Avalos value = value << HCI_LCD_BRIGHTNESS_SHIFT; 1361a39f46dfSAzael Avalos hci_result = hci_write1(dev, HCI_LCD_BRIGHTNESS, value); 1362a39f46dfSAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 1363b4f9fe12SLen Brown } 1364b4f9fe12SLen Brown 1365b4f9fe12SLen Brown static int set_lcd_status(struct backlight_device *bd) 1366b4f9fe12SLen Brown { 1367135740deSSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 1368b5163992SAzael Avalos 136962cce752SSeth Forshee return set_lcd_brightness(dev, bd->props.brightness); 1370b4f9fe12SLen Brown } 1371b4f9fe12SLen Brown 1372936c8bcdSAlexey Dobriyan static ssize_t lcd_proc_write(struct file *file, const char __user *buf, 1373936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1374b4f9fe12SLen Brown { 1375d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1376936c8bcdSAlexey Dobriyan char cmd[42]; 1377936c8bcdSAlexey Dobriyan size_t len; 1378b4f9fe12SLen Brown int value; 1379b4f9fe12SLen Brown int ret; 1380121b7b0dSAkio Idehara int levels = dev->backlight_dev->props.max_brightness + 1; 1381b4f9fe12SLen Brown 1382936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1383936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1384936c8bcdSAlexey Dobriyan return -EFAULT; 1385936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1386936c8bcdSAlexey Dobriyan 1387936c8bcdSAlexey Dobriyan if (sscanf(cmd, " brightness : %i", &value) == 1 && 1388121b7b0dSAkio Idehara value >= 0 && value < levels) { 138962cce752SSeth Forshee ret = set_lcd_brightness(dev, value); 1390b4f9fe12SLen Brown if (ret == 0) 1391b4f9fe12SLen Brown ret = count; 1392b4f9fe12SLen Brown } else { 1393b4f9fe12SLen Brown ret = -EINVAL; 1394b4f9fe12SLen Brown } 1395b4f9fe12SLen Brown return ret; 1396b4f9fe12SLen Brown } 1397b4f9fe12SLen Brown 1398936c8bcdSAlexey Dobriyan static const struct file_operations lcd_proc_fops = { 1399936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1400936c8bcdSAlexey Dobriyan .open = lcd_proc_open, 1401936c8bcdSAlexey Dobriyan .read = seq_read, 1402936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1403936c8bcdSAlexey Dobriyan .release = single_release, 1404936c8bcdSAlexey Dobriyan .write = lcd_proc_write, 1405936c8bcdSAlexey Dobriyan }; 1406936c8bcdSAlexey Dobriyan 140736d03f93SSeth Forshee static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status) 140836d03f93SSeth Forshee { 140936d03f93SSeth Forshee u32 hci_result; 141036d03f93SSeth Forshee 1411893f3f62SAzael Avalos hci_result = hci_read1(dev, HCI_VIDEO_OUT, status); 14121864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 141336d03f93SSeth Forshee } 141436d03f93SSeth Forshee 1415936c8bcdSAlexey Dobriyan static int video_proc_show(struct seq_file *m, void *v) 1416b4f9fe12SLen Brown { 1417135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1418b4f9fe12SLen Brown u32 value; 141936d03f93SSeth Forshee int ret; 1420b4f9fe12SLen Brown 142136d03f93SSeth Forshee ret = get_video_status(dev, &value); 142236d03f93SSeth Forshee if (!ret) { 1423b4f9fe12SLen Brown int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; 1424b4f9fe12SLen Brown int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; 1425b4f9fe12SLen Brown int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; 1426b5163992SAzael Avalos 1427936c8bcdSAlexey Dobriyan seq_printf(m, "lcd_out: %d\n", is_lcd); 1428936c8bcdSAlexey Dobriyan seq_printf(m, "crt_out: %d\n", is_crt); 1429936c8bcdSAlexey Dobriyan seq_printf(m, "tv_out: %d\n", is_tv); 1430b4f9fe12SLen Brown } 1431b4f9fe12SLen Brown 143236d03f93SSeth Forshee return ret; 1433b4f9fe12SLen Brown } 1434b4f9fe12SLen Brown 1435936c8bcdSAlexey Dobriyan static int video_proc_open(struct inode *inode, struct file *file) 1436b4f9fe12SLen Brown { 1437d9dda78bSAl Viro return single_open(file, video_proc_show, PDE_DATA(inode)); 1438936c8bcdSAlexey Dobriyan } 1439936c8bcdSAlexey Dobriyan 1440936c8bcdSAlexey Dobriyan static ssize_t video_proc_write(struct file *file, const char __user *buf, 1441936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1442936c8bcdSAlexey Dobriyan { 1443d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1444936c8bcdSAlexey Dobriyan char *cmd, *buffer; 144536d03f93SSeth Forshee int ret; 1446b4f9fe12SLen Brown int value; 1447b4f9fe12SLen Brown int remain = count; 1448b4f9fe12SLen Brown int lcd_out = -1; 1449b4f9fe12SLen Brown int crt_out = -1; 1450b4f9fe12SLen Brown int tv_out = -1; 1451b4f9fe12SLen Brown u32 video_out; 1452b4f9fe12SLen Brown 1453936c8bcdSAlexey Dobriyan cmd = kmalloc(count + 1, GFP_KERNEL); 1454936c8bcdSAlexey Dobriyan if (!cmd) 1455936c8bcdSAlexey Dobriyan return -ENOMEM; 1456936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, count)) { 1457936c8bcdSAlexey Dobriyan kfree(cmd); 1458936c8bcdSAlexey Dobriyan return -EFAULT; 1459936c8bcdSAlexey Dobriyan } 1460936c8bcdSAlexey Dobriyan cmd[count] = '\0'; 1461936c8bcdSAlexey Dobriyan 1462936c8bcdSAlexey Dobriyan buffer = cmd; 1463936c8bcdSAlexey Dobriyan 1464e0769fe6SDarren Hart /* 1465e0769fe6SDarren Hart * Scan expression. Multiple expressions may be delimited with ; 1466e0769fe6SDarren Hart * NOTE: To keep scanning simple, invalid fields are ignored. 1467b4f9fe12SLen Brown */ 1468b4f9fe12SLen Brown while (remain) { 1469b4f9fe12SLen Brown if (sscanf(buffer, " lcd_out : %i", &value) == 1) 1470b4f9fe12SLen Brown lcd_out = value & 1; 1471b4f9fe12SLen Brown else if (sscanf(buffer, " crt_out : %i", &value) == 1) 1472b4f9fe12SLen Brown crt_out = value & 1; 1473b4f9fe12SLen Brown else if (sscanf(buffer, " tv_out : %i", &value) == 1) 1474b4f9fe12SLen Brown tv_out = value & 1; 1475e0769fe6SDarren Hart /* Advance to one character past the next ; */ 1476b4f9fe12SLen Brown do { 1477b4f9fe12SLen Brown ++buffer; 1478b4f9fe12SLen Brown --remain; 1479b5163992SAzael Avalos } while (remain && *(buffer - 1) != ';'); 1480b4f9fe12SLen Brown } 1481b4f9fe12SLen Brown 1482936c8bcdSAlexey Dobriyan kfree(cmd); 1483936c8bcdSAlexey Dobriyan 148436d03f93SSeth Forshee ret = get_video_status(dev, &video_out); 148536d03f93SSeth Forshee if (!ret) { 1486b4f9fe12SLen Brown unsigned int new_video_out = video_out; 1487b5163992SAzael Avalos 1488b4f9fe12SLen Brown if (lcd_out != -1) 1489b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out); 1490b4f9fe12SLen Brown if (crt_out != -1) 1491b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out); 1492b4f9fe12SLen Brown if (tv_out != -1) 1493b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out); 1494e0769fe6SDarren Hart /* 1495e0769fe6SDarren Hart * To avoid unnecessary video disruption, only write the new 1496b4f9fe12SLen Brown * video setting if something changed. */ 1497b4f9fe12SLen Brown if (new_video_out != video_out) 149832bcd5cbSSeth Forshee ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out); 1499b4f9fe12SLen Brown } 1500b4f9fe12SLen Brown 150132bcd5cbSSeth Forshee return ret ? ret : count; 1502b4f9fe12SLen Brown } 1503b4f9fe12SLen Brown 1504936c8bcdSAlexey Dobriyan static const struct file_operations video_proc_fops = { 1505936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1506936c8bcdSAlexey Dobriyan .open = video_proc_open, 1507936c8bcdSAlexey Dobriyan .read = seq_read, 1508936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1509936c8bcdSAlexey Dobriyan .release = single_release, 1510936c8bcdSAlexey Dobriyan .write = video_proc_write, 1511936c8bcdSAlexey Dobriyan }; 1512936c8bcdSAlexey Dobriyan 151336d03f93SSeth Forshee static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status) 151436d03f93SSeth Forshee { 151536d03f93SSeth Forshee u32 hci_result; 151636d03f93SSeth Forshee 1517893f3f62SAzael Avalos hci_result = hci_read1(dev, HCI_FAN, status); 15181864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 151936d03f93SSeth Forshee } 152036d03f93SSeth Forshee 1521936c8bcdSAlexey Dobriyan static int fan_proc_show(struct seq_file *m, void *v) 1522b4f9fe12SLen Brown { 1523135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 152436d03f93SSeth Forshee int ret; 1525b4f9fe12SLen Brown u32 value; 1526b4f9fe12SLen Brown 152736d03f93SSeth Forshee ret = get_fan_status(dev, &value); 152836d03f93SSeth Forshee if (!ret) { 1529936c8bcdSAlexey Dobriyan seq_printf(m, "running: %d\n", (value > 0)); 1530135740deSSeth Forshee seq_printf(m, "force_on: %d\n", dev->force_fan); 1531b4f9fe12SLen Brown } 1532b4f9fe12SLen Brown 153336d03f93SSeth Forshee return ret; 1534b4f9fe12SLen Brown } 1535b4f9fe12SLen Brown 1536936c8bcdSAlexey Dobriyan static int fan_proc_open(struct inode *inode, struct file *file) 1537b4f9fe12SLen Brown { 1538d9dda78bSAl Viro return single_open(file, fan_proc_show, PDE_DATA(inode)); 1539936c8bcdSAlexey Dobriyan } 1540936c8bcdSAlexey Dobriyan 1541936c8bcdSAlexey Dobriyan static ssize_t fan_proc_write(struct file *file, const char __user *buf, 1542936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1543936c8bcdSAlexey Dobriyan { 1544d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1545936c8bcdSAlexey Dobriyan char cmd[42]; 1546936c8bcdSAlexey Dobriyan size_t len; 1547b4f9fe12SLen Brown int value; 1548b4f9fe12SLen Brown u32 hci_result; 1549b4f9fe12SLen Brown 1550936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1551936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1552936c8bcdSAlexey Dobriyan return -EFAULT; 1553936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1554936c8bcdSAlexey Dobriyan 1555936c8bcdSAlexey Dobriyan if (sscanf(cmd, " force_on : %i", &value) == 1 && 1556b4f9fe12SLen Brown value >= 0 && value <= 1) { 1557893f3f62SAzael Avalos hci_result = hci_write1(dev, HCI_FAN, value); 1558b5163992SAzael Avalos if (hci_result == TOS_SUCCESS) 1559135740deSSeth Forshee dev->force_fan = value; 1560b5163992SAzael Avalos else 1561b5163992SAzael Avalos return -EIO; 1562b4f9fe12SLen Brown } else { 1563b4f9fe12SLen Brown return -EINVAL; 1564b4f9fe12SLen Brown } 1565b4f9fe12SLen Brown 1566b4f9fe12SLen Brown return count; 1567b4f9fe12SLen Brown } 1568b4f9fe12SLen Brown 1569936c8bcdSAlexey Dobriyan static const struct file_operations fan_proc_fops = { 1570936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1571936c8bcdSAlexey Dobriyan .open = fan_proc_open, 1572936c8bcdSAlexey Dobriyan .read = seq_read, 1573936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1574936c8bcdSAlexey Dobriyan .release = single_release, 1575936c8bcdSAlexey Dobriyan .write = fan_proc_write, 1576936c8bcdSAlexey Dobriyan }; 1577936c8bcdSAlexey Dobriyan 1578936c8bcdSAlexey Dobriyan static int keys_proc_show(struct seq_file *m, void *v) 1579b4f9fe12SLen Brown { 1580135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1581b4f9fe12SLen Brown u32 hci_result; 1582b4f9fe12SLen Brown u32 value; 1583b4f9fe12SLen Brown 158411948b93SSeth Forshee if (!dev->key_event_valid && dev->system_event_supported) { 1585893f3f62SAzael Avalos hci_result = hci_read1(dev, HCI_SYSTEM_EVENT, &value); 15861864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) { 1587135740deSSeth Forshee dev->key_event_valid = 1; 1588135740deSSeth Forshee dev->last_key_event = value; 15891864bbc2SAzael Avalos } else if (hci_result == TOS_FIFO_EMPTY) { 1590e0769fe6SDarren Hart /* Better luck next time */ 15911864bbc2SAzael Avalos } else if (hci_result == TOS_NOT_SUPPORTED) { 1592e0769fe6SDarren Hart /* 1593e0769fe6SDarren Hart * This is a workaround for an unresolved issue on 1594b4f9fe12SLen Brown * some machines where system events sporadically 1595e0769fe6SDarren Hart * become disabled. 1596e0769fe6SDarren Hart */ 1597893f3f62SAzael Avalos hci_result = hci_write1(dev, HCI_SYSTEM_EVENT, 1); 15987e33460dSJoe Perches pr_notice("Re-enabled hotkeys\n"); 1599b4f9fe12SLen Brown } else { 16007e33460dSJoe Perches pr_err("Error reading hotkey status\n"); 160132bcd5cbSSeth Forshee return -EIO; 1602b4f9fe12SLen Brown } 1603b4f9fe12SLen Brown } 1604b4f9fe12SLen Brown 1605135740deSSeth Forshee seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid); 1606135740deSSeth Forshee seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event); 1607936c8bcdSAlexey Dobriyan return 0; 1608b4f9fe12SLen Brown } 1609b4f9fe12SLen Brown 1610936c8bcdSAlexey Dobriyan static int keys_proc_open(struct inode *inode, struct file *file) 1611b4f9fe12SLen Brown { 1612d9dda78bSAl Viro return single_open(file, keys_proc_show, PDE_DATA(inode)); 1613936c8bcdSAlexey Dobriyan } 1614936c8bcdSAlexey Dobriyan 1615936c8bcdSAlexey Dobriyan static ssize_t keys_proc_write(struct file *file, const char __user *buf, 1616936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1617936c8bcdSAlexey Dobriyan { 1618d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1619936c8bcdSAlexey Dobriyan char cmd[42]; 1620936c8bcdSAlexey Dobriyan size_t len; 1621b4f9fe12SLen Brown int value; 1622b4f9fe12SLen Brown 1623936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1624936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1625936c8bcdSAlexey Dobriyan return -EFAULT; 1626936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1627936c8bcdSAlexey Dobriyan 1628b5163992SAzael Avalos if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) 1629135740deSSeth Forshee dev->key_event_valid = 0; 1630b5163992SAzael Avalos else 1631b4f9fe12SLen Brown return -EINVAL; 1632b4f9fe12SLen Brown 1633b4f9fe12SLen Brown return count; 1634b4f9fe12SLen Brown } 1635b4f9fe12SLen Brown 1636936c8bcdSAlexey Dobriyan static const struct file_operations keys_proc_fops = { 1637936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1638936c8bcdSAlexey Dobriyan .open = keys_proc_open, 1639936c8bcdSAlexey Dobriyan .read = seq_read, 1640936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1641936c8bcdSAlexey Dobriyan .release = single_release, 1642936c8bcdSAlexey Dobriyan .write = keys_proc_write, 1643936c8bcdSAlexey Dobriyan }; 1644936c8bcdSAlexey Dobriyan 1645936c8bcdSAlexey Dobriyan static int version_proc_show(struct seq_file *m, void *v) 1646b4f9fe12SLen Brown { 1647936c8bcdSAlexey Dobriyan seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION); 1648936c8bcdSAlexey Dobriyan seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION); 1649936c8bcdSAlexey Dobriyan return 0; 1650b4f9fe12SLen Brown } 1651b4f9fe12SLen Brown 1652936c8bcdSAlexey Dobriyan static int version_proc_open(struct inode *inode, struct file *file) 1653936c8bcdSAlexey Dobriyan { 1654d9dda78bSAl Viro return single_open(file, version_proc_show, PDE_DATA(inode)); 1655936c8bcdSAlexey Dobriyan } 1656936c8bcdSAlexey Dobriyan 1657936c8bcdSAlexey Dobriyan static const struct file_operations version_proc_fops = { 1658936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1659936c8bcdSAlexey Dobriyan .open = version_proc_open, 1660936c8bcdSAlexey Dobriyan .read = seq_read, 1661936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1662936c8bcdSAlexey Dobriyan .release = single_release, 1663936c8bcdSAlexey Dobriyan }; 1664936c8bcdSAlexey Dobriyan 1665e0769fe6SDarren Hart /* 1666e0769fe6SDarren Hart * Proc and module init 1667b4f9fe12SLen Brown */ 1668b4f9fe12SLen Brown 1669b4f9fe12SLen Brown #define PROC_TOSHIBA "toshiba" 1670b4f9fe12SLen Brown 1671b859f159SGreg Kroah-Hartman static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1672b4f9fe12SLen Brown { 167336d03f93SSeth Forshee if (dev->backlight_dev) 1674135740deSSeth Forshee proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1675135740deSSeth Forshee &lcd_proc_fops, dev); 167636d03f93SSeth Forshee if (dev->video_supported) 1677135740deSSeth Forshee proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1678135740deSSeth Forshee &video_proc_fops, dev); 167936d03f93SSeth Forshee if (dev->fan_supported) 1680135740deSSeth Forshee proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1681135740deSSeth Forshee &fan_proc_fops, dev); 168236d03f93SSeth Forshee if (dev->hotkey_dev) 1683135740deSSeth Forshee proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1684135740deSSeth Forshee &keys_proc_fops, dev); 1685135740deSSeth Forshee proc_create_data("version", S_IRUGO, toshiba_proc_dir, 1686135740deSSeth Forshee &version_proc_fops, dev); 1687b4f9fe12SLen Brown } 1688b4f9fe12SLen Brown 168936d03f93SSeth Forshee static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1690b4f9fe12SLen Brown { 169136d03f93SSeth Forshee if (dev->backlight_dev) 1692936c8bcdSAlexey Dobriyan remove_proc_entry("lcd", toshiba_proc_dir); 169336d03f93SSeth Forshee if (dev->video_supported) 1694936c8bcdSAlexey Dobriyan remove_proc_entry("video", toshiba_proc_dir); 169536d03f93SSeth Forshee if (dev->fan_supported) 1696936c8bcdSAlexey Dobriyan remove_proc_entry("fan", toshiba_proc_dir); 169736d03f93SSeth Forshee if (dev->hotkey_dev) 1698936c8bcdSAlexey Dobriyan remove_proc_entry("keys", toshiba_proc_dir); 1699936c8bcdSAlexey Dobriyan remove_proc_entry("version", toshiba_proc_dir); 1700b4f9fe12SLen Brown } 1701b4f9fe12SLen Brown 1702acc2472eSLionel Debroux static const struct backlight_ops toshiba_backlight_data = { 1703121b7b0dSAkio Idehara .options = BL_CORE_SUSPENDRESUME, 170462cce752SSeth Forshee .get_brightness = get_lcd_brightness, 1705b4f9fe12SLen Brown .update_status = set_lcd_status, 1706b4f9fe12SLen Brown }; 1707b4f9fe12SLen Brown 1708360f0f39SAzael Avalos /* 1709360f0f39SAzael Avalos * Sysfs files 1710360f0f39SAzael Avalos */ 17119d309848SAzael Avalos static ssize_t version_show(struct device *dev, 1712c6c68ff8SAzael Avalos struct device_attribute *attr, char *buf) 1713c6c68ff8SAzael Avalos { 1714c6c68ff8SAzael Avalos return sprintf(buf, "%s\n", TOSHIBA_ACPI_VERSION); 1715c6c68ff8SAzael Avalos } 17160c3c0f10SAzael Avalos static DEVICE_ATTR_RO(version); 1717c6c68ff8SAzael Avalos 17189d309848SAzael Avalos static ssize_t fan_store(struct device *dev, 171994477d4cSAzael Avalos struct device_attribute *attr, 172094477d4cSAzael Avalos const char *buf, size_t count) 172194477d4cSAzael Avalos { 172294477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 172394477d4cSAzael Avalos u32 result; 172494477d4cSAzael Avalos int state; 172594477d4cSAzael Avalos int ret; 172694477d4cSAzael Avalos 172794477d4cSAzael Avalos ret = kstrtoint(buf, 0, &state); 172894477d4cSAzael Avalos if (ret) 172994477d4cSAzael Avalos return ret; 173094477d4cSAzael Avalos 173194477d4cSAzael Avalos if (state != 0 && state != 1) 173294477d4cSAzael Avalos return -EINVAL; 173394477d4cSAzael Avalos 173494477d4cSAzael Avalos result = hci_write1(toshiba, HCI_FAN, state); 173594477d4cSAzael Avalos if (result == TOS_FAILURE) 173694477d4cSAzael Avalos return -EIO; 173794477d4cSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 173894477d4cSAzael Avalos return -ENODEV; 173994477d4cSAzael Avalos 174094477d4cSAzael Avalos return count; 174194477d4cSAzael Avalos } 174294477d4cSAzael Avalos 17439d309848SAzael Avalos static ssize_t fan_show(struct device *dev, 174494477d4cSAzael Avalos struct device_attribute *attr, char *buf) 174594477d4cSAzael Avalos { 174694477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 174794477d4cSAzael Avalos u32 value; 174894477d4cSAzael Avalos int ret; 174994477d4cSAzael Avalos 175094477d4cSAzael Avalos ret = get_fan_status(toshiba, &value); 175194477d4cSAzael Avalos if (ret) 175294477d4cSAzael Avalos return ret; 175394477d4cSAzael Avalos 175494477d4cSAzael Avalos return sprintf(buf, "%d\n", value); 175594477d4cSAzael Avalos } 17560c3c0f10SAzael Avalos static DEVICE_ATTR_RW(fan); 175794477d4cSAzael Avalos 17589d309848SAzael Avalos static ssize_t kbd_backlight_mode_store(struct device *dev, 1759360f0f39SAzael Avalos struct device_attribute *attr, 1760360f0f39SAzael Avalos const char *buf, size_t count) 1761360f0f39SAzael Avalos { 1762360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1763aeaac098SDan Carpenter int mode; 1764aeaac098SDan Carpenter int time; 1765aeaac098SDan Carpenter int ret; 1766360f0f39SAzael Avalos 1767aeaac098SDan Carpenter 1768aeaac098SDan Carpenter ret = kstrtoint(buf, 0, &mode); 1769aeaac098SDan Carpenter if (ret) 1770aeaac098SDan Carpenter return ret; 177193f8c16dSAzael Avalos 177293f8c16dSAzael Avalos /* Check for supported modes depending on keyboard backlight type */ 177393f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 177493f8c16dSAzael Avalos /* Type 1 supports SCI_KBD_MODE_FNZ and SCI_KBD_MODE_AUTO */ 1775aeaac098SDan Carpenter if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO) 1776360f0f39SAzael Avalos return -EINVAL; 177793f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 177893f8c16dSAzael Avalos /* Type 2 doesn't support SCI_KBD_MODE_FNZ */ 177993f8c16dSAzael Avalos if (mode != SCI_KBD_MODE_AUTO && mode != SCI_KBD_MODE_ON && 178093f8c16dSAzael Avalos mode != SCI_KBD_MODE_OFF) 178193f8c16dSAzael Avalos return -EINVAL; 178293f8c16dSAzael Avalos } 1783360f0f39SAzael Avalos 1784e0769fe6SDarren Hart /* 1785e0769fe6SDarren Hart * Set the Keyboard Backlight Mode where: 1786360f0f39SAzael Avalos * Auto - KBD backlight turns off automatically in given time 1787360f0f39SAzael Avalos * FN-Z - KBD backlight "toggles" when hotkey pressed 178893f8c16dSAzael Avalos * ON - KBD backlight is always on 178993f8c16dSAzael Avalos * OFF - KBD backlight is always off 1790360f0f39SAzael Avalos */ 179193f8c16dSAzael Avalos 179293f8c16dSAzael Avalos /* Only make a change if the actual mode has changed */ 1793aeaac098SDan Carpenter if (toshiba->kbd_mode != mode) { 179493f8c16dSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 1795360f0f39SAzael Avalos time = toshiba->kbd_time << HCI_MISC_SHIFT; 179693f8c16dSAzael Avalos 179793f8c16dSAzael Avalos /* OR the "base time" to the actual method format */ 179893f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 179993f8c16dSAzael Avalos /* Type 1 requires the current mode */ 180093f8c16dSAzael Avalos time |= toshiba->kbd_mode; 180193f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 180293f8c16dSAzael Avalos /* Type 2 requires the desired mode */ 180393f8c16dSAzael Avalos time |= mode; 180493f8c16dSAzael Avalos } 180593f8c16dSAzael Avalos 1806aeaac098SDan Carpenter ret = toshiba_kbd_illum_status_set(toshiba, time); 1807aeaac098SDan Carpenter if (ret) 1808aeaac098SDan Carpenter return ret; 180993f8c16dSAzael Avalos 1810360f0f39SAzael Avalos toshiba->kbd_mode = mode; 1811360f0f39SAzael Avalos } 1812360f0f39SAzael Avalos 1813360f0f39SAzael Avalos return count; 1814360f0f39SAzael Avalos } 1815360f0f39SAzael Avalos 18169d309848SAzael Avalos static ssize_t kbd_backlight_mode_show(struct device *dev, 1817360f0f39SAzael Avalos struct device_attribute *attr, 1818360f0f39SAzael Avalos char *buf) 1819360f0f39SAzael Avalos { 1820360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1821360f0f39SAzael Avalos u32 time; 1822360f0f39SAzael Avalos 1823360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1824360f0f39SAzael Avalos return -EIO; 1825360f0f39SAzael Avalos 182693f8c16dSAzael Avalos return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK); 182793f8c16dSAzael Avalos } 18280c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_mode); 182993f8c16dSAzael Avalos 18309d309848SAzael Avalos static ssize_t kbd_type_show(struct device *dev, 18319d309848SAzael Avalos struct device_attribute *attr, char *buf) 183293f8c16dSAzael Avalos { 183393f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 183493f8c16dSAzael Avalos 183593f8c16dSAzael Avalos return sprintf(buf, "%d\n", toshiba->kbd_type); 183693f8c16dSAzael Avalos } 18370c3c0f10SAzael Avalos static DEVICE_ATTR_RO(kbd_type); 183893f8c16dSAzael Avalos 18399d309848SAzael Avalos static ssize_t available_kbd_modes_show(struct device *dev, 184093f8c16dSAzael Avalos struct device_attribute *attr, 184193f8c16dSAzael Avalos char *buf) 184293f8c16dSAzael Avalos { 184393f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 184493f8c16dSAzael Avalos 184593f8c16dSAzael Avalos if (toshiba->kbd_type == 1) 184693f8c16dSAzael Avalos return sprintf(buf, "%x %x\n", 184793f8c16dSAzael Avalos SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO); 184893f8c16dSAzael Avalos 184993f8c16dSAzael Avalos return sprintf(buf, "%x %x %x\n", 185093f8c16dSAzael Avalos SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF); 1851360f0f39SAzael Avalos } 18520c3c0f10SAzael Avalos static DEVICE_ATTR_RO(available_kbd_modes); 1853360f0f39SAzael Avalos 18549d309848SAzael Avalos static ssize_t kbd_backlight_timeout_store(struct device *dev, 1855360f0f39SAzael Avalos struct device_attribute *attr, 1856360f0f39SAzael Avalos const char *buf, size_t count) 1857360f0f39SAzael Avalos { 1858360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1859eabde0faSAzael Avalos int time; 1860eabde0faSAzael Avalos int ret; 1861360f0f39SAzael Avalos 1862eabde0faSAzael Avalos ret = kstrtoint(buf, 0, &time); 1863eabde0faSAzael Avalos if (ret) 1864eabde0faSAzael Avalos return ret; 1865eabde0faSAzael Avalos 1866eabde0faSAzael Avalos /* Check for supported values depending on kbd_type */ 1867eabde0faSAzael Avalos if (toshiba->kbd_type == 1) { 1868eabde0faSAzael Avalos if (time < 0 || time > 60) 1869360f0f39SAzael Avalos return -EINVAL; 1870eabde0faSAzael Avalos } else if (toshiba->kbd_type == 2) { 1871eabde0faSAzael Avalos if (time < 1 || time > 60) 1872eabde0faSAzael Avalos return -EINVAL; 1873eabde0faSAzael Avalos } 1874360f0f39SAzael Avalos 1875eabde0faSAzael Avalos /* Set the Keyboard Backlight Timeout */ 1876eabde0faSAzael Avalos 1877eabde0faSAzael Avalos /* Only make a change if the actual timeout has changed */ 1878eabde0faSAzael Avalos if (toshiba->kbd_time != time) { 1879eabde0faSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 1880360f0f39SAzael Avalos time = time << HCI_MISC_SHIFT; 1881eabde0faSAzael Avalos /* OR the "base time" to the actual method format */ 1882eabde0faSAzael Avalos if (toshiba->kbd_type == 1) 1883eabde0faSAzael Avalos time |= SCI_KBD_MODE_FNZ; 1884eabde0faSAzael Avalos else if (toshiba->kbd_type == 2) 1885eabde0faSAzael Avalos time |= SCI_KBD_MODE_AUTO; 1886eabde0faSAzael Avalos 1887eabde0faSAzael Avalos ret = toshiba_kbd_illum_status_set(toshiba, time); 1888eabde0faSAzael Avalos if (ret) 1889eabde0faSAzael Avalos return ret; 1890eabde0faSAzael Avalos 1891360f0f39SAzael Avalos toshiba->kbd_time = time >> HCI_MISC_SHIFT; 1892360f0f39SAzael Avalos } 1893360f0f39SAzael Avalos 1894360f0f39SAzael Avalos return count; 1895360f0f39SAzael Avalos } 1896360f0f39SAzael Avalos 18979d309848SAzael Avalos static ssize_t kbd_backlight_timeout_show(struct device *dev, 1898360f0f39SAzael Avalos struct device_attribute *attr, 1899360f0f39SAzael Avalos char *buf) 1900360f0f39SAzael Avalos { 1901360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1902360f0f39SAzael Avalos u32 time; 1903360f0f39SAzael Avalos 1904360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1905360f0f39SAzael Avalos return -EIO; 1906360f0f39SAzael Avalos 1907360f0f39SAzael Avalos return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT); 1908360f0f39SAzael Avalos } 19090c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_timeout); 1910360f0f39SAzael Avalos 19119d309848SAzael Avalos static ssize_t touchpad_store(struct device *dev, 19129d8658acSAzael Avalos struct device_attribute *attr, 19139d8658acSAzael Avalos const char *buf, size_t count) 19149d8658acSAzael Avalos { 19159d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 19169d8658acSAzael Avalos int state; 1917c8a41669SAzael Avalos int ret; 19189d8658acSAzael Avalos 19199d8658acSAzael Avalos /* Set the TouchPad on/off, 0 - Disable | 1 - Enable */ 1920c8a41669SAzael Avalos ret = kstrtoint(buf, 0, &state); 1921c8a41669SAzael Avalos if (ret) 1922c8a41669SAzael Avalos return ret; 1923c8a41669SAzael Avalos if (state != 0 && state != 1) 1924c8a41669SAzael Avalos return -EINVAL; 1925c8a41669SAzael Avalos 1926c8a41669SAzael Avalos ret = toshiba_touchpad_set(toshiba, state); 1927c8a41669SAzael Avalos if (ret) 1928c8a41669SAzael Avalos return ret; 19299d8658acSAzael Avalos 19309d8658acSAzael Avalos return count; 19319d8658acSAzael Avalos } 19329d8658acSAzael Avalos 19339d309848SAzael Avalos static ssize_t touchpad_show(struct device *dev, 19349d8658acSAzael Avalos struct device_attribute *attr, char *buf) 19359d8658acSAzael Avalos { 19369d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 19379d8658acSAzael Avalos u32 state; 19389d8658acSAzael Avalos int ret; 19399d8658acSAzael Avalos 19409d8658acSAzael Avalos ret = toshiba_touchpad_get(toshiba, &state); 19419d8658acSAzael Avalos if (ret < 0) 19429d8658acSAzael Avalos return ret; 19439d8658acSAzael Avalos 19449d8658acSAzael Avalos return sprintf(buf, "%i\n", state); 19459d8658acSAzael Avalos } 19460c3c0f10SAzael Avalos static DEVICE_ATTR_RW(touchpad); 19479d8658acSAzael Avalos 19489d309848SAzael Avalos static ssize_t position_show(struct device *dev, 19495a2813e9SAzael Avalos struct device_attribute *attr, char *buf) 19505a2813e9SAzael Avalos { 19515a2813e9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 19525a2813e9SAzael Avalos u32 xyval, zval, tmp; 19535a2813e9SAzael Avalos u16 x, y, z; 19545a2813e9SAzael Avalos int ret; 19555a2813e9SAzael Avalos 19565a2813e9SAzael Avalos xyval = zval = 0; 19575a2813e9SAzael Avalos ret = toshiba_accelerometer_get(toshiba, &xyval, &zval); 19585a2813e9SAzael Avalos if (ret < 0) 19595a2813e9SAzael Avalos return ret; 19605a2813e9SAzael Avalos 19615a2813e9SAzael Avalos x = xyval & HCI_ACCEL_MASK; 19625a2813e9SAzael Avalos tmp = xyval >> HCI_MISC_SHIFT; 19635a2813e9SAzael Avalos y = tmp & HCI_ACCEL_MASK; 19645a2813e9SAzael Avalos z = zval & HCI_ACCEL_MASK; 19655a2813e9SAzael Avalos 19665a2813e9SAzael Avalos return sprintf(buf, "%d %d %d\n", x, y, z); 19675a2813e9SAzael Avalos } 19680c3c0f10SAzael Avalos static DEVICE_ATTR_RO(position); 19695a2813e9SAzael Avalos 19709d309848SAzael Avalos static ssize_t usb_sleep_charge_show(struct device *dev, 19719d309848SAzael Avalos struct device_attribute *attr, char *buf) 1972e26ffe51SAzael Avalos { 1973e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1974e26ffe51SAzael Avalos u32 mode; 1975e26ffe51SAzael Avalos int ret; 1976e26ffe51SAzael Avalos 1977e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_get(toshiba, &mode); 1978e26ffe51SAzael Avalos if (ret < 0) 1979e26ffe51SAzael Avalos return ret; 1980e26ffe51SAzael Avalos 1981e26ffe51SAzael Avalos return sprintf(buf, "%x\n", mode & SCI_USB_CHARGE_MODE_MASK); 1982e26ffe51SAzael Avalos } 1983e26ffe51SAzael Avalos 19849d309848SAzael Avalos static ssize_t usb_sleep_charge_store(struct device *dev, 1985e26ffe51SAzael Avalos struct device_attribute *attr, 1986e26ffe51SAzael Avalos const char *buf, size_t count) 1987e26ffe51SAzael Avalos { 1988e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1989e26ffe51SAzael Avalos u32 mode; 1990e26ffe51SAzael Avalos int state; 1991e26ffe51SAzael Avalos int ret; 1992e26ffe51SAzael Avalos 1993e26ffe51SAzael Avalos ret = kstrtoint(buf, 0, &state); 1994e26ffe51SAzael Avalos if (ret) 1995e26ffe51SAzael Avalos return ret; 1996e0769fe6SDarren Hart /* 1997e0769fe6SDarren Hart * Check for supported values, where: 1998e26ffe51SAzael Avalos * 0 - Disabled 1999e26ffe51SAzael Avalos * 1 - Alternate (Non USB conformant devices that require more power) 2000e26ffe51SAzael Avalos * 2 - Auto (USB conformant devices) 2001e26ffe51SAzael Avalos */ 2002e26ffe51SAzael Avalos if (state != 0 && state != 1 && state != 2) 2003e26ffe51SAzael Avalos return -EINVAL; 2004e26ffe51SAzael Avalos 2005e26ffe51SAzael Avalos /* Set the USB charging mode to internal value */ 2006e26ffe51SAzael Avalos if (state == 0) 2007e26ffe51SAzael Avalos mode = SCI_USB_CHARGE_DISABLED; 2008e26ffe51SAzael Avalos else if (state == 1) 2009e26ffe51SAzael Avalos mode = SCI_USB_CHARGE_ALTERNATE; 2010e26ffe51SAzael Avalos else if (state == 2) 2011e26ffe51SAzael Avalos mode = SCI_USB_CHARGE_AUTO; 2012e26ffe51SAzael Avalos 2013e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_set(toshiba, mode); 2014e26ffe51SAzael Avalos if (ret) 2015e26ffe51SAzael Avalos return ret; 2016e26ffe51SAzael Avalos 2017e26ffe51SAzael Avalos return count; 2018e26ffe51SAzael Avalos } 20190c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_charge); 2020e26ffe51SAzael Avalos 2021182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_show(struct device *dev, 2022182bcaa5SAzael Avalos struct device_attribute *attr, 2023182bcaa5SAzael Avalos char *buf) 2024182bcaa5SAzael Avalos { 2025182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2026182bcaa5SAzael Avalos u32 state; 2027182bcaa5SAzael Avalos int bat_lvl; 2028182bcaa5SAzael Avalos int status; 2029182bcaa5SAzael Avalos int ret; 2030182bcaa5SAzael Avalos int tmp; 2031182bcaa5SAzael Avalos 2032182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_get(toshiba, &state); 2033182bcaa5SAzael Avalos if (ret < 0) 2034182bcaa5SAzael Avalos return ret; 2035182bcaa5SAzael Avalos 2036182bcaa5SAzael Avalos /* Determine the status: 0x4 - Enabled | 0x1 - Disabled */ 2037182bcaa5SAzael Avalos tmp = state & SCI_USB_CHARGE_BAT_MASK; 2038182bcaa5SAzael Avalos status = (tmp == 0x4) ? 1 : 0; 2039182bcaa5SAzael Avalos /* Determine the battery level set */ 2040182bcaa5SAzael Avalos bat_lvl = state >> HCI_MISC_SHIFT; 2041182bcaa5SAzael Avalos 2042182bcaa5SAzael Avalos return sprintf(buf, "%d %d\n", status, bat_lvl); 2043182bcaa5SAzael Avalos } 2044182bcaa5SAzael Avalos 2045182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_store(struct device *dev, 2046182bcaa5SAzael Avalos struct device_attribute *attr, 2047182bcaa5SAzael Avalos const char *buf, size_t count) 2048182bcaa5SAzael Avalos { 2049182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2050182bcaa5SAzael Avalos u32 status; 2051182bcaa5SAzael Avalos int value; 2052182bcaa5SAzael Avalos int ret; 2053182bcaa5SAzael Avalos int tmp; 2054182bcaa5SAzael Avalos 2055182bcaa5SAzael Avalos ret = kstrtoint(buf, 0, &value); 2056182bcaa5SAzael Avalos if (ret) 2057182bcaa5SAzael Avalos return ret; 2058182bcaa5SAzael Avalos 2059e0769fe6SDarren Hart /* 2060e0769fe6SDarren Hart * Set the status of the function: 2061182bcaa5SAzael Avalos * 0 - Disabled 2062182bcaa5SAzael Avalos * 1-100 - Enabled 2063182bcaa5SAzael Avalos */ 2064182bcaa5SAzael Avalos if (value < 0 || value > 100) 2065182bcaa5SAzael Avalos return -EINVAL; 2066182bcaa5SAzael Avalos 2067182bcaa5SAzael Avalos if (value == 0) { 2068182bcaa5SAzael Avalos tmp = toshiba->usbsc_bat_level << HCI_MISC_SHIFT; 2069182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_OFF; 2070182bcaa5SAzael Avalos } else { 2071182bcaa5SAzael Avalos tmp = value << HCI_MISC_SHIFT; 2072182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_ON; 2073182bcaa5SAzael Avalos } 2074182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_set(toshiba, status); 2075182bcaa5SAzael Avalos if (ret < 0) 2076182bcaa5SAzael Avalos return ret; 2077182bcaa5SAzael Avalos 2078182bcaa5SAzael Avalos toshiba->usbsc_bat_level = status >> HCI_MISC_SHIFT; 2079182bcaa5SAzael Avalos 2080182bcaa5SAzael Avalos return count; 2081182bcaa5SAzael Avalos } 20820c3c0f10SAzael Avalos static DEVICE_ATTR_RW(sleep_functions_on_battery); 2083182bcaa5SAzael Avalos 20849d309848SAzael Avalos static ssize_t usb_rapid_charge_show(struct device *dev, 20859d309848SAzael Avalos struct device_attribute *attr, char *buf) 2086bb3fe01fSAzael Avalos { 2087bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2088bb3fe01fSAzael Avalos u32 state; 2089bb3fe01fSAzael Avalos int ret; 2090bb3fe01fSAzael Avalos 2091bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(toshiba, &state); 2092bb3fe01fSAzael Avalos if (ret < 0) 2093bb3fe01fSAzael Avalos return ret; 2094bb3fe01fSAzael Avalos 2095bb3fe01fSAzael Avalos return sprintf(buf, "%d\n", state); 2096bb3fe01fSAzael Avalos } 2097bb3fe01fSAzael Avalos 20989d309848SAzael Avalos static ssize_t usb_rapid_charge_store(struct device *dev, 2099bb3fe01fSAzael Avalos struct device_attribute *attr, 2100bb3fe01fSAzael Avalos const char *buf, size_t count) 2101bb3fe01fSAzael Avalos { 2102bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2103bb3fe01fSAzael Avalos int state; 2104bb3fe01fSAzael Avalos int ret; 2105bb3fe01fSAzael Avalos 2106bb3fe01fSAzael Avalos ret = kstrtoint(buf, 0, &state); 2107bb3fe01fSAzael Avalos if (ret) 2108bb3fe01fSAzael Avalos return ret; 2109bb3fe01fSAzael Avalos if (state != 0 && state != 1) 2110bb3fe01fSAzael Avalos return -EINVAL; 2111bb3fe01fSAzael Avalos 2112bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_set(toshiba, state); 2113bb3fe01fSAzael Avalos if (ret) 2114bb3fe01fSAzael Avalos return ret; 2115bb3fe01fSAzael Avalos 2116bb3fe01fSAzael Avalos return count; 2117bb3fe01fSAzael Avalos } 21180c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_rapid_charge); 2119bb3fe01fSAzael Avalos 21209d309848SAzael Avalos static ssize_t usb_sleep_music_show(struct device *dev, 21219d309848SAzael Avalos struct device_attribute *attr, char *buf) 2122172ce0a9SAzael Avalos { 2123172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2124172ce0a9SAzael Avalos u32 state; 2125172ce0a9SAzael Avalos int ret; 2126172ce0a9SAzael Avalos 2127172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(toshiba, &state); 2128172ce0a9SAzael Avalos if (ret < 0) 2129172ce0a9SAzael Avalos return ret; 2130172ce0a9SAzael Avalos 2131172ce0a9SAzael Avalos return sprintf(buf, "%d\n", state); 2132172ce0a9SAzael Avalos } 2133172ce0a9SAzael Avalos 21349d309848SAzael Avalos static ssize_t usb_sleep_music_store(struct device *dev, 2135172ce0a9SAzael Avalos struct device_attribute *attr, 2136172ce0a9SAzael Avalos const char *buf, size_t count) 2137172ce0a9SAzael Avalos { 2138172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2139172ce0a9SAzael Avalos int state; 2140172ce0a9SAzael Avalos int ret; 2141172ce0a9SAzael Avalos 2142172ce0a9SAzael Avalos ret = kstrtoint(buf, 0, &state); 2143172ce0a9SAzael Avalos if (ret) 2144172ce0a9SAzael Avalos return ret; 2145172ce0a9SAzael Avalos if (state != 0 && state != 1) 2146172ce0a9SAzael Avalos return -EINVAL; 2147172ce0a9SAzael Avalos 2148172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_set(toshiba, state); 2149172ce0a9SAzael Avalos if (ret) 2150172ce0a9SAzael Avalos return ret; 2151172ce0a9SAzael Avalos 2152172ce0a9SAzael Avalos return count; 2153172ce0a9SAzael Avalos } 21540c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_music); 2155172ce0a9SAzael Avalos 21569d309848SAzael Avalos static ssize_t kbd_function_keys_show(struct device *dev, 21579d309848SAzael Avalos struct device_attribute *attr, char *buf) 2158bae84195SAzael Avalos { 2159bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2160bae84195SAzael Avalos int mode; 2161bae84195SAzael Avalos int ret; 2162bae84195SAzael Avalos 2163bae84195SAzael Avalos ret = toshiba_function_keys_get(toshiba, &mode); 2164bae84195SAzael Avalos if (ret < 0) 2165bae84195SAzael Avalos return ret; 2166bae84195SAzael Avalos 2167bae84195SAzael Avalos return sprintf(buf, "%d\n", mode); 2168bae84195SAzael Avalos } 2169bae84195SAzael Avalos 21709d309848SAzael Avalos static ssize_t kbd_function_keys_store(struct device *dev, 2171bae84195SAzael Avalos struct device_attribute *attr, 2172bae84195SAzael Avalos const char *buf, size_t count) 2173bae84195SAzael Avalos { 2174bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2175bae84195SAzael Avalos int mode; 2176bae84195SAzael Avalos int ret; 2177bae84195SAzael Avalos 2178bae84195SAzael Avalos ret = kstrtoint(buf, 0, &mode); 2179bae84195SAzael Avalos if (ret) 2180bae84195SAzael Avalos return ret; 2181e0769fe6SDarren Hart /* 2182e0769fe6SDarren Hart * Check for the function keys mode where: 2183bae84195SAzael Avalos * 0 - Normal operation (F{1-12} as usual and hotkeys via FN-F{1-12}) 2184bae84195SAzael Avalos * 1 - Special functions (Opposite of the above setting) 2185bae84195SAzael Avalos */ 2186bae84195SAzael Avalos if (mode != 0 && mode != 1) 2187bae84195SAzael Avalos return -EINVAL; 2188bae84195SAzael Avalos 2189bae84195SAzael Avalos ret = toshiba_function_keys_set(toshiba, mode); 2190bae84195SAzael Avalos if (ret) 2191bae84195SAzael Avalos return ret; 2192bae84195SAzael Avalos 2193bae84195SAzael Avalos pr_info("Reboot for changes to KBD Function Keys to take effect"); 2194bae84195SAzael Avalos 2195bae84195SAzael Avalos return count; 2196bae84195SAzael Avalos } 21970c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_function_keys); 2198bae84195SAzael Avalos 21999d309848SAzael Avalos static ssize_t panel_power_on_show(struct device *dev, 22009d309848SAzael Avalos struct device_attribute *attr, char *buf) 220135d53ceaSAzael Avalos { 220235d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 220335d53ceaSAzael Avalos u32 state; 220435d53ceaSAzael Avalos int ret; 220535d53ceaSAzael Avalos 220635d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(toshiba, &state); 220735d53ceaSAzael Avalos if (ret < 0) 220835d53ceaSAzael Avalos return ret; 220935d53ceaSAzael Avalos 221035d53ceaSAzael Avalos return sprintf(buf, "%d\n", state); 221135d53ceaSAzael Avalos } 221235d53ceaSAzael Avalos 22139d309848SAzael Avalos static ssize_t panel_power_on_store(struct device *dev, 221435d53ceaSAzael Avalos struct device_attribute *attr, 221535d53ceaSAzael Avalos const char *buf, size_t count) 221635d53ceaSAzael Avalos { 221735d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 221835d53ceaSAzael Avalos int state; 221935d53ceaSAzael Avalos int ret; 222035d53ceaSAzael Avalos 222135d53ceaSAzael Avalos ret = kstrtoint(buf, 0, &state); 222235d53ceaSAzael Avalos if (ret) 222335d53ceaSAzael Avalos return ret; 222435d53ceaSAzael Avalos if (state != 0 && state != 1) 222535d53ceaSAzael Avalos return -EINVAL; 222635d53ceaSAzael Avalos 222735d53ceaSAzael Avalos ret = toshiba_panel_power_on_set(toshiba, state); 222835d53ceaSAzael Avalos if (ret) 222935d53ceaSAzael Avalos return ret; 223035d53ceaSAzael Avalos 223135d53ceaSAzael Avalos pr_info("Reboot for changes to Panel Power ON to take effect"); 223235d53ceaSAzael Avalos 223335d53ceaSAzael Avalos return count; 223435d53ceaSAzael Avalos } 22350c3c0f10SAzael Avalos static DEVICE_ATTR_RW(panel_power_on); 223635d53ceaSAzael Avalos 22379d309848SAzael Avalos static ssize_t usb_three_show(struct device *dev, 22389d309848SAzael Avalos struct device_attribute *attr, char *buf) 223917fe4b3dSAzael Avalos { 224017fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 224117fe4b3dSAzael Avalos u32 state; 224217fe4b3dSAzael Avalos int ret; 224317fe4b3dSAzael Avalos 224417fe4b3dSAzael Avalos ret = toshiba_usb_three_get(toshiba, &state); 224517fe4b3dSAzael Avalos if (ret < 0) 224617fe4b3dSAzael Avalos return ret; 224717fe4b3dSAzael Avalos 224817fe4b3dSAzael Avalos return sprintf(buf, "%d\n", state); 224917fe4b3dSAzael Avalos } 225017fe4b3dSAzael Avalos 22519d309848SAzael Avalos static ssize_t usb_three_store(struct device *dev, 225217fe4b3dSAzael Avalos struct device_attribute *attr, 225317fe4b3dSAzael Avalos const char *buf, size_t count) 225417fe4b3dSAzael Avalos { 225517fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 225617fe4b3dSAzael Avalos int state; 225717fe4b3dSAzael Avalos int ret; 225817fe4b3dSAzael Avalos 225917fe4b3dSAzael Avalos ret = kstrtoint(buf, 0, &state); 226017fe4b3dSAzael Avalos if (ret) 226117fe4b3dSAzael Avalos return ret; 2262e0769fe6SDarren Hart /* 2263e0769fe6SDarren Hart * Check for USB 3 mode where: 226417fe4b3dSAzael Avalos * 0 - Disabled (Acts like a USB 2 port, saving power) 226517fe4b3dSAzael Avalos * 1 - Enabled 226617fe4b3dSAzael Avalos */ 226717fe4b3dSAzael Avalos if (state != 0 && state != 1) 226817fe4b3dSAzael Avalos return -EINVAL; 226917fe4b3dSAzael Avalos 227017fe4b3dSAzael Avalos ret = toshiba_usb_three_set(toshiba, state); 227117fe4b3dSAzael Avalos if (ret) 227217fe4b3dSAzael Avalos return ret; 227317fe4b3dSAzael Avalos 227417fe4b3dSAzael Avalos pr_info("Reboot for changes to USB 3 to take effect"); 227517fe4b3dSAzael Avalos 227617fe4b3dSAzael Avalos return count; 227717fe4b3dSAzael Avalos } 22780c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_three); 22799bd1213bSAzael Avalos 22809bd1213bSAzael Avalos static struct attribute *toshiba_attributes[] = { 22819bd1213bSAzael Avalos &dev_attr_version.attr, 22829bd1213bSAzael Avalos &dev_attr_fan.attr, 22839bd1213bSAzael Avalos &dev_attr_kbd_backlight_mode.attr, 22849bd1213bSAzael Avalos &dev_attr_kbd_type.attr, 22859bd1213bSAzael Avalos &dev_attr_available_kbd_modes.attr, 22869bd1213bSAzael Avalos &dev_attr_kbd_backlight_timeout.attr, 22879bd1213bSAzael Avalos &dev_attr_touchpad.attr, 22889bd1213bSAzael Avalos &dev_attr_position.attr, 22899bd1213bSAzael Avalos &dev_attr_usb_sleep_charge.attr, 22909bd1213bSAzael Avalos &dev_attr_sleep_functions_on_battery.attr, 22919bd1213bSAzael Avalos &dev_attr_usb_rapid_charge.attr, 22929bd1213bSAzael Avalos &dev_attr_usb_sleep_music.attr, 22939bd1213bSAzael Avalos &dev_attr_kbd_function_keys.attr, 22949bd1213bSAzael Avalos &dev_attr_panel_power_on.attr, 22959bd1213bSAzael Avalos &dev_attr_usb_three.attr, 22969bd1213bSAzael Avalos NULL, 22979bd1213bSAzael Avalos }; 22989bd1213bSAzael Avalos 2299360f0f39SAzael Avalos static umode_t toshiba_sysfs_is_visible(struct kobject *kobj, 2300360f0f39SAzael Avalos struct attribute *attr, int idx) 2301360f0f39SAzael Avalos { 2302360f0f39SAzael Avalos struct device *dev = container_of(kobj, struct device, kobj); 2303360f0f39SAzael Avalos struct toshiba_acpi_dev *drv = dev_get_drvdata(dev); 2304360f0f39SAzael Avalos bool exists = true; 2305360f0f39SAzael Avalos 230694477d4cSAzael Avalos if (attr == &dev_attr_fan.attr) 230794477d4cSAzael Avalos exists = (drv->fan_supported) ? true : false; 230894477d4cSAzael Avalos else if (attr == &dev_attr_kbd_backlight_mode.attr) 2309360f0f39SAzael Avalos exists = (drv->kbd_illum_supported) ? true : false; 2310360f0f39SAzael Avalos else if (attr == &dev_attr_kbd_backlight_timeout.attr) 2311360f0f39SAzael Avalos exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false; 23129d8658acSAzael Avalos else if (attr == &dev_attr_touchpad.attr) 23139d8658acSAzael Avalos exists = (drv->touchpad_supported) ? true : false; 23145a2813e9SAzael Avalos else if (attr == &dev_attr_position.attr) 23155a2813e9SAzael Avalos exists = (drv->accelerometer_supported) ? true : false; 2316e26ffe51SAzael Avalos else if (attr == &dev_attr_usb_sleep_charge.attr) 2317e26ffe51SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2318182bcaa5SAzael Avalos else if (attr == &dev_attr_sleep_functions_on_battery.attr) 2319182bcaa5SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2320bb3fe01fSAzael Avalos else if (attr == &dev_attr_usb_rapid_charge.attr) 2321bb3fe01fSAzael Avalos exists = (drv->usb_rapid_charge_supported) ? true : false; 2322172ce0a9SAzael Avalos else if (attr == &dev_attr_usb_sleep_music.attr) 2323172ce0a9SAzael Avalos exists = (drv->usb_sleep_music_supported) ? true : false; 2324bae84195SAzael Avalos else if (attr == &dev_attr_kbd_function_keys.attr) 2325bae84195SAzael Avalos exists = (drv->kbd_function_keys_supported) ? true : false; 232635d53ceaSAzael Avalos else if (attr == &dev_attr_panel_power_on.attr) 232735d53ceaSAzael Avalos exists = (drv->panel_power_on_supported) ? true : false; 232817fe4b3dSAzael Avalos else if (attr == &dev_attr_usb_three.attr) 232917fe4b3dSAzael Avalos exists = (drv->usb_three_supported) ? true : false; 2330360f0f39SAzael Avalos 2331360f0f39SAzael Avalos return exists ? attr->mode : 0; 2332360f0f39SAzael Avalos } 2333360f0f39SAzael Avalos 23349bd1213bSAzael Avalos static struct attribute_group toshiba_attr_group = { 23359bd1213bSAzael Avalos .is_visible = toshiba_sysfs_is_visible, 23369bd1213bSAzael Avalos .attrs = toshiba_attributes, 23379bd1213bSAzael Avalos }; 23389bd1213bSAzael Avalos 23391f28f290SAzael Avalos /* 23401f28f290SAzael Avalos * Hotkeys 23411f28f290SAzael Avalos */ 23421f28f290SAzael Avalos static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev) 23431f28f290SAzael Avalos { 23441f28f290SAzael Avalos acpi_status status; 23451f28f290SAzael Avalos u32 result; 23461f28f290SAzael Avalos 23471f28f290SAzael Avalos status = acpi_evaluate_object(dev->acpi_dev->handle, 23481f28f290SAzael Avalos "ENAB", NULL, NULL); 23491f28f290SAzael Avalos if (ACPI_FAILURE(status)) 23501f28f290SAzael Avalos return -ENODEV; 23511f28f290SAzael Avalos 23521f28f290SAzael Avalos result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE); 23531f28f290SAzael Avalos if (result == TOS_FAILURE) 23541f28f290SAzael Avalos return -EIO; 23551f28f290SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 23561f28f290SAzael Avalos return -ENODEV; 23571f28f290SAzael Avalos 23581f28f290SAzael Avalos return 0; 23591f28f290SAzael Avalos } 23601f28f290SAzael Avalos 236129cd293fSSeth Forshee static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, 236229cd293fSSeth Forshee struct serio *port) 236329cd293fSSeth Forshee { 236498280374SGiedrius Statkevičius if (str & I8042_STR_AUXDATA) 236529cd293fSSeth Forshee return false; 236629cd293fSSeth Forshee 236729cd293fSSeth Forshee if (unlikely(data == 0xe0)) 236829cd293fSSeth Forshee return false; 236929cd293fSSeth Forshee 237029cd293fSSeth Forshee if ((data & 0x7f) == TOS1900_FN_SCAN) { 237129cd293fSSeth Forshee schedule_work(&toshiba_acpi->hotkey_work); 237229cd293fSSeth Forshee return true; 237329cd293fSSeth Forshee } 237429cd293fSSeth Forshee 237529cd293fSSeth Forshee return false; 237629cd293fSSeth Forshee } 237729cd293fSSeth Forshee 237829cd293fSSeth Forshee static void toshiba_acpi_hotkey_work(struct work_struct *work) 237929cd293fSSeth Forshee { 238029cd293fSSeth Forshee acpi_handle ec_handle = ec_get_handle(); 238129cd293fSSeth Forshee acpi_status status; 238229cd293fSSeth Forshee 238329cd293fSSeth Forshee if (!ec_handle) 238429cd293fSSeth Forshee return; 238529cd293fSSeth Forshee 238629cd293fSSeth Forshee status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL); 238729cd293fSSeth Forshee if (ACPI_FAILURE(status)) 238829cd293fSSeth Forshee pr_err("ACPI NTFY method execution failed\n"); 238929cd293fSSeth Forshee } 239029cd293fSSeth Forshee 239129cd293fSSeth Forshee /* 239229cd293fSSeth Forshee * Returns hotkey scancode, or < 0 on failure. 239329cd293fSSeth Forshee */ 239429cd293fSSeth Forshee static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev) 239529cd293fSSeth Forshee { 239674facaf7SZhang Rui unsigned long long value; 239729cd293fSSeth Forshee acpi_status status; 239829cd293fSSeth Forshee 239974facaf7SZhang Rui status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO", 240074facaf7SZhang Rui NULL, &value); 240174facaf7SZhang Rui if (ACPI_FAILURE(status)) { 240229cd293fSSeth Forshee pr_err("ACPI INFO method execution failed\n"); 240329cd293fSSeth Forshee return -EIO; 240429cd293fSSeth Forshee } 240529cd293fSSeth Forshee 240674facaf7SZhang Rui return value; 240729cd293fSSeth Forshee } 240829cd293fSSeth Forshee 240929cd293fSSeth Forshee static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev, 241029cd293fSSeth Forshee int scancode) 241129cd293fSSeth Forshee { 241229cd293fSSeth Forshee if (scancode == 0x100) 241329cd293fSSeth Forshee return; 241429cd293fSSeth Forshee 2415e0769fe6SDarren Hart /* Act on key press; ignore key release */ 241629cd293fSSeth Forshee if (scancode & 0x80) 241729cd293fSSeth Forshee return; 241829cd293fSSeth Forshee 241929cd293fSSeth Forshee if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true)) 242029cd293fSSeth Forshee pr_info("Unknown key %x\n", scancode); 242129cd293fSSeth Forshee } 242229cd293fSSeth Forshee 242371454d78SAzael Avalos static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) 242471454d78SAzael Avalos { 242571454d78SAzael Avalos u32 hci_result, value; 242671454d78SAzael Avalos int retries = 3; 242771454d78SAzael Avalos int scancode; 242871454d78SAzael Avalos 242971454d78SAzael Avalos if (dev->info_supported) { 243071454d78SAzael Avalos scancode = toshiba_acpi_query_hotkey(dev); 243171454d78SAzael Avalos if (scancode < 0) 243271454d78SAzael Avalos pr_err("Failed to query hotkey event\n"); 243371454d78SAzael Avalos else if (scancode != 0) 243471454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, scancode); 243571454d78SAzael Avalos } else if (dev->system_event_supported) { 243671454d78SAzael Avalos do { 243771454d78SAzael Avalos hci_result = hci_read1(dev, HCI_SYSTEM_EVENT, &value); 243871454d78SAzael Avalos switch (hci_result) { 243971454d78SAzael Avalos case TOS_SUCCESS: 244071454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, (int)value); 244171454d78SAzael Avalos break; 244271454d78SAzael Avalos case TOS_NOT_SUPPORTED: 244371454d78SAzael Avalos /* 244471454d78SAzael Avalos * This is a workaround for an unresolved 244571454d78SAzael Avalos * issue on some machines where system events 244671454d78SAzael Avalos * sporadically become disabled. 244771454d78SAzael Avalos */ 244871454d78SAzael Avalos hci_result = 244971454d78SAzael Avalos hci_write1(dev, HCI_SYSTEM_EVENT, 1); 245071454d78SAzael Avalos pr_notice("Re-enabled hotkeys\n"); 2451e0769fe6SDarren Hart /* Fall through */ 245271454d78SAzael Avalos default: 245371454d78SAzael Avalos retries--; 245471454d78SAzael Avalos break; 245571454d78SAzael Avalos } 245671454d78SAzael Avalos } while (retries && hci_result != TOS_FIFO_EMPTY); 245771454d78SAzael Avalos } 245871454d78SAzael Avalos } 245971454d78SAzael Avalos 2460b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) 24616335e4d5SMatthew Garrett { 2462e2e19606SZhang Rui acpi_handle ec_handle; 2463135740deSSeth Forshee int error; 246429cd293fSSeth Forshee u32 hci_result; 2465fe808bfbSTakashi Iwai const struct key_entry *keymap = toshiba_acpi_keymap; 2466135740deSSeth Forshee 2467135740deSSeth Forshee dev->hotkey_dev = input_allocate_device(); 2468b222cca6SJoe Perches if (!dev->hotkey_dev) 2469135740deSSeth Forshee return -ENOMEM; 2470135740deSSeth Forshee 2471135740deSSeth Forshee dev->hotkey_dev->name = "Toshiba input device"; 24726e02cc7eSSeth Forshee dev->hotkey_dev->phys = "toshiba_acpi/input0"; 2473135740deSSeth Forshee dev->hotkey_dev->id.bustype = BUS_HOST; 2474135740deSSeth Forshee 2475fe808bfbSTakashi Iwai if (dmi_check_system(toshiba_alt_keymap_dmi)) 2476fe808bfbSTakashi Iwai keymap = toshiba_acpi_alt_keymap; 2477fe808bfbSTakashi Iwai error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL); 2478135740deSSeth Forshee if (error) 2479135740deSSeth Forshee goto err_free_dev; 2480135740deSSeth Forshee 248129cd293fSSeth Forshee /* 248229cd293fSSeth Forshee * For some machines the SCI responsible for providing hotkey 248329cd293fSSeth Forshee * notification doesn't fire. We can trigger the notification 248429cd293fSSeth Forshee * whenever the Fn key is pressed using the NTFY method, if 248529cd293fSSeth Forshee * supported, so if it's present set up an i8042 key filter 248629cd293fSSeth Forshee * for this purpose. 248729cd293fSSeth Forshee */ 248829cd293fSSeth Forshee ec_handle = ec_get_handle(); 2489e2e19606SZhang Rui if (ec_handle && acpi_has_method(ec_handle, "NTFY")) { 249029cd293fSSeth Forshee INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work); 249129cd293fSSeth Forshee 249229cd293fSSeth Forshee error = i8042_install_filter(toshiba_acpi_i8042_filter); 249329cd293fSSeth Forshee if (error) { 249429cd293fSSeth Forshee pr_err("Error installing key filter\n"); 249529cd293fSSeth Forshee goto err_free_keymap; 249629cd293fSSeth Forshee } 249729cd293fSSeth Forshee 249829cd293fSSeth Forshee dev->ntfy_supported = 1; 249929cd293fSSeth Forshee } 250029cd293fSSeth Forshee 250129cd293fSSeth Forshee /* 250229cd293fSSeth Forshee * Determine hotkey query interface. Prefer using the INFO 250329cd293fSSeth Forshee * method when it is available. 250429cd293fSSeth Forshee */ 2505e2e19606SZhang Rui if (acpi_has_method(dev->acpi_dev->handle, "INFO")) 250629cd293fSSeth Forshee dev->info_supported = 1; 2507e2e19606SZhang Rui else { 2508893f3f62SAzael Avalos hci_result = hci_write1(dev, HCI_SYSTEM_EVENT, 1); 25091864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) 251029cd293fSSeth Forshee dev->system_event_supported = 1; 251129cd293fSSeth Forshee } 251229cd293fSSeth Forshee 251329cd293fSSeth Forshee if (!dev->info_supported && !dev->system_event_supported) { 251429cd293fSSeth Forshee pr_warn("No hotkey query interface found\n"); 251529cd293fSSeth Forshee goto err_remove_filter; 251629cd293fSSeth Forshee } 251729cd293fSSeth Forshee 25181f28f290SAzael Avalos error = toshiba_acpi_enable_hotkeys(dev); 25191f28f290SAzael Avalos if (error) { 2520135740deSSeth Forshee pr_info("Unable to enable hotkeys\n"); 252129cd293fSSeth Forshee goto err_remove_filter; 2522135740deSSeth Forshee } 2523135740deSSeth Forshee 2524135740deSSeth Forshee error = input_register_device(dev->hotkey_dev); 2525135740deSSeth Forshee if (error) { 2526135740deSSeth Forshee pr_info("Unable to register input device\n"); 252729cd293fSSeth Forshee goto err_remove_filter; 2528135740deSSeth Forshee } 2529135740deSSeth Forshee 2530135740deSSeth Forshee return 0; 2531135740deSSeth Forshee 253229cd293fSSeth Forshee err_remove_filter: 253329cd293fSSeth Forshee if (dev->ntfy_supported) 253429cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 2535135740deSSeth Forshee err_free_keymap: 2536135740deSSeth Forshee sparse_keymap_free(dev->hotkey_dev); 2537135740deSSeth Forshee err_free_dev: 2538135740deSSeth Forshee input_free_device(dev->hotkey_dev); 2539135740deSSeth Forshee dev->hotkey_dev = NULL; 2540135740deSSeth Forshee return error; 2541135740deSSeth Forshee } 2542135740deSSeth Forshee 2543b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) 254462cce752SSeth Forshee { 254562cce752SSeth Forshee struct backlight_properties props; 254662cce752SSeth Forshee int brightness; 254762cce752SSeth Forshee int ret; 2548121b7b0dSAkio Idehara bool enabled; 254962cce752SSeth Forshee 255062cce752SSeth Forshee /* 255162cce752SSeth Forshee * Some machines don't support the backlight methods at all, and 255262cce752SSeth Forshee * others support it read-only. Either of these is pretty useless, 255362cce752SSeth Forshee * so only register the backlight device if the backlight method 255462cce752SSeth Forshee * supports both reads and writes. 255562cce752SSeth Forshee */ 255662cce752SSeth Forshee brightness = __get_lcd_brightness(dev); 255762cce752SSeth Forshee if (brightness < 0) 255862cce752SSeth Forshee return 0; 255962cce752SSeth Forshee ret = set_lcd_brightness(dev, brightness); 256062cce752SSeth Forshee if (ret) { 256162cce752SSeth Forshee pr_debug("Backlight method is read-only, disabling backlight support\n"); 256262cce752SSeth Forshee return 0; 256362cce752SSeth Forshee } 256462cce752SSeth Forshee 2565121b7b0dSAkio Idehara /* Determine whether or not BIOS supports transflective backlight */ 2566121b7b0dSAkio Idehara ret = get_tr_backlight_status(dev, &enabled); 2567121b7b0dSAkio Idehara dev->tr_backlight_supported = !ret; 2568121b7b0dSAkio Idehara 256953039f22SMatthew Garrett memset(&props, 0, sizeof(props)); 257062cce752SSeth Forshee props.type = BACKLIGHT_PLATFORM; 257162cce752SSeth Forshee props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; 257262cce752SSeth Forshee 2573e0769fe6SDarren Hart /* Adding an extra level and having 0 change to transflective mode */ 2574121b7b0dSAkio Idehara if (dev->tr_backlight_supported) 2575121b7b0dSAkio Idehara props.max_brightness++; 2576121b7b0dSAkio Idehara 257762cce752SSeth Forshee dev->backlight_dev = backlight_device_register("toshiba", 257862cce752SSeth Forshee &dev->acpi_dev->dev, 257962cce752SSeth Forshee dev, 258062cce752SSeth Forshee &toshiba_backlight_data, 258162cce752SSeth Forshee &props); 258262cce752SSeth Forshee if (IS_ERR(dev->backlight_dev)) { 258362cce752SSeth Forshee ret = PTR_ERR(dev->backlight_dev); 258462cce752SSeth Forshee pr_err("Could not register toshiba backlight device\n"); 258562cce752SSeth Forshee dev->backlight_dev = NULL; 258662cce752SSeth Forshee return ret; 258762cce752SSeth Forshee } 258862cce752SSeth Forshee 258962cce752SSeth Forshee dev->backlight_dev->props.brightness = brightness; 259062cce752SSeth Forshee return 0; 259162cce752SSeth Forshee } 259262cce752SSeth Forshee 259351fac838SRafael J. Wysocki static int toshiba_acpi_remove(struct acpi_device *acpi_dev) 2594135740deSSeth Forshee { 2595135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 2596135740deSSeth Forshee 259736d03f93SSeth Forshee remove_toshiba_proc_entries(dev); 2598135740deSSeth Forshee 2599360f0f39SAzael Avalos if (dev->sysfs_created) 2600360f0f39SAzael Avalos sysfs_remove_group(&dev->acpi_dev->dev.kobj, 2601360f0f39SAzael Avalos &toshiba_attr_group); 2602360f0f39SAzael Avalos 260329cd293fSSeth Forshee if (dev->ntfy_supported) { 260429cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 260529cd293fSSeth Forshee cancel_work_sync(&dev->hotkey_work); 260629cd293fSSeth Forshee } 260729cd293fSSeth Forshee 2608135740deSSeth Forshee if (dev->hotkey_dev) { 2609135740deSSeth Forshee input_unregister_device(dev->hotkey_dev); 2610135740deSSeth Forshee sparse_keymap_free(dev->hotkey_dev); 2611135740deSSeth Forshee } 2612135740deSSeth Forshee 2613135740deSSeth Forshee if (dev->bt_rfk) { 2614135740deSSeth Forshee rfkill_unregister(dev->bt_rfk); 2615135740deSSeth Forshee rfkill_destroy(dev->bt_rfk); 2616135740deSSeth Forshee } 2617135740deSSeth Forshee 2618135740deSSeth Forshee backlight_device_unregister(dev->backlight_dev); 2619135740deSSeth Forshee 262036d03f93SSeth Forshee if (dev->illumination_supported) 2621135740deSSeth Forshee led_classdev_unregister(&dev->led_dev); 2622135740deSSeth Forshee 2623360f0f39SAzael Avalos if (dev->kbd_led_registered) 2624360f0f39SAzael Avalos led_classdev_unregister(&dev->kbd_led); 2625360f0f39SAzael Avalos 2626def6c4e2SAzael Avalos if (dev->eco_supported) 2627def6c4e2SAzael Avalos led_classdev_unregister(&dev->eco_led); 2628def6c4e2SAzael Avalos 262929cd293fSSeth Forshee if (toshiba_acpi) 263029cd293fSSeth Forshee toshiba_acpi = NULL; 263129cd293fSSeth Forshee 2632135740deSSeth Forshee kfree(dev); 2633135740deSSeth Forshee 2634135740deSSeth Forshee return 0; 2635135740deSSeth Forshee } 2636135740deSSeth Forshee 2637b859f159SGreg Kroah-Hartman static const char *find_hci_method(acpi_handle handle) 2638a540d6b5SSeth Forshee { 2639e2e19606SZhang Rui if (acpi_has_method(handle, "GHCI")) 2640a540d6b5SSeth Forshee return "GHCI"; 2641a540d6b5SSeth Forshee 2642e2e19606SZhang Rui if (acpi_has_method(handle, "SPFC")) 2643a540d6b5SSeth Forshee return "SPFC"; 2644a540d6b5SSeth Forshee 2645a540d6b5SSeth Forshee return NULL; 2646a540d6b5SSeth Forshee } 2647a540d6b5SSeth Forshee 2648b859f159SGreg Kroah-Hartman static int toshiba_acpi_add(struct acpi_device *acpi_dev) 2649135740deSSeth Forshee { 2650135740deSSeth Forshee struct toshiba_acpi_dev *dev; 2651a540d6b5SSeth Forshee const char *hci_method; 265236d03f93SSeth Forshee u32 dummy; 2653135740deSSeth Forshee bool bt_present; 2654135740deSSeth Forshee int ret = 0; 2655135740deSSeth Forshee 265629cd293fSSeth Forshee if (toshiba_acpi) 265729cd293fSSeth Forshee return -EBUSY; 265829cd293fSSeth Forshee 2659135740deSSeth Forshee pr_info("Toshiba Laptop ACPI Extras version %s\n", 2660135740deSSeth Forshee TOSHIBA_ACPI_VERSION); 2661135740deSSeth Forshee 2662a540d6b5SSeth Forshee hci_method = find_hci_method(acpi_dev->handle); 2663a540d6b5SSeth Forshee if (!hci_method) { 2664a540d6b5SSeth Forshee pr_err("HCI interface not found\n"); 26656e02cc7eSSeth Forshee return -ENODEV; 2666a540d6b5SSeth Forshee } 26676e02cc7eSSeth Forshee 2668135740deSSeth Forshee dev = kzalloc(sizeof(*dev), GFP_KERNEL); 2669135740deSSeth Forshee if (!dev) 2670135740deSSeth Forshee return -ENOMEM; 2671135740deSSeth Forshee dev->acpi_dev = acpi_dev; 2672a540d6b5SSeth Forshee dev->method_hci = hci_method; 2673135740deSSeth Forshee acpi_dev->driver_data = dev; 2674360f0f39SAzael Avalos dev_set_drvdata(&acpi_dev->dev, dev); 2675135740deSSeth Forshee 26766e02cc7eSSeth Forshee if (toshiba_acpi_setup_keyboard(dev)) 2677135740deSSeth Forshee pr_info("Unable to activate hotkeys\n"); 2678135740deSSeth Forshee 2679135740deSSeth Forshee mutex_init(&dev->mutex); 2680135740deSSeth Forshee 268162cce752SSeth Forshee ret = toshiba_acpi_setup_backlight(dev); 268262cce752SSeth Forshee if (ret) 2683135740deSSeth Forshee goto error; 2684135740deSSeth Forshee 2685135740deSSeth Forshee /* Register rfkill switch for Bluetooth */ 26861864bbc2SAzael Avalos if (hci_get_bt_present(dev, &bt_present) == TOS_SUCCESS && bt_present) { 2687135740deSSeth Forshee dev->bt_rfk = rfkill_alloc("Toshiba Bluetooth", 2688135740deSSeth Forshee &acpi_dev->dev, 2689135740deSSeth Forshee RFKILL_TYPE_BLUETOOTH, 2690135740deSSeth Forshee &toshiba_rfk_ops, 2691135740deSSeth Forshee dev); 2692135740deSSeth Forshee if (!dev->bt_rfk) { 2693135740deSSeth Forshee pr_err("unable to allocate rfkill device\n"); 2694135740deSSeth Forshee ret = -ENOMEM; 2695135740deSSeth Forshee goto error; 2696135740deSSeth Forshee } 2697135740deSSeth Forshee 2698135740deSSeth Forshee ret = rfkill_register(dev->bt_rfk); 2699135740deSSeth Forshee if (ret) { 2700135740deSSeth Forshee pr_err("unable to register rfkill device\n"); 2701135740deSSeth Forshee rfkill_destroy(dev->bt_rfk); 2702135740deSSeth Forshee goto error; 2703135740deSSeth Forshee } 2704135740deSSeth Forshee } 2705135740deSSeth Forshee 2706135740deSSeth Forshee if (toshiba_illumination_available(dev)) { 2707135740deSSeth Forshee dev->led_dev.name = "toshiba::illumination"; 2708135740deSSeth Forshee dev->led_dev.max_brightness = 1; 2709135740deSSeth Forshee dev->led_dev.brightness_set = toshiba_illumination_set; 2710135740deSSeth Forshee dev->led_dev.brightness_get = toshiba_illumination_get; 2711135740deSSeth Forshee if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev)) 271236d03f93SSeth Forshee dev->illumination_supported = 1; 2713135740deSSeth Forshee } 2714135740deSSeth Forshee 2715def6c4e2SAzael Avalos if (toshiba_eco_mode_available(dev)) { 2716def6c4e2SAzael Avalos dev->eco_led.name = "toshiba::eco_mode"; 2717def6c4e2SAzael Avalos dev->eco_led.max_brightness = 1; 2718def6c4e2SAzael Avalos dev->eco_led.brightness_set = toshiba_eco_mode_set_status; 2719def6c4e2SAzael Avalos dev->eco_led.brightness_get = toshiba_eco_mode_get_status; 2720def6c4e2SAzael Avalos if (!led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led)) 2721def6c4e2SAzael Avalos dev->eco_supported = 1; 2722def6c4e2SAzael Avalos } 2723def6c4e2SAzael Avalos 272493f8c16dSAzael Avalos dev->kbd_illum_supported = toshiba_kbd_illum_available(dev); 2725360f0f39SAzael Avalos /* 2726360f0f39SAzael Avalos * Only register the LED if KBD illumination is supported 2727360f0f39SAzael Avalos * and the keyboard backlight operation mode is set to FN-Z 2728360f0f39SAzael Avalos */ 2729360f0f39SAzael Avalos if (dev->kbd_illum_supported && dev->kbd_mode == SCI_KBD_MODE_FNZ) { 2730360f0f39SAzael Avalos dev->kbd_led.name = "toshiba::kbd_backlight"; 2731360f0f39SAzael Avalos dev->kbd_led.max_brightness = 1; 2732360f0f39SAzael Avalos dev->kbd_led.brightness_set = toshiba_kbd_backlight_set; 2733360f0f39SAzael Avalos dev->kbd_led.brightness_get = toshiba_kbd_backlight_get; 2734360f0f39SAzael Avalos if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led)) 2735360f0f39SAzael Avalos dev->kbd_led_registered = 1; 2736360f0f39SAzael Avalos } 2737360f0f39SAzael Avalos 27389d8658acSAzael Avalos ret = toshiba_touchpad_get(dev, &dummy); 27399d8658acSAzael Avalos dev->touchpad_supported = !ret; 27409d8658acSAzael Avalos 27415a2813e9SAzael Avalos ret = toshiba_accelerometer_supported(dev); 27425a2813e9SAzael Avalos dev->accelerometer_supported = !ret; 27435a2813e9SAzael Avalos 2744e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_get(dev, &dummy); 2745e26ffe51SAzael Avalos dev->usb_sleep_charge_supported = !ret; 2746e26ffe51SAzael Avalos 2747bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(dev, &dummy); 2748bb3fe01fSAzael Avalos dev->usb_rapid_charge_supported = !ret; 2749bb3fe01fSAzael Avalos 2750172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(dev, &dummy); 2751172ce0a9SAzael Avalos dev->usb_sleep_music_supported = !ret; 2752172ce0a9SAzael Avalos 2753bae84195SAzael Avalos ret = toshiba_function_keys_get(dev, &dummy); 2754bae84195SAzael Avalos dev->kbd_function_keys_supported = !ret; 2755bae84195SAzael Avalos 275635d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(dev, &dummy); 275735d53ceaSAzael Avalos dev->panel_power_on_supported = !ret; 275835d53ceaSAzael Avalos 275917fe4b3dSAzael Avalos ret = toshiba_usb_three_get(dev, &dummy); 276017fe4b3dSAzael Avalos dev->usb_three_supported = !ret; 276117fe4b3dSAzael Avalos 276236d03f93SSeth Forshee /* Determine whether or not BIOS supports fan and video interfaces */ 276336d03f93SSeth Forshee 276436d03f93SSeth Forshee ret = get_video_status(dev, &dummy); 276536d03f93SSeth Forshee dev->video_supported = !ret; 276636d03f93SSeth Forshee 276736d03f93SSeth Forshee ret = get_fan_status(dev, &dummy); 276836d03f93SSeth Forshee dev->fan_supported = !ret; 276936d03f93SSeth Forshee 2770360f0f39SAzael Avalos ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, 2771360f0f39SAzael Avalos &toshiba_attr_group); 2772360f0f39SAzael Avalos if (ret) { 2773360f0f39SAzael Avalos dev->sysfs_created = 0; 2774360f0f39SAzael Avalos goto error; 2775360f0f39SAzael Avalos } 2776360f0f39SAzael Avalos dev->sysfs_created = !ret; 2777360f0f39SAzael Avalos 277836d03f93SSeth Forshee create_toshiba_proc_entries(dev); 277936d03f93SSeth Forshee 278029cd293fSSeth Forshee toshiba_acpi = dev; 278129cd293fSSeth Forshee 2782135740deSSeth Forshee return 0; 2783135740deSSeth Forshee 2784135740deSSeth Forshee error: 278551fac838SRafael J. Wysocki toshiba_acpi_remove(acpi_dev); 2786135740deSSeth Forshee return ret; 2787135740deSSeth Forshee } 2788135740deSSeth Forshee 2789135740deSSeth Forshee static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) 2790135740deSSeth Forshee { 2791135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 279280546905SAzael Avalos int ret; 27936335e4d5SMatthew Garrett 279471454d78SAzael Avalos switch (event) { 279571454d78SAzael Avalos case 0x80: /* Hotkeys and some system events */ 279671454d78SAzael Avalos toshiba_acpi_process_hotkeys(dev); 279711948b93SSeth Forshee break; 2798bab09e23SAzael Avalos case 0x81: /* Dock events */ 2799bab09e23SAzael Avalos case 0x82: 2800bab09e23SAzael Avalos case 0x83: 2801bab09e23SAzael Avalos pr_info("Dock event received %x\n", event); 2802bab09e23SAzael Avalos break; 2803bab09e23SAzael Avalos case 0x88: /* Thermal events */ 2804bab09e23SAzael Avalos pr_info("Thermal event received\n"); 2805bab09e23SAzael Avalos break; 2806bab09e23SAzael Avalos case 0x8f: /* LID closed */ 2807bab09e23SAzael Avalos case 0x90: /* LID is closed and Dock has been ejected */ 2808bab09e23SAzael Avalos break; 2809bab09e23SAzael Avalos case 0x8c: /* SATA power events */ 2810bab09e23SAzael Avalos case 0x8b: 2811bab09e23SAzael Avalos pr_info("SATA power event received %x\n", event); 2812bab09e23SAzael Avalos break; 281380546905SAzael Avalos case 0x92: /* Keyboard backlight mode changed */ 281480546905SAzael Avalos /* Update sysfs entries */ 281580546905SAzael Avalos ret = sysfs_update_group(&acpi_dev->dev.kobj, 281680546905SAzael Avalos &toshiba_attr_group); 281780546905SAzael Avalos if (ret) 281880546905SAzael Avalos pr_err("Unable to update sysfs entries\n"); 281980546905SAzael Avalos break; 2820bab09e23SAzael Avalos case 0x85: /* Unknown */ 2821bab09e23SAzael Avalos case 0x8d: /* Unknown */ 282271454d78SAzael Avalos case 0x8e: /* Unknown */ 2823bab09e23SAzael Avalos case 0x94: /* Unknown */ 2824bab09e23SAzael Avalos case 0x95: /* Unknown */ 282511948b93SSeth Forshee default: 282671454d78SAzael Avalos pr_info("Unknown event received %x\n", event); 282711948b93SSeth Forshee break; 28286335e4d5SMatthew Garrett } 2829bab09e23SAzael Avalos 2830bab09e23SAzael Avalos acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class, 2831bab09e23SAzael Avalos dev_name(&acpi_dev->dev), 2832bab09e23SAzael Avalos event, 0); 283329cd293fSSeth Forshee } 28346335e4d5SMatthew Garrett 28353567a4e2SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 283643d2fd3bSRafael J. Wysocki static int toshiba_acpi_suspend(struct device *device) 283729cd293fSSeth Forshee { 283843d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 283929cd293fSSeth Forshee u32 result; 284029cd293fSSeth Forshee 284129cd293fSSeth Forshee if (dev->hotkey_dev) 2842893f3f62SAzael Avalos result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE); 284329cd293fSSeth Forshee 284429cd293fSSeth Forshee return 0; 284529cd293fSSeth Forshee } 284629cd293fSSeth Forshee 284743d2fd3bSRafael J. Wysocki static int toshiba_acpi_resume(struct device *device) 284829cd293fSSeth Forshee { 284943d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 28501f28f290SAzael Avalos int error; 285129cd293fSSeth Forshee 2852e7fdb762SBenjamin Tissoires if (dev->hotkey_dev) { 28531f28f290SAzael Avalos error = toshiba_acpi_enable_hotkeys(dev); 28541f28f290SAzael Avalos if (error) 2855e7fdb762SBenjamin Tissoires pr_info("Unable to re-enable hotkeys\n"); 2856e7fdb762SBenjamin Tissoires } 285729cd293fSSeth Forshee 285829cd293fSSeth Forshee return 0; 285929cd293fSSeth Forshee } 28603567a4e2SRafael J. Wysocki #endif 28616335e4d5SMatthew Garrett 286243d2fd3bSRafael J. Wysocki static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm, 286343d2fd3bSRafael J. Wysocki toshiba_acpi_suspend, toshiba_acpi_resume); 286443d2fd3bSRafael J. Wysocki 2865135740deSSeth Forshee static struct acpi_driver toshiba_acpi_driver = { 2866135740deSSeth Forshee .name = "Toshiba ACPI driver", 2867135740deSSeth Forshee .owner = THIS_MODULE, 2868135740deSSeth Forshee .ids = toshiba_device_ids, 2869135740deSSeth Forshee .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, 2870135740deSSeth Forshee .ops = { 2871135740deSSeth Forshee .add = toshiba_acpi_add, 2872135740deSSeth Forshee .remove = toshiba_acpi_remove, 2873135740deSSeth Forshee .notify = toshiba_acpi_notify, 2874135740deSSeth Forshee }, 287543d2fd3bSRafael J. Wysocki .drv.pm = &toshiba_acpi_pm, 2876135740deSSeth Forshee }; 2877b4f9fe12SLen Brown 2878b4f9fe12SLen Brown static int __init toshiba_acpi_init(void) 2879b4f9fe12SLen Brown { 2880135740deSSeth Forshee int ret; 2881b4f9fe12SLen Brown 2882f11f999eSSeth Forshee /* 2883f11f999eSSeth Forshee * Machines with this WMI guid aren't supported due to bugs in 2884f11f999eSSeth Forshee * their AML. This check relies on wmi initializing before 2885f11f999eSSeth Forshee * toshiba_acpi to guarantee guids have been identified. 2886f11f999eSSeth Forshee */ 2887f11f999eSSeth Forshee if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) 2888f11f999eSSeth Forshee return -ENODEV; 2889f11f999eSSeth Forshee 2890b4f9fe12SLen Brown toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); 2891b4f9fe12SLen Brown if (!toshiba_proc_dir) { 2892135740deSSeth Forshee pr_err("Unable to create proc dir " PROC_TOSHIBA "\n"); 2893b4f9fe12SLen Brown return -ENODEV; 2894b4f9fe12SLen Brown } 2895b4f9fe12SLen Brown 2896135740deSSeth Forshee ret = acpi_bus_register_driver(&toshiba_acpi_driver); 2897b4f9fe12SLen Brown if (ret) { 2898135740deSSeth Forshee pr_err("Failed to register ACPI driver: %d\n", ret); 2899135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 2900135740deSSeth Forshee } 2901135740deSSeth Forshee 2902b4f9fe12SLen Brown return ret; 2903b4f9fe12SLen Brown } 2904b4f9fe12SLen Brown 2905135740deSSeth Forshee static void __exit toshiba_acpi_exit(void) 2906135740deSSeth Forshee { 2907135740deSSeth Forshee acpi_bus_unregister_driver(&toshiba_acpi_driver); 2908135740deSSeth Forshee if (toshiba_proc_dir) 2909135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 2910b4f9fe12SLen Brown } 2911b4f9fe12SLen Brown 2912b4f9fe12SLen Brown module_init(toshiba_acpi_init); 2913b4f9fe12SLen Brown module_exit(toshiba_acpi_exit); 2914