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 3463ba3e28SAzael Avalos #define TOSHIBA_ACPI_VERSION "0.22" 35b4f9fe12SLen Brown #define PROC_INTERFACE_VERSION 1 36b4f9fe12SLen Brown 37b4f9fe12SLen Brown #include <linux/kernel.h> 38b4f9fe12SLen Brown #include <linux/module.h> 39b4f9fe12SLen Brown #include <linux/init.h> 40b4f9fe12SLen Brown #include <linux/types.h> 41b4f9fe12SLen Brown #include <linux/proc_fs.h> 42936c8bcdSAlexey Dobriyan #include <linux/seq_file.h> 43b4f9fe12SLen Brown #include <linux/backlight.h> 446335e4d5SMatthew Garrett #include <linux/input.h> 45384a7cd9SDmitry Torokhov #include <linux/input/sparse-keymap.h> 466c3f6e6cSPierre Ducroquet #include <linux/leds.h> 475a0e3ad6STejun Heo #include <linux/slab.h> 4829cd293fSSeth Forshee #include <linux/workqueue.h> 4929cd293fSSeth Forshee #include <linux/i8042.h> 508b48463fSLv Zheng #include <linux/acpi.h> 51358d6a2cSHans de Goede #include <linux/dmi.h> 52b5163992SAzael Avalos #include <linux/uaccess.h> 53fc5462f8SAzael Avalos #include <linux/miscdevice.h> 54fc5462f8SAzael Avalos #include <linux/toshiba.h> 55358d6a2cSHans de Goede #include <acpi/video.h> 56b4f9fe12SLen Brown 57b4f9fe12SLen Brown MODULE_AUTHOR("John Belmonte"); 58b4f9fe12SLen Brown MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); 59b4f9fe12SLen Brown MODULE_LICENSE("GPL"); 60b4f9fe12SLen Brown 61f11f999eSSeth Forshee #define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100" 62f11f999eSSeth Forshee 6329cd293fSSeth Forshee /* Scan code for Fn key on TOS1900 models */ 6429cd293fSSeth Forshee #define TOS1900_FN_SCAN 0x6e 6529cd293fSSeth Forshee 66b4f9fe12SLen Brown /* Toshiba ACPI method paths */ 67b4f9fe12SLen Brown #define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX" 68b4f9fe12SLen Brown 69e0769fe6SDarren Hart /* 70e0769fe6SDarren Hart * The Toshiba configuration interface is composed of the HCI and the SCI, 71258c5903SAzael Avalos * which are defined as follows: 72b4f9fe12SLen Brown * 73b4f9fe12SLen Brown * HCI is Toshiba's "Hardware Control Interface" which is supposed to 74b4f9fe12SLen Brown * be uniform across all their models. Ideally we would just call 75b4f9fe12SLen Brown * dedicated ACPI methods instead of using this primitive interface. 76b4f9fe12SLen Brown * However the ACPI methods seem to be incomplete in some areas (for 77b4f9fe12SLen Brown * example they allow setting, but not reading, the LCD brightness value), 78b4f9fe12SLen Brown * so this is still useful. 7984a6273fSAzael Avalos * 8084a6273fSAzael Avalos * SCI stands for "System Configuration Interface" which aim is to 8184a6273fSAzael Avalos * conceal differences in hardware between different models. 82b4f9fe12SLen Brown */ 83b4f9fe12SLen Brown 84258c5903SAzael Avalos #define TCI_WORDS 6 85b4f9fe12SLen Brown 863f75bbe9SAzael Avalos /* Operations */ 87b4f9fe12SLen Brown #define HCI_SET 0xff00 88b4f9fe12SLen Brown #define HCI_GET 0xfe00 8984a6273fSAzael Avalos #define SCI_OPEN 0xf100 9084a6273fSAzael Avalos #define SCI_CLOSE 0xf200 9184a6273fSAzael Avalos #define SCI_GET 0xf300 9284a6273fSAzael Avalos #define SCI_SET 0xf400 93b4f9fe12SLen Brown 943f75bbe9SAzael Avalos /* Return codes */ 951864bbc2SAzael Avalos #define TOS_SUCCESS 0x0000 961864bbc2SAzael Avalos #define TOS_OPEN_CLOSE_OK 0x0044 971864bbc2SAzael Avalos #define TOS_FAILURE 0x1000 981864bbc2SAzael Avalos #define TOS_NOT_SUPPORTED 0x8000 991864bbc2SAzael Avalos #define TOS_ALREADY_OPEN 0x8100 1001864bbc2SAzael Avalos #define TOS_NOT_OPENED 0x8200 1011864bbc2SAzael Avalos #define TOS_INPUT_DATA_ERROR 0x8300 1021864bbc2SAzael Avalos #define TOS_WRITE_PROTECTED 0x8400 1031864bbc2SAzael Avalos #define TOS_NOT_PRESENT 0x8600 1041864bbc2SAzael Avalos #define TOS_FIFO_EMPTY 0x8c00 1051864bbc2SAzael Avalos #define TOS_DATA_NOT_AVAILABLE 0x8d20 1061864bbc2SAzael Avalos #define TOS_NOT_INITIALIZED 0x8d50 10798fc4ec6SAzael Avalos #define TOS_NOT_INSTALLED 0x8e00 108b4f9fe12SLen Brown 1093f75bbe9SAzael Avalos /* Registers */ 110b4f9fe12SLen Brown #define HCI_FAN 0x0004 111121b7b0dSAkio Idehara #define HCI_TR_BACKLIGHT 0x0005 112b4f9fe12SLen Brown #define HCI_SYSTEM_EVENT 0x0016 113b4f9fe12SLen Brown #define HCI_VIDEO_OUT 0x001c 114b4f9fe12SLen Brown #define HCI_HOTKEY_EVENT 0x001e 115b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS 0x002a 1165a2813e9SAzael Avalos #define HCI_ACCELEROMETER 0x006d 117360f0f39SAzael Avalos #define HCI_KBD_ILLUMINATION 0x0095 118def6c4e2SAzael Avalos #define HCI_ECO_MODE 0x0097 1195a2813e9SAzael Avalos #define HCI_ACCELEROMETER2 0x00a6 12056e6b353SAzael Avalos #define HCI_SYSTEM_INFO 0xc000 12135d53ceaSAzael Avalos #define SCI_PANEL_POWER_ON 0x010d 122fdb79081SAzael Avalos #define SCI_ILLUMINATION 0x014e 123e26ffe51SAzael Avalos #define SCI_USB_SLEEP_CHARGE 0x0150 124360f0f39SAzael Avalos #define SCI_KBD_ILLUM_STATUS 0x015c 125172ce0a9SAzael Avalos #define SCI_USB_SLEEP_MUSIC 0x015e 12617fe4b3dSAzael Avalos #define SCI_USB_THREE 0x0169 1279d8658acSAzael Avalos #define SCI_TOUCHPAD 0x050e 128bae84195SAzael Avalos #define SCI_KBD_FUNCTION_KEYS 0x0522 129b4f9fe12SLen Brown 1303f75bbe9SAzael Avalos /* Field definitions */ 1315a2813e9SAzael Avalos #define HCI_ACCEL_MASK 0x7fff 13229cd293fSSeth Forshee #define HCI_HOTKEY_DISABLE 0x0b 13329cd293fSSeth Forshee #define HCI_HOTKEY_ENABLE 0x09 134fb42d1f4SAzael Avalos #define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10 135b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_BITS 3 136b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) 137b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS) 138360f0f39SAzael Avalos #define HCI_MISC_SHIFT 0x10 13956e6b353SAzael Avalos #define HCI_SYSTEM_TYPE1 0x10 14056e6b353SAzael Avalos #define HCI_SYSTEM_TYPE2 0x11 141b4f9fe12SLen Brown #define HCI_VIDEO_OUT_LCD 0x1 142b4f9fe12SLen Brown #define HCI_VIDEO_OUT_CRT 0x2 143b4f9fe12SLen Brown #define HCI_VIDEO_OUT_TV 0x4 14493f8c16dSAzael Avalos #define SCI_KBD_MODE_MASK 0x1f 145360f0f39SAzael Avalos #define SCI_KBD_MODE_FNZ 0x1 146360f0f39SAzael Avalos #define SCI_KBD_MODE_AUTO 0x2 14793f8c16dSAzael Avalos #define SCI_KBD_MODE_ON 0x8 14893f8c16dSAzael Avalos #define SCI_KBD_MODE_OFF 0x10 14993f8c16dSAzael Avalos #define SCI_KBD_TIME_MAX 0x3c001a 150e26ffe51SAzael Avalos #define SCI_USB_CHARGE_MODE_MASK 0xff 151c8c91842SAzael Avalos #define SCI_USB_CHARGE_DISABLED 0x00 152c8c91842SAzael Avalos #define SCI_USB_CHARGE_ALTERNATE 0x09 153c8c91842SAzael Avalos #define SCI_USB_CHARGE_TYPICAL 0x11 154c8c91842SAzael Avalos #define SCI_USB_CHARGE_AUTO 0x21 155182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_MASK 0x7 156182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_OFF 0x1 157182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_ON 0x4 158182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL 0x0200 159bb3fe01fSAzael Avalos #define SCI_USB_CHARGE_RAPID_DSP 0x0300 160b4f9fe12SLen Brown 161135740deSSeth Forshee struct toshiba_acpi_dev { 162135740deSSeth Forshee struct acpi_device *acpi_dev; 163135740deSSeth Forshee const char *method_hci; 164135740deSSeth Forshee struct input_dev *hotkey_dev; 16529cd293fSSeth Forshee struct work_struct hotkey_work; 166135740deSSeth Forshee struct backlight_device *backlight_dev; 167135740deSSeth Forshee struct led_classdev led_dev; 168360f0f39SAzael Avalos struct led_classdev kbd_led; 169def6c4e2SAzael Avalos struct led_classdev eco_led; 170fc5462f8SAzael Avalos struct miscdevice miscdev; 17136d03f93SSeth Forshee 172135740deSSeth Forshee int force_fan; 173135740deSSeth Forshee int last_key_event; 174135740deSSeth Forshee int key_event_valid; 17593f8c16dSAzael Avalos int kbd_type; 176360f0f39SAzael Avalos int kbd_mode; 177360f0f39SAzael Avalos int kbd_time; 178182bcaa5SAzael Avalos int usbsc_bat_level; 179c8c91842SAzael Avalos int usbsc_mode_base; 180a2b3471bSAzael Avalos int hotkey_event_type; 181135740deSSeth Forshee 182592b746cSDan Carpenter unsigned int illumination_supported:1; 183592b746cSDan Carpenter unsigned int video_supported:1; 184592b746cSDan Carpenter unsigned int fan_supported:1; 185592b746cSDan Carpenter unsigned int system_event_supported:1; 18629cd293fSSeth Forshee unsigned int ntfy_supported:1; 18729cd293fSSeth Forshee unsigned int info_supported:1; 188121b7b0dSAkio Idehara unsigned int tr_backlight_supported:1; 189360f0f39SAzael Avalos unsigned int kbd_illum_supported:1; 190360f0f39SAzael Avalos unsigned int kbd_led_registered:1; 1919d8658acSAzael Avalos unsigned int touchpad_supported:1; 192def6c4e2SAzael Avalos unsigned int eco_supported:1; 1935a2813e9SAzael Avalos unsigned int accelerometer_supported:1; 194e26ffe51SAzael Avalos unsigned int usb_sleep_charge_supported:1; 195bb3fe01fSAzael Avalos unsigned int usb_rapid_charge_supported:1; 196172ce0a9SAzael Avalos unsigned int usb_sleep_music_supported:1; 197bae84195SAzael Avalos unsigned int kbd_function_keys_supported:1; 19835d53ceaSAzael Avalos unsigned int panel_power_on_supported:1; 19917fe4b3dSAzael Avalos unsigned int usb_three_supported:1; 200360f0f39SAzael Avalos unsigned int sysfs_created:1; 201135740deSSeth Forshee }; 202135740deSSeth Forshee 20329cd293fSSeth Forshee static struct toshiba_acpi_dev *toshiba_acpi; 20429cd293fSSeth Forshee 205b4f9fe12SLen Brown static const struct acpi_device_id toshiba_device_ids[] = { 206b4f9fe12SLen Brown {"TOS6200", 0}, 20763a9e016SOndrej Zary {"TOS6207", 0}, 208b4f9fe12SLen Brown {"TOS6208", 0}, 209b4f9fe12SLen Brown {"TOS1900", 0}, 210b4f9fe12SLen Brown {"", 0}, 211b4f9fe12SLen Brown }; 212b4f9fe12SLen Brown MODULE_DEVICE_TABLE(acpi, toshiba_device_ids); 213b4f9fe12SLen Brown 214b859f159SGreg Kroah-Hartman static const struct key_entry toshiba_acpi_keymap[] = { 215fec278a1SUnai Uribarri { KE_KEY, 0x9e, { KEY_RFKILL } }, 216384a7cd9SDmitry Torokhov { KE_KEY, 0x101, { KEY_MUTE } }, 217384a7cd9SDmitry Torokhov { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 218384a7cd9SDmitry Torokhov { KE_KEY, 0x103, { KEY_ZOOMIN } }, 219408a5d13SAzael Avalos { KE_KEY, 0x10f, { KEY_TAB } }, 220af502837SAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 221af502837SAzael Avalos { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 222384a7cd9SDmitry Torokhov { KE_KEY, 0x13b, { KEY_COFFEE } }, 223384a7cd9SDmitry Torokhov { KE_KEY, 0x13c, { KEY_BATTERY } }, 224384a7cd9SDmitry Torokhov { KE_KEY, 0x13d, { KEY_SLEEP } }, 225384a7cd9SDmitry Torokhov { KE_KEY, 0x13e, { KEY_SUSPEND } }, 226384a7cd9SDmitry Torokhov { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } }, 227384a7cd9SDmitry Torokhov { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } }, 228384a7cd9SDmitry Torokhov { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } }, 229384a7cd9SDmitry Torokhov { KE_KEY, 0x142, { KEY_WLAN } }, 230af502837SAzael Avalos { KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } }, 231a49010f5SJon Dowland { KE_KEY, 0x17f, { KEY_FN } }, 232384a7cd9SDmitry Torokhov { KE_KEY, 0xb05, { KEY_PROG2 } }, 233384a7cd9SDmitry Torokhov { KE_KEY, 0xb06, { KEY_WWW } }, 234384a7cd9SDmitry Torokhov { KE_KEY, 0xb07, { KEY_MAIL } }, 235384a7cd9SDmitry Torokhov { KE_KEY, 0xb30, { KEY_STOP } }, 236384a7cd9SDmitry Torokhov { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } }, 237384a7cd9SDmitry Torokhov { KE_KEY, 0xb32, { KEY_NEXTSONG } }, 238384a7cd9SDmitry Torokhov { KE_KEY, 0xb33, { KEY_PLAYPAUSE } }, 239384a7cd9SDmitry Torokhov { KE_KEY, 0xb5a, { KEY_MEDIA } }, 240408a5d13SAzael Avalos { KE_IGNORE, 0x1430, { KEY_RESERVED } }, /* Wake from sleep */ 241408a5d13SAzael Avalos { KE_IGNORE, 0x1501, { KEY_RESERVED } }, /* Output changed */ 242408a5d13SAzael Avalos { KE_IGNORE, 0x1502, { KEY_RESERVED } }, /* HDMI plugged/unplugged */ 243408a5d13SAzael Avalos { KE_IGNORE, 0x1ABE, { KEY_RESERVED } }, /* Protection level set */ 244408a5d13SAzael Avalos { KE_IGNORE, 0x1ABF, { KEY_RESERVED } }, /* Protection level off */ 245384a7cd9SDmitry Torokhov { KE_END, 0 }, 2466335e4d5SMatthew Garrett }; 2476335e4d5SMatthew Garrett 248fe808bfbSTakashi Iwai static const struct key_entry toshiba_acpi_alt_keymap[] = { 249fe808bfbSTakashi Iwai { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 250fe808bfbSTakashi Iwai { KE_KEY, 0x103, { KEY_ZOOMIN } }, 251e6efad7fSAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 252fe808bfbSTakashi Iwai { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 253fe808bfbSTakashi Iwai { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } }, 254fe808bfbSTakashi Iwai { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } }, 255*d50c9005SAzael Avalos { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } }, 256fe808bfbSTakashi Iwai { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } }, 257*d50c9005SAzael Avalos { KE_KEY, 0x157, { KEY_MUTE } }, 258*d50c9005SAzael Avalos { KE_KEY, 0x158, { KEY_WLAN } }, 259fe808bfbSTakashi Iwai { KE_END, 0 }, 260fe808bfbSTakashi Iwai }; 261fe808bfbSTakashi Iwai 262e0769fe6SDarren Hart /* 263358d6a2cSHans de Goede * List of models which have a broken acpi-video backlight interface and thus 264358d6a2cSHans de Goede * need to use the toshiba (vendor) interface instead. 265358d6a2cSHans de Goede */ 266358d6a2cSHans de Goede static const struct dmi_system_id toshiba_vendor_backlight_dmi[] = { 267358d6a2cSHans de Goede {} 268358d6a2cSHans de Goede }; 269358d6a2cSHans de Goede 270358d6a2cSHans de Goede /* 271e0769fe6SDarren Hart * Utility 272b4f9fe12SLen Brown */ 273b4f9fe12SLen Brown 274b5163992SAzael Avalos static inline void _set_bit(u32 *word, u32 mask, int value) 275b4f9fe12SLen Brown { 276b4f9fe12SLen Brown *word = (*word & ~mask) | (mask * value); 277b4f9fe12SLen Brown } 278b4f9fe12SLen Brown 279e0769fe6SDarren Hart /* 280e0769fe6SDarren Hart * ACPI interface wrappers 281b4f9fe12SLen Brown */ 282b4f9fe12SLen Brown 283b4f9fe12SLen Brown static int write_acpi_int(const char *methodName, int val) 284b4f9fe12SLen Brown { 285b4f9fe12SLen Brown acpi_status status; 286b4f9fe12SLen Brown 287619400daSZhang Rui status = acpi_execute_simple_method(NULL, (char *)methodName, val); 28832bcd5cbSSeth Forshee return (status == AE_OK) ? 0 : -EIO; 289b4f9fe12SLen Brown } 290b4f9fe12SLen Brown 291e0769fe6SDarren Hart /* 292e0769fe6SDarren Hart * Perform a raw configuration call. Here we don't care about input or output 293258c5903SAzael Avalos * buffer format. 294b4f9fe12SLen Brown */ 295258c5903SAzael Avalos static acpi_status tci_raw(struct toshiba_acpi_dev *dev, 296258c5903SAzael Avalos const u32 in[TCI_WORDS], u32 out[TCI_WORDS]) 297b4f9fe12SLen Brown { 298b4f9fe12SLen Brown struct acpi_object_list params; 299258c5903SAzael Avalos union acpi_object in_objs[TCI_WORDS]; 300b4f9fe12SLen Brown struct acpi_buffer results; 301258c5903SAzael Avalos union acpi_object out_objs[TCI_WORDS + 1]; 302b4f9fe12SLen Brown acpi_status status; 303b4f9fe12SLen Brown int i; 304b4f9fe12SLen Brown 305258c5903SAzael Avalos params.count = TCI_WORDS; 306b4f9fe12SLen Brown params.pointer = in_objs; 307258c5903SAzael Avalos for (i = 0; i < TCI_WORDS; ++i) { 308b4f9fe12SLen Brown in_objs[i].type = ACPI_TYPE_INTEGER; 309b4f9fe12SLen Brown in_objs[i].integer.value = in[i]; 310b4f9fe12SLen Brown } 311b4f9fe12SLen Brown 312b4f9fe12SLen Brown results.length = sizeof(out_objs); 313b4f9fe12SLen Brown results.pointer = out_objs; 314b4f9fe12SLen Brown 3156e02cc7eSSeth Forshee status = acpi_evaluate_object(dev->acpi_dev->handle, 3166e02cc7eSSeth Forshee (char *)dev->method_hci, ¶ms, 317b4f9fe12SLen Brown &results); 318258c5903SAzael Avalos if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) { 319b5163992SAzael Avalos for (i = 0; i < out_objs->package.count; ++i) 320b4f9fe12SLen Brown out[i] = out_objs->package.elements[i].integer.value; 321b4f9fe12SLen Brown } 322b4f9fe12SLen Brown 323b4f9fe12SLen Brown return status; 324b4f9fe12SLen Brown } 325b4f9fe12SLen Brown 326e0769fe6SDarren Hart /* 327d37782bdSAzael Avalos * Common hci tasks 328b4f9fe12SLen Brown * 329b4f9fe12SLen Brown * In addition to the ACPI status, the HCI system returns a result which 330b4f9fe12SLen Brown * may be useful (such as "not supported"). 331b4f9fe12SLen Brown */ 332b4f9fe12SLen Brown 333d37782bdSAzael Avalos static u32 hci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 334b4f9fe12SLen Brown { 335258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 }; 336258c5903SAzael Avalos u32 out[TCI_WORDS]; 337258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 338893f3f62SAzael Avalos 339893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 340b4f9fe12SLen Brown } 341b4f9fe12SLen Brown 342d37782bdSAzael Avalos static u32 hci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 343b4f9fe12SLen Brown { 344258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 }; 345258c5903SAzael Avalos u32 out[TCI_WORDS]; 346258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 347b5163992SAzael Avalos 348893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 349893f3f62SAzael Avalos return TOS_FAILURE; 350893f3f62SAzael Avalos 351b4f9fe12SLen Brown *out1 = out[2]; 352893f3f62SAzael Avalos 353893f3f62SAzael Avalos return out[0]; 354b4f9fe12SLen Brown } 355b4f9fe12SLen Brown 356e0769fe6SDarren Hart /* 357e0769fe6SDarren Hart * Common sci tasks 35884a6273fSAzael Avalos */ 35984a6273fSAzael Avalos 36084a6273fSAzael Avalos static int sci_open(struct toshiba_acpi_dev *dev) 36184a6273fSAzael Avalos { 362258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 }; 363258c5903SAzael Avalos u32 out[TCI_WORDS]; 36484a6273fSAzael Avalos acpi_status status; 36584a6273fSAzael Avalos 366258c5903SAzael Avalos status = tci_raw(dev, in, out); 3678baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 36884a6273fSAzael Avalos pr_err("ACPI call to open SCI failed\n"); 36984a6273fSAzael Avalos return 0; 37084a6273fSAzael Avalos } 37184a6273fSAzael Avalos 3721864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) { 37384a6273fSAzael Avalos return 1; 3741864bbc2SAzael Avalos } else if (out[0] == TOS_ALREADY_OPEN) { 37584a6273fSAzael Avalos pr_info("Toshiba SCI already opened\n"); 37684a6273fSAzael Avalos return 1; 377fa465739SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 378e0769fe6SDarren Hart /* 379e0769fe6SDarren Hart * Some BIOSes do not have the SCI open/close functions 380fa465739SAzael Avalos * implemented and return 0x8000 (Not Supported), failing to 381fa465739SAzael Avalos * register some supported features. 382fa465739SAzael Avalos * 383fa465739SAzael Avalos * Simply return 1 if we hit those affected laptops to make the 384fa465739SAzael Avalos * supported features work. 385fa465739SAzael Avalos * 386fa465739SAzael Avalos * In the case that some laptops really do not support the SCI, 387fa465739SAzael Avalos * all the SCI dependent functions check for TOS_NOT_SUPPORTED, 388fa465739SAzael Avalos * and thus, not registering support for the queried feature. 389fa465739SAzael Avalos */ 390fa465739SAzael Avalos return 1; 3911864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_PRESENT) { 39284a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 39384a6273fSAzael Avalos } 39484a6273fSAzael Avalos 39584a6273fSAzael Avalos return 0; 39684a6273fSAzael Avalos } 39784a6273fSAzael Avalos 39884a6273fSAzael Avalos static void sci_close(struct toshiba_acpi_dev *dev) 39984a6273fSAzael Avalos { 400258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 }; 401258c5903SAzael Avalos u32 out[TCI_WORDS]; 40284a6273fSAzael Avalos acpi_status status; 40384a6273fSAzael Avalos 404258c5903SAzael Avalos status = tci_raw(dev, in, out); 4058baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 40684a6273fSAzael Avalos pr_err("ACPI call to close SCI failed\n"); 40784a6273fSAzael Avalos return; 40884a6273fSAzael Avalos } 40984a6273fSAzael Avalos 4101864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) 41184a6273fSAzael Avalos return; 4121864bbc2SAzael Avalos else if (out[0] == TOS_NOT_OPENED) 41384a6273fSAzael Avalos pr_info("Toshiba SCI not opened\n"); 4141864bbc2SAzael Avalos else if (out[0] == TOS_NOT_PRESENT) 41584a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 41684a6273fSAzael Avalos } 41784a6273fSAzael Avalos 418893f3f62SAzael Avalos static u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 41984a6273fSAzael Avalos { 420258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 }; 421258c5903SAzael Avalos u32 out[TCI_WORDS]; 422258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 423b5163992SAzael Avalos 424893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 425893f3f62SAzael Avalos return TOS_FAILURE; 426893f3f62SAzael Avalos 42784a6273fSAzael Avalos *out1 = out[2]; 428893f3f62SAzael Avalos 429893f3f62SAzael Avalos return out[0]; 43084a6273fSAzael Avalos } 43184a6273fSAzael Avalos 432893f3f62SAzael Avalos static u32 sci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 43384a6273fSAzael Avalos { 434258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 }; 435258c5903SAzael Avalos u32 out[TCI_WORDS]; 436258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 437893f3f62SAzael Avalos 438893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 43984a6273fSAzael Avalos } 44084a6273fSAzael Avalos 4416c3f6e6cSPierre Ducroquet /* Illumination support */ 442135740deSSeth Forshee static int toshiba_illumination_available(struct toshiba_acpi_dev *dev) 4436c3f6e6cSPierre Ducroquet { 444258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 }; 445258c5903SAzael Avalos u32 out[TCI_WORDS]; 4466c3f6e6cSPierre Ducroquet acpi_status status; 4476c3f6e6cSPierre Ducroquet 448fdb79081SAzael Avalos if (!sci_open(dev)) 449fdb79081SAzael Avalos return 0; 450fdb79081SAzael Avalos 451258c5903SAzael Avalos status = tci_raw(dev, in, out); 452fdb79081SAzael Avalos sci_close(dev); 4538baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 454fdb79081SAzael Avalos pr_err("ACPI call to query Illumination support failed\n"); 455fdb79081SAzael Avalos return 0; 4561864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 4577e33460dSJoe Perches pr_info("Illumination device not available\n"); 4586c3f6e6cSPierre Ducroquet return 0; 4596c3f6e6cSPierre Ducroquet } 460fdb79081SAzael Avalos 4616c3f6e6cSPierre Ducroquet return 1; 4626c3f6e6cSPierre Ducroquet } 4636c3f6e6cSPierre Ducroquet 4646c3f6e6cSPierre Ducroquet static void toshiba_illumination_set(struct led_classdev *cdev, 4656c3f6e6cSPierre Ducroquet enum led_brightness brightness) 4666c3f6e6cSPierre Ducroquet { 467135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 468135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 469fdb79081SAzael Avalos u32 state, result; 4706c3f6e6cSPierre Ducroquet 4716c3f6e6cSPierre Ducroquet /* First request : initialize communication. */ 472fdb79081SAzael Avalos if (!sci_open(dev)) 4736c3f6e6cSPierre Ducroquet return; 4746c3f6e6cSPierre Ducroquet 475fdb79081SAzael Avalos /* Switch the illumination on/off */ 476fdb79081SAzael Avalos state = brightness ? 1 : 0; 477893f3f62SAzael Avalos result = sci_write(dev, SCI_ILLUMINATION, state); 478fdb79081SAzael Avalos sci_close(dev); 479893f3f62SAzael Avalos if (result == TOS_FAILURE) { 480fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 481fdb79081SAzael Avalos return; 4821864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 483fdb79081SAzael Avalos pr_info("Illumination not supported\n"); 4846c3f6e6cSPierre Ducroquet return; 4856c3f6e6cSPierre Ducroquet } 4866c3f6e6cSPierre Ducroquet } 4876c3f6e6cSPierre Ducroquet 4886c3f6e6cSPierre Ducroquet static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) 4896c3f6e6cSPierre Ducroquet { 490135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 491135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 492fdb79081SAzael Avalos u32 state, result; 4936c3f6e6cSPierre Ducroquet 4943f75bbe9SAzael Avalos /* First request : initialize communication. */ 495fdb79081SAzael Avalos if (!sci_open(dev)) 4966c3f6e6cSPierre Ducroquet return LED_OFF; 4976c3f6e6cSPierre Ducroquet 4986c3f6e6cSPierre Ducroquet /* Check the illumination */ 499893f3f62SAzael Avalos result = sci_read(dev, SCI_ILLUMINATION, &state); 500fdb79081SAzael Avalos sci_close(dev); 501893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 502fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 503fdb79081SAzael Avalos return LED_OFF; 5041864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 505fdb79081SAzael Avalos pr_info("Illumination not supported\n"); 5066c3f6e6cSPierre Ducroquet return LED_OFF; 5076c3f6e6cSPierre Ducroquet } 5086c3f6e6cSPierre Ducroquet 509fdb79081SAzael Avalos return state ? LED_FULL : LED_OFF; 5106c3f6e6cSPierre Ducroquet } 5116c3f6e6cSPierre Ducroquet 512360f0f39SAzael Avalos /* KBD Illumination */ 51393f8c16dSAzael Avalos static int toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev) 51493f8c16dSAzael Avalos { 515258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 }; 516258c5903SAzael Avalos u32 out[TCI_WORDS]; 51793f8c16dSAzael Avalos acpi_status status; 51893f8c16dSAzael Avalos 51993f8c16dSAzael Avalos if (!sci_open(dev)) 52093f8c16dSAzael Avalos return 0; 52193f8c16dSAzael Avalos 522258c5903SAzael Avalos status = tci_raw(dev, in, out); 52393f8c16dSAzael Avalos sci_close(dev); 5241864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 52593f8c16dSAzael Avalos pr_err("ACPI call to query kbd illumination support failed\n"); 52693f8c16dSAzael Avalos return 0; 5271864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 52893f8c16dSAzael Avalos pr_info("Keyboard illumination not available\n"); 52993f8c16dSAzael Avalos return 0; 53093f8c16dSAzael Avalos } 53193f8c16dSAzael Avalos 532e0769fe6SDarren Hart /* 533e0769fe6SDarren Hart * Check for keyboard backlight timeout max value, 53493f8c16dSAzael Avalos * previous kbd backlight implementation set this to 53593f8c16dSAzael Avalos * 0x3c0003, and now the new implementation set this 536e0769fe6SDarren Hart * to 0x3c001a, use this to distinguish between them. 53793f8c16dSAzael Avalos */ 53893f8c16dSAzael Avalos if (out[3] == SCI_KBD_TIME_MAX) 53993f8c16dSAzael Avalos dev->kbd_type = 2; 54093f8c16dSAzael Avalos else 54193f8c16dSAzael Avalos dev->kbd_type = 1; 54293f8c16dSAzael Avalos /* Get the current keyboard backlight mode */ 54393f8c16dSAzael Avalos dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK; 54493f8c16dSAzael Avalos /* Get the current time (1-60 seconds) */ 54593f8c16dSAzael Avalos dev->kbd_time = out[2] >> HCI_MISC_SHIFT; 54693f8c16dSAzael Avalos 54793f8c16dSAzael Avalos return 1; 54893f8c16dSAzael Avalos } 54993f8c16dSAzael Avalos 550360f0f39SAzael Avalos static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time) 551360f0f39SAzael Avalos { 552360f0f39SAzael Avalos u32 result; 553360f0f39SAzael Avalos 554360f0f39SAzael Avalos if (!sci_open(dev)) 555360f0f39SAzael Avalos return -EIO; 556360f0f39SAzael Avalos 557893f3f62SAzael Avalos result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time); 558360f0f39SAzael Avalos sci_close(dev); 559893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 560360f0f39SAzael Avalos pr_err("ACPI call to set KBD backlight status failed\n"); 561360f0f39SAzael Avalos return -EIO; 5621864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 563360f0f39SAzael Avalos pr_info("Keyboard backlight status not supported\n"); 564360f0f39SAzael Avalos return -ENODEV; 565360f0f39SAzael Avalos } 566360f0f39SAzael Avalos 567360f0f39SAzael Avalos return 0; 568360f0f39SAzael Avalos } 569360f0f39SAzael Avalos 570360f0f39SAzael Avalos static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time) 571360f0f39SAzael Avalos { 572360f0f39SAzael Avalos u32 result; 573360f0f39SAzael Avalos 574360f0f39SAzael Avalos if (!sci_open(dev)) 575360f0f39SAzael Avalos return -EIO; 576360f0f39SAzael Avalos 577893f3f62SAzael Avalos result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time); 578360f0f39SAzael Avalos sci_close(dev); 579893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 580360f0f39SAzael Avalos pr_err("ACPI call to get KBD backlight status failed\n"); 581360f0f39SAzael Avalos return -EIO; 5821864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 583360f0f39SAzael Avalos pr_info("Keyboard backlight status not supported\n"); 584360f0f39SAzael Avalos return -ENODEV; 585360f0f39SAzael Avalos } 586360f0f39SAzael Avalos 587360f0f39SAzael Avalos return 0; 588360f0f39SAzael Avalos } 589360f0f39SAzael Avalos 590360f0f39SAzael Avalos static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev) 591360f0f39SAzael Avalos { 592360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 593360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 594360f0f39SAzael Avalos u32 state, result; 595360f0f39SAzael Avalos 596360f0f39SAzael Avalos /* Check the keyboard backlight state */ 597d37782bdSAzael Avalos result = hci_read(dev, HCI_KBD_ILLUMINATION, &state); 598893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 599360f0f39SAzael Avalos pr_err("ACPI call to get the keyboard backlight failed\n"); 600360f0f39SAzael Avalos return LED_OFF; 6011864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 602360f0f39SAzael Avalos pr_info("Keyboard backlight not supported\n"); 603360f0f39SAzael Avalos return LED_OFF; 604360f0f39SAzael Avalos } 605360f0f39SAzael Avalos 606360f0f39SAzael Avalos return state ? LED_FULL : LED_OFF; 607360f0f39SAzael Avalos } 608360f0f39SAzael Avalos 609360f0f39SAzael Avalos static void toshiba_kbd_backlight_set(struct led_classdev *cdev, 610360f0f39SAzael Avalos enum led_brightness brightness) 611360f0f39SAzael Avalos { 612360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 613360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 614360f0f39SAzael Avalos u32 state, result; 615360f0f39SAzael Avalos 616360f0f39SAzael Avalos /* Set the keyboard backlight state */ 617360f0f39SAzael Avalos state = brightness ? 1 : 0; 618d37782bdSAzael Avalos result = hci_write(dev, HCI_KBD_ILLUMINATION, state); 619893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 620360f0f39SAzael Avalos pr_err("ACPI call to set KBD Illumination mode failed\n"); 621360f0f39SAzael Avalos return; 6221864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 623360f0f39SAzael Avalos pr_info("Keyboard backlight not supported\n"); 624360f0f39SAzael Avalos return; 625360f0f39SAzael Avalos } 626360f0f39SAzael Avalos } 627360f0f39SAzael Avalos 6289d8658acSAzael Avalos /* TouchPad support */ 6299d8658acSAzael Avalos static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state) 6309d8658acSAzael Avalos { 6319d8658acSAzael Avalos u32 result; 6329d8658acSAzael Avalos 6339d8658acSAzael Avalos if (!sci_open(dev)) 6349d8658acSAzael Avalos return -EIO; 6359d8658acSAzael Avalos 636893f3f62SAzael Avalos result = sci_write(dev, SCI_TOUCHPAD, state); 6379d8658acSAzael Avalos sci_close(dev); 638893f3f62SAzael Avalos if (result == TOS_FAILURE) { 6399d8658acSAzael Avalos pr_err("ACPI call to set the touchpad failed\n"); 6409d8658acSAzael Avalos return -EIO; 6411864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 6429d8658acSAzael Avalos return -ENODEV; 6439d8658acSAzael Avalos } 6449d8658acSAzael Avalos 6459d8658acSAzael Avalos return 0; 6469d8658acSAzael Avalos } 6479d8658acSAzael Avalos 6489d8658acSAzael Avalos static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) 6499d8658acSAzael Avalos { 6509d8658acSAzael Avalos u32 result; 6519d8658acSAzael Avalos 6529d8658acSAzael Avalos if (!sci_open(dev)) 6539d8658acSAzael Avalos return -EIO; 6549d8658acSAzael Avalos 655893f3f62SAzael Avalos result = sci_read(dev, SCI_TOUCHPAD, state); 6569d8658acSAzael Avalos sci_close(dev); 657893f3f62SAzael Avalos if (result == TOS_FAILURE) { 6589d8658acSAzael Avalos pr_err("ACPI call to query the touchpad failed\n"); 6599d8658acSAzael Avalos return -EIO; 6601864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 6619d8658acSAzael Avalos return -ENODEV; 6629d8658acSAzael Avalos } 6639d8658acSAzael Avalos 6649d8658acSAzael Avalos return 0; 6659d8658acSAzael Avalos } 6669d8658acSAzael Avalos 667def6c4e2SAzael Avalos /* Eco Mode support */ 668def6c4e2SAzael Avalos static int toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) 669def6c4e2SAzael Avalos { 670def6c4e2SAzael Avalos acpi_status status; 67198fc4ec6SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 }; 672258c5903SAzael Avalos u32 out[TCI_WORDS]; 673def6c4e2SAzael Avalos 674258c5903SAzael Avalos status = tci_raw(dev, in, out); 6758baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 67698fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 67798fc4ec6SAzael Avalos } else if (out[0] == TOS_NOT_INSTALLED) { 67898fc4ec6SAzael Avalos pr_info("ECO led not installed"); 67998fc4ec6SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 680e0769fe6SDarren Hart /* 681e0769fe6SDarren Hart * If we receive 0x8300 (Input Data Error), it means that the 68298fc4ec6SAzael Avalos * LED device is present, but that we just screwed the input 68398fc4ec6SAzael Avalos * parameters. 68498fc4ec6SAzael Avalos * 68598fc4ec6SAzael Avalos * Let's query the status of the LED to see if we really have a 68698fc4ec6SAzael Avalos * success response, indicating the actual presense of the LED, 68798fc4ec6SAzael Avalos * bail out otherwise. 68898fc4ec6SAzael Avalos */ 68998fc4ec6SAzael Avalos in[3] = 1; 69098fc4ec6SAzael Avalos status = tci_raw(dev, in, out); 69198fc4ec6SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) 69298fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 69398fc4ec6SAzael Avalos else if (out[0] == TOS_SUCCESS) 69498fc4ec6SAzael Avalos return 1; 695def6c4e2SAzael Avalos } 696def6c4e2SAzael Avalos 69798fc4ec6SAzael Avalos return 0; 698def6c4e2SAzael Avalos } 699def6c4e2SAzael Avalos 700b5163992SAzael Avalos static enum led_brightness 701b5163992SAzael Avalos toshiba_eco_mode_get_status(struct led_classdev *cdev) 702def6c4e2SAzael Avalos { 703def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 704def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 705258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 }; 706258c5903SAzael Avalos u32 out[TCI_WORDS]; 707def6c4e2SAzael Avalos acpi_status status; 708def6c4e2SAzael Avalos 709258c5903SAzael Avalos status = tci_raw(dev, in, out); 7101864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 711def6c4e2SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 712def6c4e2SAzael Avalos return LED_OFF; 713def6c4e2SAzael Avalos } 714def6c4e2SAzael Avalos 715def6c4e2SAzael Avalos return out[2] ? LED_FULL : LED_OFF; 716def6c4e2SAzael Avalos } 717def6c4e2SAzael Avalos 718def6c4e2SAzael Avalos static void toshiba_eco_mode_set_status(struct led_classdev *cdev, 719def6c4e2SAzael Avalos enum led_brightness brightness) 720def6c4e2SAzael Avalos { 721def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 722def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 723258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 }; 724258c5903SAzael Avalos u32 out[TCI_WORDS]; 725def6c4e2SAzael Avalos acpi_status status; 726def6c4e2SAzael Avalos 727def6c4e2SAzael Avalos /* Switch the Eco Mode led on/off */ 728def6c4e2SAzael Avalos in[2] = (brightness) ? 1 : 0; 729258c5903SAzael Avalos status = tci_raw(dev, in, out); 7301864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 731def6c4e2SAzael Avalos pr_err("ACPI call to set ECO led failed\n"); 732def6c4e2SAzael Avalos return; 733def6c4e2SAzael Avalos } 734def6c4e2SAzael Avalos } 735def6c4e2SAzael Avalos 7365a2813e9SAzael Avalos /* Accelerometer support */ 7375a2813e9SAzael Avalos static int toshiba_accelerometer_supported(struct toshiba_acpi_dev *dev) 7385a2813e9SAzael Avalos { 739258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 }; 740258c5903SAzael Avalos u32 out[TCI_WORDS]; 7415a2813e9SAzael Avalos acpi_status status; 7425a2813e9SAzael Avalos 743e0769fe6SDarren Hart /* 744e0769fe6SDarren Hart * Check if the accelerometer call exists, 7455a2813e9SAzael Avalos * this call also serves as initialization 7465a2813e9SAzael Avalos */ 747258c5903SAzael Avalos status = tci_raw(dev, in, out); 7481864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 7495a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 7505a2813e9SAzael Avalos return -EIO; 7511864bbc2SAzael Avalos } else if (out[0] == TOS_DATA_NOT_AVAILABLE || 7521864bbc2SAzael Avalos out[0] == TOS_NOT_INITIALIZED) { 7535a2813e9SAzael Avalos pr_err("Accelerometer not initialized\n"); 7545a2813e9SAzael Avalos return -EIO; 7551864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 7565a2813e9SAzael Avalos pr_info("Accelerometer not supported\n"); 7575a2813e9SAzael Avalos return -ENODEV; 7585a2813e9SAzael Avalos } 7595a2813e9SAzael Avalos 7605a2813e9SAzael Avalos return 0; 7615a2813e9SAzael Avalos } 7625a2813e9SAzael Avalos 7635a2813e9SAzael Avalos static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, 7645a2813e9SAzael Avalos u32 *xy, u32 *z) 7655a2813e9SAzael Avalos { 766258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 }; 767258c5903SAzael Avalos u32 out[TCI_WORDS]; 7685a2813e9SAzael Avalos acpi_status status; 7695a2813e9SAzael Avalos 7705a2813e9SAzael Avalos /* Check the Accelerometer status */ 771258c5903SAzael Avalos status = tci_raw(dev, in, out); 7721864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 7735a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 7745a2813e9SAzael Avalos return -EIO; 7755a2813e9SAzael Avalos } 7765a2813e9SAzael Avalos 7775a2813e9SAzael Avalos *xy = out[2]; 7785a2813e9SAzael Avalos *z = out[4]; 7795a2813e9SAzael Avalos 7805a2813e9SAzael Avalos return 0; 7815a2813e9SAzael Avalos } 7825a2813e9SAzael Avalos 783e26ffe51SAzael Avalos /* Sleep (Charge and Music) utilities support */ 784c8c91842SAzael Avalos static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev) 785c8c91842SAzael Avalos { 786c8c91842SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 787c8c91842SAzael Avalos u32 out[TCI_WORDS]; 788c8c91842SAzael Avalos acpi_status status; 789c8c91842SAzael Avalos 790c8c91842SAzael Avalos /* Set the feature to "not supported" in case of error */ 791c8c91842SAzael Avalos dev->usb_sleep_charge_supported = 0; 792c8c91842SAzael Avalos 793c8c91842SAzael Avalos if (!sci_open(dev)) 794c8c91842SAzael Avalos return; 795c8c91842SAzael Avalos 796c8c91842SAzael Avalos status = tci_raw(dev, in, out); 7978baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 798c8c91842SAzael Avalos pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); 799c8c91842SAzael Avalos sci_close(dev); 800c8c91842SAzael Avalos return; 801c8c91842SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 802c8c91842SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 803c8c91842SAzael Avalos sci_close(dev); 804c8c91842SAzael Avalos return; 805c8c91842SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 806c8c91842SAzael Avalos dev->usbsc_mode_base = out[4]; 807c8c91842SAzael Avalos } 808c8c91842SAzael Avalos 809c8c91842SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 810c8c91842SAzael Avalos status = tci_raw(dev, in, out); 8118baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 812c8c91842SAzael Avalos pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); 813c8c91842SAzael Avalos sci_close(dev); 814c8c91842SAzael Avalos return; 815c8c91842SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 816c8c91842SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 817c8c91842SAzael Avalos sci_close(dev); 818c8c91842SAzael Avalos return; 819c8c91842SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 820c8c91842SAzael Avalos dev->usbsc_bat_level = out[2]; 821c8c91842SAzael Avalos /* 822c8c91842SAzael Avalos * If we reach this point, it means that the laptop has support 823c8c91842SAzael Avalos * for this feature and all values are initialized. 824c8c91842SAzael Avalos * Set it as supported. 825c8c91842SAzael Avalos */ 826c8c91842SAzael Avalos dev->usb_sleep_charge_supported = 1; 827c8c91842SAzael Avalos } 828c8c91842SAzael Avalos 829c8c91842SAzael Avalos sci_close(dev); 830c8c91842SAzael Avalos } 831c8c91842SAzael Avalos 832e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, 833e26ffe51SAzael Avalos u32 *mode) 834e26ffe51SAzael Avalos { 835e26ffe51SAzael Avalos u32 result; 836e26ffe51SAzael Avalos 837e26ffe51SAzael Avalos if (!sci_open(dev)) 838e26ffe51SAzael Avalos return -EIO; 839e26ffe51SAzael Avalos 840e26ffe51SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode); 841e26ffe51SAzael Avalos sci_close(dev); 842e26ffe51SAzael Avalos if (result == TOS_FAILURE) { 843e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 844e26ffe51SAzael Avalos return -EIO; 845e26ffe51SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 846e26ffe51SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 847e26ffe51SAzael Avalos return -ENODEV; 848e26ffe51SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 849e26ffe51SAzael Avalos return -EIO; 850e26ffe51SAzael Avalos } 851e26ffe51SAzael Avalos 852e26ffe51SAzael Avalos return 0; 853e26ffe51SAzael Avalos } 854e26ffe51SAzael Avalos 855e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev, 856e26ffe51SAzael Avalos u32 mode) 857e26ffe51SAzael Avalos { 858e26ffe51SAzael Avalos u32 result; 859e26ffe51SAzael Avalos 860e26ffe51SAzael Avalos if (!sci_open(dev)) 861e26ffe51SAzael Avalos return -EIO; 862e26ffe51SAzael Avalos 863e26ffe51SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode); 864e26ffe51SAzael Avalos sci_close(dev); 865e26ffe51SAzael Avalos if (result == TOS_FAILURE) { 866e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 867e26ffe51SAzael Avalos return -EIO; 868e26ffe51SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 869e26ffe51SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 870e26ffe51SAzael Avalos return -ENODEV; 871e26ffe51SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 872e26ffe51SAzael Avalos return -EIO; 873e26ffe51SAzael Avalos } 874e26ffe51SAzael Avalos 875e26ffe51SAzael Avalos return 0; 876e26ffe51SAzael Avalos } 877e26ffe51SAzael Avalos 878182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev, 879182bcaa5SAzael Avalos u32 *mode) 880182bcaa5SAzael Avalos { 881182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 882182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 883182bcaa5SAzael Avalos acpi_status status; 884182bcaa5SAzael Avalos 885182bcaa5SAzael Avalos if (!sci_open(dev)) 886182bcaa5SAzael Avalos return -EIO; 887182bcaa5SAzael Avalos 888182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 889182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 890182bcaa5SAzael Avalos sci_close(dev); 8918baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 892182bcaa5SAzael Avalos pr_err("ACPI call to get USB S&C battery level failed\n"); 893182bcaa5SAzael Avalos return -EIO; 894182bcaa5SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 895182bcaa5SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 896182bcaa5SAzael Avalos return -ENODEV; 897182bcaa5SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 898182bcaa5SAzael Avalos return -EIO; 899182bcaa5SAzael Avalos } 900182bcaa5SAzael Avalos 901182bcaa5SAzael Avalos *mode = out[2]; 902182bcaa5SAzael Avalos 903182bcaa5SAzael Avalos return 0; 904182bcaa5SAzael Avalos } 905182bcaa5SAzael Avalos 906182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, 907182bcaa5SAzael Avalos u32 mode) 908182bcaa5SAzael Avalos { 909182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 910182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 911182bcaa5SAzael Avalos acpi_status status; 912182bcaa5SAzael Avalos 913182bcaa5SAzael Avalos if (!sci_open(dev)) 914182bcaa5SAzael Avalos return -EIO; 915182bcaa5SAzael Avalos 916182bcaa5SAzael Avalos in[2] = mode; 917182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 918182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 919182bcaa5SAzael Avalos sci_close(dev); 9208baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 921182bcaa5SAzael Avalos pr_err("ACPI call to set USB S&C battery level failed\n"); 922182bcaa5SAzael Avalos return -EIO; 923182bcaa5SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 924182bcaa5SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 925182bcaa5SAzael Avalos return -ENODEV; 926182bcaa5SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 927182bcaa5SAzael Avalos return -EIO; 928182bcaa5SAzael Avalos } 929182bcaa5SAzael Avalos 930182bcaa5SAzael Avalos return 0; 931182bcaa5SAzael Avalos } 932182bcaa5SAzael Avalos 933bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, 934bb3fe01fSAzael Avalos u32 *state) 935bb3fe01fSAzael Avalos { 936bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 937bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 938bb3fe01fSAzael Avalos acpi_status status; 939bb3fe01fSAzael Avalos 940bb3fe01fSAzael Avalos if (!sci_open(dev)) 941bb3fe01fSAzael Avalos return -EIO; 942bb3fe01fSAzael Avalos 943bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 944bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 945bb3fe01fSAzael Avalos sci_close(dev); 9468baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 947bb26f189SAzael Avalos pr_err("ACPI call to get USB Rapid Charge failed\n"); 948bb3fe01fSAzael Avalos return -EIO; 949bb3fe01fSAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED || 950bb3fe01fSAzael Avalos out[0] == TOS_INPUT_DATA_ERROR) { 951bb26f189SAzael Avalos pr_info("USB Rapid Charge not supported\n"); 952bb3fe01fSAzael Avalos return -ENODEV; 953bb3fe01fSAzael Avalos } 954bb3fe01fSAzael Avalos 955bb3fe01fSAzael Avalos *state = out[2]; 956bb3fe01fSAzael Avalos 957bb3fe01fSAzael Avalos return 0; 958bb3fe01fSAzael Avalos } 959bb3fe01fSAzael Avalos 960bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, 961bb3fe01fSAzael Avalos u32 state) 962bb3fe01fSAzael Avalos { 963bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 964bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 965bb3fe01fSAzael Avalos acpi_status status; 966bb3fe01fSAzael Avalos 967bb3fe01fSAzael Avalos if (!sci_open(dev)) 968bb3fe01fSAzael Avalos return -EIO; 969bb3fe01fSAzael Avalos 970bb3fe01fSAzael Avalos in[2] = state; 971bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 972bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 973bb3fe01fSAzael Avalos sci_close(dev); 9748baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 975bb26f189SAzael Avalos pr_err("ACPI call to set USB Rapid Charge failed\n"); 976bb3fe01fSAzael Avalos return -EIO; 977bb3fe01fSAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 978bb26f189SAzael Avalos pr_info("USB Rapid Charge not supported\n"); 979bb3fe01fSAzael Avalos return -ENODEV; 980bb3fe01fSAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 981bb3fe01fSAzael Avalos return -EIO; 982bb3fe01fSAzael Avalos } 983bb3fe01fSAzael Avalos 984bb3fe01fSAzael Avalos return 0; 985bb3fe01fSAzael Avalos } 986bb3fe01fSAzael Avalos 987172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state) 988172ce0a9SAzael Avalos { 989172ce0a9SAzael Avalos u32 result; 990172ce0a9SAzael Avalos 991172ce0a9SAzael Avalos if (!sci_open(dev)) 992172ce0a9SAzael Avalos return -EIO; 993172ce0a9SAzael Avalos 994172ce0a9SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state); 995172ce0a9SAzael Avalos sci_close(dev); 996172ce0a9SAzael Avalos if (result == TOS_FAILURE) { 997bb26f189SAzael Avalos pr_err("ACPI call to get Sleep and Music failed\n"); 998172ce0a9SAzael Avalos return -EIO; 999172ce0a9SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1000bb26f189SAzael Avalos pr_info("Sleep and Music not supported\n"); 1001172ce0a9SAzael Avalos return -ENODEV; 1002172ce0a9SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 1003172ce0a9SAzael Avalos return -EIO; 1004172ce0a9SAzael Avalos } 1005172ce0a9SAzael Avalos 1006172ce0a9SAzael Avalos return 0; 1007172ce0a9SAzael Avalos } 1008172ce0a9SAzael Avalos 1009172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state) 1010172ce0a9SAzael Avalos { 1011172ce0a9SAzael Avalos u32 result; 1012172ce0a9SAzael Avalos 1013172ce0a9SAzael Avalos if (!sci_open(dev)) 1014172ce0a9SAzael Avalos return -EIO; 1015172ce0a9SAzael Avalos 1016172ce0a9SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state); 1017172ce0a9SAzael Avalos sci_close(dev); 1018172ce0a9SAzael Avalos if (result == TOS_FAILURE) { 1019bb26f189SAzael Avalos pr_err("ACPI call to set Sleep and Music failed\n"); 1020172ce0a9SAzael Avalos return -EIO; 1021172ce0a9SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1022bb26f189SAzael Avalos pr_info("Sleep and Music not supported\n"); 1023172ce0a9SAzael Avalos return -ENODEV; 1024172ce0a9SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 1025172ce0a9SAzael Avalos return -EIO; 1026172ce0a9SAzael Avalos } 1027172ce0a9SAzael Avalos 1028172ce0a9SAzael Avalos return 0; 1029172ce0a9SAzael Avalos } 1030172ce0a9SAzael Avalos 1031bae84195SAzael Avalos /* Keyboard function keys */ 1032bae84195SAzael Avalos static int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode) 1033bae84195SAzael Avalos { 1034bae84195SAzael Avalos u32 result; 1035bae84195SAzael Avalos 1036bae84195SAzael Avalos if (!sci_open(dev)) 1037bae84195SAzael Avalos return -EIO; 1038bae84195SAzael Avalos 1039bae84195SAzael Avalos result = sci_read(dev, SCI_KBD_FUNCTION_KEYS, mode); 1040bae84195SAzael Avalos sci_close(dev); 1041bae84195SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 1042bae84195SAzael Avalos pr_err("ACPI call to get KBD function keys failed\n"); 1043bae84195SAzael Avalos return -EIO; 1044bae84195SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1045bae84195SAzael Avalos pr_info("KBD function keys not supported\n"); 1046bae84195SAzael Avalos return -ENODEV; 1047bae84195SAzael Avalos } 1048bae84195SAzael Avalos 1049bae84195SAzael Avalos return 0; 1050bae84195SAzael Avalos } 1051bae84195SAzael Avalos 1052bae84195SAzael Avalos static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode) 1053bae84195SAzael Avalos { 1054bae84195SAzael Avalos u32 result; 1055bae84195SAzael Avalos 1056bae84195SAzael Avalos if (!sci_open(dev)) 1057bae84195SAzael Avalos return -EIO; 1058bae84195SAzael Avalos 1059bae84195SAzael Avalos result = sci_write(dev, SCI_KBD_FUNCTION_KEYS, mode); 1060bae84195SAzael Avalos sci_close(dev); 1061bae84195SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 1062bae84195SAzael Avalos pr_err("ACPI call to set KBD function keys failed\n"); 1063bae84195SAzael Avalos return -EIO; 1064bae84195SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1065bae84195SAzael Avalos pr_info("KBD function keys not supported\n"); 1066bae84195SAzael Avalos return -ENODEV; 1067bae84195SAzael Avalos } 1068bae84195SAzael Avalos 1069bae84195SAzael Avalos return 0; 1070bae84195SAzael Avalos } 1071bae84195SAzael Avalos 107235d53ceaSAzael Avalos /* Panel Power ON */ 107335d53ceaSAzael Avalos static int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state) 107435d53ceaSAzael Avalos { 107535d53ceaSAzael Avalos u32 result; 107635d53ceaSAzael Avalos 107735d53ceaSAzael Avalos if (!sci_open(dev)) 107835d53ceaSAzael Avalos return -EIO; 107935d53ceaSAzael Avalos 108035d53ceaSAzael Avalos result = sci_read(dev, SCI_PANEL_POWER_ON, state); 108135d53ceaSAzael Avalos sci_close(dev); 108235d53ceaSAzael Avalos if (result == TOS_FAILURE) { 108335d53ceaSAzael Avalos pr_err("ACPI call to get Panel Power ON failed\n"); 108435d53ceaSAzael Avalos return -EIO; 108535d53ceaSAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 108635d53ceaSAzael Avalos pr_info("Panel Power on not supported\n"); 108735d53ceaSAzael Avalos return -ENODEV; 108835d53ceaSAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 108935d53ceaSAzael Avalos return -EIO; 109035d53ceaSAzael Avalos } 109135d53ceaSAzael Avalos 109235d53ceaSAzael Avalos return 0; 109335d53ceaSAzael Avalos } 109435d53ceaSAzael Avalos 109535d53ceaSAzael Avalos static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state) 109635d53ceaSAzael Avalos { 109735d53ceaSAzael Avalos u32 result; 109835d53ceaSAzael Avalos 109935d53ceaSAzael Avalos if (!sci_open(dev)) 110035d53ceaSAzael Avalos return -EIO; 110135d53ceaSAzael Avalos 110235d53ceaSAzael Avalos result = sci_write(dev, SCI_PANEL_POWER_ON, state); 110335d53ceaSAzael Avalos sci_close(dev); 110435d53ceaSAzael Avalos if (result == TOS_FAILURE) { 110535d53ceaSAzael Avalos pr_err("ACPI call to set Panel Power ON failed\n"); 110635d53ceaSAzael Avalos return -EIO; 110735d53ceaSAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 110835d53ceaSAzael Avalos pr_info("Panel Power ON not supported\n"); 110935d53ceaSAzael Avalos return -ENODEV; 111035d53ceaSAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 111135d53ceaSAzael Avalos return -EIO; 111235d53ceaSAzael Avalos } 111335d53ceaSAzael Avalos 111435d53ceaSAzael Avalos return 0; 111535d53ceaSAzael Avalos } 111635d53ceaSAzael Avalos 111717fe4b3dSAzael Avalos /* USB Three */ 111817fe4b3dSAzael Avalos static int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state) 111917fe4b3dSAzael Avalos { 112017fe4b3dSAzael Avalos u32 result; 112117fe4b3dSAzael Avalos 112217fe4b3dSAzael Avalos if (!sci_open(dev)) 112317fe4b3dSAzael Avalos return -EIO; 112417fe4b3dSAzael Avalos 112517fe4b3dSAzael Avalos result = sci_read(dev, SCI_USB_THREE, state); 112617fe4b3dSAzael Avalos sci_close(dev); 112717fe4b3dSAzael Avalos if (result == TOS_FAILURE) { 112817fe4b3dSAzael Avalos pr_err("ACPI call to get USB 3 failed\n"); 112917fe4b3dSAzael Avalos return -EIO; 113017fe4b3dSAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 113117fe4b3dSAzael Avalos pr_info("USB 3 not supported\n"); 113217fe4b3dSAzael Avalos return -ENODEV; 113317fe4b3dSAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 113417fe4b3dSAzael Avalos return -EIO; 113517fe4b3dSAzael Avalos } 113617fe4b3dSAzael Avalos 113717fe4b3dSAzael Avalos return 0; 113817fe4b3dSAzael Avalos } 113917fe4b3dSAzael Avalos 114017fe4b3dSAzael Avalos static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state) 114117fe4b3dSAzael Avalos { 114217fe4b3dSAzael Avalos u32 result; 114317fe4b3dSAzael Avalos 114417fe4b3dSAzael Avalos if (!sci_open(dev)) 114517fe4b3dSAzael Avalos return -EIO; 114617fe4b3dSAzael Avalos 114717fe4b3dSAzael Avalos result = sci_write(dev, SCI_USB_THREE, state); 114817fe4b3dSAzael Avalos sci_close(dev); 114917fe4b3dSAzael Avalos if (result == TOS_FAILURE) { 115017fe4b3dSAzael Avalos pr_err("ACPI call to set USB 3 failed\n"); 115117fe4b3dSAzael Avalos return -EIO; 115217fe4b3dSAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 115317fe4b3dSAzael Avalos pr_info("USB 3 not supported\n"); 115417fe4b3dSAzael Avalos return -ENODEV; 115517fe4b3dSAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 115617fe4b3dSAzael Avalos return -EIO; 115717fe4b3dSAzael Avalos } 115817fe4b3dSAzael Avalos 115917fe4b3dSAzael Avalos return 0; 116017fe4b3dSAzael Avalos } 116117fe4b3dSAzael Avalos 116256e6b353SAzael Avalos /* Hotkey Event type */ 116356e6b353SAzael Avalos static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev, 116456e6b353SAzael Avalos u32 *type) 116556e6b353SAzael Avalos { 11663b876000SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_SYSTEM_INFO, 0x03, 0, 0, 0 }; 11673b876000SAzael Avalos u32 out[TCI_WORDS]; 11683b876000SAzael Avalos acpi_status status; 116956e6b353SAzael Avalos 11703b876000SAzael Avalos status = tci_raw(dev, in, out); 11713b876000SAzael Avalos if (ACPI_FAILURE(status)) { 117256e6b353SAzael Avalos pr_err("ACPI call to get System type failed\n"); 117356e6b353SAzael Avalos return -EIO; 11743b876000SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 117556e6b353SAzael Avalos pr_info("System type not supported\n"); 117656e6b353SAzael Avalos return -ENODEV; 117756e6b353SAzael Avalos } 117856e6b353SAzael Avalos 11793b876000SAzael Avalos *type = out[3]; 118056e6b353SAzael Avalos 118156e6b353SAzael Avalos return 0; 118256e6b353SAzael Avalos } 118356e6b353SAzael Avalos 11843f75bbe9SAzael Avalos /* Transflective Backlight */ 1185695f6060SAzael Avalos static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status) 1186121b7b0dSAkio Idehara { 1187695f6060SAzael Avalos u32 hci_result = hci_read(dev, HCI_TR_BACKLIGHT, status); 1188121b7b0dSAkio Idehara 11891864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 1190121b7b0dSAkio Idehara } 1191121b7b0dSAkio Idehara 1192695f6060SAzael Avalos static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 status) 1193121b7b0dSAkio Idehara { 1194695f6060SAzael Avalos u32 hci_result = hci_write(dev, HCI_TR_BACKLIGHT, !status); 1195121b7b0dSAkio Idehara 11961864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 1197121b7b0dSAkio Idehara } 1198121b7b0dSAkio Idehara 11993f75bbe9SAzael Avalos static struct proc_dir_entry *toshiba_proc_dir; 1200b4f9fe12SLen Brown 12013f75bbe9SAzael Avalos /* LCD Brightness */ 120262cce752SSeth Forshee static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) 1203b4f9fe12SLen Brown { 1204b4f9fe12SLen Brown u32 hci_result; 1205b4f9fe12SLen Brown u32 value; 1206121b7b0dSAkio Idehara int brightness = 0; 1207121b7b0dSAkio Idehara 1208121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1209695f6060SAzael Avalos int ret = get_tr_backlight_status(dev, &value); 1210b5163992SAzael Avalos 1211121b7b0dSAkio Idehara if (ret) 1212121b7b0dSAkio Idehara return ret; 1213695f6060SAzael Avalos if (value) 1214121b7b0dSAkio Idehara return 0; 1215121b7b0dSAkio Idehara brightness++; 1216121b7b0dSAkio Idehara } 1217b4f9fe12SLen Brown 1218d37782bdSAzael Avalos hci_result = hci_read(dev, HCI_LCD_BRIGHTNESS, &value); 12191864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) 1220121b7b0dSAkio Idehara return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT); 122132bcd5cbSSeth Forshee 122232bcd5cbSSeth Forshee return -EIO; 1223b4f9fe12SLen Brown } 1224b4f9fe12SLen Brown 122562cce752SSeth Forshee static int get_lcd_brightness(struct backlight_device *bd) 122662cce752SSeth Forshee { 122762cce752SSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 1228b5163992SAzael Avalos 122962cce752SSeth Forshee return __get_lcd_brightness(dev); 123062cce752SSeth Forshee } 123162cce752SSeth Forshee 1232936c8bcdSAlexey Dobriyan static int lcd_proc_show(struct seq_file *m, void *v) 1233b4f9fe12SLen Brown { 1234135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1235135740deSSeth Forshee int value; 1236121b7b0dSAkio Idehara int levels; 1237b4f9fe12SLen Brown 1238135740deSSeth Forshee if (!dev->backlight_dev) 1239135740deSSeth Forshee return -ENODEV; 1240135740deSSeth Forshee 1241121b7b0dSAkio Idehara levels = dev->backlight_dev->props.max_brightness + 1; 124262cce752SSeth Forshee value = get_lcd_brightness(dev->backlight_dev); 1243b4f9fe12SLen Brown if (value >= 0) { 1244936c8bcdSAlexey Dobriyan seq_printf(m, "brightness: %d\n", value); 1245121b7b0dSAkio Idehara seq_printf(m, "brightness_levels: %d\n", levels); 124632bcd5cbSSeth Forshee return 0; 1247b4f9fe12SLen Brown } 1248b4f9fe12SLen Brown 124932bcd5cbSSeth Forshee pr_err("Error reading LCD brightness\n"); 125032bcd5cbSSeth Forshee return -EIO; 1251936c8bcdSAlexey Dobriyan } 1252936c8bcdSAlexey Dobriyan 1253936c8bcdSAlexey Dobriyan static int lcd_proc_open(struct inode *inode, struct file *file) 1254936c8bcdSAlexey Dobriyan { 1255d9dda78bSAl Viro return single_open(file, lcd_proc_show, PDE_DATA(inode)); 1256b4f9fe12SLen Brown } 1257b4f9fe12SLen Brown 125862cce752SSeth Forshee static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) 1259b4f9fe12SLen Brown { 1260a39f46dfSAzael Avalos u32 hci_result; 1261b4f9fe12SLen Brown 1262121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1263695f6060SAzael Avalos int ret = set_tr_backlight_status(dev, !value); 1264b5163992SAzael Avalos 1265121b7b0dSAkio Idehara if (ret) 1266121b7b0dSAkio Idehara return ret; 1267121b7b0dSAkio Idehara if (value) 1268121b7b0dSAkio Idehara value--; 1269121b7b0dSAkio Idehara } 1270121b7b0dSAkio Idehara 1271a39f46dfSAzael Avalos value = value << HCI_LCD_BRIGHTNESS_SHIFT; 1272d37782bdSAzael Avalos hci_result = hci_write(dev, HCI_LCD_BRIGHTNESS, value); 1273a39f46dfSAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 1274b4f9fe12SLen Brown } 1275b4f9fe12SLen Brown 1276b4f9fe12SLen Brown static int set_lcd_status(struct backlight_device *bd) 1277b4f9fe12SLen Brown { 1278135740deSSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 1279b5163992SAzael Avalos 128062cce752SSeth Forshee return set_lcd_brightness(dev, bd->props.brightness); 1281b4f9fe12SLen Brown } 1282b4f9fe12SLen Brown 1283936c8bcdSAlexey Dobriyan static ssize_t lcd_proc_write(struct file *file, const char __user *buf, 1284936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1285b4f9fe12SLen Brown { 1286d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1287936c8bcdSAlexey Dobriyan char cmd[42]; 1288936c8bcdSAlexey Dobriyan size_t len; 1289b4f9fe12SLen Brown int value; 1290b4f9fe12SLen Brown int ret; 1291121b7b0dSAkio Idehara int levels = dev->backlight_dev->props.max_brightness + 1; 1292b4f9fe12SLen Brown 1293936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1294936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1295936c8bcdSAlexey Dobriyan return -EFAULT; 1296936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1297936c8bcdSAlexey Dobriyan 1298936c8bcdSAlexey Dobriyan if (sscanf(cmd, " brightness : %i", &value) == 1 && 1299121b7b0dSAkio Idehara value >= 0 && value < levels) { 130062cce752SSeth Forshee ret = set_lcd_brightness(dev, value); 1301b4f9fe12SLen Brown if (ret == 0) 1302b4f9fe12SLen Brown ret = count; 1303b4f9fe12SLen Brown } else { 1304b4f9fe12SLen Brown ret = -EINVAL; 1305b4f9fe12SLen Brown } 1306b4f9fe12SLen Brown return ret; 1307b4f9fe12SLen Brown } 1308b4f9fe12SLen Brown 1309936c8bcdSAlexey Dobriyan static const struct file_operations lcd_proc_fops = { 1310936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1311936c8bcdSAlexey Dobriyan .open = lcd_proc_open, 1312936c8bcdSAlexey Dobriyan .read = seq_read, 1313936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1314936c8bcdSAlexey Dobriyan .release = single_release, 1315936c8bcdSAlexey Dobriyan .write = lcd_proc_write, 1316936c8bcdSAlexey Dobriyan }; 1317936c8bcdSAlexey Dobriyan 131836d03f93SSeth Forshee static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status) 131936d03f93SSeth Forshee { 132036d03f93SSeth Forshee u32 hci_result; 132136d03f93SSeth Forshee 1322d37782bdSAzael Avalos hci_result = hci_read(dev, HCI_VIDEO_OUT, status); 13231864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 132436d03f93SSeth Forshee } 132536d03f93SSeth Forshee 1326936c8bcdSAlexey Dobriyan static int video_proc_show(struct seq_file *m, void *v) 1327b4f9fe12SLen Brown { 1328135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1329b4f9fe12SLen Brown u32 value; 133036d03f93SSeth Forshee int ret; 1331b4f9fe12SLen Brown 133236d03f93SSeth Forshee ret = get_video_status(dev, &value); 133336d03f93SSeth Forshee if (!ret) { 1334b4f9fe12SLen Brown int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; 1335b4f9fe12SLen Brown int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; 1336b4f9fe12SLen Brown int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; 1337b5163992SAzael Avalos 1338936c8bcdSAlexey Dobriyan seq_printf(m, "lcd_out: %d\n", is_lcd); 1339936c8bcdSAlexey Dobriyan seq_printf(m, "crt_out: %d\n", is_crt); 1340936c8bcdSAlexey Dobriyan seq_printf(m, "tv_out: %d\n", is_tv); 1341b4f9fe12SLen Brown } 1342b4f9fe12SLen Brown 134336d03f93SSeth Forshee return ret; 1344b4f9fe12SLen Brown } 1345b4f9fe12SLen Brown 1346936c8bcdSAlexey Dobriyan static int video_proc_open(struct inode *inode, struct file *file) 1347b4f9fe12SLen Brown { 1348d9dda78bSAl Viro return single_open(file, video_proc_show, PDE_DATA(inode)); 1349936c8bcdSAlexey Dobriyan } 1350936c8bcdSAlexey Dobriyan 1351936c8bcdSAlexey Dobriyan static ssize_t video_proc_write(struct file *file, const char __user *buf, 1352936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1353936c8bcdSAlexey Dobriyan { 1354d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1355936c8bcdSAlexey Dobriyan char *cmd, *buffer; 135636d03f93SSeth Forshee int ret; 1357b4f9fe12SLen Brown int value; 1358b4f9fe12SLen Brown int remain = count; 1359b4f9fe12SLen Brown int lcd_out = -1; 1360b4f9fe12SLen Brown int crt_out = -1; 1361b4f9fe12SLen Brown int tv_out = -1; 1362b4f9fe12SLen Brown u32 video_out; 1363b4f9fe12SLen Brown 1364936c8bcdSAlexey Dobriyan cmd = kmalloc(count + 1, GFP_KERNEL); 1365936c8bcdSAlexey Dobriyan if (!cmd) 1366936c8bcdSAlexey Dobriyan return -ENOMEM; 1367936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, count)) { 1368936c8bcdSAlexey Dobriyan kfree(cmd); 1369936c8bcdSAlexey Dobriyan return -EFAULT; 1370936c8bcdSAlexey Dobriyan } 1371936c8bcdSAlexey Dobriyan cmd[count] = '\0'; 1372936c8bcdSAlexey Dobriyan 1373936c8bcdSAlexey Dobriyan buffer = cmd; 1374936c8bcdSAlexey Dobriyan 1375e0769fe6SDarren Hart /* 1376e0769fe6SDarren Hart * Scan expression. Multiple expressions may be delimited with ; 1377e0769fe6SDarren Hart * NOTE: To keep scanning simple, invalid fields are ignored. 1378b4f9fe12SLen Brown */ 1379b4f9fe12SLen Brown while (remain) { 1380b4f9fe12SLen Brown if (sscanf(buffer, " lcd_out : %i", &value) == 1) 1381b4f9fe12SLen Brown lcd_out = value & 1; 1382b4f9fe12SLen Brown else if (sscanf(buffer, " crt_out : %i", &value) == 1) 1383b4f9fe12SLen Brown crt_out = value & 1; 1384b4f9fe12SLen Brown else if (sscanf(buffer, " tv_out : %i", &value) == 1) 1385b4f9fe12SLen Brown tv_out = value & 1; 1386e0769fe6SDarren Hart /* Advance to one character past the next ; */ 1387b4f9fe12SLen Brown do { 1388b4f9fe12SLen Brown ++buffer; 1389b4f9fe12SLen Brown --remain; 1390b5163992SAzael Avalos } while (remain && *(buffer - 1) != ';'); 1391b4f9fe12SLen Brown } 1392b4f9fe12SLen Brown 1393936c8bcdSAlexey Dobriyan kfree(cmd); 1394936c8bcdSAlexey Dobriyan 139536d03f93SSeth Forshee ret = get_video_status(dev, &video_out); 139636d03f93SSeth Forshee if (!ret) { 1397b4f9fe12SLen Brown unsigned int new_video_out = video_out; 1398b5163992SAzael Avalos 1399b4f9fe12SLen Brown if (lcd_out != -1) 1400b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out); 1401b4f9fe12SLen Brown if (crt_out != -1) 1402b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out); 1403b4f9fe12SLen Brown if (tv_out != -1) 1404b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out); 1405e0769fe6SDarren Hart /* 1406e0769fe6SDarren Hart * To avoid unnecessary video disruption, only write the new 14073f75bbe9SAzael Avalos * video setting if something changed. 14083f75bbe9SAzael Avalos */ 1409b4f9fe12SLen Brown if (new_video_out != video_out) 141032bcd5cbSSeth Forshee ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out); 1411b4f9fe12SLen Brown } 1412b4f9fe12SLen Brown 141332bcd5cbSSeth Forshee return ret ? ret : count; 1414b4f9fe12SLen Brown } 1415b4f9fe12SLen Brown 1416936c8bcdSAlexey Dobriyan static const struct file_operations video_proc_fops = { 1417936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1418936c8bcdSAlexey Dobriyan .open = video_proc_open, 1419936c8bcdSAlexey Dobriyan .read = seq_read, 1420936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1421936c8bcdSAlexey Dobriyan .release = single_release, 1422936c8bcdSAlexey Dobriyan .write = video_proc_write, 1423936c8bcdSAlexey Dobriyan }; 1424936c8bcdSAlexey Dobriyan 142536d03f93SSeth Forshee static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status) 142636d03f93SSeth Forshee { 142736d03f93SSeth Forshee u32 hci_result; 142836d03f93SSeth Forshee 1429d37782bdSAzael Avalos hci_result = hci_read(dev, HCI_FAN, status); 14301864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 143136d03f93SSeth Forshee } 143236d03f93SSeth Forshee 1433936c8bcdSAlexey Dobriyan static int fan_proc_show(struct seq_file *m, void *v) 1434b4f9fe12SLen Brown { 1435135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 143636d03f93SSeth Forshee int ret; 1437b4f9fe12SLen Brown u32 value; 1438b4f9fe12SLen Brown 143936d03f93SSeth Forshee ret = get_fan_status(dev, &value); 144036d03f93SSeth Forshee if (!ret) { 1441936c8bcdSAlexey Dobriyan seq_printf(m, "running: %d\n", (value > 0)); 1442135740deSSeth Forshee seq_printf(m, "force_on: %d\n", dev->force_fan); 1443b4f9fe12SLen Brown } 1444b4f9fe12SLen Brown 144536d03f93SSeth Forshee return ret; 1446b4f9fe12SLen Brown } 1447b4f9fe12SLen Brown 1448936c8bcdSAlexey Dobriyan static int fan_proc_open(struct inode *inode, struct file *file) 1449b4f9fe12SLen Brown { 1450d9dda78bSAl Viro return single_open(file, fan_proc_show, PDE_DATA(inode)); 1451936c8bcdSAlexey Dobriyan } 1452936c8bcdSAlexey Dobriyan 1453936c8bcdSAlexey Dobriyan static ssize_t fan_proc_write(struct file *file, const char __user *buf, 1454936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1455936c8bcdSAlexey Dobriyan { 1456d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1457936c8bcdSAlexey Dobriyan char cmd[42]; 1458936c8bcdSAlexey Dobriyan size_t len; 1459b4f9fe12SLen Brown int value; 1460b4f9fe12SLen Brown u32 hci_result; 1461b4f9fe12SLen Brown 1462936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1463936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1464936c8bcdSAlexey Dobriyan return -EFAULT; 1465936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1466936c8bcdSAlexey Dobriyan 1467936c8bcdSAlexey Dobriyan if (sscanf(cmd, " force_on : %i", &value) == 1 && 1468b4f9fe12SLen Brown value >= 0 && value <= 1) { 1469d37782bdSAzael Avalos hci_result = hci_write(dev, HCI_FAN, value); 1470b5163992SAzael Avalos if (hci_result == TOS_SUCCESS) 1471135740deSSeth Forshee dev->force_fan = value; 1472b5163992SAzael Avalos else 1473b5163992SAzael Avalos return -EIO; 1474b4f9fe12SLen Brown } else { 1475b4f9fe12SLen Brown return -EINVAL; 1476b4f9fe12SLen Brown } 1477b4f9fe12SLen Brown 1478b4f9fe12SLen Brown return count; 1479b4f9fe12SLen Brown } 1480b4f9fe12SLen Brown 1481936c8bcdSAlexey Dobriyan static const struct file_operations fan_proc_fops = { 1482936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1483936c8bcdSAlexey Dobriyan .open = fan_proc_open, 1484936c8bcdSAlexey Dobriyan .read = seq_read, 1485936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1486936c8bcdSAlexey Dobriyan .release = single_release, 1487936c8bcdSAlexey Dobriyan .write = fan_proc_write, 1488936c8bcdSAlexey Dobriyan }; 1489936c8bcdSAlexey Dobriyan 1490936c8bcdSAlexey Dobriyan static int keys_proc_show(struct seq_file *m, void *v) 1491b4f9fe12SLen Brown { 1492135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1493b4f9fe12SLen Brown 1494135740deSSeth Forshee seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid); 1495135740deSSeth Forshee seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event); 14967deef550SAzael Avalos 1497936c8bcdSAlexey Dobriyan return 0; 1498b4f9fe12SLen Brown } 1499b4f9fe12SLen Brown 1500936c8bcdSAlexey Dobriyan static int keys_proc_open(struct inode *inode, struct file *file) 1501b4f9fe12SLen Brown { 1502d9dda78bSAl Viro return single_open(file, keys_proc_show, PDE_DATA(inode)); 1503936c8bcdSAlexey Dobriyan } 1504936c8bcdSAlexey Dobriyan 1505936c8bcdSAlexey Dobriyan static ssize_t keys_proc_write(struct file *file, const char __user *buf, 1506936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1507936c8bcdSAlexey Dobriyan { 1508d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1509936c8bcdSAlexey Dobriyan char cmd[42]; 1510936c8bcdSAlexey Dobriyan size_t len; 1511b4f9fe12SLen Brown int value; 1512b4f9fe12SLen Brown 1513936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1514936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1515936c8bcdSAlexey Dobriyan return -EFAULT; 1516936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1517936c8bcdSAlexey Dobriyan 1518b5163992SAzael Avalos if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) 1519135740deSSeth Forshee dev->key_event_valid = 0; 1520b5163992SAzael Avalos else 1521b4f9fe12SLen Brown return -EINVAL; 1522b4f9fe12SLen Brown 1523b4f9fe12SLen Brown return count; 1524b4f9fe12SLen Brown } 1525b4f9fe12SLen Brown 1526936c8bcdSAlexey Dobriyan static const struct file_operations keys_proc_fops = { 1527936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1528936c8bcdSAlexey Dobriyan .open = keys_proc_open, 1529936c8bcdSAlexey Dobriyan .read = seq_read, 1530936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1531936c8bcdSAlexey Dobriyan .release = single_release, 1532936c8bcdSAlexey Dobriyan .write = keys_proc_write, 1533936c8bcdSAlexey Dobriyan }; 1534936c8bcdSAlexey Dobriyan 1535936c8bcdSAlexey Dobriyan static int version_proc_show(struct seq_file *m, void *v) 1536b4f9fe12SLen Brown { 1537936c8bcdSAlexey Dobriyan seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION); 1538936c8bcdSAlexey Dobriyan seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION); 1539936c8bcdSAlexey Dobriyan return 0; 1540b4f9fe12SLen Brown } 1541b4f9fe12SLen Brown 1542936c8bcdSAlexey Dobriyan static int version_proc_open(struct inode *inode, struct file *file) 1543936c8bcdSAlexey Dobriyan { 1544d9dda78bSAl Viro return single_open(file, version_proc_show, PDE_DATA(inode)); 1545936c8bcdSAlexey Dobriyan } 1546936c8bcdSAlexey Dobriyan 1547936c8bcdSAlexey Dobriyan static const struct file_operations version_proc_fops = { 1548936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1549936c8bcdSAlexey Dobriyan .open = version_proc_open, 1550936c8bcdSAlexey Dobriyan .read = seq_read, 1551936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1552936c8bcdSAlexey Dobriyan .release = single_release, 1553936c8bcdSAlexey Dobriyan }; 1554936c8bcdSAlexey Dobriyan 1555e0769fe6SDarren Hart /* 1556e0769fe6SDarren Hart * Proc and module init 1557b4f9fe12SLen Brown */ 1558b4f9fe12SLen Brown 1559b4f9fe12SLen Brown #define PROC_TOSHIBA "toshiba" 1560b4f9fe12SLen Brown 1561b859f159SGreg Kroah-Hartman static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1562b4f9fe12SLen Brown { 156336d03f93SSeth Forshee if (dev->backlight_dev) 1564135740deSSeth Forshee proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1565135740deSSeth Forshee &lcd_proc_fops, dev); 156636d03f93SSeth Forshee if (dev->video_supported) 1567135740deSSeth Forshee proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1568135740deSSeth Forshee &video_proc_fops, dev); 156936d03f93SSeth Forshee if (dev->fan_supported) 1570135740deSSeth Forshee proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1571135740deSSeth Forshee &fan_proc_fops, dev); 157236d03f93SSeth Forshee if (dev->hotkey_dev) 1573135740deSSeth Forshee proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1574135740deSSeth Forshee &keys_proc_fops, dev); 1575135740deSSeth Forshee proc_create_data("version", S_IRUGO, toshiba_proc_dir, 1576135740deSSeth Forshee &version_proc_fops, dev); 1577b4f9fe12SLen Brown } 1578b4f9fe12SLen Brown 157936d03f93SSeth Forshee static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1580b4f9fe12SLen Brown { 158136d03f93SSeth Forshee if (dev->backlight_dev) 1582936c8bcdSAlexey Dobriyan remove_proc_entry("lcd", toshiba_proc_dir); 158336d03f93SSeth Forshee if (dev->video_supported) 1584936c8bcdSAlexey Dobriyan remove_proc_entry("video", toshiba_proc_dir); 158536d03f93SSeth Forshee if (dev->fan_supported) 1586936c8bcdSAlexey Dobriyan remove_proc_entry("fan", toshiba_proc_dir); 158736d03f93SSeth Forshee if (dev->hotkey_dev) 1588936c8bcdSAlexey Dobriyan remove_proc_entry("keys", toshiba_proc_dir); 1589936c8bcdSAlexey Dobriyan remove_proc_entry("version", toshiba_proc_dir); 1590b4f9fe12SLen Brown } 1591b4f9fe12SLen Brown 1592acc2472eSLionel Debroux static const struct backlight_ops toshiba_backlight_data = { 1593121b7b0dSAkio Idehara .options = BL_CORE_SUSPENDRESUME, 159462cce752SSeth Forshee .get_brightness = get_lcd_brightness, 1595b4f9fe12SLen Brown .update_status = set_lcd_status, 1596b4f9fe12SLen Brown }; 1597b4f9fe12SLen Brown 1598360f0f39SAzael Avalos /* 1599360f0f39SAzael Avalos * Sysfs files 1600360f0f39SAzael Avalos */ 16019d309848SAzael Avalos static ssize_t version_show(struct device *dev, 1602c6c68ff8SAzael Avalos struct device_attribute *attr, char *buf) 1603c6c68ff8SAzael Avalos { 1604c6c68ff8SAzael Avalos return sprintf(buf, "%s\n", TOSHIBA_ACPI_VERSION); 1605c6c68ff8SAzael Avalos } 16060c3c0f10SAzael Avalos static DEVICE_ATTR_RO(version); 1607c6c68ff8SAzael Avalos 16089d309848SAzael Avalos static ssize_t fan_store(struct device *dev, 160994477d4cSAzael Avalos struct device_attribute *attr, 161094477d4cSAzael Avalos const char *buf, size_t count) 161194477d4cSAzael Avalos { 161294477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 161394477d4cSAzael Avalos u32 result; 161494477d4cSAzael Avalos int state; 161594477d4cSAzael Avalos int ret; 161694477d4cSAzael Avalos 161794477d4cSAzael Avalos ret = kstrtoint(buf, 0, &state); 161894477d4cSAzael Avalos if (ret) 161994477d4cSAzael Avalos return ret; 162094477d4cSAzael Avalos 162194477d4cSAzael Avalos if (state != 0 && state != 1) 162294477d4cSAzael Avalos return -EINVAL; 162394477d4cSAzael Avalos 1624d37782bdSAzael Avalos result = hci_write(toshiba, HCI_FAN, state); 162594477d4cSAzael Avalos if (result == TOS_FAILURE) 162694477d4cSAzael Avalos return -EIO; 162794477d4cSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 162894477d4cSAzael Avalos return -ENODEV; 162994477d4cSAzael Avalos 163094477d4cSAzael Avalos return count; 163194477d4cSAzael Avalos } 163294477d4cSAzael Avalos 16339d309848SAzael Avalos static ssize_t fan_show(struct device *dev, 163494477d4cSAzael Avalos struct device_attribute *attr, char *buf) 163594477d4cSAzael Avalos { 163694477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 163794477d4cSAzael Avalos u32 value; 163894477d4cSAzael Avalos int ret; 163994477d4cSAzael Avalos 164094477d4cSAzael Avalos ret = get_fan_status(toshiba, &value); 164194477d4cSAzael Avalos if (ret) 164294477d4cSAzael Avalos return ret; 164394477d4cSAzael Avalos 164494477d4cSAzael Avalos return sprintf(buf, "%d\n", value); 164594477d4cSAzael Avalos } 16460c3c0f10SAzael Avalos static DEVICE_ATTR_RW(fan); 164794477d4cSAzael Avalos 16489d309848SAzael Avalos static ssize_t kbd_backlight_mode_store(struct device *dev, 1649360f0f39SAzael Avalos struct device_attribute *attr, 1650360f0f39SAzael Avalos const char *buf, size_t count) 1651360f0f39SAzael Avalos { 1652360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1653aeaac098SDan Carpenter int mode; 1654aeaac098SDan Carpenter int time; 1655aeaac098SDan Carpenter int ret; 1656360f0f39SAzael Avalos 1657aeaac098SDan Carpenter 1658aeaac098SDan Carpenter ret = kstrtoint(buf, 0, &mode); 1659aeaac098SDan Carpenter if (ret) 1660aeaac098SDan Carpenter return ret; 166193f8c16dSAzael Avalos 166293f8c16dSAzael Avalos /* Check for supported modes depending on keyboard backlight type */ 166393f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 166493f8c16dSAzael Avalos /* Type 1 supports SCI_KBD_MODE_FNZ and SCI_KBD_MODE_AUTO */ 1665aeaac098SDan Carpenter if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO) 1666360f0f39SAzael Avalos return -EINVAL; 166793f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 166893f8c16dSAzael Avalos /* Type 2 doesn't support SCI_KBD_MODE_FNZ */ 166993f8c16dSAzael Avalos if (mode != SCI_KBD_MODE_AUTO && mode != SCI_KBD_MODE_ON && 167093f8c16dSAzael Avalos mode != SCI_KBD_MODE_OFF) 167193f8c16dSAzael Avalos return -EINVAL; 167293f8c16dSAzael Avalos } 1673360f0f39SAzael Avalos 1674e0769fe6SDarren Hart /* 1675e0769fe6SDarren Hart * Set the Keyboard Backlight Mode where: 1676360f0f39SAzael Avalos * Auto - KBD backlight turns off automatically in given time 1677360f0f39SAzael Avalos * FN-Z - KBD backlight "toggles" when hotkey pressed 167893f8c16dSAzael Avalos * ON - KBD backlight is always on 167993f8c16dSAzael Avalos * OFF - KBD backlight is always off 1680360f0f39SAzael Avalos */ 168193f8c16dSAzael Avalos 168293f8c16dSAzael Avalos /* Only make a change if the actual mode has changed */ 1683aeaac098SDan Carpenter if (toshiba->kbd_mode != mode) { 168493f8c16dSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 1685360f0f39SAzael Avalos time = toshiba->kbd_time << HCI_MISC_SHIFT; 168693f8c16dSAzael Avalos 168793f8c16dSAzael Avalos /* OR the "base time" to the actual method format */ 168893f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 168993f8c16dSAzael Avalos /* Type 1 requires the current mode */ 169093f8c16dSAzael Avalos time |= toshiba->kbd_mode; 169193f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 169293f8c16dSAzael Avalos /* Type 2 requires the desired mode */ 169393f8c16dSAzael Avalos time |= mode; 169493f8c16dSAzael Avalos } 169593f8c16dSAzael Avalos 1696aeaac098SDan Carpenter ret = toshiba_kbd_illum_status_set(toshiba, time); 1697aeaac098SDan Carpenter if (ret) 1698aeaac098SDan Carpenter return ret; 169993f8c16dSAzael Avalos 1700360f0f39SAzael Avalos toshiba->kbd_mode = mode; 1701360f0f39SAzael Avalos } 1702360f0f39SAzael Avalos 1703360f0f39SAzael Avalos return count; 1704360f0f39SAzael Avalos } 1705360f0f39SAzael Avalos 17069d309848SAzael Avalos static ssize_t kbd_backlight_mode_show(struct device *dev, 1707360f0f39SAzael Avalos struct device_attribute *attr, 1708360f0f39SAzael Avalos char *buf) 1709360f0f39SAzael Avalos { 1710360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1711360f0f39SAzael Avalos u32 time; 1712360f0f39SAzael Avalos 1713360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1714360f0f39SAzael Avalos return -EIO; 1715360f0f39SAzael Avalos 171693f8c16dSAzael Avalos return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK); 171793f8c16dSAzael Avalos } 17180c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_mode); 171993f8c16dSAzael Avalos 17209d309848SAzael Avalos static ssize_t kbd_type_show(struct device *dev, 17219d309848SAzael Avalos struct device_attribute *attr, char *buf) 172293f8c16dSAzael Avalos { 172393f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 172493f8c16dSAzael Avalos 172593f8c16dSAzael Avalos return sprintf(buf, "%d\n", toshiba->kbd_type); 172693f8c16dSAzael Avalos } 17270c3c0f10SAzael Avalos static DEVICE_ATTR_RO(kbd_type); 172893f8c16dSAzael Avalos 17299d309848SAzael Avalos static ssize_t available_kbd_modes_show(struct device *dev, 173093f8c16dSAzael Avalos struct device_attribute *attr, 173193f8c16dSAzael Avalos char *buf) 173293f8c16dSAzael Avalos { 173393f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 173493f8c16dSAzael Avalos 173593f8c16dSAzael Avalos if (toshiba->kbd_type == 1) 173693f8c16dSAzael Avalos return sprintf(buf, "%x %x\n", 173793f8c16dSAzael Avalos SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO); 173893f8c16dSAzael Avalos 173993f8c16dSAzael Avalos return sprintf(buf, "%x %x %x\n", 174093f8c16dSAzael Avalos SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF); 1741360f0f39SAzael Avalos } 17420c3c0f10SAzael Avalos static DEVICE_ATTR_RO(available_kbd_modes); 1743360f0f39SAzael Avalos 17449d309848SAzael Avalos static ssize_t kbd_backlight_timeout_store(struct device *dev, 1745360f0f39SAzael Avalos struct device_attribute *attr, 1746360f0f39SAzael Avalos const char *buf, size_t count) 1747360f0f39SAzael Avalos { 1748360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1749eabde0faSAzael Avalos int time; 1750eabde0faSAzael Avalos int ret; 1751360f0f39SAzael Avalos 1752eabde0faSAzael Avalos ret = kstrtoint(buf, 0, &time); 1753eabde0faSAzael Avalos if (ret) 1754eabde0faSAzael Avalos return ret; 1755eabde0faSAzael Avalos 1756eabde0faSAzael Avalos /* Check for supported values depending on kbd_type */ 1757eabde0faSAzael Avalos if (toshiba->kbd_type == 1) { 1758eabde0faSAzael Avalos if (time < 0 || time > 60) 1759360f0f39SAzael Avalos return -EINVAL; 1760eabde0faSAzael Avalos } else if (toshiba->kbd_type == 2) { 1761eabde0faSAzael Avalos if (time < 1 || time > 60) 1762eabde0faSAzael Avalos return -EINVAL; 1763eabde0faSAzael Avalos } 1764360f0f39SAzael Avalos 1765eabde0faSAzael Avalos /* Set the Keyboard Backlight Timeout */ 1766eabde0faSAzael Avalos 1767eabde0faSAzael Avalos /* Only make a change if the actual timeout has changed */ 1768eabde0faSAzael Avalos if (toshiba->kbd_time != time) { 1769eabde0faSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 1770360f0f39SAzael Avalos time = time << HCI_MISC_SHIFT; 1771eabde0faSAzael Avalos /* OR the "base time" to the actual method format */ 1772eabde0faSAzael Avalos if (toshiba->kbd_type == 1) 1773eabde0faSAzael Avalos time |= SCI_KBD_MODE_FNZ; 1774eabde0faSAzael Avalos else if (toshiba->kbd_type == 2) 1775eabde0faSAzael Avalos time |= SCI_KBD_MODE_AUTO; 1776eabde0faSAzael Avalos 1777eabde0faSAzael Avalos ret = toshiba_kbd_illum_status_set(toshiba, time); 1778eabde0faSAzael Avalos if (ret) 1779eabde0faSAzael Avalos return ret; 1780eabde0faSAzael Avalos 1781360f0f39SAzael Avalos toshiba->kbd_time = time >> HCI_MISC_SHIFT; 1782360f0f39SAzael Avalos } 1783360f0f39SAzael Avalos 1784360f0f39SAzael Avalos return count; 1785360f0f39SAzael Avalos } 1786360f0f39SAzael Avalos 17879d309848SAzael Avalos static ssize_t kbd_backlight_timeout_show(struct device *dev, 1788360f0f39SAzael Avalos struct device_attribute *attr, 1789360f0f39SAzael Avalos char *buf) 1790360f0f39SAzael Avalos { 1791360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1792360f0f39SAzael Avalos u32 time; 1793360f0f39SAzael Avalos 1794360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1795360f0f39SAzael Avalos return -EIO; 1796360f0f39SAzael Avalos 1797360f0f39SAzael Avalos return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT); 1798360f0f39SAzael Avalos } 17990c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_timeout); 1800360f0f39SAzael Avalos 18019d309848SAzael Avalos static ssize_t touchpad_store(struct device *dev, 18029d8658acSAzael Avalos struct device_attribute *attr, 18039d8658acSAzael Avalos const char *buf, size_t count) 18049d8658acSAzael Avalos { 18059d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 18069d8658acSAzael Avalos int state; 1807c8a41669SAzael Avalos int ret; 18089d8658acSAzael Avalos 18099d8658acSAzael Avalos /* Set the TouchPad on/off, 0 - Disable | 1 - Enable */ 1810c8a41669SAzael Avalos ret = kstrtoint(buf, 0, &state); 1811c8a41669SAzael Avalos if (ret) 1812c8a41669SAzael Avalos return ret; 1813c8a41669SAzael Avalos if (state != 0 && state != 1) 1814c8a41669SAzael Avalos return -EINVAL; 1815c8a41669SAzael Avalos 1816c8a41669SAzael Avalos ret = toshiba_touchpad_set(toshiba, state); 1817c8a41669SAzael Avalos if (ret) 1818c8a41669SAzael Avalos return ret; 18199d8658acSAzael Avalos 18209d8658acSAzael Avalos return count; 18219d8658acSAzael Avalos } 18229d8658acSAzael Avalos 18239d309848SAzael Avalos static ssize_t touchpad_show(struct device *dev, 18249d8658acSAzael Avalos struct device_attribute *attr, char *buf) 18259d8658acSAzael Avalos { 18269d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 18279d8658acSAzael Avalos u32 state; 18289d8658acSAzael Avalos int ret; 18299d8658acSAzael Avalos 18309d8658acSAzael Avalos ret = toshiba_touchpad_get(toshiba, &state); 18319d8658acSAzael Avalos if (ret < 0) 18329d8658acSAzael Avalos return ret; 18339d8658acSAzael Avalos 18349d8658acSAzael Avalos return sprintf(buf, "%i\n", state); 18359d8658acSAzael Avalos } 18360c3c0f10SAzael Avalos static DEVICE_ATTR_RW(touchpad); 18379d8658acSAzael Avalos 18389d309848SAzael Avalos static ssize_t position_show(struct device *dev, 18395a2813e9SAzael Avalos struct device_attribute *attr, char *buf) 18405a2813e9SAzael Avalos { 18415a2813e9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 18425a2813e9SAzael Avalos u32 xyval, zval, tmp; 18435a2813e9SAzael Avalos u16 x, y, z; 18445a2813e9SAzael Avalos int ret; 18455a2813e9SAzael Avalos 18465a2813e9SAzael Avalos xyval = zval = 0; 18475a2813e9SAzael Avalos ret = toshiba_accelerometer_get(toshiba, &xyval, &zval); 18485a2813e9SAzael Avalos if (ret < 0) 18495a2813e9SAzael Avalos return ret; 18505a2813e9SAzael Avalos 18515a2813e9SAzael Avalos x = xyval & HCI_ACCEL_MASK; 18525a2813e9SAzael Avalos tmp = xyval >> HCI_MISC_SHIFT; 18535a2813e9SAzael Avalos y = tmp & HCI_ACCEL_MASK; 18545a2813e9SAzael Avalos z = zval & HCI_ACCEL_MASK; 18555a2813e9SAzael Avalos 18565a2813e9SAzael Avalos return sprintf(buf, "%d %d %d\n", x, y, z); 18575a2813e9SAzael Avalos } 18580c3c0f10SAzael Avalos static DEVICE_ATTR_RO(position); 18595a2813e9SAzael Avalos 18609d309848SAzael Avalos static ssize_t usb_sleep_charge_show(struct device *dev, 18619d309848SAzael Avalos struct device_attribute *attr, char *buf) 1862e26ffe51SAzael Avalos { 1863e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1864e26ffe51SAzael Avalos u32 mode; 1865e26ffe51SAzael Avalos int ret; 1866e26ffe51SAzael Avalos 1867e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_get(toshiba, &mode); 1868e26ffe51SAzael Avalos if (ret < 0) 1869e26ffe51SAzael Avalos return ret; 1870e26ffe51SAzael Avalos 1871e26ffe51SAzael Avalos return sprintf(buf, "%x\n", mode & SCI_USB_CHARGE_MODE_MASK); 1872e26ffe51SAzael Avalos } 1873e26ffe51SAzael Avalos 18749d309848SAzael Avalos static ssize_t usb_sleep_charge_store(struct device *dev, 1875e26ffe51SAzael Avalos struct device_attribute *attr, 1876e26ffe51SAzael Avalos const char *buf, size_t count) 1877e26ffe51SAzael Avalos { 1878e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1879e26ffe51SAzael Avalos u32 mode; 1880e26ffe51SAzael Avalos int state; 1881e26ffe51SAzael Avalos int ret; 1882e26ffe51SAzael Avalos 1883e26ffe51SAzael Avalos ret = kstrtoint(buf, 0, &state); 1884e26ffe51SAzael Avalos if (ret) 1885e26ffe51SAzael Avalos return ret; 1886e0769fe6SDarren Hart /* 1887e0769fe6SDarren Hart * Check for supported values, where: 1888e26ffe51SAzael Avalos * 0 - Disabled 1889e26ffe51SAzael Avalos * 1 - Alternate (Non USB conformant devices that require more power) 1890e26ffe51SAzael Avalos * 2 - Auto (USB conformant devices) 1891c8c91842SAzael Avalos * 3 - Typical 1892e26ffe51SAzael Avalos */ 1893c8c91842SAzael Avalos if (state != 0 && state != 1 && state != 2 && state != 3) 1894e26ffe51SAzael Avalos return -EINVAL; 1895e26ffe51SAzael Avalos 1896e26ffe51SAzael Avalos /* Set the USB charging mode to internal value */ 1897c8c91842SAzael Avalos mode = toshiba->usbsc_mode_base; 1898e26ffe51SAzael Avalos if (state == 0) 1899c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_DISABLED; 1900e26ffe51SAzael Avalos else if (state == 1) 1901c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_ALTERNATE; 1902e26ffe51SAzael Avalos else if (state == 2) 1903c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_AUTO; 1904c8c91842SAzael Avalos else if (state == 3) 1905c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_TYPICAL; 1906e26ffe51SAzael Avalos 1907e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_set(toshiba, mode); 1908e26ffe51SAzael Avalos if (ret) 1909e26ffe51SAzael Avalos return ret; 1910e26ffe51SAzael Avalos 1911e26ffe51SAzael Avalos return count; 1912e26ffe51SAzael Avalos } 19130c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_charge); 1914e26ffe51SAzael Avalos 1915182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_show(struct device *dev, 1916182bcaa5SAzael Avalos struct device_attribute *attr, 1917182bcaa5SAzael Avalos char *buf) 1918182bcaa5SAzael Avalos { 1919182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1920182bcaa5SAzael Avalos u32 state; 1921182bcaa5SAzael Avalos int bat_lvl; 1922182bcaa5SAzael Avalos int status; 1923182bcaa5SAzael Avalos int ret; 1924182bcaa5SAzael Avalos int tmp; 1925182bcaa5SAzael Avalos 1926182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_get(toshiba, &state); 1927182bcaa5SAzael Avalos if (ret < 0) 1928182bcaa5SAzael Avalos return ret; 1929182bcaa5SAzael Avalos 1930182bcaa5SAzael Avalos /* Determine the status: 0x4 - Enabled | 0x1 - Disabled */ 1931182bcaa5SAzael Avalos tmp = state & SCI_USB_CHARGE_BAT_MASK; 1932182bcaa5SAzael Avalos status = (tmp == 0x4) ? 1 : 0; 1933182bcaa5SAzael Avalos /* Determine the battery level set */ 1934182bcaa5SAzael Avalos bat_lvl = state >> HCI_MISC_SHIFT; 1935182bcaa5SAzael Avalos 1936182bcaa5SAzael Avalos return sprintf(buf, "%d %d\n", status, bat_lvl); 1937182bcaa5SAzael Avalos } 1938182bcaa5SAzael Avalos 1939182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_store(struct device *dev, 1940182bcaa5SAzael Avalos struct device_attribute *attr, 1941182bcaa5SAzael Avalos const char *buf, size_t count) 1942182bcaa5SAzael Avalos { 1943182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1944182bcaa5SAzael Avalos u32 status; 1945182bcaa5SAzael Avalos int value; 1946182bcaa5SAzael Avalos int ret; 1947182bcaa5SAzael Avalos int tmp; 1948182bcaa5SAzael Avalos 1949182bcaa5SAzael Avalos ret = kstrtoint(buf, 0, &value); 1950182bcaa5SAzael Avalos if (ret) 1951182bcaa5SAzael Avalos return ret; 1952182bcaa5SAzael Avalos 1953e0769fe6SDarren Hart /* 1954e0769fe6SDarren Hart * Set the status of the function: 1955182bcaa5SAzael Avalos * 0 - Disabled 1956182bcaa5SAzael Avalos * 1-100 - Enabled 1957182bcaa5SAzael Avalos */ 1958182bcaa5SAzael Avalos if (value < 0 || value > 100) 1959182bcaa5SAzael Avalos return -EINVAL; 1960182bcaa5SAzael Avalos 1961182bcaa5SAzael Avalos if (value == 0) { 1962182bcaa5SAzael Avalos tmp = toshiba->usbsc_bat_level << HCI_MISC_SHIFT; 1963182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_OFF; 1964182bcaa5SAzael Avalos } else { 1965182bcaa5SAzael Avalos tmp = value << HCI_MISC_SHIFT; 1966182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_ON; 1967182bcaa5SAzael Avalos } 1968182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_set(toshiba, status); 1969182bcaa5SAzael Avalos if (ret < 0) 1970182bcaa5SAzael Avalos return ret; 1971182bcaa5SAzael Avalos 1972182bcaa5SAzael Avalos toshiba->usbsc_bat_level = status >> HCI_MISC_SHIFT; 1973182bcaa5SAzael Avalos 1974182bcaa5SAzael Avalos return count; 1975182bcaa5SAzael Avalos } 19760c3c0f10SAzael Avalos static DEVICE_ATTR_RW(sleep_functions_on_battery); 1977182bcaa5SAzael Avalos 19789d309848SAzael Avalos static ssize_t usb_rapid_charge_show(struct device *dev, 19799d309848SAzael Avalos struct device_attribute *attr, char *buf) 1980bb3fe01fSAzael Avalos { 1981bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1982bb3fe01fSAzael Avalos u32 state; 1983bb3fe01fSAzael Avalos int ret; 1984bb3fe01fSAzael Avalos 1985bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(toshiba, &state); 1986bb3fe01fSAzael Avalos if (ret < 0) 1987bb3fe01fSAzael Avalos return ret; 1988bb3fe01fSAzael Avalos 1989bb3fe01fSAzael Avalos return sprintf(buf, "%d\n", state); 1990bb3fe01fSAzael Avalos } 1991bb3fe01fSAzael Avalos 19929d309848SAzael Avalos static ssize_t usb_rapid_charge_store(struct device *dev, 1993bb3fe01fSAzael Avalos struct device_attribute *attr, 1994bb3fe01fSAzael Avalos const char *buf, size_t count) 1995bb3fe01fSAzael Avalos { 1996bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1997bb3fe01fSAzael Avalos int state; 1998bb3fe01fSAzael Avalos int ret; 1999bb3fe01fSAzael Avalos 2000bb3fe01fSAzael Avalos ret = kstrtoint(buf, 0, &state); 2001bb3fe01fSAzael Avalos if (ret) 2002bb3fe01fSAzael Avalos return ret; 2003bb3fe01fSAzael Avalos if (state != 0 && state != 1) 2004bb3fe01fSAzael Avalos return -EINVAL; 2005bb3fe01fSAzael Avalos 2006bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_set(toshiba, state); 2007bb3fe01fSAzael Avalos if (ret) 2008bb3fe01fSAzael Avalos return ret; 2009bb3fe01fSAzael Avalos 2010bb3fe01fSAzael Avalos return count; 2011bb3fe01fSAzael Avalos } 20120c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_rapid_charge); 2013bb3fe01fSAzael Avalos 20149d309848SAzael Avalos static ssize_t usb_sleep_music_show(struct device *dev, 20159d309848SAzael Avalos struct device_attribute *attr, char *buf) 2016172ce0a9SAzael Avalos { 2017172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2018172ce0a9SAzael Avalos u32 state; 2019172ce0a9SAzael Avalos int ret; 2020172ce0a9SAzael Avalos 2021172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(toshiba, &state); 2022172ce0a9SAzael Avalos if (ret < 0) 2023172ce0a9SAzael Avalos return ret; 2024172ce0a9SAzael Avalos 2025172ce0a9SAzael Avalos return sprintf(buf, "%d\n", state); 2026172ce0a9SAzael Avalos } 2027172ce0a9SAzael Avalos 20289d309848SAzael Avalos static ssize_t usb_sleep_music_store(struct device *dev, 2029172ce0a9SAzael Avalos struct device_attribute *attr, 2030172ce0a9SAzael Avalos const char *buf, size_t count) 2031172ce0a9SAzael Avalos { 2032172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2033172ce0a9SAzael Avalos int state; 2034172ce0a9SAzael Avalos int ret; 2035172ce0a9SAzael Avalos 2036172ce0a9SAzael Avalos ret = kstrtoint(buf, 0, &state); 2037172ce0a9SAzael Avalos if (ret) 2038172ce0a9SAzael Avalos return ret; 2039172ce0a9SAzael Avalos if (state != 0 && state != 1) 2040172ce0a9SAzael Avalos return -EINVAL; 2041172ce0a9SAzael Avalos 2042172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_set(toshiba, state); 2043172ce0a9SAzael Avalos if (ret) 2044172ce0a9SAzael Avalos return ret; 2045172ce0a9SAzael Avalos 2046172ce0a9SAzael Avalos return count; 2047172ce0a9SAzael Avalos } 20480c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_music); 2049172ce0a9SAzael Avalos 20509d309848SAzael Avalos static ssize_t kbd_function_keys_show(struct device *dev, 20519d309848SAzael Avalos struct device_attribute *attr, char *buf) 2052bae84195SAzael Avalos { 2053bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2054bae84195SAzael Avalos int mode; 2055bae84195SAzael Avalos int ret; 2056bae84195SAzael Avalos 2057bae84195SAzael Avalos ret = toshiba_function_keys_get(toshiba, &mode); 2058bae84195SAzael Avalos if (ret < 0) 2059bae84195SAzael Avalos return ret; 2060bae84195SAzael Avalos 2061bae84195SAzael Avalos return sprintf(buf, "%d\n", mode); 2062bae84195SAzael Avalos } 2063bae84195SAzael Avalos 20649d309848SAzael Avalos static ssize_t kbd_function_keys_store(struct device *dev, 2065bae84195SAzael Avalos struct device_attribute *attr, 2066bae84195SAzael Avalos const char *buf, size_t count) 2067bae84195SAzael Avalos { 2068bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2069bae84195SAzael Avalos int mode; 2070bae84195SAzael Avalos int ret; 2071bae84195SAzael Avalos 2072bae84195SAzael Avalos ret = kstrtoint(buf, 0, &mode); 2073bae84195SAzael Avalos if (ret) 2074bae84195SAzael Avalos return ret; 2075e0769fe6SDarren Hart /* 2076e0769fe6SDarren Hart * Check for the function keys mode where: 2077bae84195SAzael Avalos * 0 - Normal operation (F{1-12} as usual and hotkeys via FN-F{1-12}) 2078bae84195SAzael Avalos * 1 - Special functions (Opposite of the above setting) 2079bae84195SAzael Avalos */ 2080bae84195SAzael Avalos if (mode != 0 && mode != 1) 2081bae84195SAzael Avalos return -EINVAL; 2082bae84195SAzael Avalos 2083bae84195SAzael Avalos ret = toshiba_function_keys_set(toshiba, mode); 2084bae84195SAzael Avalos if (ret) 2085bae84195SAzael Avalos return ret; 2086bae84195SAzael Avalos 2087bae84195SAzael Avalos pr_info("Reboot for changes to KBD Function Keys to take effect"); 2088bae84195SAzael Avalos 2089bae84195SAzael Avalos return count; 2090bae84195SAzael Avalos } 20910c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_function_keys); 2092bae84195SAzael Avalos 20939d309848SAzael Avalos static ssize_t panel_power_on_show(struct device *dev, 20949d309848SAzael Avalos struct device_attribute *attr, char *buf) 209535d53ceaSAzael Avalos { 209635d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 209735d53ceaSAzael Avalos u32 state; 209835d53ceaSAzael Avalos int ret; 209935d53ceaSAzael Avalos 210035d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(toshiba, &state); 210135d53ceaSAzael Avalos if (ret < 0) 210235d53ceaSAzael Avalos return ret; 210335d53ceaSAzael Avalos 210435d53ceaSAzael Avalos return sprintf(buf, "%d\n", state); 210535d53ceaSAzael Avalos } 210635d53ceaSAzael Avalos 21079d309848SAzael Avalos static ssize_t panel_power_on_store(struct device *dev, 210835d53ceaSAzael Avalos struct device_attribute *attr, 210935d53ceaSAzael Avalos const char *buf, size_t count) 211035d53ceaSAzael Avalos { 211135d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 211235d53ceaSAzael Avalos int state; 211335d53ceaSAzael Avalos int ret; 211435d53ceaSAzael Avalos 211535d53ceaSAzael Avalos ret = kstrtoint(buf, 0, &state); 211635d53ceaSAzael Avalos if (ret) 211735d53ceaSAzael Avalos return ret; 211835d53ceaSAzael Avalos if (state != 0 && state != 1) 211935d53ceaSAzael Avalos return -EINVAL; 212035d53ceaSAzael Avalos 212135d53ceaSAzael Avalos ret = toshiba_panel_power_on_set(toshiba, state); 212235d53ceaSAzael Avalos if (ret) 212335d53ceaSAzael Avalos return ret; 212435d53ceaSAzael Avalos 212535d53ceaSAzael Avalos pr_info("Reboot for changes to Panel Power ON to take effect"); 212635d53ceaSAzael Avalos 212735d53ceaSAzael Avalos return count; 212835d53ceaSAzael Avalos } 21290c3c0f10SAzael Avalos static DEVICE_ATTR_RW(panel_power_on); 213035d53ceaSAzael Avalos 21319d309848SAzael Avalos static ssize_t usb_three_show(struct device *dev, 21329d309848SAzael Avalos struct device_attribute *attr, char *buf) 213317fe4b3dSAzael Avalos { 213417fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 213517fe4b3dSAzael Avalos u32 state; 213617fe4b3dSAzael Avalos int ret; 213717fe4b3dSAzael Avalos 213817fe4b3dSAzael Avalos ret = toshiba_usb_three_get(toshiba, &state); 213917fe4b3dSAzael Avalos if (ret < 0) 214017fe4b3dSAzael Avalos return ret; 214117fe4b3dSAzael Avalos 214217fe4b3dSAzael Avalos return sprintf(buf, "%d\n", state); 214317fe4b3dSAzael Avalos } 214417fe4b3dSAzael Avalos 21459d309848SAzael Avalos static ssize_t usb_three_store(struct device *dev, 214617fe4b3dSAzael Avalos struct device_attribute *attr, 214717fe4b3dSAzael Avalos const char *buf, size_t count) 214817fe4b3dSAzael Avalos { 214917fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 215017fe4b3dSAzael Avalos int state; 215117fe4b3dSAzael Avalos int ret; 215217fe4b3dSAzael Avalos 215317fe4b3dSAzael Avalos ret = kstrtoint(buf, 0, &state); 215417fe4b3dSAzael Avalos if (ret) 215517fe4b3dSAzael Avalos return ret; 2156e0769fe6SDarren Hart /* 2157e0769fe6SDarren Hart * Check for USB 3 mode where: 215817fe4b3dSAzael Avalos * 0 - Disabled (Acts like a USB 2 port, saving power) 215917fe4b3dSAzael Avalos * 1 - Enabled 216017fe4b3dSAzael Avalos */ 216117fe4b3dSAzael Avalos if (state != 0 && state != 1) 216217fe4b3dSAzael Avalos return -EINVAL; 216317fe4b3dSAzael Avalos 216417fe4b3dSAzael Avalos ret = toshiba_usb_three_set(toshiba, state); 216517fe4b3dSAzael Avalos if (ret) 216617fe4b3dSAzael Avalos return ret; 216717fe4b3dSAzael Avalos 216817fe4b3dSAzael Avalos pr_info("Reboot for changes to USB 3 to take effect"); 216917fe4b3dSAzael Avalos 217017fe4b3dSAzael Avalos return count; 217117fe4b3dSAzael Avalos } 21720c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_three); 21739bd1213bSAzael Avalos 21749bd1213bSAzael Avalos static struct attribute *toshiba_attributes[] = { 21759bd1213bSAzael Avalos &dev_attr_version.attr, 21769bd1213bSAzael Avalos &dev_attr_fan.attr, 21779bd1213bSAzael Avalos &dev_attr_kbd_backlight_mode.attr, 21789bd1213bSAzael Avalos &dev_attr_kbd_type.attr, 21799bd1213bSAzael Avalos &dev_attr_available_kbd_modes.attr, 21809bd1213bSAzael Avalos &dev_attr_kbd_backlight_timeout.attr, 21819bd1213bSAzael Avalos &dev_attr_touchpad.attr, 21829bd1213bSAzael Avalos &dev_attr_position.attr, 21839bd1213bSAzael Avalos &dev_attr_usb_sleep_charge.attr, 21849bd1213bSAzael Avalos &dev_attr_sleep_functions_on_battery.attr, 21859bd1213bSAzael Avalos &dev_attr_usb_rapid_charge.attr, 21869bd1213bSAzael Avalos &dev_attr_usb_sleep_music.attr, 21879bd1213bSAzael Avalos &dev_attr_kbd_function_keys.attr, 21889bd1213bSAzael Avalos &dev_attr_panel_power_on.attr, 21899bd1213bSAzael Avalos &dev_attr_usb_three.attr, 21909bd1213bSAzael Avalos NULL, 21919bd1213bSAzael Avalos }; 21929bd1213bSAzael Avalos 2193360f0f39SAzael Avalos static umode_t toshiba_sysfs_is_visible(struct kobject *kobj, 2194360f0f39SAzael Avalos struct attribute *attr, int idx) 2195360f0f39SAzael Avalos { 2196360f0f39SAzael Avalos struct device *dev = container_of(kobj, struct device, kobj); 2197360f0f39SAzael Avalos struct toshiba_acpi_dev *drv = dev_get_drvdata(dev); 2198360f0f39SAzael Avalos bool exists = true; 2199360f0f39SAzael Avalos 220094477d4cSAzael Avalos if (attr == &dev_attr_fan.attr) 220194477d4cSAzael Avalos exists = (drv->fan_supported) ? true : false; 220294477d4cSAzael Avalos else if (attr == &dev_attr_kbd_backlight_mode.attr) 2203360f0f39SAzael Avalos exists = (drv->kbd_illum_supported) ? true : false; 2204360f0f39SAzael Avalos else if (attr == &dev_attr_kbd_backlight_timeout.attr) 2205360f0f39SAzael Avalos exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false; 22069d8658acSAzael Avalos else if (attr == &dev_attr_touchpad.attr) 22079d8658acSAzael Avalos exists = (drv->touchpad_supported) ? true : false; 22085a2813e9SAzael Avalos else if (attr == &dev_attr_position.attr) 22095a2813e9SAzael Avalos exists = (drv->accelerometer_supported) ? true : false; 2210e26ffe51SAzael Avalos else if (attr == &dev_attr_usb_sleep_charge.attr) 2211e26ffe51SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2212182bcaa5SAzael Avalos else if (attr == &dev_attr_sleep_functions_on_battery.attr) 2213182bcaa5SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2214bb3fe01fSAzael Avalos else if (attr == &dev_attr_usb_rapid_charge.attr) 2215bb3fe01fSAzael Avalos exists = (drv->usb_rapid_charge_supported) ? true : false; 2216172ce0a9SAzael Avalos else if (attr == &dev_attr_usb_sleep_music.attr) 2217172ce0a9SAzael Avalos exists = (drv->usb_sleep_music_supported) ? true : false; 2218bae84195SAzael Avalos else if (attr == &dev_attr_kbd_function_keys.attr) 2219bae84195SAzael Avalos exists = (drv->kbd_function_keys_supported) ? true : false; 222035d53ceaSAzael Avalos else if (attr == &dev_attr_panel_power_on.attr) 222135d53ceaSAzael Avalos exists = (drv->panel_power_on_supported) ? true : false; 222217fe4b3dSAzael Avalos else if (attr == &dev_attr_usb_three.attr) 222317fe4b3dSAzael Avalos exists = (drv->usb_three_supported) ? true : false; 2224360f0f39SAzael Avalos 2225360f0f39SAzael Avalos return exists ? attr->mode : 0; 2226360f0f39SAzael Avalos } 2227360f0f39SAzael Avalos 22289bd1213bSAzael Avalos static struct attribute_group toshiba_attr_group = { 22299bd1213bSAzael Avalos .is_visible = toshiba_sysfs_is_visible, 22309bd1213bSAzael Avalos .attrs = toshiba_attributes, 22319bd1213bSAzael Avalos }; 22329bd1213bSAzael Avalos 22331f28f290SAzael Avalos /* 2234fc5462f8SAzael Avalos * Misc device 2235fc5462f8SAzael Avalos */ 2236fc5462f8SAzael Avalos static int toshiba_acpi_smm_bridge(SMMRegisters *regs) 2237fc5462f8SAzael Avalos { 2238fc5462f8SAzael Avalos u32 in[TCI_WORDS] = { regs->eax, regs->ebx, regs->ecx, 2239fc5462f8SAzael Avalos regs->edx, regs->esi, regs->edi }; 2240fc5462f8SAzael Avalos u32 out[TCI_WORDS]; 2241fc5462f8SAzael Avalos acpi_status status; 2242fc5462f8SAzael Avalos 2243fc5462f8SAzael Avalos status = tci_raw(toshiba_acpi, in, out); 2244fc5462f8SAzael Avalos if (ACPI_FAILURE(status)) { 2245fc5462f8SAzael Avalos pr_err("ACPI call to query SMM registers failed\n"); 2246fc5462f8SAzael Avalos return -EIO; 2247fc5462f8SAzael Avalos } 2248fc5462f8SAzael Avalos 2249fc5462f8SAzael Avalos /* Fillout the SMM struct with the TCI call results */ 2250fc5462f8SAzael Avalos regs->eax = out[0]; 2251fc5462f8SAzael Avalos regs->ebx = out[1]; 2252fc5462f8SAzael Avalos regs->ecx = out[2]; 2253fc5462f8SAzael Avalos regs->edx = out[3]; 2254fc5462f8SAzael Avalos regs->esi = out[4]; 2255fc5462f8SAzael Avalos regs->edi = out[5]; 2256fc5462f8SAzael Avalos 2257fc5462f8SAzael Avalos return 0; 2258fc5462f8SAzael Avalos } 2259fc5462f8SAzael Avalos 2260fc5462f8SAzael Avalos static long toshiba_acpi_ioctl(struct file *fp, unsigned int cmd, 2261fc5462f8SAzael Avalos unsigned long arg) 2262fc5462f8SAzael Avalos { 2263fc5462f8SAzael Avalos SMMRegisters __user *argp = (SMMRegisters __user *)arg; 2264fc5462f8SAzael Avalos SMMRegisters regs; 2265fc5462f8SAzael Avalos int ret; 2266fc5462f8SAzael Avalos 2267fc5462f8SAzael Avalos if (!argp) 2268fc5462f8SAzael Avalos return -EINVAL; 2269fc5462f8SAzael Avalos 2270fc5462f8SAzael Avalos switch (cmd) { 2271fc5462f8SAzael Avalos case TOSH_SMM: 2272fc5462f8SAzael Avalos if (copy_from_user(®s, argp, sizeof(SMMRegisters))) 2273fc5462f8SAzael Avalos return -EFAULT; 2274fc5462f8SAzael Avalos ret = toshiba_acpi_smm_bridge(®s); 2275fc5462f8SAzael Avalos if (ret) 2276fc5462f8SAzael Avalos return ret; 2277fc5462f8SAzael Avalos if (copy_to_user(argp, ®s, sizeof(SMMRegisters))) 2278fc5462f8SAzael Avalos return -EFAULT; 2279fc5462f8SAzael Avalos break; 2280fc5462f8SAzael Avalos case TOSHIBA_ACPI_SCI: 2281fc5462f8SAzael Avalos if (copy_from_user(®s, argp, sizeof(SMMRegisters))) 2282fc5462f8SAzael Avalos return -EFAULT; 2283fc5462f8SAzael Avalos /* Ensure we are being called with a SCI_{GET, SET} register */ 2284fc5462f8SAzael Avalos if (regs.eax != SCI_GET && regs.eax != SCI_SET) 2285fc5462f8SAzael Avalos return -EINVAL; 2286fc5462f8SAzael Avalos if (!sci_open(toshiba_acpi)) 2287fc5462f8SAzael Avalos return -EIO; 2288fc5462f8SAzael Avalos ret = toshiba_acpi_smm_bridge(®s); 2289fc5462f8SAzael Avalos sci_close(toshiba_acpi); 2290fc5462f8SAzael Avalos if (ret) 2291fc5462f8SAzael Avalos return ret; 2292fc5462f8SAzael Avalos if (copy_to_user(argp, ®s, sizeof(SMMRegisters))) 2293fc5462f8SAzael Avalos return -EFAULT; 2294fc5462f8SAzael Avalos break; 2295fc5462f8SAzael Avalos default: 2296fc5462f8SAzael Avalos return -EINVAL; 2297fc5462f8SAzael Avalos } 2298fc5462f8SAzael Avalos 2299fc5462f8SAzael Avalos return 0; 2300fc5462f8SAzael Avalos } 2301fc5462f8SAzael Avalos 2302fc5462f8SAzael Avalos static const struct file_operations toshiba_acpi_fops = { 2303fc5462f8SAzael Avalos .owner = THIS_MODULE, 2304fc5462f8SAzael Avalos .unlocked_ioctl = toshiba_acpi_ioctl, 2305fc5462f8SAzael Avalos .llseek = noop_llseek, 2306fc5462f8SAzael Avalos }; 2307fc5462f8SAzael Avalos 2308fc5462f8SAzael Avalos /* 23091f28f290SAzael Avalos * Hotkeys 23101f28f290SAzael Avalos */ 23111f28f290SAzael Avalos static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev) 23121f28f290SAzael Avalos { 23131f28f290SAzael Avalos acpi_status status; 23141f28f290SAzael Avalos u32 result; 23151f28f290SAzael Avalos 23161f28f290SAzael Avalos status = acpi_evaluate_object(dev->acpi_dev->handle, 23171f28f290SAzael Avalos "ENAB", NULL, NULL); 23181f28f290SAzael Avalos if (ACPI_FAILURE(status)) 23191f28f290SAzael Avalos return -ENODEV; 23201f28f290SAzael Avalos 2321d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE); 23221f28f290SAzael Avalos if (result == TOS_FAILURE) 23231f28f290SAzael Avalos return -EIO; 23241f28f290SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 23251f28f290SAzael Avalos return -ENODEV; 23261f28f290SAzael Avalos 23271f28f290SAzael Avalos return 0; 23281f28f290SAzael Avalos } 23291f28f290SAzael Avalos 2330fb42d1f4SAzael Avalos static void toshiba_acpi_enable_special_functions(struct toshiba_acpi_dev *dev) 2331fb42d1f4SAzael Avalos { 2332fb42d1f4SAzael Avalos u32 result; 2333fb42d1f4SAzael Avalos 2334fb42d1f4SAzael Avalos /* 2335fb42d1f4SAzael Avalos * Re-activate the hotkeys, but this time, we are using the 2336fb42d1f4SAzael Avalos * "Special Functions" mode. 2337fb42d1f4SAzael Avalos */ 2338d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, 2339fb42d1f4SAzael Avalos HCI_HOTKEY_SPECIAL_FUNCTIONS); 2340fb42d1f4SAzael Avalos if (result != TOS_SUCCESS) 2341fb42d1f4SAzael Avalos pr_err("Could not enable the Special Function mode\n"); 2342fb42d1f4SAzael Avalos } 2343fb42d1f4SAzael Avalos 234429cd293fSSeth Forshee static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, 234529cd293fSSeth Forshee struct serio *port) 234629cd293fSSeth Forshee { 234798280374SGiedrius Statkevičius if (str & I8042_STR_AUXDATA) 234829cd293fSSeth Forshee return false; 234929cd293fSSeth Forshee 235029cd293fSSeth Forshee if (unlikely(data == 0xe0)) 235129cd293fSSeth Forshee return false; 235229cd293fSSeth Forshee 235329cd293fSSeth Forshee if ((data & 0x7f) == TOS1900_FN_SCAN) { 235429cd293fSSeth Forshee schedule_work(&toshiba_acpi->hotkey_work); 235529cd293fSSeth Forshee return true; 235629cd293fSSeth Forshee } 235729cd293fSSeth Forshee 235829cd293fSSeth Forshee return false; 235929cd293fSSeth Forshee } 236029cd293fSSeth Forshee 236129cd293fSSeth Forshee static void toshiba_acpi_hotkey_work(struct work_struct *work) 236229cd293fSSeth Forshee { 236329cd293fSSeth Forshee acpi_handle ec_handle = ec_get_handle(); 236429cd293fSSeth Forshee acpi_status status; 236529cd293fSSeth Forshee 236629cd293fSSeth Forshee if (!ec_handle) 236729cd293fSSeth Forshee return; 236829cd293fSSeth Forshee 236929cd293fSSeth Forshee status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL); 237029cd293fSSeth Forshee if (ACPI_FAILURE(status)) 237129cd293fSSeth Forshee pr_err("ACPI NTFY method execution failed\n"); 237229cd293fSSeth Forshee } 237329cd293fSSeth Forshee 237429cd293fSSeth Forshee /* 237529cd293fSSeth Forshee * Returns hotkey scancode, or < 0 on failure. 237629cd293fSSeth Forshee */ 237729cd293fSSeth Forshee static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev) 237829cd293fSSeth Forshee { 237974facaf7SZhang Rui unsigned long long value; 238029cd293fSSeth Forshee acpi_status status; 238129cd293fSSeth Forshee 238274facaf7SZhang Rui status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO", 238374facaf7SZhang Rui NULL, &value); 238474facaf7SZhang Rui if (ACPI_FAILURE(status)) { 238529cd293fSSeth Forshee pr_err("ACPI INFO method execution failed\n"); 238629cd293fSSeth Forshee return -EIO; 238729cd293fSSeth Forshee } 238829cd293fSSeth Forshee 238974facaf7SZhang Rui return value; 239029cd293fSSeth Forshee } 239129cd293fSSeth Forshee 239229cd293fSSeth Forshee static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev, 239329cd293fSSeth Forshee int scancode) 239429cd293fSSeth Forshee { 239529cd293fSSeth Forshee if (scancode == 0x100) 239629cd293fSSeth Forshee return; 239729cd293fSSeth Forshee 2398e0769fe6SDarren Hart /* Act on key press; ignore key release */ 239929cd293fSSeth Forshee if (scancode & 0x80) 240029cd293fSSeth Forshee return; 240129cd293fSSeth Forshee 240229cd293fSSeth Forshee if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true)) 240329cd293fSSeth Forshee pr_info("Unknown key %x\n", scancode); 240429cd293fSSeth Forshee } 240529cd293fSSeth Forshee 240671454d78SAzael Avalos static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) 240771454d78SAzael Avalos { 240871454d78SAzael Avalos if (dev->info_supported) { 24097deef550SAzael Avalos int scancode = toshiba_acpi_query_hotkey(dev); 24107deef550SAzael Avalos 24117deef550SAzael Avalos if (scancode < 0) { 241271454d78SAzael Avalos pr_err("Failed to query hotkey event\n"); 24137deef550SAzael Avalos } else if (scancode != 0) { 241471454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, scancode); 24157deef550SAzael Avalos dev->key_event_valid = 1; 24167deef550SAzael Avalos dev->last_key_event = scancode; 24177deef550SAzael Avalos } 241871454d78SAzael Avalos } else if (dev->system_event_supported) { 24197deef550SAzael Avalos u32 result; 24207deef550SAzael Avalos u32 value; 24217deef550SAzael Avalos int retries = 3; 24227deef550SAzael Avalos 242371454d78SAzael Avalos do { 24247deef550SAzael Avalos result = hci_read(dev, HCI_SYSTEM_EVENT, &value); 24257deef550SAzael Avalos switch (result) { 242671454d78SAzael Avalos case TOS_SUCCESS: 242771454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, (int)value); 24287deef550SAzael Avalos dev->key_event_valid = 1; 24297deef550SAzael Avalos dev->last_key_event = value; 243071454d78SAzael Avalos break; 243171454d78SAzael Avalos case TOS_NOT_SUPPORTED: 243271454d78SAzael Avalos /* 243371454d78SAzael Avalos * This is a workaround for an unresolved 243471454d78SAzael Avalos * issue on some machines where system events 243571454d78SAzael Avalos * sporadically become disabled. 243671454d78SAzael Avalos */ 24377deef550SAzael Avalos result = hci_write(dev, HCI_SYSTEM_EVENT, 1); 24387deef550SAzael Avalos if (result == TOS_SUCCESS) 243971454d78SAzael Avalos pr_notice("Re-enabled hotkeys\n"); 2440e0769fe6SDarren Hart /* Fall through */ 244171454d78SAzael Avalos default: 244271454d78SAzael Avalos retries--; 244371454d78SAzael Avalos break; 244471454d78SAzael Avalos } 24457deef550SAzael Avalos } while (retries && result != TOS_FIFO_EMPTY); 244671454d78SAzael Avalos } 244771454d78SAzael Avalos } 244871454d78SAzael Avalos 2449b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) 24506335e4d5SMatthew Garrett { 2451fe808bfbSTakashi Iwai const struct key_entry *keymap = toshiba_acpi_keymap; 2452a2b3471bSAzael Avalos acpi_handle ec_handle; 2453a2b3471bSAzael Avalos u32 events_type; 2454a2b3471bSAzael Avalos u32 hci_result; 2455a2b3471bSAzael Avalos int error; 2456a2b3471bSAzael Avalos 2457a88bc06eSAzael Avalos if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) { 2458a88bc06eSAzael Avalos pr_info("WMI event detected, hotkeys will not be monitored\n"); 2459a88bc06eSAzael Avalos return 0; 2460a88bc06eSAzael Avalos } 2461a88bc06eSAzael Avalos 2462a2b3471bSAzael Avalos error = toshiba_acpi_enable_hotkeys(dev); 2463a2b3471bSAzael Avalos if (error) 2464a2b3471bSAzael Avalos return error; 2465a2b3471bSAzael Avalos 2466a2b3471bSAzael Avalos error = toshiba_hotkey_event_type_get(dev, &events_type); 2467a2b3471bSAzael Avalos if (error) { 2468a2b3471bSAzael Avalos pr_err("Unable to query Hotkey Event Type\n"); 2469a2b3471bSAzael Avalos return error; 2470a2b3471bSAzael Avalos } 2471a2b3471bSAzael Avalos dev->hotkey_event_type = events_type; 2472135740deSSeth Forshee 2473135740deSSeth Forshee dev->hotkey_dev = input_allocate_device(); 2474b222cca6SJoe Perches if (!dev->hotkey_dev) 2475135740deSSeth Forshee return -ENOMEM; 2476135740deSSeth Forshee 2477135740deSSeth Forshee dev->hotkey_dev->name = "Toshiba input device"; 24786e02cc7eSSeth Forshee dev->hotkey_dev->phys = "toshiba_acpi/input0"; 2479135740deSSeth Forshee dev->hotkey_dev->id.bustype = BUS_HOST; 2480135740deSSeth Forshee 2481a2b3471bSAzael Avalos if (events_type == HCI_SYSTEM_TYPE1 || 2482a2b3471bSAzael Avalos !dev->kbd_function_keys_supported) 2483a2b3471bSAzael Avalos keymap = toshiba_acpi_keymap; 2484a2b3471bSAzael Avalos else if (events_type == HCI_SYSTEM_TYPE2 || 2485a2b3471bSAzael Avalos dev->kbd_function_keys_supported) 2486fe808bfbSTakashi Iwai keymap = toshiba_acpi_alt_keymap; 2487a2b3471bSAzael Avalos else 2488a2b3471bSAzael Avalos pr_info("Unknown event type received %x\n", events_type); 2489fe808bfbSTakashi Iwai error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL); 2490135740deSSeth Forshee if (error) 2491135740deSSeth Forshee goto err_free_dev; 2492135740deSSeth Forshee 249329cd293fSSeth Forshee /* 249429cd293fSSeth Forshee * For some machines the SCI responsible for providing hotkey 249529cd293fSSeth Forshee * notification doesn't fire. We can trigger the notification 249629cd293fSSeth Forshee * whenever the Fn key is pressed using the NTFY method, if 249729cd293fSSeth Forshee * supported, so if it's present set up an i8042 key filter 249829cd293fSSeth Forshee * for this purpose. 249929cd293fSSeth Forshee */ 250029cd293fSSeth Forshee ec_handle = ec_get_handle(); 2501e2e19606SZhang Rui if (ec_handle && acpi_has_method(ec_handle, "NTFY")) { 250229cd293fSSeth Forshee INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work); 250329cd293fSSeth Forshee 250429cd293fSSeth Forshee error = i8042_install_filter(toshiba_acpi_i8042_filter); 250529cd293fSSeth Forshee if (error) { 250629cd293fSSeth Forshee pr_err("Error installing key filter\n"); 250729cd293fSSeth Forshee goto err_free_keymap; 250829cd293fSSeth Forshee } 250929cd293fSSeth Forshee 251029cd293fSSeth Forshee dev->ntfy_supported = 1; 251129cd293fSSeth Forshee } 251229cd293fSSeth Forshee 251329cd293fSSeth Forshee /* 251429cd293fSSeth Forshee * Determine hotkey query interface. Prefer using the INFO 251529cd293fSSeth Forshee * method when it is available. 251629cd293fSSeth Forshee */ 2517e2e19606SZhang Rui if (acpi_has_method(dev->acpi_dev->handle, "INFO")) 251829cd293fSSeth Forshee dev->info_supported = 1; 2519e2e19606SZhang Rui else { 2520d37782bdSAzael Avalos hci_result = hci_write(dev, HCI_SYSTEM_EVENT, 1); 25211864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) 252229cd293fSSeth Forshee dev->system_event_supported = 1; 252329cd293fSSeth Forshee } 252429cd293fSSeth Forshee 252529cd293fSSeth Forshee if (!dev->info_supported && !dev->system_event_supported) { 252629cd293fSSeth Forshee pr_warn("No hotkey query interface found\n"); 252729cd293fSSeth Forshee goto err_remove_filter; 252829cd293fSSeth Forshee } 252929cd293fSSeth Forshee 2530135740deSSeth Forshee error = input_register_device(dev->hotkey_dev); 2531135740deSSeth Forshee if (error) { 2532135740deSSeth Forshee pr_info("Unable to register input device\n"); 253329cd293fSSeth Forshee goto err_remove_filter; 2534135740deSSeth Forshee } 2535135740deSSeth Forshee 2536135740deSSeth Forshee return 0; 2537135740deSSeth Forshee 253829cd293fSSeth Forshee err_remove_filter: 253929cd293fSSeth Forshee if (dev->ntfy_supported) 254029cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 2541135740deSSeth Forshee err_free_keymap: 2542135740deSSeth Forshee sparse_keymap_free(dev->hotkey_dev); 2543135740deSSeth Forshee err_free_dev: 2544135740deSSeth Forshee input_free_device(dev->hotkey_dev); 2545135740deSSeth Forshee dev->hotkey_dev = NULL; 2546135740deSSeth Forshee return error; 2547135740deSSeth Forshee } 2548135740deSSeth Forshee 2549b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) 255062cce752SSeth Forshee { 255162cce752SSeth Forshee struct backlight_properties props; 255262cce752SSeth Forshee int brightness; 255362cce752SSeth Forshee int ret; 255462cce752SSeth Forshee 255562cce752SSeth Forshee /* 255662cce752SSeth Forshee * Some machines don't support the backlight methods at all, and 255762cce752SSeth Forshee * others support it read-only. Either of these is pretty useless, 255862cce752SSeth Forshee * so only register the backlight device if the backlight method 255962cce752SSeth Forshee * supports both reads and writes. 256062cce752SSeth Forshee */ 256162cce752SSeth Forshee brightness = __get_lcd_brightness(dev); 256262cce752SSeth Forshee if (brightness < 0) 256362cce752SSeth Forshee return 0; 256462cce752SSeth Forshee ret = set_lcd_brightness(dev, brightness); 256562cce752SSeth Forshee if (ret) { 256662cce752SSeth Forshee pr_debug("Backlight method is read-only, disabling backlight support\n"); 256762cce752SSeth Forshee return 0; 256862cce752SSeth Forshee } 256962cce752SSeth Forshee 2570358d6a2cSHans de Goede /* 2571358d6a2cSHans de Goede * Tell acpi-video-detect code to prefer vendor backlight on all 2572358d6a2cSHans de Goede * systems with transflective backlight and on dmi matched systems. 2573358d6a2cSHans de Goede */ 2574358d6a2cSHans de Goede if (dev->tr_backlight_supported || 2575358d6a2cSHans de Goede dmi_check_system(toshiba_vendor_backlight_dmi)) 2576234b7cf8SHans de Goede acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); 2577358d6a2cSHans de Goede 2578234b7cf8SHans de Goede if (acpi_video_get_backlight_type() != acpi_backlight_vendor) 2579358d6a2cSHans de Goede return 0; 2580358d6a2cSHans de Goede 258153039f22SMatthew Garrett memset(&props, 0, sizeof(props)); 258262cce752SSeth Forshee props.type = BACKLIGHT_PLATFORM; 258362cce752SSeth Forshee props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; 258462cce752SSeth Forshee 2585e0769fe6SDarren Hart /* Adding an extra level and having 0 change to transflective mode */ 2586121b7b0dSAkio Idehara if (dev->tr_backlight_supported) 2587121b7b0dSAkio Idehara props.max_brightness++; 2588121b7b0dSAkio Idehara 258962cce752SSeth Forshee dev->backlight_dev = backlight_device_register("toshiba", 259062cce752SSeth Forshee &dev->acpi_dev->dev, 259162cce752SSeth Forshee dev, 259262cce752SSeth Forshee &toshiba_backlight_data, 259362cce752SSeth Forshee &props); 259462cce752SSeth Forshee if (IS_ERR(dev->backlight_dev)) { 259562cce752SSeth Forshee ret = PTR_ERR(dev->backlight_dev); 259662cce752SSeth Forshee pr_err("Could not register toshiba backlight device\n"); 259762cce752SSeth Forshee dev->backlight_dev = NULL; 259862cce752SSeth Forshee return ret; 259962cce752SSeth Forshee } 260062cce752SSeth Forshee 260162cce752SSeth Forshee dev->backlight_dev->props.brightness = brightness; 260262cce752SSeth Forshee return 0; 260362cce752SSeth Forshee } 260462cce752SSeth Forshee 260551fac838SRafael J. Wysocki static int toshiba_acpi_remove(struct acpi_device *acpi_dev) 2606135740deSSeth Forshee { 2607135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 2608135740deSSeth Forshee 2609fc5462f8SAzael Avalos misc_deregister(&dev->miscdev); 2610fc5462f8SAzael Avalos 261136d03f93SSeth Forshee remove_toshiba_proc_entries(dev); 2612135740deSSeth Forshee 2613360f0f39SAzael Avalos if (dev->sysfs_created) 2614360f0f39SAzael Avalos sysfs_remove_group(&dev->acpi_dev->dev.kobj, 2615360f0f39SAzael Avalos &toshiba_attr_group); 2616360f0f39SAzael Avalos 261729cd293fSSeth Forshee if (dev->ntfy_supported) { 261829cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 261929cd293fSSeth Forshee cancel_work_sync(&dev->hotkey_work); 262029cd293fSSeth Forshee } 262129cd293fSSeth Forshee 2622135740deSSeth Forshee if (dev->hotkey_dev) { 2623135740deSSeth Forshee input_unregister_device(dev->hotkey_dev); 2624135740deSSeth Forshee sparse_keymap_free(dev->hotkey_dev); 2625135740deSSeth Forshee } 2626135740deSSeth Forshee 2627135740deSSeth Forshee backlight_device_unregister(dev->backlight_dev); 2628135740deSSeth Forshee 262936d03f93SSeth Forshee if (dev->illumination_supported) 2630135740deSSeth Forshee led_classdev_unregister(&dev->led_dev); 2631135740deSSeth Forshee 2632360f0f39SAzael Avalos if (dev->kbd_led_registered) 2633360f0f39SAzael Avalos led_classdev_unregister(&dev->kbd_led); 2634360f0f39SAzael Avalos 2635def6c4e2SAzael Avalos if (dev->eco_supported) 2636def6c4e2SAzael Avalos led_classdev_unregister(&dev->eco_led); 2637def6c4e2SAzael Avalos 263829cd293fSSeth Forshee if (toshiba_acpi) 263929cd293fSSeth Forshee toshiba_acpi = NULL; 264029cd293fSSeth Forshee 2641135740deSSeth Forshee kfree(dev); 2642135740deSSeth Forshee 2643135740deSSeth Forshee return 0; 2644135740deSSeth Forshee } 2645135740deSSeth Forshee 2646b859f159SGreg Kroah-Hartman static const char *find_hci_method(acpi_handle handle) 2647a540d6b5SSeth Forshee { 2648e2e19606SZhang Rui if (acpi_has_method(handle, "GHCI")) 2649a540d6b5SSeth Forshee return "GHCI"; 2650a540d6b5SSeth Forshee 2651e2e19606SZhang Rui if (acpi_has_method(handle, "SPFC")) 2652a540d6b5SSeth Forshee return "SPFC"; 2653a540d6b5SSeth Forshee 2654a540d6b5SSeth Forshee return NULL; 2655a540d6b5SSeth Forshee } 2656a540d6b5SSeth Forshee 2657b859f159SGreg Kroah-Hartman static int toshiba_acpi_add(struct acpi_device *acpi_dev) 2658135740deSSeth Forshee { 2659135740deSSeth Forshee struct toshiba_acpi_dev *dev; 2660a540d6b5SSeth Forshee const char *hci_method; 2661fb42d1f4SAzael Avalos u32 special_functions; 266236d03f93SSeth Forshee u32 dummy; 2663135740deSSeth Forshee int ret = 0; 2664135740deSSeth Forshee 266529cd293fSSeth Forshee if (toshiba_acpi) 266629cd293fSSeth Forshee return -EBUSY; 266729cd293fSSeth Forshee 2668135740deSSeth Forshee pr_info("Toshiba Laptop ACPI Extras version %s\n", 2669135740deSSeth Forshee TOSHIBA_ACPI_VERSION); 2670135740deSSeth Forshee 2671a540d6b5SSeth Forshee hci_method = find_hci_method(acpi_dev->handle); 2672a540d6b5SSeth Forshee if (!hci_method) { 2673a540d6b5SSeth Forshee pr_err("HCI interface not found\n"); 26746e02cc7eSSeth Forshee return -ENODEV; 2675a540d6b5SSeth Forshee } 26766e02cc7eSSeth Forshee 2677135740deSSeth Forshee dev = kzalloc(sizeof(*dev), GFP_KERNEL); 2678135740deSSeth Forshee if (!dev) 2679135740deSSeth Forshee return -ENOMEM; 2680135740deSSeth Forshee dev->acpi_dev = acpi_dev; 2681a540d6b5SSeth Forshee dev->method_hci = hci_method; 2682fc5462f8SAzael Avalos dev->miscdev.minor = MISC_DYNAMIC_MINOR; 2683fc5462f8SAzael Avalos dev->miscdev.name = "toshiba_acpi"; 2684fc5462f8SAzael Avalos dev->miscdev.fops = &toshiba_acpi_fops; 2685fc5462f8SAzael Avalos 2686fc5462f8SAzael Avalos ret = misc_register(&dev->miscdev); 2687fc5462f8SAzael Avalos if (ret) { 2688fc5462f8SAzael Avalos pr_err("Failed to register miscdevice\n"); 2689fc5462f8SAzael Avalos kfree(dev); 2690fc5462f8SAzael Avalos return ret; 2691fc5462f8SAzael Avalos } 2692fc5462f8SAzael Avalos 2693135740deSSeth Forshee acpi_dev->driver_data = dev; 2694360f0f39SAzael Avalos dev_set_drvdata(&acpi_dev->dev, dev); 2695135740deSSeth Forshee 2696a2b3471bSAzael Avalos /* Query the BIOS for supported features */ 2697a2b3471bSAzael Avalos 2698a2b3471bSAzael Avalos /* 2699a2b3471bSAzael Avalos * The "Special Functions" are always supported by the laptops 2700a2b3471bSAzael Avalos * with the new keyboard layout, query for its presence to help 2701a2b3471bSAzael Avalos * determine the keymap layout to use. 2702a2b3471bSAzael Avalos */ 2703fb42d1f4SAzael Avalos ret = toshiba_function_keys_get(dev, &special_functions); 2704a2b3471bSAzael Avalos dev->kbd_function_keys_supported = !ret; 2705a2b3471bSAzael Avalos 27066e02cc7eSSeth Forshee if (toshiba_acpi_setup_keyboard(dev)) 2707135740deSSeth Forshee pr_info("Unable to activate hotkeys\n"); 2708135740deSSeth Forshee 2709695f6060SAzael Avalos /* Determine whether or not BIOS supports transflective backlight */ 2710695f6060SAzael Avalos ret = get_tr_backlight_status(dev, &dummy); 2711695f6060SAzael Avalos dev->tr_backlight_supported = !ret; 2712695f6060SAzael Avalos 271362cce752SSeth Forshee ret = toshiba_acpi_setup_backlight(dev); 271462cce752SSeth Forshee if (ret) 2715135740deSSeth Forshee goto error; 2716135740deSSeth Forshee 2717135740deSSeth Forshee if (toshiba_illumination_available(dev)) { 2718135740deSSeth Forshee dev->led_dev.name = "toshiba::illumination"; 2719135740deSSeth Forshee dev->led_dev.max_brightness = 1; 2720135740deSSeth Forshee dev->led_dev.brightness_set = toshiba_illumination_set; 2721135740deSSeth Forshee dev->led_dev.brightness_get = toshiba_illumination_get; 2722135740deSSeth Forshee if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev)) 272336d03f93SSeth Forshee dev->illumination_supported = 1; 2724135740deSSeth Forshee } 2725135740deSSeth Forshee 2726def6c4e2SAzael Avalos if (toshiba_eco_mode_available(dev)) { 2727def6c4e2SAzael Avalos dev->eco_led.name = "toshiba::eco_mode"; 2728def6c4e2SAzael Avalos dev->eco_led.max_brightness = 1; 2729def6c4e2SAzael Avalos dev->eco_led.brightness_set = toshiba_eco_mode_set_status; 2730def6c4e2SAzael Avalos dev->eco_led.brightness_get = toshiba_eco_mode_get_status; 2731def6c4e2SAzael Avalos if (!led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led)) 2732def6c4e2SAzael Avalos dev->eco_supported = 1; 2733def6c4e2SAzael Avalos } 2734def6c4e2SAzael Avalos 273593f8c16dSAzael Avalos dev->kbd_illum_supported = toshiba_kbd_illum_available(dev); 2736360f0f39SAzael Avalos /* 2737360f0f39SAzael Avalos * Only register the LED if KBD illumination is supported 2738360f0f39SAzael Avalos * and the keyboard backlight operation mode is set to FN-Z 2739360f0f39SAzael Avalos */ 2740360f0f39SAzael Avalos if (dev->kbd_illum_supported && dev->kbd_mode == SCI_KBD_MODE_FNZ) { 2741360f0f39SAzael Avalos dev->kbd_led.name = "toshiba::kbd_backlight"; 2742360f0f39SAzael Avalos dev->kbd_led.max_brightness = 1; 2743360f0f39SAzael Avalos dev->kbd_led.brightness_set = toshiba_kbd_backlight_set; 2744360f0f39SAzael Avalos dev->kbd_led.brightness_get = toshiba_kbd_backlight_get; 2745360f0f39SAzael Avalos if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led)) 2746360f0f39SAzael Avalos dev->kbd_led_registered = 1; 2747360f0f39SAzael Avalos } 2748360f0f39SAzael Avalos 27499d8658acSAzael Avalos ret = toshiba_touchpad_get(dev, &dummy); 27509d8658acSAzael Avalos dev->touchpad_supported = !ret; 27519d8658acSAzael Avalos 27525a2813e9SAzael Avalos ret = toshiba_accelerometer_supported(dev); 27535a2813e9SAzael Avalos dev->accelerometer_supported = !ret; 27545a2813e9SAzael Avalos 2755c8c91842SAzael Avalos toshiba_usb_sleep_charge_available(dev); 2756e26ffe51SAzael Avalos 2757bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(dev, &dummy); 2758bb3fe01fSAzael Avalos dev->usb_rapid_charge_supported = !ret; 2759bb3fe01fSAzael Avalos 2760172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(dev, &dummy); 2761172ce0a9SAzael Avalos dev->usb_sleep_music_supported = !ret; 2762172ce0a9SAzael Avalos 276335d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(dev, &dummy); 276435d53ceaSAzael Avalos dev->panel_power_on_supported = !ret; 276535d53ceaSAzael Avalos 276617fe4b3dSAzael Avalos ret = toshiba_usb_three_get(dev, &dummy); 276717fe4b3dSAzael Avalos dev->usb_three_supported = !ret; 276817fe4b3dSAzael Avalos 276936d03f93SSeth Forshee ret = get_video_status(dev, &dummy); 277036d03f93SSeth Forshee dev->video_supported = !ret; 277136d03f93SSeth Forshee 277236d03f93SSeth Forshee ret = get_fan_status(dev, &dummy); 277336d03f93SSeth Forshee dev->fan_supported = !ret; 277436d03f93SSeth Forshee 2775fb42d1f4SAzael Avalos /* 2776fb42d1f4SAzael Avalos * Enable the "Special Functions" mode only if they are 2777fb42d1f4SAzael Avalos * supported and if they are activated. 2778fb42d1f4SAzael Avalos */ 2779fb42d1f4SAzael Avalos if (dev->kbd_function_keys_supported && special_functions) 2780fb42d1f4SAzael Avalos toshiba_acpi_enable_special_functions(dev); 2781fb42d1f4SAzael Avalos 2782360f0f39SAzael Avalos ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, 2783360f0f39SAzael Avalos &toshiba_attr_group); 2784360f0f39SAzael Avalos if (ret) { 2785360f0f39SAzael Avalos dev->sysfs_created = 0; 2786360f0f39SAzael Avalos goto error; 2787360f0f39SAzael Avalos } 2788360f0f39SAzael Avalos dev->sysfs_created = !ret; 2789360f0f39SAzael Avalos 279036d03f93SSeth Forshee create_toshiba_proc_entries(dev); 279136d03f93SSeth Forshee 279229cd293fSSeth Forshee toshiba_acpi = dev; 279329cd293fSSeth Forshee 2794135740deSSeth Forshee return 0; 2795135740deSSeth Forshee 2796135740deSSeth Forshee error: 279751fac838SRafael J. Wysocki toshiba_acpi_remove(acpi_dev); 2798135740deSSeth Forshee return ret; 2799135740deSSeth Forshee } 2800135740deSSeth Forshee 2801135740deSSeth Forshee static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) 2802135740deSSeth Forshee { 2803135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 280480546905SAzael Avalos int ret; 28056335e4d5SMatthew Garrett 280671454d78SAzael Avalos switch (event) { 280771454d78SAzael Avalos case 0x80: /* Hotkeys and some system events */ 2808a88bc06eSAzael Avalos /* 2809a88bc06eSAzael Avalos * Machines with this WMI GUID aren't supported due to bugs in 2810a88bc06eSAzael Avalos * their AML. 2811a88bc06eSAzael Avalos * 2812a88bc06eSAzael Avalos * Return silently to avoid triggering a netlink event. 2813a88bc06eSAzael Avalos */ 2814a88bc06eSAzael Avalos if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) 2815a88bc06eSAzael Avalos return; 281671454d78SAzael Avalos toshiba_acpi_process_hotkeys(dev); 281711948b93SSeth Forshee break; 2818bab09e23SAzael Avalos case 0x81: /* Dock events */ 2819bab09e23SAzael Avalos case 0x82: 2820bab09e23SAzael Avalos case 0x83: 2821bab09e23SAzael Avalos pr_info("Dock event received %x\n", event); 2822bab09e23SAzael Avalos break; 2823bab09e23SAzael Avalos case 0x88: /* Thermal events */ 2824bab09e23SAzael Avalos pr_info("Thermal event received\n"); 2825bab09e23SAzael Avalos break; 2826bab09e23SAzael Avalos case 0x8f: /* LID closed */ 2827bab09e23SAzael Avalos case 0x90: /* LID is closed and Dock has been ejected */ 2828bab09e23SAzael Avalos break; 2829bab09e23SAzael Avalos case 0x8c: /* SATA power events */ 2830bab09e23SAzael Avalos case 0x8b: 2831bab09e23SAzael Avalos pr_info("SATA power event received %x\n", event); 2832bab09e23SAzael Avalos break; 283380546905SAzael Avalos case 0x92: /* Keyboard backlight mode changed */ 283480546905SAzael Avalos /* Update sysfs entries */ 283580546905SAzael Avalos ret = sysfs_update_group(&acpi_dev->dev.kobj, 283680546905SAzael Avalos &toshiba_attr_group); 283780546905SAzael Avalos if (ret) 283880546905SAzael Avalos pr_err("Unable to update sysfs entries\n"); 283980546905SAzael Avalos break; 2840bab09e23SAzael Avalos case 0x85: /* Unknown */ 2841bab09e23SAzael Avalos case 0x8d: /* Unknown */ 284271454d78SAzael Avalos case 0x8e: /* Unknown */ 2843bab09e23SAzael Avalos case 0x94: /* Unknown */ 2844bab09e23SAzael Avalos case 0x95: /* Unknown */ 284511948b93SSeth Forshee default: 284671454d78SAzael Avalos pr_info("Unknown event received %x\n", event); 284711948b93SSeth Forshee break; 28486335e4d5SMatthew Garrett } 2849bab09e23SAzael Avalos 2850bab09e23SAzael Avalos acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class, 2851bab09e23SAzael Avalos dev_name(&acpi_dev->dev), 2852bab09e23SAzael Avalos event, 0); 285329cd293fSSeth Forshee } 28546335e4d5SMatthew Garrett 28553567a4e2SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 285643d2fd3bSRafael J. Wysocki static int toshiba_acpi_suspend(struct device *device) 285729cd293fSSeth Forshee { 285843d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 285929cd293fSSeth Forshee u32 result; 286029cd293fSSeth Forshee 286129cd293fSSeth Forshee if (dev->hotkey_dev) 2862d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE); 286329cd293fSSeth Forshee 286429cd293fSSeth Forshee return 0; 286529cd293fSSeth Forshee } 286629cd293fSSeth Forshee 286743d2fd3bSRafael J. Wysocki static int toshiba_acpi_resume(struct device *device) 286829cd293fSSeth Forshee { 286943d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 28701f28f290SAzael Avalos int error; 287129cd293fSSeth Forshee 2872e7fdb762SBenjamin Tissoires if (dev->hotkey_dev) { 28731f28f290SAzael Avalos error = toshiba_acpi_enable_hotkeys(dev); 28741f28f290SAzael Avalos if (error) 2875e7fdb762SBenjamin Tissoires pr_info("Unable to re-enable hotkeys\n"); 2876e7fdb762SBenjamin Tissoires } 287729cd293fSSeth Forshee 287829cd293fSSeth Forshee return 0; 287929cd293fSSeth Forshee } 28803567a4e2SRafael J. Wysocki #endif 28816335e4d5SMatthew Garrett 288243d2fd3bSRafael J. Wysocki static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm, 288343d2fd3bSRafael J. Wysocki toshiba_acpi_suspend, toshiba_acpi_resume); 288443d2fd3bSRafael J. Wysocki 2885135740deSSeth Forshee static struct acpi_driver toshiba_acpi_driver = { 2886135740deSSeth Forshee .name = "Toshiba ACPI driver", 2887135740deSSeth Forshee .owner = THIS_MODULE, 2888135740deSSeth Forshee .ids = toshiba_device_ids, 2889135740deSSeth Forshee .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, 2890135740deSSeth Forshee .ops = { 2891135740deSSeth Forshee .add = toshiba_acpi_add, 2892135740deSSeth Forshee .remove = toshiba_acpi_remove, 2893135740deSSeth Forshee .notify = toshiba_acpi_notify, 2894135740deSSeth Forshee }, 289543d2fd3bSRafael J. Wysocki .drv.pm = &toshiba_acpi_pm, 2896135740deSSeth Forshee }; 2897b4f9fe12SLen Brown 2898b4f9fe12SLen Brown static int __init toshiba_acpi_init(void) 2899b4f9fe12SLen Brown { 2900135740deSSeth Forshee int ret; 2901b4f9fe12SLen Brown 2902b4f9fe12SLen Brown toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); 2903b4f9fe12SLen Brown if (!toshiba_proc_dir) { 2904135740deSSeth Forshee pr_err("Unable to create proc dir " PROC_TOSHIBA "\n"); 2905b4f9fe12SLen Brown return -ENODEV; 2906b4f9fe12SLen Brown } 2907b4f9fe12SLen Brown 2908135740deSSeth Forshee ret = acpi_bus_register_driver(&toshiba_acpi_driver); 2909b4f9fe12SLen Brown if (ret) { 2910135740deSSeth Forshee pr_err("Failed to register ACPI driver: %d\n", ret); 2911135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 2912135740deSSeth Forshee } 2913135740deSSeth Forshee 2914b4f9fe12SLen Brown return ret; 2915b4f9fe12SLen Brown } 2916b4f9fe12SLen Brown 2917135740deSSeth Forshee static void __exit toshiba_acpi_exit(void) 2918135740deSSeth Forshee { 2919135740deSSeth Forshee acpi_bus_unregister_driver(&toshiba_acpi_driver); 2920135740deSSeth Forshee if (toshiba_proc_dir) 2921135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 2922b4f9fe12SLen Brown } 2923b4f9fe12SLen Brown 2924b4f9fe12SLen Brown module_init(toshiba_acpi_init); 2925b4f9fe12SLen Brown module_exit(toshiba_acpi_exit); 2926