19ab65affSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2b4f9fe12SLen Brown /* 3b4f9fe12SLen Brown * toshiba_acpi.c - Toshiba Laptop ACPI Extras 4b4f9fe12SLen Brown * 5b4f9fe12SLen Brown * Copyright (C) 2002-2004 John Belmonte 6b4f9fe12SLen Brown * Copyright (C) 2008 Philip Langdale 76c3f6e6cSPierre Ducroquet * Copyright (C) 2010 Pierre Ducroquet 895d16d81SAzael Avalos * Copyright (C) 2014-2016 Azael Avalos 9b4f9fe12SLen Brown * 10b4f9fe12SLen Brown * The devolpment page for this driver is located at 11b4f9fe12SLen Brown * http://memebeam.org/toys/ToshibaAcpiDriver. 12b4f9fe12SLen Brown * 13b4f9fe12SLen Brown * Credits: 14b4f9fe12SLen Brown * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse 15b4f9fe12SLen Brown * engineering the Windows drivers 16b4f9fe12SLen Brown * Yasushi Nagato - changes for linux kernel 2.4 -> 2.5 17b4f9fe12SLen Brown * Rob Miller - TV out and hotkeys help 18b4f9fe12SLen Brown */ 19b4f9fe12SLen Brown 207e33460dSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 217e33460dSJoe Perches 2295d16d81SAzael Avalos #define TOSHIBA_ACPI_VERSION "0.24" 23b4f9fe12SLen Brown #define PROC_INTERFACE_VERSION 1 24b4f9fe12SLen Brown 25c2e2a618SRandy Dunlap #include <linux/compiler.h> 26b4f9fe12SLen Brown #include <linux/kernel.h> 27b4f9fe12SLen Brown #include <linux/module.h> 287faa6a37SAzael Avalos #include <linux/moduleparam.h> 29b4f9fe12SLen Brown #include <linux/init.h> 30b4f9fe12SLen Brown #include <linux/types.h> 31b4f9fe12SLen Brown #include <linux/proc_fs.h> 32936c8bcdSAlexey Dobriyan #include <linux/seq_file.h> 33b4f9fe12SLen Brown #include <linux/backlight.h> 346335e4d5SMatthew Garrett #include <linux/input.h> 35384a7cd9SDmitry Torokhov #include <linux/input/sparse-keymap.h> 366c3f6e6cSPierre Ducroquet #include <linux/leds.h> 375a0e3ad6STejun Heo #include <linux/slab.h> 3829cd293fSSeth Forshee #include <linux/workqueue.h> 3929cd293fSSeth Forshee #include <linux/i8042.h> 408b48463fSLv Zheng #include <linux/acpi.h> 41358d6a2cSHans de Goede #include <linux/dmi.h> 42b5163992SAzael Avalos #include <linux/uaccess.h> 43fc5462f8SAzael Avalos #include <linux/miscdevice.h> 442fdde834SAzael Avalos #include <linux/rfkill.h> 45*c727ba4cSArvid Norlander #include <linux/hwmon.h> 4698010f1eSAzael Avalos #include <linux/iio/iio.h> 47fc5462f8SAzael Avalos #include <linux/toshiba.h> 48358d6a2cSHans de Goede #include <acpi/video.h> 49b4f9fe12SLen Brown 50b4f9fe12SLen Brown MODULE_AUTHOR("John Belmonte"); 51b4f9fe12SLen Brown MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); 52b4f9fe12SLen Brown MODULE_LICENSE("GPL"); 53b4f9fe12SLen Brown 54f11f999eSSeth Forshee #define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100" 55f11f999eSSeth Forshee 5629cd293fSSeth Forshee /* Scan code for Fn key on TOS1900 models */ 5729cd293fSSeth Forshee #define TOS1900_FN_SCAN 0x6e 5829cd293fSSeth Forshee 59b4f9fe12SLen Brown /* Toshiba ACPI method paths */ 60b4f9fe12SLen Brown #define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX" 61b4f9fe12SLen Brown 62e0769fe6SDarren Hart /* 63e0769fe6SDarren Hart * The Toshiba configuration interface is composed of the HCI and the SCI, 64258c5903SAzael Avalos * which are defined as follows: 65b4f9fe12SLen Brown * 66b4f9fe12SLen Brown * HCI is Toshiba's "Hardware Control Interface" which is supposed to 67b4f9fe12SLen Brown * be uniform across all their models. Ideally we would just call 68b4f9fe12SLen Brown * dedicated ACPI methods instead of using this primitive interface. 69b4f9fe12SLen Brown * However the ACPI methods seem to be incomplete in some areas (for 70b4f9fe12SLen Brown * example they allow setting, but not reading, the LCD brightness value), 71b4f9fe12SLen Brown * so this is still useful. 7284a6273fSAzael Avalos * 7384a6273fSAzael Avalos * SCI stands for "System Configuration Interface" which aim is to 7484a6273fSAzael Avalos * conceal differences in hardware between different models. 75b4f9fe12SLen Brown */ 76b4f9fe12SLen Brown 77258c5903SAzael Avalos #define TCI_WORDS 6 78b4f9fe12SLen Brown 793f75bbe9SAzael Avalos /* Operations */ 80b4f9fe12SLen Brown #define HCI_SET 0xff00 81b4f9fe12SLen Brown #define HCI_GET 0xfe00 8284a6273fSAzael Avalos #define SCI_OPEN 0xf100 8384a6273fSAzael Avalos #define SCI_CLOSE 0xf200 8484a6273fSAzael Avalos #define SCI_GET 0xf300 8584a6273fSAzael Avalos #define SCI_SET 0xf400 86b4f9fe12SLen Brown 873f75bbe9SAzael Avalos /* Return codes */ 881864bbc2SAzael Avalos #define TOS_SUCCESS 0x0000 89e1a949c1SAzael Avalos #define TOS_SUCCESS2 0x0001 901864bbc2SAzael Avalos #define TOS_OPEN_CLOSE_OK 0x0044 911864bbc2SAzael Avalos #define TOS_FAILURE 0x1000 921864bbc2SAzael Avalos #define TOS_NOT_SUPPORTED 0x8000 931864bbc2SAzael Avalos #define TOS_ALREADY_OPEN 0x8100 941864bbc2SAzael Avalos #define TOS_NOT_OPENED 0x8200 951864bbc2SAzael Avalos #define TOS_INPUT_DATA_ERROR 0x8300 961864bbc2SAzael Avalos #define TOS_WRITE_PROTECTED 0x8400 971864bbc2SAzael Avalos #define TOS_NOT_PRESENT 0x8600 981864bbc2SAzael Avalos #define TOS_FIFO_EMPTY 0x8c00 991864bbc2SAzael Avalos #define TOS_DATA_NOT_AVAILABLE 0x8d20 1001864bbc2SAzael Avalos #define TOS_NOT_INITIALIZED 0x8d50 10198fc4ec6SAzael Avalos #define TOS_NOT_INSTALLED 0x8e00 102b4f9fe12SLen Brown 1033f75bbe9SAzael Avalos /* Registers */ 104b4f9fe12SLen Brown #define HCI_FAN 0x0004 105121b7b0dSAkio Idehara #define HCI_TR_BACKLIGHT 0x0005 106b4f9fe12SLen Brown #define HCI_SYSTEM_EVENT 0x0016 107b4f9fe12SLen Brown #define HCI_VIDEO_OUT 0x001c 108b4f9fe12SLen Brown #define HCI_HOTKEY_EVENT 0x001e 109b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS 0x002a 110dd193dcdSArvid Norlander #define HCI_FAN_RPM 0x0045 1116873f46aSAzael Avalos #define HCI_WIRELESS 0x0056 1125a2813e9SAzael Avalos #define HCI_ACCELEROMETER 0x006d 113763ff32fSAzael Avalos #define HCI_COOLING_METHOD 0x007f 114360f0f39SAzael Avalos #define HCI_KBD_ILLUMINATION 0x0095 115def6c4e2SAzael Avalos #define HCI_ECO_MODE 0x0097 1165a2813e9SAzael Avalos #define HCI_ACCELEROMETER2 0x00a6 11756e6b353SAzael Avalos #define HCI_SYSTEM_INFO 0xc000 11835d53ceaSAzael Avalos #define SCI_PANEL_POWER_ON 0x010d 119fdb79081SAzael Avalos #define SCI_ILLUMINATION 0x014e 120e26ffe51SAzael Avalos #define SCI_USB_SLEEP_CHARGE 0x0150 121360f0f39SAzael Avalos #define SCI_KBD_ILLUM_STATUS 0x015c 122172ce0a9SAzael Avalos #define SCI_USB_SLEEP_MUSIC 0x015e 12317fe4b3dSAzael Avalos #define SCI_USB_THREE 0x0169 1249d8658acSAzael Avalos #define SCI_TOUCHPAD 0x050e 125bae84195SAzael Avalos #define SCI_KBD_FUNCTION_KEYS 0x0522 126b4f9fe12SLen Brown 1273f75bbe9SAzael Avalos /* Field definitions */ 1285a2813e9SAzael Avalos #define HCI_ACCEL_MASK 0x7fff 12998010f1eSAzael Avalos #define HCI_ACCEL_DIRECTION_MASK 0x8000 13029cd293fSSeth Forshee #define HCI_HOTKEY_DISABLE 0x0b 131a30b8f81SAzael Avalos #define HCI_HOTKEY_ENABLE 0x09 132fb42d1f4SAzael Avalos #define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10 133b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_BITS 3 134b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) 135b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS) 136360f0f39SAzael Avalos #define HCI_MISC_SHIFT 0x10 13756e6b353SAzael Avalos #define HCI_SYSTEM_TYPE1 0x10 13856e6b353SAzael Avalos #define HCI_SYSTEM_TYPE2 0x11 139b4f9fe12SLen Brown #define HCI_VIDEO_OUT_LCD 0x1 140b4f9fe12SLen Brown #define HCI_VIDEO_OUT_CRT 0x2 141b4f9fe12SLen Brown #define HCI_VIDEO_OUT_TV 0x4 14293f8c16dSAzael Avalos #define SCI_KBD_MODE_MASK 0x1f 143360f0f39SAzael Avalos #define SCI_KBD_MODE_FNZ 0x1 144360f0f39SAzael Avalos #define SCI_KBD_MODE_AUTO 0x2 14593f8c16dSAzael Avalos #define SCI_KBD_MODE_ON 0x8 14693f8c16dSAzael Avalos #define SCI_KBD_MODE_OFF 0x10 14793f8c16dSAzael Avalos #define SCI_KBD_TIME_MAX 0x3c001a 1486873f46aSAzael Avalos #define HCI_WIRELESS_STATUS 0x1 1496873f46aSAzael Avalos #define HCI_WIRELESS_WWAN 0x3 1506873f46aSAzael Avalos #define HCI_WIRELESS_WWAN_STATUS 0x2000 1516873f46aSAzael Avalos #define HCI_WIRELESS_WWAN_POWER 0x4000 152e26ffe51SAzael Avalos #define SCI_USB_CHARGE_MODE_MASK 0xff 153c8c91842SAzael Avalos #define SCI_USB_CHARGE_DISABLED 0x00 154c8c91842SAzael Avalos #define SCI_USB_CHARGE_ALTERNATE 0x09 155c8c91842SAzael Avalos #define SCI_USB_CHARGE_TYPICAL 0x11 156c8c91842SAzael Avalos #define SCI_USB_CHARGE_AUTO 0x21 157182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_MASK 0x7 158182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_OFF 0x1 159182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_ON 0x4 160182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL 0x0200 161bb3fe01fSAzael Avalos #define SCI_USB_CHARGE_RAPID_DSP 0x0300 162b4f9fe12SLen Brown 163135740deSSeth Forshee struct toshiba_acpi_dev { 164135740deSSeth Forshee struct acpi_device *acpi_dev; 165135740deSSeth Forshee const char *method_hci; 166135740deSSeth Forshee struct input_dev *hotkey_dev; 16729cd293fSSeth Forshee struct work_struct hotkey_work; 168135740deSSeth Forshee struct backlight_device *backlight_dev; 169135740deSSeth Forshee struct led_classdev led_dev; 170360f0f39SAzael Avalos struct led_classdev kbd_led; 171def6c4e2SAzael Avalos struct led_classdev eco_led; 172fc5462f8SAzael Avalos struct miscdevice miscdev; 1732fdde834SAzael Avalos struct rfkill *wwan_rfk; 17498010f1eSAzael Avalos struct iio_dev *indio_dev; 175*c727ba4cSArvid Norlander #if IS_ENABLED(CONFIG_HWMON) 176*c727ba4cSArvid Norlander struct device *hwmon_device; 177*c727ba4cSArvid Norlander #endif 17836d03f93SSeth Forshee 179135740deSSeth Forshee int force_fan; 180135740deSSeth Forshee int last_key_event; 181135740deSSeth Forshee int key_event_valid; 18293f8c16dSAzael Avalos int kbd_type; 183360f0f39SAzael Avalos int kbd_mode; 184360f0f39SAzael Avalos int kbd_time; 185182bcaa5SAzael Avalos int usbsc_bat_level; 186c8c91842SAzael Avalos int usbsc_mode_base; 187a2b3471bSAzael Avalos int hotkey_event_type; 188763ff32fSAzael Avalos int max_cooling_method; 189135740deSSeth Forshee 190592b746cSDan Carpenter unsigned int illumination_supported:1; 191592b746cSDan Carpenter unsigned int video_supported:1; 192592b746cSDan Carpenter unsigned int fan_supported:1; 193dd193dcdSArvid Norlander unsigned int fan_rpm_supported:1; 194592b746cSDan Carpenter unsigned int system_event_supported:1; 19529cd293fSSeth Forshee unsigned int ntfy_supported:1; 19629cd293fSSeth Forshee unsigned int info_supported:1; 197121b7b0dSAkio Idehara unsigned int tr_backlight_supported:1; 198360f0f39SAzael Avalos unsigned int kbd_illum_supported:1; 1999d8658acSAzael Avalos unsigned int touchpad_supported:1; 200def6c4e2SAzael Avalos unsigned int eco_supported:1; 2015a2813e9SAzael Avalos unsigned int accelerometer_supported:1; 202e26ffe51SAzael Avalos unsigned int usb_sleep_charge_supported:1; 203bb3fe01fSAzael Avalos unsigned int usb_rapid_charge_supported:1; 204172ce0a9SAzael Avalos unsigned int usb_sleep_music_supported:1; 205bae84195SAzael Avalos unsigned int kbd_function_keys_supported:1; 20635d53ceaSAzael Avalos unsigned int panel_power_on_supported:1; 20717fe4b3dSAzael Avalos unsigned int usb_three_supported:1; 2086873f46aSAzael Avalos unsigned int wwan_supported:1; 209763ff32fSAzael Avalos unsigned int cooling_method_supported:1; 210360f0f39SAzael Avalos unsigned int sysfs_created:1; 211b116fd00SAzael Avalos unsigned int special_functions; 212ea215a3fSAzael Avalos 21365e3cf9cSAzael Avalos bool kbd_event_generated; 2146873f46aSAzael Avalos bool killswitch; 215135740deSSeth Forshee }; 216135740deSSeth Forshee 21729cd293fSSeth Forshee static struct toshiba_acpi_dev *toshiba_acpi; 21829cd293fSSeth Forshee 2197faa6a37SAzael Avalos static bool disable_hotkeys; 2207faa6a37SAzael Avalos module_param(disable_hotkeys, bool, 0444); 2217faa6a37SAzael Avalos MODULE_PARM_DESC(disable_hotkeys, "Disables the hotkeys activation"); 2227faa6a37SAzael Avalos 223b4f9fe12SLen Brown static const struct acpi_device_id toshiba_device_ids[] = { 224b4f9fe12SLen Brown {"TOS6200", 0}, 22563a9e016SOndrej Zary {"TOS6207", 0}, 226b4f9fe12SLen Brown {"TOS6208", 0}, 227b4f9fe12SLen Brown {"TOS1900", 0}, 228b4f9fe12SLen Brown {"", 0}, 229b4f9fe12SLen Brown }; 230b4f9fe12SLen Brown MODULE_DEVICE_TABLE(acpi, toshiba_device_ids); 231b4f9fe12SLen Brown 232b859f159SGreg Kroah-Hartman static const struct key_entry toshiba_acpi_keymap[] = { 233fec278a1SUnai Uribarri { KE_KEY, 0x9e, { KEY_RFKILL } }, 234384a7cd9SDmitry Torokhov { KE_KEY, 0x101, { KEY_MUTE } }, 235384a7cd9SDmitry Torokhov { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 236384a7cd9SDmitry Torokhov { KE_KEY, 0x103, { KEY_ZOOMIN } }, 237408a5d13SAzael Avalos { KE_KEY, 0x10f, { KEY_TAB } }, 238af502837SAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 239af502837SAzael Avalos { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 240384a7cd9SDmitry Torokhov { KE_KEY, 0x13b, { KEY_COFFEE } }, 241384a7cd9SDmitry Torokhov { KE_KEY, 0x13c, { KEY_BATTERY } }, 242384a7cd9SDmitry Torokhov { KE_KEY, 0x13d, { KEY_SLEEP } }, 243384a7cd9SDmitry Torokhov { KE_KEY, 0x13e, { KEY_SUSPEND } }, 244384a7cd9SDmitry Torokhov { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } }, 245384a7cd9SDmitry Torokhov { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } }, 246384a7cd9SDmitry Torokhov { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } }, 247384a7cd9SDmitry Torokhov { KE_KEY, 0x142, { KEY_WLAN } }, 248af502837SAzael Avalos { KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } }, 249a49010f5SJon Dowland { KE_KEY, 0x17f, { KEY_FN } }, 250384a7cd9SDmitry Torokhov { KE_KEY, 0xb05, { KEY_PROG2 } }, 251384a7cd9SDmitry Torokhov { KE_KEY, 0xb06, { KEY_WWW } }, 252384a7cd9SDmitry Torokhov { KE_KEY, 0xb07, { KEY_MAIL } }, 253384a7cd9SDmitry Torokhov { KE_KEY, 0xb30, { KEY_STOP } }, 254384a7cd9SDmitry Torokhov { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } }, 255384a7cd9SDmitry Torokhov { KE_KEY, 0xb32, { KEY_NEXTSONG } }, 256384a7cd9SDmitry Torokhov { KE_KEY, 0xb33, { KEY_PLAYPAUSE } }, 257384a7cd9SDmitry Torokhov { KE_KEY, 0xb5a, { KEY_MEDIA } }, 258408a5d13SAzael Avalos { KE_IGNORE, 0x1430, { KEY_RESERVED } }, /* Wake from sleep */ 259408a5d13SAzael Avalos { KE_IGNORE, 0x1501, { KEY_RESERVED } }, /* Output changed */ 260408a5d13SAzael Avalos { KE_IGNORE, 0x1502, { KEY_RESERVED } }, /* HDMI plugged/unplugged */ 261408a5d13SAzael Avalos { KE_IGNORE, 0x1ABE, { KEY_RESERVED } }, /* Protection level set */ 262408a5d13SAzael Avalos { KE_IGNORE, 0x1ABF, { KEY_RESERVED } }, /* Protection level off */ 263384a7cd9SDmitry Torokhov { KE_END, 0 }, 2646335e4d5SMatthew Garrett }; 2656335e4d5SMatthew Garrett 266fe808bfbSTakashi Iwai static const struct key_entry toshiba_acpi_alt_keymap[] = { 267fe808bfbSTakashi Iwai { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 268fe808bfbSTakashi Iwai { KE_KEY, 0x103, { KEY_ZOOMIN } }, 269e6efad7fSAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 270fe808bfbSTakashi Iwai { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 271fe808bfbSTakashi Iwai { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } }, 272fe808bfbSTakashi Iwai { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } }, 273d50c9005SAzael Avalos { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } }, 274fe808bfbSTakashi Iwai { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } }, 275d50c9005SAzael Avalos { KE_KEY, 0x157, { KEY_MUTE } }, 276d50c9005SAzael Avalos { KE_KEY, 0x158, { KEY_WLAN } }, 277fe808bfbSTakashi Iwai { KE_END, 0 }, 278fe808bfbSTakashi Iwai }; 279fe808bfbSTakashi Iwai 280e0769fe6SDarren Hart /* 281e0769fe6SDarren Hart * Utility 282b4f9fe12SLen Brown */ 283b4f9fe12SLen Brown 284b5163992SAzael Avalos static inline void _set_bit(u32 *word, u32 mask, int value) 285b4f9fe12SLen Brown { 286b4f9fe12SLen Brown *word = (*word & ~mask) | (mask * value); 287b4f9fe12SLen Brown } 288b4f9fe12SLen Brown 289e0769fe6SDarren Hart /* 290e0769fe6SDarren Hart * ACPI interface wrappers 291b4f9fe12SLen Brown */ 292b4f9fe12SLen Brown 293b4f9fe12SLen Brown static int write_acpi_int(const char *methodName, int val) 294b4f9fe12SLen Brown { 295b4f9fe12SLen Brown acpi_status status; 296b4f9fe12SLen Brown 297619400daSZhang Rui status = acpi_execute_simple_method(NULL, (char *)methodName, val); 29832bcd5cbSSeth Forshee return (status == AE_OK) ? 0 : -EIO; 299b4f9fe12SLen Brown } 300b4f9fe12SLen Brown 301e0769fe6SDarren Hart /* 302e0769fe6SDarren Hart * Perform a raw configuration call. Here we don't care about input or output 303258c5903SAzael Avalos * buffer format. 304b4f9fe12SLen Brown */ 305258c5903SAzael Avalos static acpi_status tci_raw(struct toshiba_acpi_dev *dev, 306258c5903SAzael Avalos const u32 in[TCI_WORDS], u32 out[TCI_WORDS]) 307b4f9fe12SLen Brown { 30878429e55SAzael Avalos union acpi_object in_objs[TCI_WORDS], out_objs[TCI_WORDS + 1]; 309b4f9fe12SLen Brown struct acpi_object_list params; 310b4f9fe12SLen Brown struct acpi_buffer results; 311b4f9fe12SLen Brown acpi_status status; 312b4f9fe12SLen Brown int i; 313b4f9fe12SLen Brown 314258c5903SAzael Avalos params.count = TCI_WORDS; 315b4f9fe12SLen Brown params.pointer = in_objs; 316258c5903SAzael Avalos for (i = 0; i < TCI_WORDS; ++i) { 317b4f9fe12SLen Brown in_objs[i].type = ACPI_TYPE_INTEGER; 318b4f9fe12SLen Brown in_objs[i].integer.value = in[i]; 319b4f9fe12SLen Brown } 320b4f9fe12SLen Brown 321b4f9fe12SLen Brown results.length = sizeof(out_objs); 322b4f9fe12SLen Brown results.pointer = out_objs; 323b4f9fe12SLen Brown 3246e02cc7eSSeth Forshee status = acpi_evaluate_object(dev->acpi_dev->handle, 3256e02cc7eSSeth Forshee (char *)dev->method_hci, ¶ms, 326b4f9fe12SLen Brown &results); 327258c5903SAzael Avalos if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) { 328b5163992SAzael Avalos for (i = 0; i < out_objs->package.count; ++i) 329b4f9fe12SLen Brown out[i] = out_objs->package.elements[i].integer.value; 330b4f9fe12SLen Brown } 331b4f9fe12SLen Brown 332b4f9fe12SLen Brown return status; 333b4f9fe12SLen Brown } 334b4f9fe12SLen Brown 335e0769fe6SDarren Hart /* 336d37782bdSAzael Avalos * Common hci tasks 337b4f9fe12SLen Brown * 338b4f9fe12SLen Brown * In addition to the ACPI status, the HCI system returns a result which 339b4f9fe12SLen Brown * may be useful (such as "not supported"). 340b4f9fe12SLen Brown */ 341b4f9fe12SLen Brown 342d37782bdSAzael Avalos static u32 hci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 343b4f9fe12SLen Brown { 344258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 }; 345258c5903SAzael Avalos u32 out[TCI_WORDS]; 346258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 347893f3f62SAzael Avalos 348893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 349b4f9fe12SLen Brown } 350b4f9fe12SLen Brown 351d37782bdSAzael Avalos static u32 hci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 352b4f9fe12SLen Brown { 353258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 }; 354258c5903SAzael Avalos u32 out[TCI_WORDS]; 355258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 356b5163992SAzael Avalos 357893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 358893f3f62SAzael Avalos return TOS_FAILURE; 359893f3f62SAzael Avalos 360b4f9fe12SLen Brown *out1 = out[2]; 361893f3f62SAzael Avalos 362893f3f62SAzael Avalos return out[0]; 363b4f9fe12SLen Brown } 364b4f9fe12SLen Brown 365e0769fe6SDarren Hart /* 366e0769fe6SDarren Hart * Common sci tasks 36784a6273fSAzael Avalos */ 36884a6273fSAzael Avalos 36984a6273fSAzael Avalos static int sci_open(struct toshiba_acpi_dev *dev) 37084a6273fSAzael Avalos { 371258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 }; 372258c5903SAzael Avalos u32 out[TCI_WORDS]; 37378429e55SAzael Avalos acpi_status status = tci_raw(dev, in, out); 37484a6273fSAzael Avalos 3758baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 37684a6273fSAzael Avalos pr_err("ACPI call to open SCI failed\n"); 37784a6273fSAzael Avalos return 0; 37884a6273fSAzael Avalos } 37984a6273fSAzael Avalos 3801864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) { 38184a6273fSAzael Avalos return 1; 3821864bbc2SAzael Avalos } else if (out[0] == TOS_ALREADY_OPEN) { 38384a6273fSAzael Avalos pr_info("Toshiba SCI already opened\n"); 38484a6273fSAzael Avalos return 1; 385fa465739SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 386e0769fe6SDarren Hart /* 387e0769fe6SDarren Hart * Some BIOSes do not have the SCI open/close functions 388fa465739SAzael Avalos * implemented and return 0x8000 (Not Supported), failing to 389fa465739SAzael Avalos * register some supported features. 390fa465739SAzael Avalos * 391fa465739SAzael Avalos * Simply return 1 if we hit those affected laptops to make the 392fa465739SAzael Avalos * supported features work. 393fa465739SAzael Avalos * 394fa465739SAzael Avalos * In the case that some laptops really do not support the SCI, 395fa465739SAzael Avalos * all the SCI dependent functions check for TOS_NOT_SUPPORTED, 396fa465739SAzael Avalos * and thus, not registering support for the queried feature. 397fa465739SAzael Avalos */ 398fa465739SAzael Avalos return 1; 3991864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_PRESENT) { 40084a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 40184a6273fSAzael Avalos } 40284a6273fSAzael Avalos 40384a6273fSAzael Avalos return 0; 40484a6273fSAzael Avalos } 40584a6273fSAzael Avalos 40684a6273fSAzael Avalos static void sci_close(struct toshiba_acpi_dev *dev) 40784a6273fSAzael Avalos { 408258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 }; 409258c5903SAzael Avalos u32 out[TCI_WORDS]; 41078429e55SAzael Avalos acpi_status status = tci_raw(dev, in, out); 41184a6273fSAzael Avalos 4128baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 41384a6273fSAzael Avalos pr_err("ACPI call to close SCI failed\n"); 41484a6273fSAzael Avalos return; 41584a6273fSAzael Avalos } 41684a6273fSAzael Avalos 4171864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) 41884a6273fSAzael Avalos return; 4191864bbc2SAzael Avalos else if (out[0] == TOS_NOT_OPENED) 42084a6273fSAzael Avalos pr_info("Toshiba SCI not opened\n"); 4211864bbc2SAzael Avalos else if (out[0] == TOS_NOT_PRESENT) 42284a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 42384a6273fSAzael Avalos } 42484a6273fSAzael Avalos 425893f3f62SAzael Avalos static u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 42684a6273fSAzael Avalos { 427258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 }; 428258c5903SAzael Avalos u32 out[TCI_WORDS]; 429258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 430b5163992SAzael Avalos 431893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 432893f3f62SAzael Avalos return TOS_FAILURE; 433893f3f62SAzael Avalos 43484a6273fSAzael Avalos *out1 = out[2]; 435893f3f62SAzael Avalos 436893f3f62SAzael Avalos return out[0]; 43784a6273fSAzael Avalos } 43884a6273fSAzael Avalos 439893f3f62SAzael Avalos static u32 sci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 44084a6273fSAzael Avalos { 441258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 }; 442258c5903SAzael Avalos u32 out[TCI_WORDS]; 443258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 444893f3f62SAzael Avalos 445893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 44684a6273fSAzael Avalos } 44784a6273fSAzael Avalos 4486c3f6e6cSPierre Ducroquet /* Illumination support */ 449ea215a3fSAzael Avalos static void toshiba_illumination_available(struct toshiba_acpi_dev *dev) 4506c3f6e6cSPierre Ducroquet { 451258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 }; 452258c5903SAzael Avalos u32 out[TCI_WORDS]; 4536c3f6e6cSPierre Ducroquet acpi_status status; 4546c3f6e6cSPierre Ducroquet 455ea215a3fSAzael Avalos dev->illumination_supported = 0; 456ea215a3fSAzael Avalos 457fdb79081SAzael Avalos if (!sci_open(dev)) 458ea215a3fSAzael Avalos return; 459fdb79081SAzael Avalos 460258c5903SAzael Avalos status = tci_raw(dev, in, out); 461fdb79081SAzael Avalos sci_close(dev); 462513ee146SAzael Avalos if (ACPI_FAILURE(status)) { 463fdb79081SAzael Avalos pr_err("ACPI call to query Illumination support failed\n"); 464513ee146SAzael Avalos return; 465513ee146SAzael Avalos } 466513ee146SAzael Avalos 467513ee146SAzael Avalos if (out[0] != TOS_SUCCESS) 468513ee146SAzael Avalos return; 469513ee146SAzael Avalos 470ea215a3fSAzael Avalos dev->illumination_supported = 1; 4716c3f6e6cSPierre Ducroquet } 4726c3f6e6cSPierre Ducroquet 4736c3f6e6cSPierre Ducroquet static void toshiba_illumination_set(struct led_classdev *cdev, 4746c3f6e6cSPierre Ducroquet enum led_brightness brightness) 4756c3f6e6cSPierre Ducroquet { 476135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 477135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 478e1a949c1SAzael Avalos u32 result; 479e1a949c1SAzael Avalos u32 state; 4806c3f6e6cSPierre Ducroquet 4816c3f6e6cSPierre Ducroquet /* First request : initialize communication. */ 482fdb79081SAzael Avalos if (!sci_open(dev)) 4836c3f6e6cSPierre Ducroquet return; 4846c3f6e6cSPierre Ducroquet 485fdb79081SAzael Avalos /* Switch the illumination on/off */ 486fdb79081SAzael Avalos state = brightness ? 1 : 0; 487893f3f62SAzael Avalos result = sci_write(dev, SCI_ILLUMINATION, state); 488fdb79081SAzael Avalos sci_close(dev); 489a6b5354fSAzael Avalos if (result == TOS_FAILURE) 490fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 4916c3f6e6cSPierre Ducroquet } 4926c3f6e6cSPierre Ducroquet 4936c3f6e6cSPierre Ducroquet static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) 4946c3f6e6cSPierre Ducroquet { 495135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 496135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 49778429e55SAzael Avalos u32 result; 49878429e55SAzael Avalos u32 state; 4996c3f6e6cSPierre Ducroquet 5003f75bbe9SAzael Avalos /* First request : initialize communication. */ 501fdb79081SAzael Avalos if (!sci_open(dev)) 5026c3f6e6cSPierre Ducroquet return LED_OFF; 5036c3f6e6cSPierre Ducroquet 5046c3f6e6cSPierre Ducroquet /* Check the illumination */ 505893f3f62SAzael Avalos result = sci_read(dev, SCI_ILLUMINATION, &state); 506fdb79081SAzael Avalos sci_close(dev); 507a6b5354fSAzael Avalos if (result == TOS_FAILURE) { 508fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 509fdb79081SAzael Avalos return LED_OFF; 510e1a949c1SAzael Avalos } else if (result != TOS_SUCCESS) { 5116c3f6e6cSPierre Ducroquet return LED_OFF; 5126c3f6e6cSPierre Ducroquet } 5136c3f6e6cSPierre Ducroquet 514fdb79081SAzael Avalos return state ? LED_FULL : LED_OFF; 5156c3f6e6cSPierre Ducroquet } 5166c3f6e6cSPierre Ducroquet 517360f0f39SAzael Avalos /* KBD Illumination */ 518ea215a3fSAzael Avalos static void toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev) 51993f8c16dSAzael Avalos { 520258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 }; 521258c5903SAzael Avalos u32 out[TCI_WORDS]; 52293f8c16dSAzael Avalos acpi_status status; 52393f8c16dSAzael Avalos 524ea215a3fSAzael Avalos dev->kbd_illum_supported = 0; 52565e3cf9cSAzael Avalos dev->kbd_event_generated = false; 526ea215a3fSAzael Avalos 52793f8c16dSAzael Avalos if (!sci_open(dev)) 528ea215a3fSAzael Avalos return; 52993f8c16dSAzael Avalos 530258c5903SAzael Avalos status = tci_raw(dev, in, out); 53193f8c16dSAzael Avalos sci_close(dev); 532a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) { 53393f8c16dSAzael Avalos pr_err("ACPI call to query kbd illumination support failed\n"); 534513ee146SAzael Avalos return; 535513ee146SAzael Avalos } 536513ee146SAzael Avalos 537513ee146SAzael Avalos if (out[0] != TOS_SUCCESS) 538513ee146SAzael Avalos return; 539513ee146SAzael Avalos 540e0769fe6SDarren Hart /* 541e0769fe6SDarren Hart * Check for keyboard backlight timeout max value, 54293f8c16dSAzael Avalos * previous kbd backlight implementation set this to 54393f8c16dSAzael Avalos * 0x3c0003, and now the new implementation set this 544e0769fe6SDarren Hart * to 0x3c001a, use this to distinguish between them. 54593f8c16dSAzael Avalos */ 54693f8c16dSAzael Avalos if (out[3] == SCI_KBD_TIME_MAX) 54793f8c16dSAzael Avalos dev->kbd_type = 2; 54893f8c16dSAzael Avalos else 54993f8c16dSAzael Avalos dev->kbd_type = 1; 55093f8c16dSAzael Avalos /* Get the current keyboard backlight mode */ 55193f8c16dSAzael Avalos dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK; 55293f8c16dSAzael Avalos /* Get the current time (1-60 seconds) */ 55393f8c16dSAzael Avalos dev->kbd_time = out[2] >> HCI_MISC_SHIFT; 554ea215a3fSAzael Avalos /* Flag as supported */ 555ea215a3fSAzael Avalos dev->kbd_illum_supported = 1; 556ea215a3fSAzael Avalos } 55793f8c16dSAzael Avalos 558360f0f39SAzael Avalos static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time) 559360f0f39SAzael Avalos { 560360f0f39SAzael Avalos u32 result; 561360f0f39SAzael Avalos 562360f0f39SAzael Avalos if (!sci_open(dev)) 563360f0f39SAzael Avalos return -EIO; 564360f0f39SAzael Avalos 565893f3f62SAzael Avalos result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time); 566360f0f39SAzael Avalos sci_close(dev); 567a6b5354fSAzael Avalos if (result == TOS_FAILURE) 568360f0f39SAzael Avalos pr_err("ACPI call to set KBD backlight status failed\n"); 569a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 570360f0f39SAzael Avalos return -ENODEV; 571360f0f39SAzael Avalos 572e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 573360f0f39SAzael Avalos } 574360f0f39SAzael Avalos 575360f0f39SAzael Avalos static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time) 576360f0f39SAzael Avalos { 577360f0f39SAzael Avalos u32 result; 578360f0f39SAzael Avalos 579360f0f39SAzael Avalos if (!sci_open(dev)) 580360f0f39SAzael Avalos return -EIO; 581360f0f39SAzael Avalos 582893f3f62SAzael Avalos result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time); 583360f0f39SAzael Avalos sci_close(dev); 584a6b5354fSAzael Avalos if (result == TOS_FAILURE) 585360f0f39SAzael Avalos pr_err("ACPI call to get KBD backlight status failed\n"); 586a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 587360f0f39SAzael Avalos return -ENODEV; 588360f0f39SAzael Avalos 589e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 590360f0f39SAzael Avalos } 591360f0f39SAzael Avalos 592360f0f39SAzael Avalos static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev) 593360f0f39SAzael Avalos { 594360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 595360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 596e1a949c1SAzael Avalos u32 result; 597e1a949c1SAzael Avalos u32 state; 598360f0f39SAzael Avalos 599360f0f39SAzael Avalos /* Check the keyboard backlight state */ 600d37782bdSAzael Avalos result = hci_read(dev, HCI_KBD_ILLUMINATION, &state); 601a6b5354fSAzael Avalos if (result == TOS_FAILURE) { 602360f0f39SAzael Avalos pr_err("ACPI call to get the keyboard backlight failed\n"); 603360f0f39SAzael Avalos return LED_OFF; 604e1a949c1SAzael Avalos } else if (result != TOS_SUCCESS) { 605360f0f39SAzael Avalos return LED_OFF; 606360f0f39SAzael Avalos } 607360f0f39SAzael Avalos 608360f0f39SAzael Avalos return state ? LED_FULL : LED_OFF; 609360f0f39SAzael Avalos } 610360f0f39SAzael Avalos 611360f0f39SAzael Avalos static void toshiba_kbd_backlight_set(struct led_classdev *cdev, 612360f0f39SAzael Avalos enum led_brightness brightness) 613360f0f39SAzael Avalos { 614360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 615360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 616e1a949c1SAzael Avalos u32 result; 617e1a949c1SAzael Avalos u32 state; 618360f0f39SAzael Avalos 619360f0f39SAzael Avalos /* Set the keyboard backlight state */ 620360f0f39SAzael Avalos state = brightness ? 1 : 0; 621d37782bdSAzael Avalos result = hci_write(dev, HCI_KBD_ILLUMINATION, state); 622a6b5354fSAzael Avalos if (result == TOS_FAILURE) 623360f0f39SAzael Avalos pr_err("ACPI call to set KBD Illumination mode failed\n"); 624360f0f39SAzael Avalos } 625360f0f39SAzael Avalos 6269d8658acSAzael Avalos /* TouchPad support */ 6279d8658acSAzael Avalos static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state) 6289d8658acSAzael Avalos { 6299d8658acSAzael Avalos u32 result; 6309d8658acSAzael Avalos 6319d8658acSAzael Avalos if (!sci_open(dev)) 6329d8658acSAzael Avalos return -EIO; 6339d8658acSAzael Avalos 634893f3f62SAzael Avalos result = sci_write(dev, SCI_TOUCHPAD, state); 6359d8658acSAzael Avalos sci_close(dev); 636a6b5354fSAzael Avalos if (result == TOS_FAILURE) 6379d8658acSAzael Avalos pr_err("ACPI call to set the touchpad failed\n"); 638a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 6399d8658acSAzael Avalos return -ENODEV; 6409d8658acSAzael Avalos 641e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 6429d8658acSAzael Avalos } 6439d8658acSAzael Avalos 6449d8658acSAzael Avalos static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) 6459d8658acSAzael Avalos { 6469d8658acSAzael Avalos u32 result; 6479d8658acSAzael Avalos 6489d8658acSAzael Avalos if (!sci_open(dev)) 6499d8658acSAzael Avalos return -EIO; 6509d8658acSAzael Avalos 651893f3f62SAzael Avalos result = sci_read(dev, SCI_TOUCHPAD, state); 6529d8658acSAzael Avalos sci_close(dev); 653a6b5354fSAzael Avalos if (result == TOS_FAILURE) 6549d8658acSAzael Avalos pr_err("ACPI call to query the touchpad failed\n"); 655a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 6569d8658acSAzael Avalos return -ENODEV; 6579d8658acSAzael Avalos 658e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 6599d8658acSAzael Avalos } 6609d8658acSAzael Avalos 661def6c4e2SAzael Avalos /* Eco Mode support */ 662ea215a3fSAzael Avalos static void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) 663def6c4e2SAzael Avalos { 66498fc4ec6SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 }; 665258c5903SAzael Avalos u32 out[TCI_WORDS]; 66678429e55SAzael Avalos acpi_status status; 667def6c4e2SAzael Avalos 668ea215a3fSAzael Avalos dev->eco_supported = 0; 669ea215a3fSAzael Avalos 670258c5903SAzael Avalos status = tci_raw(dev, in, out); 6718baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 67298fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 673513ee146SAzael Avalos return; 674513ee146SAzael Avalos } 675513ee146SAzael Avalos 6764058ea22SArvid Norlander if (out[0] == TOS_INPUT_DATA_ERROR || out[0] == TOS_NOT_SUPPORTED) { 677e0769fe6SDarren Hart /* 678e0769fe6SDarren Hart * If we receive 0x8300 (Input Data Error), it means that the 67998fc4ec6SAzael Avalos * LED device is present, but that we just screwed the input 68098fc4ec6SAzael Avalos * parameters. 68198fc4ec6SAzael Avalos * 6824058ea22SArvid Norlander * On some laptops 0x8000 (Not supported) is also returned in 6834058ea22SArvid Norlander * this case, so we need to allow for that as well. 6844058ea22SArvid Norlander * 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); 691513ee146SAzael Avalos if (ACPI_FAILURE(status)) { 69298fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 693513ee146SAzael Avalos return; 694513ee146SAzael Avalos } 695513ee146SAzael Avalos 696513ee146SAzael Avalos if (out[0] != TOS_SUCCESS) 697513ee146SAzael Avalos return; 698513ee146SAzael Avalos 699ea215a3fSAzael Avalos dev->eco_supported = 1; 700def6c4e2SAzael Avalos } 701def6c4e2SAzael Avalos } 702def6c4e2SAzael Avalos 703b5163992SAzael Avalos static enum led_brightness 704b5163992SAzael Avalos toshiba_eco_mode_get_status(struct led_classdev *cdev) 705def6c4e2SAzael Avalos { 706def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 707def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 708258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 }; 709258c5903SAzael Avalos u32 out[TCI_WORDS]; 710def6c4e2SAzael Avalos acpi_status status; 711def6c4e2SAzael Avalos 712258c5903SAzael Avalos status = tci_raw(dev, in, out); 713a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) { 714def6c4e2SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 715def6c4e2SAzael Avalos return LED_OFF; 716def6c4e2SAzael Avalos } 717def6c4e2SAzael Avalos 718513ee146SAzael Avalos if (out[0] != TOS_SUCCESS) 719513ee146SAzael Avalos return LED_OFF; 720513ee146SAzael Avalos 721def6c4e2SAzael Avalos return out[2] ? LED_FULL : LED_OFF; 722def6c4e2SAzael Avalos } 723def6c4e2SAzael Avalos 724def6c4e2SAzael Avalos static void toshiba_eco_mode_set_status(struct led_classdev *cdev, 725def6c4e2SAzael Avalos enum led_brightness brightness) 726def6c4e2SAzael Avalos { 727def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 728def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 729258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 }; 730258c5903SAzael Avalos u32 out[TCI_WORDS]; 731def6c4e2SAzael Avalos acpi_status status; 732def6c4e2SAzael Avalos 733def6c4e2SAzael Avalos /* Switch the Eco Mode led on/off */ 734def6c4e2SAzael Avalos in[2] = (brightness) ? 1 : 0; 735258c5903SAzael Avalos status = tci_raw(dev, in, out); 736a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) 737def6c4e2SAzael Avalos pr_err("ACPI call to set ECO led failed\n"); 738def6c4e2SAzael Avalos } 739def6c4e2SAzael Avalos 7405a2813e9SAzael Avalos /* Accelerometer support */ 741ea215a3fSAzael Avalos static void toshiba_accelerometer_available(struct toshiba_acpi_dev *dev) 7425a2813e9SAzael Avalos { 743258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 }; 744258c5903SAzael Avalos u32 out[TCI_WORDS]; 7455a2813e9SAzael Avalos acpi_status status; 7465a2813e9SAzael Avalos 747ea215a3fSAzael Avalos dev->accelerometer_supported = 0; 748ea215a3fSAzael Avalos 749e0769fe6SDarren Hart /* 750e0769fe6SDarren Hart * Check if the accelerometer call exists, 7515a2813e9SAzael Avalos * this call also serves as initialization 7525a2813e9SAzael Avalos */ 753258c5903SAzael Avalos status = tci_raw(dev, in, out); 754513ee146SAzael Avalos if (ACPI_FAILURE(status)) { 7555a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 756513ee146SAzael Avalos return; 757513ee146SAzael Avalos } 758513ee146SAzael Avalos 759513ee146SAzael Avalos if (out[0] != TOS_SUCCESS) 760513ee146SAzael Avalos return; 761513ee146SAzael Avalos 762ea215a3fSAzael Avalos dev->accelerometer_supported = 1; 7635a2813e9SAzael Avalos } 7645a2813e9SAzael Avalos 7655a2813e9SAzael Avalos static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, 7665a2813e9SAzael Avalos u32 *xy, u32 *z) 7675a2813e9SAzael Avalos { 768258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 }; 769258c5903SAzael Avalos u32 out[TCI_WORDS]; 7705a2813e9SAzael Avalos acpi_status status; 7715a2813e9SAzael Avalos 7725a2813e9SAzael Avalos /* Check the Accelerometer status */ 773258c5903SAzael Avalos status = tci_raw(dev, in, out); 774a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) { 7755a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 7765a2813e9SAzael Avalos return -EIO; 7775a2813e9SAzael Avalos } 7785a2813e9SAzael Avalos 779513ee146SAzael Avalos if (out[0] == TOS_NOT_SUPPORTED) 780513ee146SAzael Avalos return -ENODEV; 781513ee146SAzael Avalos 782513ee146SAzael Avalos if (out[0] != TOS_SUCCESS) 783e1a949c1SAzael Avalos return -EIO; 784513ee146SAzael Avalos 785513ee146SAzael Avalos *xy = out[2]; 786513ee146SAzael Avalos *z = out[4]; 787513ee146SAzael Avalos 788513ee146SAzael Avalos return 0; 789e1a949c1SAzael Avalos } 790e1a949c1SAzael Avalos 791e26ffe51SAzael Avalos /* Sleep (Charge and Music) utilities support */ 792c8c91842SAzael Avalos static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev) 793c8c91842SAzael Avalos { 794c8c91842SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 795c8c91842SAzael Avalos u32 out[TCI_WORDS]; 796c8c91842SAzael Avalos acpi_status status; 797c8c91842SAzael Avalos 798c8c91842SAzael Avalos dev->usb_sleep_charge_supported = 0; 799c8c91842SAzael Avalos 800c8c91842SAzael Avalos if (!sci_open(dev)) 801c8c91842SAzael Avalos return; 802c8c91842SAzael Avalos 803c8c91842SAzael Avalos status = tci_raw(dev, in, out); 8048baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 805c8c91842SAzael Avalos pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); 806c8c91842SAzael Avalos sci_close(dev); 807c8c91842SAzael Avalos return; 808513ee146SAzael Avalos } 809513ee146SAzael Avalos 810513ee146SAzael Avalos if (out[0] != TOS_SUCCESS) { 811c8c91842SAzael Avalos sci_close(dev); 812c8c91842SAzael Avalos return; 813c8c91842SAzael Avalos } 814c8c91842SAzael Avalos 815513ee146SAzael Avalos dev->usbsc_mode_base = out[4]; 816513ee146SAzael Avalos 817c8c91842SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 818c8c91842SAzael Avalos status = tci_raw(dev, in, out); 819ea215a3fSAzael Avalos sci_close(dev); 8208baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 821c8c91842SAzael Avalos pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); 822513ee146SAzael Avalos return; 823513ee146SAzael Avalos } 824513ee146SAzael Avalos 825513ee146SAzael Avalos if (out[0] != TOS_SUCCESS) 826513ee146SAzael Avalos return; 827513ee146SAzael Avalos 828c8c91842SAzael Avalos dev->usbsc_bat_level = out[2]; 829ea215a3fSAzael Avalos /* Flag as supported */ 830c8c91842SAzael Avalos dev->usb_sleep_charge_supported = 1; 831c8c91842SAzael Avalos } 832c8c91842SAzael Avalos 833e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, 834e26ffe51SAzael Avalos u32 *mode) 835e26ffe51SAzael Avalos { 836e26ffe51SAzael Avalos u32 result; 837e26ffe51SAzael Avalos 838e26ffe51SAzael Avalos if (!sci_open(dev)) 839e26ffe51SAzael Avalos return -EIO; 840e26ffe51SAzael Avalos 841e26ffe51SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode); 842e26ffe51SAzael Avalos sci_close(dev); 843a6b5354fSAzael Avalos if (result == TOS_FAILURE) 844e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 845a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 846e26ffe51SAzael Avalos return -ENODEV; 847e26ffe51SAzael Avalos 848e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 849e26ffe51SAzael Avalos } 850e26ffe51SAzael Avalos 851e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev, 852e26ffe51SAzael Avalos u32 mode) 853e26ffe51SAzael Avalos { 854e26ffe51SAzael Avalos u32 result; 855e26ffe51SAzael Avalos 856e26ffe51SAzael Avalos if (!sci_open(dev)) 857e26ffe51SAzael Avalos return -EIO; 858e26ffe51SAzael Avalos 859e26ffe51SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode); 860e26ffe51SAzael Avalos sci_close(dev); 861a6b5354fSAzael Avalos if (result == TOS_FAILURE) 862e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 863a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 864e26ffe51SAzael Avalos return -ENODEV; 865e26ffe51SAzael Avalos 866e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 867e26ffe51SAzael Avalos } 868e26ffe51SAzael Avalos 869182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev, 870182bcaa5SAzael Avalos u32 *mode) 871182bcaa5SAzael Avalos { 872182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 873182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 874182bcaa5SAzael Avalos acpi_status status; 875182bcaa5SAzael Avalos 876182bcaa5SAzael Avalos if (!sci_open(dev)) 877182bcaa5SAzael Avalos return -EIO; 878182bcaa5SAzael Avalos 879182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 880182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 881182bcaa5SAzael Avalos sci_close(dev); 8828baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 883182bcaa5SAzael Avalos pr_err("ACPI call to get USB S&C battery level failed\n"); 884513ee146SAzael Avalos return -EIO; 885182bcaa5SAzael Avalos } 886182bcaa5SAzael Avalos 887513ee146SAzael Avalos if (out[0] == TOS_NOT_SUPPORTED) 888513ee146SAzael Avalos return -ENODEV; 889513ee146SAzael Avalos 890513ee146SAzael Avalos if (out[0] != TOS_SUCCESS) 891e1a949c1SAzael Avalos return -EIO; 892513ee146SAzael Avalos 893513ee146SAzael Avalos *mode = out[2]; 894513ee146SAzael Avalos 895513ee146SAzael Avalos return 0; 896513ee146SAzael Avalos 897182bcaa5SAzael Avalos } 898182bcaa5SAzael Avalos 899182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, 900182bcaa5SAzael Avalos u32 mode) 901182bcaa5SAzael Avalos { 902182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 903182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 904182bcaa5SAzael Avalos acpi_status status; 905182bcaa5SAzael Avalos 906182bcaa5SAzael Avalos if (!sci_open(dev)) 907182bcaa5SAzael Avalos return -EIO; 908182bcaa5SAzael Avalos 909182bcaa5SAzael Avalos in[2] = mode; 910182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 911182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 912182bcaa5SAzael Avalos sci_close(dev); 913513ee146SAzael Avalos if (ACPI_FAILURE(status)) { 914182bcaa5SAzael Avalos pr_err("ACPI call to set USB S&C battery level failed\n"); 915513ee146SAzael Avalos return -EIO; 916513ee146SAzael Avalos } 917513ee146SAzael Avalos 918513ee146SAzael Avalos if (out[0] == TOS_NOT_SUPPORTED) 919182bcaa5SAzael Avalos return -ENODEV; 920182bcaa5SAzael Avalos 921e1a949c1SAzael Avalos return out[0] == TOS_SUCCESS ? 0 : -EIO; 922182bcaa5SAzael Avalos } 923182bcaa5SAzael Avalos 924bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, 925bb3fe01fSAzael Avalos u32 *state) 926bb3fe01fSAzael Avalos { 927bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 928bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 929bb3fe01fSAzael Avalos acpi_status status; 930bb3fe01fSAzael Avalos 931bb3fe01fSAzael Avalos if (!sci_open(dev)) 932bb3fe01fSAzael Avalos return -EIO; 933bb3fe01fSAzael Avalos 934bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 935bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 936bb3fe01fSAzael Avalos sci_close(dev); 9378baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 938bb26f189SAzael Avalos pr_err("ACPI call to get USB Rapid Charge failed\n"); 939513ee146SAzael Avalos return -EIO; 940bb3fe01fSAzael Avalos } 941bb3fe01fSAzael Avalos 942513ee146SAzael Avalos if (out[0] == TOS_NOT_SUPPORTED) 943513ee146SAzael Avalos return -ENODEV; 944513ee146SAzael Avalos 945513ee146SAzael Avalos if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2) 946e1a949c1SAzael Avalos return -EIO; 947513ee146SAzael Avalos 948513ee146SAzael Avalos *state = out[2]; 949513ee146SAzael Avalos 950513ee146SAzael Avalos return 0; 951bb3fe01fSAzael Avalos } 952bb3fe01fSAzael Avalos 953bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, 954bb3fe01fSAzael Avalos u32 state) 955bb3fe01fSAzael Avalos { 956bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 957bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 958bb3fe01fSAzael Avalos acpi_status status; 959bb3fe01fSAzael Avalos 960bb3fe01fSAzael Avalos if (!sci_open(dev)) 961bb3fe01fSAzael Avalos return -EIO; 962bb3fe01fSAzael Avalos 963bb3fe01fSAzael Avalos in[2] = state; 964bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 965bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 966bb3fe01fSAzael Avalos sci_close(dev); 967513ee146SAzael Avalos if (ACPI_FAILURE(status)) { 968bb26f189SAzael Avalos pr_err("ACPI call to set USB Rapid Charge failed\n"); 969513ee146SAzael Avalos return -EIO; 970513ee146SAzael Avalos } 971513ee146SAzael Avalos 972513ee146SAzael Avalos if (out[0] == TOS_NOT_SUPPORTED) 973bb3fe01fSAzael Avalos return -ENODEV; 974bb3fe01fSAzael Avalos 975e1a949c1SAzael Avalos return (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) ? 0 : -EIO; 976bb3fe01fSAzael Avalos } 977bb3fe01fSAzael Avalos 978172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state) 979172ce0a9SAzael Avalos { 980172ce0a9SAzael Avalos u32 result; 981172ce0a9SAzael Avalos 982172ce0a9SAzael Avalos if (!sci_open(dev)) 983172ce0a9SAzael Avalos return -EIO; 984172ce0a9SAzael Avalos 985172ce0a9SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state); 986172ce0a9SAzael Avalos sci_close(dev); 987a6b5354fSAzael Avalos if (result == TOS_FAILURE) 988bb26f189SAzael Avalos pr_err("ACPI call to get Sleep and Music failed\n"); 989a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 990172ce0a9SAzael Avalos return -ENODEV; 991172ce0a9SAzael Avalos 992cf680eaeSAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 993172ce0a9SAzael Avalos } 994172ce0a9SAzael Avalos 995172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state) 996172ce0a9SAzael Avalos { 997172ce0a9SAzael Avalos u32 result; 998172ce0a9SAzael Avalos 999172ce0a9SAzael Avalos if (!sci_open(dev)) 1000172ce0a9SAzael Avalos return -EIO; 1001172ce0a9SAzael Avalos 1002172ce0a9SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state); 1003172ce0a9SAzael Avalos sci_close(dev); 1004a6b5354fSAzael Avalos if (result == TOS_FAILURE) 1005bb26f189SAzael Avalos pr_err("ACPI call to set Sleep and Music failed\n"); 1006a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1007172ce0a9SAzael Avalos return -ENODEV; 1008172ce0a9SAzael Avalos 1009e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1010172ce0a9SAzael Avalos } 1011172ce0a9SAzael Avalos 1012bae84195SAzael Avalos /* Keyboard function keys */ 1013bae84195SAzael Avalos static int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode) 1014bae84195SAzael Avalos { 1015bae84195SAzael Avalos u32 result; 1016bae84195SAzael Avalos 1017bae84195SAzael Avalos if (!sci_open(dev)) 1018bae84195SAzael Avalos return -EIO; 1019bae84195SAzael Avalos 1020bae84195SAzael Avalos result = sci_read(dev, SCI_KBD_FUNCTION_KEYS, mode); 1021bae84195SAzael Avalos sci_close(dev); 1022a6b5354fSAzael Avalos if (result == TOS_FAILURE) 1023bae84195SAzael Avalos pr_err("ACPI call to get KBD function keys failed\n"); 1024a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1025bae84195SAzael Avalos return -ENODEV; 1026bae84195SAzael Avalos 1027e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 1028bae84195SAzael Avalos } 1029bae84195SAzael Avalos 1030bae84195SAzael Avalos static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode) 1031bae84195SAzael Avalos { 1032bae84195SAzael Avalos u32 result; 1033bae84195SAzael Avalos 1034bae84195SAzael Avalos if (!sci_open(dev)) 1035bae84195SAzael Avalos return -EIO; 1036bae84195SAzael Avalos 1037bae84195SAzael Avalos result = sci_write(dev, SCI_KBD_FUNCTION_KEYS, mode); 1038bae84195SAzael Avalos sci_close(dev); 1039a6b5354fSAzael Avalos if (result == TOS_FAILURE) 1040bae84195SAzael Avalos pr_err("ACPI call to set KBD function keys failed\n"); 1041a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1042bae84195SAzael Avalos return -ENODEV; 1043bae84195SAzael Avalos 1044e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 1045bae84195SAzael Avalos } 1046bae84195SAzael Avalos 104735d53ceaSAzael Avalos /* Panel Power ON */ 104835d53ceaSAzael Avalos static int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state) 104935d53ceaSAzael Avalos { 105035d53ceaSAzael Avalos u32 result; 105135d53ceaSAzael Avalos 105235d53ceaSAzael Avalos if (!sci_open(dev)) 105335d53ceaSAzael Avalos return -EIO; 105435d53ceaSAzael Avalos 105535d53ceaSAzael Avalos result = sci_read(dev, SCI_PANEL_POWER_ON, state); 105635d53ceaSAzael Avalos sci_close(dev); 1057a6b5354fSAzael Avalos if (result == TOS_FAILURE) 105835d53ceaSAzael Avalos pr_err("ACPI call to get Panel Power ON failed\n"); 1059a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 106035d53ceaSAzael Avalos return -ENODEV; 106135d53ceaSAzael Avalos 1062e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 106335d53ceaSAzael Avalos } 106435d53ceaSAzael Avalos 106535d53ceaSAzael Avalos static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state) 106635d53ceaSAzael Avalos { 106735d53ceaSAzael Avalos u32 result; 106835d53ceaSAzael Avalos 106935d53ceaSAzael Avalos if (!sci_open(dev)) 107035d53ceaSAzael Avalos return -EIO; 107135d53ceaSAzael Avalos 107235d53ceaSAzael Avalos result = sci_write(dev, SCI_PANEL_POWER_ON, state); 107335d53ceaSAzael Avalos sci_close(dev); 1074a6b5354fSAzael Avalos if (result == TOS_FAILURE) 107535d53ceaSAzael Avalos pr_err("ACPI call to set Panel Power ON failed\n"); 1076a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 107735d53ceaSAzael Avalos return -ENODEV; 107835d53ceaSAzael Avalos 1079e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 108035d53ceaSAzael Avalos } 108135d53ceaSAzael Avalos 108217fe4b3dSAzael Avalos /* USB Three */ 108317fe4b3dSAzael Avalos static int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state) 108417fe4b3dSAzael Avalos { 108517fe4b3dSAzael Avalos u32 result; 108617fe4b3dSAzael Avalos 108717fe4b3dSAzael Avalos if (!sci_open(dev)) 108817fe4b3dSAzael Avalos return -EIO; 108917fe4b3dSAzael Avalos 109017fe4b3dSAzael Avalos result = sci_read(dev, SCI_USB_THREE, state); 109117fe4b3dSAzael Avalos sci_close(dev); 1092a6b5354fSAzael Avalos if (result == TOS_FAILURE) 109317fe4b3dSAzael Avalos pr_err("ACPI call to get USB 3 failed\n"); 1094a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 109517fe4b3dSAzael Avalos return -ENODEV; 109617fe4b3dSAzael Avalos 1097e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 109817fe4b3dSAzael Avalos } 109917fe4b3dSAzael Avalos 110017fe4b3dSAzael Avalos static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state) 110117fe4b3dSAzael Avalos { 110217fe4b3dSAzael Avalos u32 result; 110317fe4b3dSAzael Avalos 110417fe4b3dSAzael Avalos if (!sci_open(dev)) 110517fe4b3dSAzael Avalos return -EIO; 110617fe4b3dSAzael Avalos 110717fe4b3dSAzael Avalos result = sci_write(dev, SCI_USB_THREE, state); 110817fe4b3dSAzael Avalos sci_close(dev); 1109a6b5354fSAzael Avalos if (result == TOS_FAILURE) 111017fe4b3dSAzael Avalos pr_err("ACPI call to set USB 3 failed\n"); 1111a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 111217fe4b3dSAzael Avalos return -ENODEV; 111317fe4b3dSAzael Avalos 1114e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 111517fe4b3dSAzael Avalos } 111617fe4b3dSAzael Avalos 111756e6b353SAzael Avalos /* Hotkey Event type */ 111856e6b353SAzael Avalos static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev, 111956e6b353SAzael Avalos u32 *type) 112056e6b353SAzael Avalos { 11213b876000SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_SYSTEM_INFO, 0x03, 0, 0, 0 }; 11223b876000SAzael Avalos u32 out[TCI_WORDS]; 11233b876000SAzael Avalos acpi_status status; 112456e6b353SAzael Avalos 11253b876000SAzael Avalos status = tci_raw(dev, in, out); 11263b876000SAzael Avalos if (ACPI_FAILURE(status)) { 112756e6b353SAzael Avalos pr_err("ACPI call to get System type failed\n"); 1128513ee146SAzael Avalos return -EIO; 112956e6b353SAzael Avalos } 113056e6b353SAzael Avalos 1131513ee146SAzael Avalos if (out[0] == TOS_NOT_SUPPORTED) 1132513ee146SAzael Avalos return -ENODEV; 1133513ee146SAzael Avalos 1134513ee146SAzael Avalos if (out[0] != TOS_SUCCESS) 1135e1a949c1SAzael Avalos return -EIO; 1136513ee146SAzael Avalos 1137513ee146SAzael Avalos *type = out[3]; 1138513ee146SAzael Avalos 1139513ee146SAzael Avalos return 0; 114056e6b353SAzael Avalos } 114156e6b353SAzael Avalos 11426873f46aSAzael Avalos /* Wireless status (RFKill, WLAN, BT, WWAN) */ 11436873f46aSAzael Avalos static int toshiba_wireless_status(struct toshiba_acpi_dev *dev) 11446873f46aSAzael Avalos { 11456873f46aSAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_WIRELESS, 0, 0, 0, 0 }; 11466873f46aSAzael Avalos u32 out[TCI_WORDS]; 11476873f46aSAzael Avalos acpi_status status; 11486873f46aSAzael Avalos 11496873f46aSAzael Avalos in[3] = HCI_WIRELESS_STATUS; 11506873f46aSAzael Avalos status = tci_raw(dev, in, out); 11516873f46aSAzael Avalos 11526873f46aSAzael Avalos if (ACPI_FAILURE(status)) { 11536873f46aSAzael Avalos pr_err("ACPI call to get Wireless status failed\n"); 11546873f46aSAzael Avalos return -EIO; 11556873f46aSAzael Avalos } 11566873f46aSAzael Avalos 11576873f46aSAzael Avalos if (out[0] == TOS_NOT_SUPPORTED) 11586873f46aSAzael Avalos return -ENODEV; 11596873f46aSAzael Avalos 11606873f46aSAzael Avalos if (out[0] != TOS_SUCCESS) 11616873f46aSAzael Avalos return -EIO; 11626873f46aSAzael Avalos 11636873f46aSAzael Avalos dev->killswitch = !!(out[2] & HCI_WIRELESS_STATUS); 11646873f46aSAzael Avalos 11656873f46aSAzael Avalos return 0; 11666873f46aSAzael Avalos } 11676873f46aSAzael Avalos 11686873f46aSAzael Avalos /* WWAN */ 11696873f46aSAzael Avalos static void toshiba_wwan_available(struct toshiba_acpi_dev *dev) 11706873f46aSAzael Avalos { 11716873f46aSAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_WIRELESS, 0, 0, 0, 0 }; 11726873f46aSAzael Avalos u32 out[TCI_WORDS]; 11736873f46aSAzael Avalos acpi_status status; 11746873f46aSAzael Avalos 11756873f46aSAzael Avalos dev->wwan_supported = 0; 11766873f46aSAzael Avalos 11776873f46aSAzael Avalos /* 11786873f46aSAzael Avalos * WWAN support can be queried by setting the in[3] value to 11796873f46aSAzael Avalos * HCI_WIRELESS_WWAN (0x03). 11806873f46aSAzael Avalos * 11816873f46aSAzael Avalos * If supported, out[0] contains TOS_SUCCESS and out[2] contains 11826873f46aSAzael Avalos * HCI_WIRELESS_WWAN_STATUS (0x2000). 11836873f46aSAzael Avalos * 11846873f46aSAzael Avalos * If not supported, out[0] contains TOS_INPUT_DATA_ERROR (0x8300) 11856873f46aSAzael Avalos * or TOS_NOT_SUPPORTED (0x8000). 11866873f46aSAzael Avalos */ 11876873f46aSAzael Avalos in[3] = HCI_WIRELESS_WWAN; 11886873f46aSAzael Avalos status = tci_raw(dev, in, out); 11896873f46aSAzael Avalos if (ACPI_FAILURE(status)) { 11906873f46aSAzael Avalos pr_err("ACPI call to get WWAN status failed\n"); 11916873f46aSAzael Avalos return; 11926873f46aSAzael Avalos } 11936873f46aSAzael Avalos 11946873f46aSAzael Avalos if (out[0] != TOS_SUCCESS) 11956873f46aSAzael Avalos return; 11966873f46aSAzael Avalos 11976873f46aSAzael Avalos dev->wwan_supported = (out[2] == HCI_WIRELESS_WWAN_STATUS); 11986873f46aSAzael Avalos } 11996873f46aSAzael Avalos 12006873f46aSAzael Avalos static int toshiba_wwan_set(struct toshiba_acpi_dev *dev, u32 state) 12016873f46aSAzael Avalos { 12026873f46aSAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, HCI_WIRELESS, state, 0, 0, 0 }; 12036873f46aSAzael Avalos u32 out[TCI_WORDS]; 12046873f46aSAzael Avalos acpi_status status; 12056873f46aSAzael Avalos 12066873f46aSAzael Avalos in[3] = HCI_WIRELESS_WWAN_STATUS; 12076873f46aSAzael Avalos status = tci_raw(dev, in, out); 12086873f46aSAzael Avalos if (ACPI_FAILURE(status)) { 12096873f46aSAzael Avalos pr_err("ACPI call to set WWAN status failed\n"); 12106873f46aSAzael Avalos return -EIO; 12116873f46aSAzael Avalos } 12126873f46aSAzael Avalos 12136873f46aSAzael Avalos if (out[0] == TOS_NOT_SUPPORTED) 12146873f46aSAzael Avalos return -ENODEV; 12156873f46aSAzael Avalos 12166873f46aSAzael Avalos if (out[0] != TOS_SUCCESS) 12176873f46aSAzael Avalos return -EIO; 12186873f46aSAzael Avalos 12196873f46aSAzael Avalos /* 12206873f46aSAzael Avalos * Some devices only need to call HCI_WIRELESS_WWAN_STATUS to 12216873f46aSAzael Avalos * (de)activate the device, but some others need the 12226873f46aSAzael Avalos * HCI_WIRELESS_WWAN_POWER call as well. 12236873f46aSAzael Avalos */ 12246873f46aSAzael Avalos in[3] = HCI_WIRELESS_WWAN_POWER; 12256873f46aSAzael Avalos status = tci_raw(dev, in, out); 12266873f46aSAzael Avalos if (ACPI_FAILURE(status)) { 12276873f46aSAzael Avalos pr_err("ACPI call to set WWAN power failed\n"); 12286873f46aSAzael Avalos return -EIO; 12296873f46aSAzael Avalos } 12306873f46aSAzael Avalos 12316873f46aSAzael Avalos if (out[0] == TOS_NOT_SUPPORTED) 12326873f46aSAzael Avalos return -ENODEV; 12336873f46aSAzael Avalos 12346873f46aSAzael Avalos return out[0] == TOS_SUCCESS ? 0 : -EIO; 12356873f46aSAzael Avalos } 12366873f46aSAzael Avalos 1237763ff32fSAzael Avalos /* Cooling Method */ 1238763ff32fSAzael Avalos static void toshiba_cooling_method_available(struct toshiba_acpi_dev *dev) 1239763ff32fSAzael Avalos { 1240763ff32fSAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_COOLING_METHOD, 0, 0, 0, 0 }; 1241763ff32fSAzael Avalos u32 out[TCI_WORDS]; 1242763ff32fSAzael Avalos acpi_status status; 1243763ff32fSAzael Avalos 1244763ff32fSAzael Avalos dev->cooling_method_supported = 0; 1245763ff32fSAzael Avalos dev->max_cooling_method = 0; 1246763ff32fSAzael Avalos 1247763ff32fSAzael Avalos status = tci_raw(dev, in, out); 1248513ee146SAzael Avalos if (ACPI_FAILURE(status)) { 1249763ff32fSAzael Avalos pr_err("ACPI call to get Cooling Method failed\n"); 1250513ee146SAzael Avalos return; 1251513ee146SAzael Avalos } 1252763ff32fSAzael Avalos 1253763ff32fSAzael Avalos if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2) 1254763ff32fSAzael Avalos return; 1255763ff32fSAzael Avalos 1256763ff32fSAzael Avalos dev->cooling_method_supported = 1; 1257763ff32fSAzael Avalos dev->max_cooling_method = out[3]; 1258763ff32fSAzael Avalos } 1259763ff32fSAzael Avalos 1260763ff32fSAzael Avalos static int toshiba_cooling_method_get(struct toshiba_acpi_dev *dev, u32 *state) 1261763ff32fSAzael Avalos { 1262763ff32fSAzael Avalos u32 result = hci_read(dev, HCI_COOLING_METHOD, state); 1263763ff32fSAzael Avalos 1264763ff32fSAzael Avalos if (result == TOS_FAILURE) 1265763ff32fSAzael Avalos pr_err("ACPI call to get Cooling Method failed\n"); 1266763ff32fSAzael Avalos 1267763ff32fSAzael Avalos if (result == TOS_NOT_SUPPORTED) 1268763ff32fSAzael Avalos return -ENODEV; 1269763ff32fSAzael Avalos 1270763ff32fSAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 1271763ff32fSAzael Avalos } 1272763ff32fSAzael Avalos 1273763ff32fSAzael Avalos static int toshiba_cooling_method_set(struct toshiba_acpi_dev *dev, u32 state) 1274763ff32fSAzael Avalos { 1275763ff32fSAzael Avalos u32 result = hci_write(dev, HCI_COOLING_METHOD, state); 1276763ff32fSAzael Avalos 1277763ff32fSAzael Avalos if (result == TOS_FAILURE) 1278fa1bc2a0SAzael Avalos pr_err("ACPI call to set Cooling Method failed\n"); 1279763ff32fSAzael Avalos 1280763ff32fSAzael Avalos if (result == TOS_NOT_SUPPORTED) 1281763ff32fSAzael Avalos return -ENODEV; 1282763ff32fSAzael Avalos 1283763ff32fSAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 1284763ff32fSAzael Avalos } 1285763ff32fSAzael Avalos 12863f75bbe9SAzael Avalos /* Transflective Backlight */ 1287695f6060SAzael Avalos static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status) 1288121b7b0dSAkio Idehara { 1289e1a949c1SAzael Avalos u32 result = hci_read(dev, HCI_TR_BACKLIGHT, status); 1290121b7b0dSAkio Idehara 1291e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1292e1a949c1SAzael Avalos pr_err("ACPI call to get Transflective Backlight failed\n"); 1293e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1294e1a949c1SAzael Avalos return -ENODEV; 1295e1a949c1SAzael Avalos 1296e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1297121b7b0dSAkio Idehara } 1298121b7b0dSAkio Idehara 1299695f6060SAzael Avalos static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 status) 1300121b7b0dSAkio Idehara { 1301e1a949c1SAzael Avalos u32 result = hci_write(dev, HCI_TR_BACKLIGHT, !status); 1302121b7b0dSAkio Idehara 1303e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1304e1a949c1SAzael Avalos pr_err("ACPI call to set Transflective Backlight failed\n"); 1305e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1306e1a949c1SAzael Avalos return -ENODEV; 1307e1a949c1SAzael Avalos 1308e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1309121b7b0dSAkio Idehara } 1310121b7b0dSAkio Idehara 13113f75bbe9SAzael Avalos static struct proc_dir_entry *toshiba_proc_dir; 1312b4f9fe12SLen Brown 13133f75bbe9SAzael Avalos /* LCD Brightness */ 131462cce752SSeth Forshee static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) 1315b4f9fe12SLen Brown { 131678429e55SAzael Avalos int brightness = 0; 1317e1a949c1SAzael Avalos u32 result; 1318b4f9fe12SLen Brown u32 value; 1319121b7b0dSAkio Idehara 1320121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1321695f6060SAzael Avalos int ret = get_tr_backlight_status(dev, &value); 1322b5163992SAzael Avalos 1323121b7b0dSAkio Idehara if (ret) 1324121b7b0dSAkio Idehara return ret; 1325695f6060SAzael Avalos if (value) 1326121b7b0dSAkio Idehara return 0; 1327121b7b0dSAkio Idehara brightness++; 1328121b7b0dSAkio Idehara } 1329b4f9fe12SLen Brown 1330e1a949c1SAzael Avalos result = hci_read(dev, HCI_LCD_BRIGHTNESS, &value); 1331e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1332e1a949c1SAzael Avalos pr_err("ACPI call to get LCD Brightness failed\n"); 1333e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1334e1a949c1SAzael Avalos return -ENODEV; 133532bcd5cbSSeth Forshee 1336513ee146SAzael Avalos return result == TOS_SUCCESS ? 1337513ee146SAzael Avalos brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT) : 1338513ee146SAzael Avalos -EIO; 1339b4f9fe12SLen Brown } 1340b4f9fe12SLen Brown 134162cce752SSeth Forshee static int get_lcd_brightness(struct backlight_device *bd) 134262cce752SSeth Forshee { 134362cce752SSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 1344b5163992SAzael Avalos 134562cce752SSeth Forshee return __get_lcd_brightness(dev); 134662cce752SSeth Forshee } 134762cce752SSeth Forshee 1348936c8bcdSAlexey Dobriyan static int lcd_proc_show(struct seq_file *m, void *v) 1349b4f9fe12SLen Brown { 1350135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1351121b7b0dSAkio Idehara int levels; 1352e1a949c1SAzael Avalos int value; 1353b4f9fe12SLen Brown 1354135740deSSeth Forshee if (!dev->backlight_dev) 1355135740deSSeth Forshee return -ENODEV; 1356135740deSSeth Forshee 1357121b7b0dSAkio Idehara levels = dev->backlight_dev->props.max_brightness + 1; 135862cce752SSeth Forshee value = get_lcd_brightness(dev->backlight_dev); 1359513ee146SAzael Avalos if (value < 0) { 1360513ee146SAzael Avalos pr_err("Error reading LCD brightness\n"); 1361513ee146SAzael Avalos return value; 1362b4f9fe12SLen Brown } 1363b4f9fe12SLen Brown 1364513ee146SAzael Avalos seq_printf(m, "brightness: %d\n", value); 1365513ee146SAzael Avalos seq_printf(m, "brightness_levels: %d\n", levels); 1366e1a949c1SAzael Avalos 1367513ee146SAzael Avalos return 0; 1368936c8bcdSAlexey Dobriyan } 1369936c8bcdSAlexey Dobriyan 1370936c8bcdSAlexey Dobriyan static int lcd_proc_open(struct inode *inode, struct file *file) 1371936c8bcdSAlexey Dobriyan { 1372359745d7SMuchun Song return single_open(file, lcd_proc_show, pde_data(inode)); 1373b4f9fe12SLen Brown } 1374b4f9fe12SLen Brown 137562cce752SSeth Forshee static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) 1376b4f9fe12SLen Brown { 1377e1a949c1SAzael Avalos u32 result; 1378b4f9fe12SLen Brown 1379121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1380695f6060SAzael Avalos int ret = set_tr_backlight_status(dev, !value); 1381b5163992SAzael Avalos 1382121b7b0dSAkio Idehara if (ret) 1383121b7b0dSAkio Idehara return ret; 1384121b7b0dSAkio Idehara if (value) 1385121b7b0dSAkio Idehara value--; 1386121b7b0dSAkio Idehara } 1387121b7b0dSAkio Idehara 1388a39f46dfSAzael Avalos value = value << HCI_LCD_BRIGHTNESS_SHIFT; 1389e1a949c1SAzael Avalos result = hci_write(dev, HCI_LCD_BRIGHTNESS, value); 1390e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1391e1a949c1SAzael Avalos pr_err("ACPI call to set LCD Brightness failed\n"); 1392e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1393e1a949c1SAzael Avalos return -ENODEV; 1394e1a949c1SAzael Avalos 1395e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1396b4f9fe12SLen Brown } 1397b4f9fe12SLen Brown 1398b4f9fe12SLen Brown static int set_lcd_status(struct backlight_device *bd) 1399b4f9fe12SLen Brown { 1400135740deSSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 1401b5163992SAzael Avalos 140262cce752SSeth Forshee return set_lcd_brightness(dev, bd->props.brightness); 1403b4f9fe12SLen Brown } 1404b4f9fe12SLen Brown 1405936c8bcdSAlexey Dobriyan static ssize_t lcd_proc_write(struct file *file, const char __user *buf, 1406936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1407b4f9fe12SLen Brown { 1408359745d7SMuchun Song struct toshiba_acpi_dev *dev = pde_data(file_inode(file)); 1409936c8bcdSAlexey Dobriyan char cmd[42]; 1410936c8bcdSAlexey Dobriyan size_t len; 141178429e55SAzael Avalos int levels; 1412e1a949c1SAzael Avalos int value; 1413b4f9fe12SLen Brown 1414936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1415936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1416936c8bcdSAlexey Dobriyan return -EFAULT; 1417936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1418936c8bcdSAlexey Dobriyan 141978429e55SAzael Avalos levels = dev->backlight_dev->props.max_brightness + 1; 1420e1a949c1SAzael Avalos if (sscanf(cmd, " brightness : %i", &value) != 1 && 1421e1a949c1SAzael Avalos value < 0 && value > levels) 1422e1a949c1SAzael Avalos return -EINVAL; 1423e1a949c1SAzael Avalos 1424e1a949c1SAzael Avalos if (set_lcd_brightness(dev, value)) 1425e1a949c1SAzael Avalos return -EIO; 1426e1a949c1SAzael Avalos 1427e1a949c1SAzael Avalos return count; 1428b4f9fe12SLen Brown } 1429b4f9fe12SLen Brown 143097a32539SAlexey Dobriyan static const struct proc_ops lcd_proc_ops = { 143197a32539SAlexey Dobriyan .proc_open = lcd_proc_open, 143297a32539SAlexey Dobriyan .proc_read = seq_read, 143397a32539SAlexey Dobriyan .proc_lseek = seq_lseek, 143497a32539SAlexey Dobriyan .proc_release = single_release, 143597a32539SAlexey Dobriyan .proc_write = lcd_proc_write, 1436936c8bcdSAlexey Dobriyan }; 1437936c8bcdSAlexey Dobriyan 1438e1a949c1SAzael Avalos /* Video-Out */ 143936d03f93SSeth Forshee static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status) 144036d03f93SSeth Forshee { 1441e1a949c1SAzael Avalos u32 result = hci_read(dev, HCI_VIDEO_OUT, status); 144236d03f93SSeth Forshee 1443e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1444e1a949c1SAzael Avalos pr_err("ACPI call to get Video-Out failed\n"); 1445e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1446e1a949c1SAzael Avalos return -ENODEV; 1447e1a949c1SAzael Avalos 1448e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 144936d03f93SSeth Forshee } 145036d03f93SSeth Forshee 1451936c8bcdSAlexey Dobriyan static int video_proc_show(struct seq_file *m, void *v) 1452b4f9fe12SLen Brown { 1453135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1454513ee146SAzael Avalos int is_lcd, is_crt, is_tv; 1455b4f9fe12SLen Brown u32 value; 1456b4f9fe12SLen Brown 1457513ee146SAzael Avalos if (get_video_status(dev, &value)) 1458513ee146SAzael Avalos return -EIO; 1459513ee146SAzael Avalos 1460513ee146SAzael Avalos is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; 1461513ee146SAzael Avalos is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; 1462513ee146SAzael Avalos is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; 1463b5163992SAzael Avalos 1464936c8bcdSAlexey Dobriyan seq_printf(m, "lcd_out: %d\n", is_lcd); 1465936c8bcdSAlexey Dobriyan seq_printf(m, "crt_out: %d\n", is_crt); 1466936c8bcdSAlexey Dobriyan seq_printf(m, "tv_out: %d\n", is_tv); 1467b4f9fe12SLen Brown 1468513ee146SAzael Avalos return 0; 1469b4f9fe12SLen Brown } 1470b4f9fe12SLen Brown 1471936c8bcdSAlexey Dobriyan static int video_proc_open(struct inode *inode, struct file *file) 1472b4f9fe12SLen Brown { 1473359745d7SMuchun Song return single_open(file, video_proc_show, pde_data(inode)); 1474936c8bcdSAlexey Dobriyan } 1475936c8bcdSAlexey Dobriyan 1476936c8bcdSAlexey Dobriyan static ssize_t video_proc_write(struct file *file, const char __user *buf, 1477936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1478936c8bcdSAlexey Dobriyan { 1479359745d7SMuchun Song struct toshiba_acpi_dev *dev = pde_data(file_inode(file)); 1480e1a949c1SAzael Avalos char *buffer; 1481e1a949c1SAzael Avalos char *cmd; 14822a72c46aSKaixu Xia int lcd_out = -1, crt_out = -1, tv_out = -1; 1483b4f9fe12SLen Brown int remain = count; 1484e1a949c1SAzael Avalos int value; 1485e1a949c1SAzael Avalos int ret; 1486b4f9fe12SLen Brown u32 video_out; 1487b4f9fe12SLen Brown 1488f0ee1a6dSGeliang Tang cmd = memdup_user_nul(buf, count); 1489f0ee1a6dSGeliang Tang if (IS_ERR(cmd)) 1490f0ee1a6dSGeliang Tang return PTR_ERR(cmd); 1491936c8bcdSAlexey Dobriyan 1492936c8bcdSAlexey Dobriyan buffer = cmd; 1493936c8bcdSAlexey Dobriyan 1494e0769fe6SDarren Hart /* 1495e0769fe6SDarren Hart * Scan expression. Multiple expressions may be delimited with ; 1496e0769fe6SDarren Hart * NOTE: To keep scanning simple, invalid fields are ignored. 1497b4f9fe12SLen Brown */ 1498b4f9fe12SLen Brown while (remain) { 1499b4f9fe12SLen Brown if (sscanf(buffer, " lcd_out : %i", &value) == 1) 1500b4f9fe12SLen Brown lcd_out = value & 1; 1501b4f9fe12SLen Brown else if (sscanf(buffer, " crt_out : %i", &value) == 1) 1502b4f9fe12SLen Brown crt_out = value & 1; 1503b4f9fe12SLen Brown else if (sscanf(buffer, " tv_out : %i", &value) == 1) 1504b4f9fe12SLen Brown tv_out = value & 1; 1505e0769fe6SDarren Hart /* Advance to one character past the next ; */ 1506b4f9fe12SLen Brown do { 1507b4f9fe12SLen Brown ++buffer; 1508b4f9fe12SLen Brown --remain; 1509b5163992SAzael Avalos } while (remain && *(buffer - 1) != ';'); 1510b4f9fe12SLen Brown } 1511b4f9fe12SLen Brown 1512936c8bcdSAlexey Dobriyan kfree(cmd); 1513936c8bcdSAlexey Dobriyan 151436d03f93SSeth Forshee ret = get_video_status(dev, &video_out); 151536d03f93SSeth Forshee if (!ret) { 1516b4f9fe12SLen Brown unsigned int new_video_out = video_out; 1517b5163992SAzael Avalos 1518b4f9fe12SLen Brown if (lcd_out != -1) 1519b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out); 1520b4f9fe12SLen Brown if (crt_out != -1) 1521b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out); 1522b4f9fe12SLen Brown if (tv_out != -1) 1523b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out); 1524e0769fe6SDarren Hart /* 1525e0769fe6SDarren Hart * To avoid unnecessary video disruption, only write the new 15263f75bbe9SAzael Avalos * video setting if something changed. 15273f75bbe9SAzael Avalos */ 1528b4f9fe12SLen Brown if (new_video_out != video_out) 152932bcd5cbSSeth Forshee ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out); 1530b4f9fe12SLen Brown } 1531b4f9fe12SLen Brown 1532e1a949c1SAzael Avalos return ret ? -EIO : count; 1533b4f9fe12SLen Brown } 1534b4f9fe12SLen Brown 153597a32539SAlexey Dobriyan static const struct proc_ops video_proc_ops = { 153697a32539SAlexey Dobriyan .proc_open = video_proc_open, 153797a32539SAlexey Dobriyan .proc_read = seq_read, 153897a32539SAlexey Dobriyan .proc_lseek = seq_lseek, 153997a32539SAlexey Dobriyan .proc_release = single_release, 154097a32539SAlexey Dobriyan .proc_write = video_proc_write, 1541936c8bcdSAlexey Dobriyan }; 1542936c8bcdSAlexey Dobriyan 15433e07e5baSAzael Avalos /* Fan status */ 154436d03f93SSeth Forshee static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status) 154536d03f93SSeth Forshee { 15463e07e5baSAzael Avalos u32 result = hci_read(dev, HCI_FAN, status); 154736d03f93SSeth Forshee 15483e07e5baSAzael Avalos if (result == TOS_FAILURE) 15493e07e5baSAzael Avalos pr_err("ACPI call to get Fan status failed\n"); 15503e07e5baSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 15513e07e5baSAzael Avalos return -ENODEV; 15523e07e5baSAzael Avalos 1553e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 15543e07e5baSAzael Avalos } 15553e07e5baSAzael Avalos 15563e07e5baSAzael Avalos static int set_fan_status(struct toshiba_acpi_dev *dev, u32 status) 15573e07e5baSAzael Avalos { 15583e07e5baSAzael Avalos u32 result = hci_write(dev, HCI_FAN, status); 15593e07e5baSAzael Avalos 15603e07e5baSAzael Avalos if (result == TOS_FAILURE) 15613e07e5baSAzael Avalos pr_err("ACPI call to set Fan status failed\n"); 15623e07e5baSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 15633e07e5baSAzael Avalos return -ENODEV; 15643e07e5baSAzael Avalos 1565e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 156636d03f93SSeth Forshee } 156736d03f93SSeth Forshee 1568936c8bcdSAlexey Dobriyan static int fan_proc_show(struct seq_file *m, void *v) 1569b4f9fe12SLen Brown { 1570135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1571b4f9fe12SLen Brown u32 value; 1572b4f9fe12SLen Brown 15733e07e5baSAzael Avalos if (get_fan_status(dev, &value)) 15743e07e5baSAzael Avalos return -EIO; 15753e07e5baSAzael Avalos 1576936c8bcdSAlexey Dobriyan seq_printf(m, "running: %d\n", (value > 0)); 1577135740deSSeth Forshee seq_printf(m, "force_on: %d\n", dev->force_fan); 1578b4f9fe12SLen Brown 15793e07e5baSAzael Avalos return 0; 1580b4f9fe12SLen Brown } 1581b4f9fe12SLen Brown 1582936c8bcdSAlexey Dobriyan static int fan_proc_open(struct inode *inode, struct file *file) 1583b4f9fe12SLen Brown { 1584359745d7SMuchun Song return single_open(file, fan_proc_show, pde_data(inode)); 1585936c8bcdSAlexey Dobriyan } 1586936c8bcdSAlexey Dobriyan 1587936c8bcdSAlexey Dobriyan static ssize_t fan_proc_write(struct file *file, const char __user *buf, 1588936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1589936c8bcdSAlexey Dobriyan { 1590359745d7SMuchun Song struct toshiba_acpi_dev *dev = pde_data(file_inode(file)); 1591936c8bcdSAlexey Dobriyan char cmd[42]; 1592936c8bcdSAlexey Dobriyan size_t len; 1593b4f9fe12SLen Brown int value; 1594b4f9fe12SLen Brown 1595936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1596936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1597936c8bcdSAlexey Dobriyan return -EFAULT; 1598936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1599936c8bcdSAlexey Dobriyan 16003e07e5baSAzael Avalos if (sscanf(cmd, " force_on : %i", &value) != 1 && 16013e07e5baSAzael Avalos value != 0 && value != 1) 1602b4f9fe12SLen Brown return -EINVAL; 16033e07e5baSAzael Avalos 16043e07e5baSAzael Avalos if (set_fan_status(dev, value)) 16053e07e5baSAzael Avalos return -EIO; 16063e07e5baSAzael Avalos 16073e07e5baSAzael Avalos dev->force_fan = value; 1608b4f9fe12SLen Brown 1609b4f9fe12SLen Brown return count; 1610b4f9fe12SLen Brown } 1611b4f9fe12SLen Brown 161297a32539SAlexey Dobriyan static const struct proc_ops fan_proc_ops = { 161397a32539SAlexey Dobriyan .proc_open = fan_proc_open, 161497a32539SAlexey Dobriyan .proc_read = seq_read, 161597a32539SAlexey Dobriyan .proc_lseek = seq_lseek, 161697a32539SAlexey Dobriyan .proc_release = single_release, 161797a32539SAlexey Dobriyan .proc_write = fan_proc_write, 1618936c8bcdSAlexey Dobriyan }; 1619936c8bcdSAlexey Dobriyan 1620dd193dcdSArvid Norlander /* Fan RPM */ 1621dd193dcdSArvid Norlander static int get_fan_rpm(struct toshiba_acpi_dev *dev, u32 *rpm) 1622dd193dcdSArvid Norlander { 1623dd193dcdSArvid Norlander u32 in[TCI_WORDS] = { HCI_GET, HCI_FAN_RPM, 0, 1, 0, 0 }; 1624dd193dcdSArvid Norlander u32 out[TCI_WORDS]; 1625dd193dcdSArvid Norlander acpi_status status = tci_raw(dev, in, out); 1626dd193dcdSArvid Norlander 1627dd193dcdSArvid Norlander if (ACPI_FAILURE(status)) { 1628dd193dcdSArvid Norlander pr_err("ACPI call to get Fan speed failed\n"); 1629dd193dcdSArvid Norlander return -EIO; 1630dd193dcdSArvid Norlander } 1631dd193dcdSArvid Norlander 1632dd193dcdSArvid Norlander if (out[0] == TOS_NOT_SUPPORTED) 1633dd193dcdSArvid Norlander return -ENODEV; 1634dd193dcdSArvid Norlander 1635dd193dcdSArvid Norlander if (out[0] == TOS_SUCCESS) { 1636dd193dcdSArvid Norlander *rpm = out[2]; 1637dd193dcdSArvid Norlander return 0; 1638dd193dcdSArvid Norlander } 1639dd193dcdSArvid Norlander 1640dd193dcdSArvid Norlander return -EIO; 1641dd193dcdSArvid Norlander } 1642dd193dcdSArvid Norlander 1643936c8bcdSAlexey Dobriyan static int keys_proc_show(struct seq_file *m, void *v) 1644b4f9fe12SLen Brown { 1645135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1646b4f9fe12SLen Brown 1647135740deSSeth Forshee seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid); 1648135740deSSeth Forshee seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event); 16497deef550SAzael Avalos 1650936c8bcdSAlexey Dobriyan return 0; 1651b4f9fe12SLen Brown } 1652b4f9fe12SLen Brown 1653936c8bcdSAlexey Dobriyan static int keys_proc_open(struct inode *inode, struct file *file) 1654b4f9fe12SLen Brown { 1655359745d7SMuchun Song return single_open(file, keys_proc_show, pde_data(inode)); 1656936c8bcdSAlexey Dobriyan } 1657936c8bcdSAlexey Dobriyan 1658936c8bcdSAlexey Dobriyan static ssize_t keys_proc_write(struct file *file, const char __user *buf, 1659936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1660936c8bcdSAlexey Dobriyan { 1661359745d7SMuchun Song struct toshiba_acpi_dev *dev = pde_data(file_inode(file)); 1662936c8bcdSAlexey Dobriyan char cmd[42]; 1663936c8bcdSAlexey Dobriyan size_t len; 1664b4f9fe12SLen Brown int value; 1665b4f9fe12SLen Brown 1666936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1667936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1668936c8bcdSAlexey Dobriyan return -EFAULT; 1669936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1670936c8bcdSAlexey Dobriyan 1671b5163992SAzael Avalos if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) 1672135740deSSeth Forshee dev->key_event_valid = 0; 1673b5163992SAzael Avalos else 1674b4f9fe12SLen Brown return -EINVAL; 1675b4f9fe12SLen Brown 1676b4f9fe12SLen Brown return count; 1677b4f9fe12SLen Brown } 1678b4f9fe12SLen Brown 167997a32539SAlexey Dobriyan static const struct proc_ops keys_proc_ops = { 168097a32539SAlexey Dobriyan .proc_open = keys_proc_open, 168197a32539SAlexey Dobriyan .proc_read = seq_read, 168297a32539SAlexey Dobriyan .proc_lseek = seq_lseek, 168397a32539SAlexey Dobriyan .proc_release = single_release, 168497a32539SAlexey Dobriyan .proc_write = keys_proc_write, 1685936c8bcdSAlexey Dobriyan }; 1686936c8bcdSAlexey Dobriyan 1687c2e2a618SRandy Dunlap static int __maybe_unused version_proc_show(struct seq_file *m, void *v) 1688b4f9fe12SLen Brown { 1689936c8bcdSAlexey Dobriyan seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION); 1690936c8bcdSAlexey Dobriyan seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION); 1691936c8bcdSAlexey Dobriyan return 0; 1692b4f9fe12SLen Brown } 1693b4f9fe12SLen Brown 1694e0769fe6SDarren Hart /* 1695e0769fe6SDarren Hart * Proc and module init 1696b4f9fe12SLen Brown */ 1697b4f9fe12SLen Brown 1698b4f9fe12SLen Brown #define PROC_TOSHIBA "toshiba" 1699b4f9fe12SLen Brown 1700b859f159SGreg Kroah-Hartman static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1701b4f9fe12SLen Brown { 170236d03f93SSeth Forshee if (dev->backlight_dev) 1703135740deSSeth Forshee proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, 170497a32539SAlexey Dobriyan &lcd_proc_ops, dev); 170536d03f93SSeth Forshee if (dev->video_supported) 1706135740deSSeth Forshee proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, 170797a32539SAlexey Dobriyan &video_proc_ops, dev); 170836d03f93SSeth Forshee if (dev->fan_supported) 1709135740deSSeth Forshee proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, 171097a32539SAlexey Dobriyan &fan_proc_ops, dev); 171136d03f93SSeth Forshee if (dev->hotkey_dev) 1712135740deSSeth Forshee proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, 171397a32539SAlexey Dobriyan &keys_proc_ops, dev); 17143f3942acSChristoph Hellwig proc_create_single_data("version", S_IRUGO, toshiba_proc_dir, 17153f3942acSChristoph Hellwig version_proc_show, dev); 1716b4f9fe12SLen Brown } 1717b4f9fe12SLen Brown 171836d03f93SSeth Forshee static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1719b4f9fe12SLen Brown { 172036d03f93SSeth Forshee if (dev->backlight_dev) 1721936c8bcdSAlexey Dobriyan remove_proc_entry("lcd", toshiba_proc_dir); 172236d03f93SSeth Forshee if (dev->video_supported) 1723936c8bcdSAlexey Dobriyan remove_proc_entry("video", toshiba_proc_dir); 172436d03f93SSeth Forshee if (dev->fan_supported) 1725936c8bcdSAlexey Dobriyan remove_proc_entry("fan", toshiba_proc_dir); 172636d03f93SSeth Forshee if (dev->hotkey_dev) 1727936c8bcdSAlexey Dobriyan remove_proc_entry("keys", toshiba_proc_dir); 1728936c8bcdSAlexey Dobriyan remove_proc_entry("version", toshiba_proc_dir); 1729b4f9fe12SLen Brown } 1730b4f9fe12SLen Brown 1731acc2472eSLionel Debroux static const struct backlight_ops toshiba_backlight_data = { 1732121b7b0dSAkio Idehara .options = BL_CORE_SUSPENDRESUME, 173362cce752SSeth Forshee .get_brightness = get_lcd_brightness, 1734b4f9fe12SLen Brown .update_status = set_lcd_status, 1735b4f9fe12SLen Brown }; 1736b4f9fe12SLen Brown 173765e3cf9cSAzael Avalos /* Keyboard backlight work */ 173865e3cf9cSAzael Avalos static void toshiba_acpi_kbd_bl_work(struct work_struct *work); 173965e3cf9cSAzael Avalos 174065e3cf9cSAzael Avalos static DECLARE_WORK(kbd_bl_work, toshiba_acpi_kbd_bl_work); 174165e3cf9cSAzael Avalos 1742360f0f39SAzael Avalos /* 1743360f0f39SAzael Avalos * Sysfs files 1744360f0f39SAzael Avalos */ 17459d309848SAzael Avalos static ssize_t version_show(struct device *dev, 1746c6c68ff8SAzael Avalos struct device_attribute *attr, char *buf) 1747c6c68ff8SAzael Avalos { 1748c6c68ff8SAzael Avalos return sprintf(buf, "%s\n", TOSHIBA_ACPI_VERSION); 1749c6c68ff8SAzael Avalos } 17500c3c0f10SAzael Avalos static DEVICE_ATTR_RO(version); 1751c6c68ff8SAzael Avalos 17529d309848SAzael Avalos static ssize_t fan_store(struct device *dev, 175394477d4cSAzael Avalos struct device_attribute *attr, 175494477d4cSAzael Avalos const char *buf, size_t count) 175594477d4cSAzael Avalos { 175694477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 175794477d4cSAzael Avalos int state; 175894477d4cSAzael Avalos int ret; 175994477d4cSAzael Avalos 176094477d4cSAzael Avalos ret = kstrtoint(buf, 0, &state); 176194477d4cSAzael Avalos if (ret) 176294477d4cSAzael Avalos return ret; 176394477d4cSAzael Avalos 176494477d4cSAzael Avalos if (state != 0 && state != 1) 176594477d4cSAzael Avalos return -EINVAL; 176694477d4cSAzael Avalos 17673e07e5baSAzael Avalos ret = set_fan_status(toshiba, state); 17683e07e5baSAzael Avalos if (ret) 17693e07e5baSAzael Avalos return ret; 177094477d4cSAzael Avalos 177194477d4cSAzael Avalos return count; 177294477d4cSAzael Avalos } 177394477d4cSAzael Avalos 17749d309848SAzael Avalos static ssize_t fan_show(struct device *dev, 177594477d4cSAzael Avalos struct device_attribute *attr, char *buf) 177694477d4cSAzael Avalos { 177794477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 177894477d4cSAzael Avalos u32 value; 177994477d4cSAzael Avalos int ret; 178094477d4cSAzael Avalos 178194477d4cSAzael Avalos ret = get_fan_status(toshiba, &value); 178294477d4cSAzael Avalos if (ret) 178394477d4cSAzael Avalos return ret; 178494477d4cSAzael Avalos 178594477d4cSAzael Avalos return sprintf(buf, "%d\n", value); 178694477d4cSAzael Avalos } 17870c3c0f10SAzael Avalos static DEVICE_ATTR_RW(fan); 178894477d4cSAzael Avalos 17899d309848SAzael Avalos static ssize_t kbd_backlight_mode_store(struct device *dev, 1790360f0f39SAzael Avalos struct device_attribute *attr, 1791360f0f39SAzael Avalos const char *buf, size_t count) 1792360f0f39SAzael Avalos { 1793360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1794aeaac098SDan Carpenter int mode; 1795aeaac098SDan Carpenter int ret; 1796360f0f39SAzael Avalos 1797aeaac098SDan Carpenter 1798aeaac098SDan Carpenter ret = kstrtoint(buf, 0, &mode); 1799aeaac098SDan Carpenter if (ret) 1800aeaac098SDan Carpenter return ret; 180193f8c16dSAzael Avalos 180293f8c16dSAzael Avalos /* Check for supported modes depending on keyboard backlight type */ 180393f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 180493f8c16dSAzael Avalos /* Type 1 supports SCI_KBD_MODE_FNZ and SCI_KBD_MODE_AUTO */ 1805aeaac098SDan Carpenter if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO) 1806360f0f39SAzael Avalos return -EINVAL; 180793f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 180893f8c16dSAzael Avalos /* Type 2 doesn't support SCI_KBD_MODE_FNZ */ 180993f8c16dSAzael Avalos if (mode != SCI_KBD_MODE_AUTO && mode != SCI_KBD_MODE_ON && 181093f8c16dSAzael Avalos mode != SCI_KBD_MODE_OFF) 181193f8c16dSAzael Avalos return -EINVAL; 181293f8c16dSAzael Avalos } 1813360f0f39SAzael Avalos 1814e0769fe6SDarren Hart /* 1815e0769fe6SDarren Hart * Set the Keyboard Backlight Mode where: 1816360f0f39SAzael Avalos * Auto - KBD backlight turns off automatically in given time 1817360f0f39SAzael Avalos * FN-Z - KBD backlight "toggles" when hotkey pressed 181893f8c16dSAzael Avalos * ON - KBD backlight is always on 181993f8c16dSAzael Avalos * OFF - KBD backlight is always off 1820360f0f39SAzael Avalos */ 182193f8c16dSAzael Avalos 182293f8c16dSAzael Avalos /* Only make a change if the actual mode has changed */ 1823aeaac098SDan Carpenter if (toshiba->kbd_mode != mode) { 182493f8c16dSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 18251e574dbfSAzael Avalos int time = toshiba->kbd_time << HCI_MISC_SHIFT; 182693f8c16dSAzael Avalos 182793f8c16dSAzael Avalos /* OR the "base time" to the actual method format */ 182893f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 182993f8c16dSAzael Avalos /* Type 1 requires the current mode */ 183093f8c16dSAzael Avalos time |= toshiba->kbd_mode; 183193f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 183293f8c16dSAzael Avalos /* Type 2 requires the desired mode */ 183393f8c16dSAzael Avalos time |= mode; 183493f8c16dSAzael Avalos } 183593f8c16dSAzael Avalos 1836aeaac098SDan Carpenter ret = toshiba_kbd_illum_status_set(toshiba, time); 1837aeaac098SDan Carpenter if (ret) 1838aeaac098SDan Carpenter return ret; 183993f8c16dSAzael Avalos 1840360f0f39SAzael Avalos toshiba->kbd_mode = mode; 1841147288e6SAzael Avalos toshiba_acpi->kbd_mode = mode; 184265e3cf9cSAzael Avalos 184365e3cf9cSAzael Avalos /* 184465e3cf9cSAzael Avalos * Some laptop models with the second generation backlit 184565e3cf9cSAzael Avalos * keyboard (type 2) do not generate the keyboard backlight 184665e3cf9cSAzael Avalos * changed event (0x92), and thus, the driver will never update 184765e3cf9cSAzael Avalos * the sysfs entries. 184865e3cf9cSAzael Avalos * 184965e3cf9cSAzael Avalos * The event is generated right when changing the keyboard 185065e3cf9cSAzael Avalos * backlight mode and the *notify function will set the 185165e3cf9cSAzael Avalos * kbd_event_generated to true. 185265e3cf9cSAzael Avalos * 185365e3cf9cSAzael Avalos * In case the event is not generated, schedule the keyboard 185465e3cf9cSAzael Avalos * backlight work to update the sysfs entries and emulate the 185565e3cf9cSAzael Avalos * event via genetlink. 185665e3cf9cSAzael Avalos */ 185765e3cf9cSAzael Avalos if (toshiba->kbd_type == 2 && 1858147288e6SAzael Avalos !toshiba->kbd_event_generated) 185965e3cf9cSAzael Avalos schedule_work(&kbd_bl_work); 1860360f0f39SAzael Avalos } 1861360f0f39SAzael Avalos 1862360f0f39SAzael Avalos return count; 1863360f0f39SAzael Avalos } 1864360f0f39SAzael Avalos 18659d309848SAzael Avalos static ssize_t kbd_backlight_mode_show(struct device *dev, 1866360f0f39SAzael Avalos struct device_attribute *attr, 1867360f0f39SAzael Avalos char *buf) 1868360f0f39SAzael Avalos { 1869360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1870360f0f39SAzael Avalos u32 time; 1871360f0f39SAzael Avalos 1872360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1873360f0f39SAzael Avalos return -EIO; 1874360f0f39SAzael Avalos 187593f8c16dSAzael Avalos return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK); 187693f8c16dSAzael Avalos } 18770c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_mode); 187893f8c16dSAzael Avalos 18799d309848SAzael Avalos static ssize_t kbd_type_show(struct device *dev, 18809d309848SAzael Avalos struct device_attribute *attr, char *buf) 188193f8c16dSAzael Avalos { 188293f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 188393f8c16dSAzael Avalos 188493f8c16dSAzael Avalos return sprintf(buf, "%d\n", toshiba->kbd_type); 188593f8c16dSAzael Avalos } 18860c3c0f10SAzael Avalos static DEVICE_ATTR_RO(kbd_type); 188793f8c16dSAzael Avalos 18889d309848SAzael Avalos static ssize_t available_kbd_modes_show(struct device *dev, 188993f8c16dSAzael Avalos struct device_attribute *attr, 189093f8c16dSAzael Avalos char *buf) 189193f8c16dSAzael Avalos { 189293f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 189393f8c16dSAzael Avalos 189493f8c16dSAzael Avalos if (toshiba->kbd_type == 1) 18950b498201SAzael Avalos return sprintf(buf, "0x%x 0x%x\n", 189693f8c16dSAzael Avalos SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO); 189793f8c16dSAzael Avalos 18980b498201SAzael Avalos return sprintf(buf, "0x%x 0x%x 0x%x\n", 189993f8c16dSAzael Avalos SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF); 1900360f0f39SAzael Avalos } 19010c3c0f10SAzael Avalos static DEVICE_ATTR_RO(available_kbd_modes); 1902360f0f39SAzael Avalos 19039d309848SAzael Avalos static ssize_t kbd_backlight_timeout_store(struct device *dev, 1904360f0f39SAzael Avalos struct device_attribute *attr, 1905360f0f39SAzael Avalos const char *buf, size_t count) 1906360f0f39SAzael Avalos { 1907360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1908eabde0faSAzael Avalos int time; 1909eabde0faSAzael Avalos int ret; 1910360f0f39SAzael Avalos 1911eabde0faSAzael Avalos ret = kstrtoint(buf, 0, &time); 1912eabde0faSAzael Avalos if (ret) 1913eabde0faSAzael Avalos return ret; 1914eabde0faSAzael Avalos 1915eabde0faSAzael Avalos /* Check for supported values depending on kbd_type */ 1916eabde0faSAzael Avalos if (toshiba->kbd_type == 1) { 1917eabde0faSAzael Avalos if (time < 0 || time > 60) 1918360f0f39SAzael Avalos return -EINVAL; 1919eabde0faSAzael Avalos } else if (toshiba->kbd_type == 2) { 1920eabde0faSAzael Avalos if (time < 1 || time > 60) 1921eabde0faSAzael Avalos return -EINVAL; 1922eabde0faSAzael Avalos } 1923360f0f39SAzael Avalos 1924eabde0faSAzael Avalos /* Set the Keyboard Backlight Timeout */ 1925eabde0faSAzael Avalos 1926eabde0faSAzael Avalos /* Only make a change if the actual timeout has changed */ 1927eabde0faSAzael Avalos if (toshiba->kbd_time != time) { 1928eabde0faSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 1929360f0f39SAzael Avalos time = time << HCI_MISC_SHIFT; 1930eabde0faSAzael Avalos /* OR the "base time" to the actual method format */ 1931eabde0faSAzael Avalos if (toshiba->kbd_type == 1) 1932eabde0faSAzael Avalos time |= SCI_KBD_MODE_FNZ; 1933eabde0faSAzael Avalos else if (toshiba->kbd_type == 2) 1934eabde0faSAzael Avalos time |= SCI_KBD_MODE_AUTO; 1935eabde0faSAzael Avalos 1936eabde0faSAzael Avalos ret = toshiba_kbd_illum_status_set(toshiba, time); 1937eabde0faSAzael Avalos if (ret) 1938eabde0faSAzael Avalos return ret; 1939eabde0faSAzael Avalos 1940360f0f39SAzael Avalos toshiba->kbd_time = time >> HCI_MISC_SHIFT; 1941360f0f39SAzael Avalos } 1942360f0f39SAzael Avalos 1943360f0f39SAzael Avalos return count; 1944360f0f39SAzael Avalos } 1945360f0f39SAzael Avalos 19469d309848SAzael Avalos static ssize_t kbd_backlight_timeout_show(struct device *dev, 1947360f0f39SAzael Avalos struct device_attribute *attr, 1948360f0f39SAzael Avalos char *buf) 1949360f0f39SAzael Avalos { 1950360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1951360f0f39SAzael Avalos u32 time; 1952360f0f39SAzael Avalos 1953360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1954360f0f39SAzael Avalos return -EIO; 1955360f0f39SAzael Avalos 1956360f0f39SAzael Avalos return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT); 1957360f0f39SAzael Avalos } 19580c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_timeout); 1959360f0f39SAzael Avalos 19609d309848SAzael Avalos static ssize_t touchpad_store(struct device *dev, 19619d8658acSAzael Avalos struct device_attribute *attr, 19629d8658acSAzael Avalos const char *buf, size_t count) 19639d8658acSAzael Avalos { 19649d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 19659d8658acSAzael Avalos int state; 1966c8a41669SAzael Avalos int ret; 19679d8658acSAzael Avalos 19689d8658acSAzael Avalos /* Set the TouchPad on/off, 0 - Disable | 1 - Enable */ 1969c8a41669SAzael Avalos ret = kstrtoint(buf, 0, &state); 1970c8a41669SAzael Avalos if (ret) 1971c8a41669SAzael Avalos return ret; 1972c8a41669SAzael Avalos if (state != 0 && state != 1) 1973c8a41669SAzael Avalos return -EINVAL; 1974c8a41669SAzael Avalos 1975c8a41669SAzael Avalos ret = toshiba_touchpad_set(toshiba, state); 1976c8a41669SAzael Avalos if (ret) 1977c8a41669SAzael Avalos return ret; 19789d8658acSAzael Avalos 19799d8658acSAzael Avalos return count; 19809d8658acSAzael Avalos } 19819d8658acSAzael Avalos 19829d309848SAzael Avalos static ssize_t touchpad_show(struct device *dev, 19839d8658acSAzael Avalos struct device_attribute *attr, char *buf) 19849d8658acSAzael Avalos { 19859d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 19869d8658acSAzael Avalos u32 state; 19879d8658acSAzael Avalos int ret; 19889d8658acSAzael Avalos 19899d8658acSAzael Avalos ret = toshiba_touchpad_get(toshiba, &state); 19909d8658acSAzael Avalos if (ret < 0) 19919d8658acSAzael Avalos return ret; 19929d8658acSAzael Avalos 19939d8658acSAzael Avalos return sprintf(buf, "%i\n", state); 19949d8658acSAzael Avalos } 19950c3c0f10SAzael Avalos static DEVICE_ATTR_RW(touchpad); 19969d8658acSAzael Avalos 19979d309848SAzael Avalos static ssize_t usb_sleep_charge_show(struct device *dev, 19989d309848SAzael Avalos struct device_attribute *attr, char *buf) 1999e26ffe51SAzael Avalos { 2000e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2001e26ffe51SAzael Avalos u32 mode; 2002e26ffe51SAzael Avalos int ret; 2003e26ffe51SAzael Avalos 2004e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_get(toshiba, &mode); 2005e26ffe51SAzael Avalos if (ret < 0) 2006e26ffe51SAzael Avalos return ret; 2007e26ffe51SAzael Avalos 2008e26ffe51SAzael Avalos return sprintf(buf, "%x\n", mode & SCI_USB_CHARGE_MODE_MASK); 2009e26ffe51SAzael Avalos } 2010e26ffe51SAzael Avalos 20119d309848SAzael Avalos static ssize_t usb_sleep_charge_store(struct device *dev, 2012e26ffe51SAzael Avalos struct device_attribute *attr, 2013e26ffe51SAzael Avalos const char *buf, size_t count) 2014e26ffe51SAzael Avalos { 2015e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2016e26ffe51SAzael Avalos int state; 201778429e55SAzael Avalos u32 mode; 2018e26ffe51SAzael Avalos int ret; 2019e26ffe51SAzael Avalos 2020e26ffe51SAzael Avalos ret = kstrtoint(buf, 0, &state); 2021e26ffe51SAzael Avalos if (ret) 2022e26ffe51SAzael Avalos return ret; 2023e0769fe6SDarren Hart /* 2024e0769fe6SDarren Hart * Check for supported values, where: 2025e26ffe51SAzael Avalos * 0 - Disabled 2026e26ffe51SAzael Avalos * 1 - Alternate (Non USB conformant devices that require more power) 2027e26ffe51SAzael Avalos * 2 - Auto (USB conformant devices) 2028c8c91842SAzael Avalos * 3 - Typical 2029e26ffe51SAzael Avalos */ 2030c8c91842SAzael Avalos if (state != 0 && state != 1 && state != 2 && state != 3) 2031e26ffe51SAzael Avalos return -EINVAL; 2032e26ffe51SAzael Avalos 2033e26ffe51SAzael Avalos /* Set the USB charging mode to internal value */ 2034c8c91842SAzael Avalos mode = toshiba->usbsc_mode_base; 2035e26ffe51SAzael Avalos if (state == 0) 2036c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_DISABLED; 2037e26ffe51SAzael Avalos else if (state == 1) 2038c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_ALTERNATE; 2039e26ffe51SAzael Avalos else if (state == 2) 2040c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_AUTO; 2041c8c91842SAzael Avalos else if (state == 3) 2042c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_TYPICAL; 2043e26ffe51SAzael Avalos 2044e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_set(toshiba, mode); 2045e26ffe51SAzael Avalos if (ret) 2046e26ffe51SAzael Avalos return ret; 2047e26ffe51SAzael Avalos 2048e26ffe51SAzael Avalos return count; 2049e26ffe51SAzael Avalos } 20500c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_charge); 2051e26ffe51SAzael Avalos 2052182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_show(struct device *dev, 2053182bcaa5SAzael Avalos struct device_attribute *attr, 2054182bcaa5SAzael Avalos char *buf) 2055182bcaa5SAzael Avalos { 2056182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 205778429e55SAzael Avalos int bat_lvl, status; 2058182bcaa5SAzael Avalos u32 state; 2059182bcaa5SAzael Avalos int ret; 2060182bcaa5SAzael Avalos int tmp; 2061182bcaa5SAzael Avalos 2062182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_get(toshiba, &state); 2063182bcaa5SAzael Avalos if (ret < 0) 2064182bcaa5SAzael Avalos return ret; 2065182bcaa5SAzael Avalos 2066182bcaa5SAzael Avalos /* Determine the status: 0x4 - Enabled | 0x1 - Disabled */ 2067182bcaa5SAzael Avalos tmp = state & SCI_USB_CHARGE_BAT_MASK; 2068182bcaa5SAzael Avalos status = (tmp == 0x4) ? 1 : 0; 2069182bcaa5SAzael Avalos /* Determine the battery level set */ 2070182bcaa5SAzael Avalos bat_lvl = state >> HCI_MISC_SHIFT; 2071182bcaa5SAzael Avalos 2072182bcaa5SAzael Avalos return sprintf(buf, "%d %d\n", status, bat_lvl); 2073182bcaa5SAzael Avalos } 2074182bcaa5SAzael Avalos 2075182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_store(struct device *dev, 2076182bcaa5SAzael Avalos struct device_attribute *attr, 2077182bcaa5SAzael Avalos const char *buf, size_t count) 2078182bcaa5SAzael Avalos { 2079182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2080182bcaa5SAzael Avalos u32 status; 2081182bcaa5SAzael Avalos int value; 2082182bcaa5SAzael Avalos int ret; 2083182bcaa5SAzael Avalos int tmp; 2084182bcaa5SAzael Avalos 2085182bcaa5SAzael Avalos ret = kstrtoint(buf, 0, &value); 2086182bcaa5SAzael Avalos if (ret) 2087182bcaa5SAzael Avalos return ret; 2088182bcaa5SAzael Avalos 2089e0769fe6SDarren Hart /* 2090e0769fe6SDarren Hart * Set the status of the function: 2091182bcaa5SAzael Avalos * 0 - Disabled 2092182bcaa5SAzael Avalos * 1-100 - Enabled 2093182bcaa5SAzael Avalos */ 2094182bcaa5SAzael Avalos if (value < 0 || value > 100) 2095182bcaa5SAzael Avalos return -EINVAL; 2096182bcaa5SAzael Avalos 2097182bcaa5SAzael Avalos if (value == 0) { 2098182bcaa5SAzael Avalos tmp = toshiba->usbsc_bat_level << HCI_MISC_SHIFT; 2099182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_OFF; 2100182bcaa5SAzael Avalos } else { 2101182bcaa5SAzael Avalos tmp = value << HCI_MISC_SHIFT; 2102182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_ON; 2103182bcaa5SAzael Avalos } 2104182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_set(toshiba, status); 2105182bcaa5SAzael Avalos if (ret < 0) 2106182bcaa5SAzael Avalos return ret; 2107182bcaa5SAzael Avalos 2108182bcaa5SAzael Avalos toshiba->usbsc_bat_level = status >> HCI_MISC_SHIFT; 2109182bcaa5SAzael Avalos 2110182bcaa5SAzael Avalos return count; 2111182bcaa5SAzael Avalos } 21120c3c0f10SAzael Avalos static DEVICE_ATTR_RW(sleep_functions_on_battery); 2113182bcaa5SAzael Avalos 21149d309848SAzael Avalos static ssize_t usb_rapid_charge_show(struct device *dev, 21159d309848SAzael Avalos struct device_attribute *attr, char *buf) 2116bb3fe01fSAzael Avalos { 2117bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2118bb3fe01fSAzael Avalos u32 state; 2119bb3fe01fSAzael Avalos int ret; 2120bb3fe01fSAzael Avalos 2121bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(toshiba, &state); 2122bb3fe01fSAzael Avalos if (ret < 0) 2123bb3fe01fSAzael Avalos return ret; 2124bb3fe01fSAzael Avalos 2125bb3fe01fSAzael Avalos return sprintf(buf, "%d\n", state); 2126bb3fe01fSAzael Avalos } 2127bb3fe01fSAzael Avalos 21289d309848SAzael Avalos static ssize_t usb_rapid_charge_store(struct device *dev, 2129bb3fe01fSAzael Avalos struct device_attribute *attr, 2130bb3fe01fSAzael Avalos const char *buf, size_t count) 2131bb3fe01fSAzael Avalos { 2132bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2133bb3fe01fSAzael Avalos int state; 2134bb3fe01fSAzael Avalos int ret; 2135bb3fe01fSAzael Avalos 2136bb3fe01fSAzael Avalos ret = kstrtoint(buf, 0, &state); 2137bb3fe01fSAzael Avalos if (ret) 2138bb3fe01fSAzael Avalos return ret; 2139bb3fe01fSAzael Avalos if (state != 0 && state != 1) 2140bb3fe01fSAzael Avalos return -EINVAL; 2141bb3fe01fSAzael Avalos 2142bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_set(toshiba, state); 2143bb3fe01fSAzael Avalos if (ret) 2144bb3fe01fSAzael Avalos return ret; 2145bb3fe01fSAzael Avalos 2146bb3fe01fSAzael Avalos return count; 2147bb3fe01fSAzael Avalos } 21480c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_rapid_charge); 2149bb3fe01fSAzael Avalos 21509d309848SAzael Avalos static ssize_t usb_sleep_music_show(struct device *dev, 21519d309848SAzael Avalos struct device_attribute *attr, char *buf) 2152172ce0a9SAzael Avalos { 2153172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2154172ce0a9SAzael Avalos u32 state; 2155172ce0a9SAzael Avalos int ret; 2156172ce0a9SAzael Avalos 2157172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(toshiba, &state); 2158172ce0a9SAzael Avalos if (ret < 0) 2159172ce0a9SAzael Avalos return ret; 2160172ce0a9SAzael Avalos 2161172ce0a9SAzael Avalos return sprintf(buf, "%d\n", state); 2162172ce0a9SAzael Avalos } 2163172ce0a9SAzael Avalos 21649d309848SAzael Avalos static ssize_t usb_sleep_music_store(struct device *dev, 2165172ce0a9SAzael Avalos struct device_attribute *attr, 2166172ce0a9SAzael Avalos const char *buf, size_t count) 2167172ce0a9SAzael Avalos { 2168172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2169172ce0a9SAzael Avalos int state; 2170172ce0a9SAzael Avalos int ret; 2171172ce0a9SAzael Avalos 2172172ce0a9SAzael Avalos ret = kstrtoint(buf, 0, &state); 2173172ce0a9SAzael Avalos if (ret) 2174172ce0a9SAzael Avalos return ret; 2175172ce0a9SAzael Avalos if (state != 0 && state != 1) 2176172ce0a9SAzael Avalos return -EINVAL; 2177172ce0a9SAzael Avalos 2178172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_set(toshiba, state); 2179172ce0a9SAzael Avalos if (ret) 2180172ce0a9SAzael Avalos return ret; 2181172ce0a9SAzael Avalos 2182172ce0a9SAzael Avalos return count; 2183172ce0a9SAzael Avalos } 21840c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_music); 2185172ce0a9SAzael Avalos 21869d309848SAzael Avalos static ssize_t kbd_function_keys_show(struct device *dev, 21879d309848SAzael Avalos struct device_attribute *attr, char *buf) 2188bae84195SAzael Avalos { 2189bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2190bae84195SAzael Avalos int mode; 2191bae84195SAzael Avalos int ret; 2192bae84195SAzael Avalos 2193bae84195SAzael Avalos ret = toshiba_function_keys_get(toshiba, &mode); 2194bae84195SAzael Avalos if (ret < 0) 2195bae84195SAzael Avalos return ret; 2196bae84195SAzael Avalos 2197bae84195SAzael Avalos return sprintf(buf, "%d\n", mode); 2198bae84195SAzael Avalos } 2199bae84195SAzael Avalos 22009d309848SAzael Avalos static ssize_t kbd_function_keys_store(struct device *dev, 2201bae84195SAzael Avalos struct device_attribute *attr, 2202bae84195SAzael Avalos const char *buf, size_t count) 2203bae84195SAzael Avalos { 2204bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2205bae84195SAzael Avalos int mode; 2206bae84195SAzael Avalos int ret; 2207bae84195SAzael Avalos 2208bae84195SAzael Avalos ret = kstrtoint(buf, 0, &mode); 2209bae84195SAzael Avalos if (ret) 2210bae84195SAzael Avalos return ret; 2211e0769fe6SDarren Hart /* 2212e0769fe6SDarren Hart * Check for the function keys mode where: 2213bae84195SAzael Avalos * 0 - Normal operation (F{1-12} as usual and hotkeys via FN-F{1-12}) 2214bae84195SAzael Avalos * 1 - Special functions (Opposite of the above setting) 2215bae84195SAzael Avalos */ 2216bae84195SAzael Avalos if (mode != 0 && mode != 1) 2217bae84195SAzael Avalos return -EINVAL; 2218bae84195SAzael Avalos 2219bae84195SAzael Avalos ret = toshiba_function_keys_set(toshiba, mode); 2220bae84195SAzael Avalos if (ret) 2221bae84195SAzael Avalos return ret; 2222bae84195SAzael Avalos 2223bae84195SAzael Avalos pr_info("Reboot for changes to KBD Function Keys to take effect"); 2224bae84195SAzael Avalos 2225bae84195SAzael Avalos return count; 2226bae84195SAzael Avalos } 22270c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_function_keys); 2228bae84195SAzael Avalos 22299d309848SAzael Avalos static ssize_t panel_power_on_show(struct device *dev, 22309d309848SAzael Avalos struct device_attribute *attr, char *buf) 223135d53ceaSAzael Avalos { 223235d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 223335d53ceaSAzael Avalos u32 state; 223435d53ceaSAzael Avalos int ret; 223535d53ceaSAzael Avalos 223635d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(toshiba, &state); 223735d53ceaSAzael Avalos if (ret < 0) 223835d53ceaSAzael Avalos return ret; 223935d53ceaSAzael Avalos 224035d53ceaSAzael Avalos return sprintf(buf, "%d\n", state); 224135d53ceaSAzael Avalos } 224235d53ceaSAzael Avalos 22439d309848SAzael Avalos static ssize_t panel_power_on_store(struct device *dev, 224435d53ceaSAzael Avalos struct device_attribute *attr, 224535d53ceaSAzael Avalos const char *buf, size_t count) 224635d53ceaSAzael Avalos { 224735d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 224835d53ceaSAzael Avalos int state; 224935d53ceaSAzael Avalos int ret; 225035d53ceaSAzael Avalos 225135d53ceaSAzael Avalos ret = kstrtoint(buf, 0, &state); 225235d53ceaSAzael Avalos if (ret) 225335d53ceaSAzael Avalos return ret; 225435d53ceaSAzael Avalos if (state != 0 && state != 1) 225535d53ceaSAzael Avalos return -EINVAL; 225635d53ceaSAzael Avalos 225735d53ceaSAzael Avalos ret = toshiba_panel_power_on_set(toshiba, state); 225835d53ceaSAzael Avalos if (ret) 225935d53ceaSAzael Avalos return ret; 226035d53ceaSAzael Avalos 226135d53ceaSAzael Avalos pr_info("Reboot for changes to Panel Power ON to take effect"); 226235d53ceaSAzael Avalos 226335d53ceaSAzael Avalos return count; 226435d53ceaSAzael Avalos } 22650c3c0f10SAzael Avalos static DEVICE_ATTR_RW(panel_power_on); 226635d53ceaSAzael Avalos 22679d309848SAzael Avalos static ssize_t usb_three_show(struct device *dev, 22689d309848SAzael Avalos struct device_attribute *attr, char *buf) 226917fe4b3dSAzael Avalos { 227017fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 227117fe4b3dSAzael Avalos u32 state; 227217fe4b3dSAzael Avalos int ret; 227317fe4b3dSAzael Avalos 227417fe4b3dSAzael Avalos ret = toshiba_usb_three_get(toshiba, &state); 227517fe4b3dSAzael Avalos if (ret < 0) 227617fe4b3dSAzael Avalos return ret; 227717fe4b3dSAzael Avalos 227817fe4b3dSAzael Avalos return sprintf(buf, "%d\n", state); 227917fe4b3dSAzael Avalos } 228017fe4b3dSAzael Avalos 22819d309848SAzael Avalos static ssize_t usb_three_store(struct device *dev, 228217fe4b3dSAzael Avalos struct device_attribute *attr, 228317fe4b3dSAzael Avalos const char *buf, size_t count) 228417fe4b3dSAzael Avalos { 228517fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 228617fe4b3dSAzael Avalos int state; 228717fe4b3dSAzael Avalos int ret; 228817fe4b3dSAzael Avalos 228917fe4b3dSAzael Avalos ret = kstrtoint(buf, 0, &state); 229017fe4b3dSAzael Avalos if (ret) 229117fe4b3dSAzael Avalos return ret; 2292e0769fe6SDarren Hart /* 2293e0769fe6SDarren Hart * Check for USB 3 mode where: 229417fe4b3dSAzael Avalos * 0 - Disabled (Acts like a USB 2 port, saving power) 229517fe4b3dSAzael Avalos * 1 - Enabled 229617fe4b3dSAzael Avalos */ 229717fe4b3dSAzael Avalos if (state != 0 && state != 1) 229817fe4b3dSAzael Avalos return -EINVAL; 229917fe4b3dSAzael Avalos 230017fe4b3dSAzael Avalos ret = toshiba_usb_three_set(toshiba, state); 230117fe4b3dSAzael Avalos if (ret) 230217fe4b3dSAzael Avalos return ret; 230317fe4b3dSAzael Avalos 230417fe4b3dSAzael Avalos pr_info("Reboot for changes to USB 3 to take effect"); 230517fe4b3dSAzael Avalos 230617fe4b3dSAzael Avalos return count; 230717fe4b3dSAzael Avalos } 23080c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_three); 23099bd1213bSAzael Avalos 2310b1009b91SAzael Avalos static ssize_t cooling_method_show(struct device *dev, 2311b1009b91SAzael Avalos struct device_attribute *attr, char *buf) 2312b1009b91SAzael Avalos { 2313b1009b91SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2314b1009b91SAzael Avalos int state; 2315b1009b91SAzael Avalos int ret; 2316b1009b91SAzael Avalos 2317b1009b91SAzael Avalos ret = toshiba_cooling_method_get(toshiba, &state); 2318b1009b91SAzael Avalos if (ret < 0) 2319b1009b91SAzael Avalos return ret; 2320b1009b91SAzael Avalos 2321b1009b91SAzael Avalos return sprintf(buf, "%d %d\n", state, toshiba->max_cooling_method); 2322b1009b91SAzael Avalos } 2323b1009b91SAzael Avalos 2324b1009b91SAzael Avalos static ssize_t cooling_method_store(struct device *dev, 2325b1009b91SAzael Avalos struct device_attribute *attr, 2326b1009b91SAzael Avalos const char *buf, size_t count) 2327b1009b91SAzael Avalos { 2328b1009b91SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2329b1009b91SAzael Avalos int state; 2330b1009b91SAzael Avalos int ret; 2331b1009b91SAzael Avalos 2332b1009b91SAzael Avalos ret = kstrtoint(buf, 0, &state); 2333b1009b91SAzael Avalos if (ret) 2334b1009b91SAzael Avalos return ret; 2335b1009b91SAzael Avalos 2336b1009b91SAzael Avalos /* 2337b1009b91SAzael Avalos * Check for supported values 2338b1009b91SAzael Avalos * Depending on the laptop model, some only support these two: 2339b1009b91SAzael Avalos * 0 - Maximum Performance 2340b1009b91SAzael Avalos * 1 - Battery Optimized 2341b1009b91SAzael Avalos * 2342b1009b91SAzael Avalos * While some others support all three methods: 2343b1009b91SAzael Avalos * 0 - Maximum Performance 2344b1009b91SAzael Avalos * 1 - Performance 2345b1009b91SAzael Avalos * 2 - Battery Optimized 2346b1009b91SAzael Avalos */ 2347b1009b91SAzael Avalos if (state < 0 || state > toshiba->max_cooling_method) 2348b1009b91SAzael Avalos return -EINVAL; 2349b1009b91SAzael Avalos 2350b1009b91SAzael Avalos ret = toshiba_cooling_method_set(toshiba, state); 2351b1009b91SAzael Avalos if (ret) 2352b1009b91SAzael Avalos return ret; 2353b1009b91SAzael Avalos 2354b1009b91SAzael Avalos return count; 2355b1009b91SAzael Avalos } 2356b1009b91SAzael Avalos static DEVICE_ATTR_RW(cooling_method); 2357b1009b91SAzael Avalos 23589bd1213bSAzael Avalos static struct attribute *toshiba_attributes[] = { 23599bd1213bSAzael Avalos &dev_attr_version.attr, 23609bd1213bSAzael Avalos &dev_attr_fan.attr, 23619bd1213bSAzael Avalos &dev_attr_kbd_backlight_mode.attr, 23629bd1213bSAzael Avalos &dev_attr_kbd_type.attr, 23639bd1213bSAzael Avalos &dev_attr_available_kbd_modes.attr, 23649bd1213bSAzael Avalos &dev_attr_kbd_backlight_timeout.attr, 23659bd1213bSAzael Avalos &dev_attr_touchpad.attr, 23669bd1213bSAzael Avalos &dev_attr_usb_sleep_charge.attr, 23679bd1213bSAzael Avalos &dev_attr_sleep_functions_on_battery.attr, 23689bd1213bSAzael Avalos &dev_attr_usb_rapid_charge.attr, 23699bd1213bSAzael Avalos &dev_attr_usb_sleep_music.attr, 23709bd1213bSAzael Avalos &dev_attr_kbd_function_keys.attr, 23719bd1213bSAzael Avalos &dev_attr_panel_power_on.attr, 23729bd1213bSAzael Avalos &dev_attr_usb_three.attr, 2373b1009b91SAzael Avalos &dev_attr_cooling_method.attr, 23749bd1213bSAzael Avalos NULL, 23759bd1213bSAzael Avalos }; 23769bd1213bSAzael Avalos 2377360f0f39SAzael Avalos static umode_t toshiba_sysfs_is_visible(struct kobject *kobj, 2378360f0f39SAzael Avalos struct attribute *attr, int idx) 2379360f0f39SAzael Avalos { 238046ecf720SMinghao Chi struct device *dev = kobj_to_dev(kobj); 2381360f0f39SAzael Avalos struct toshiba_acpi_dev *drv = dev_get_drvdata(dev); 2382360f0f39SAzael Avalos bool exists = true; 2383360f0f39SAzael Avalos 238494477d4cSAzael Avalos if (attr == &dev_attr_fan.attr) 238594477d4cSAzael Avalos exists = (drv->fan_supported) ? true : false; 238694477d4cSAzael Avalos else if (attr == &dev_attr_kbd_backlight_mode.attr) 2387360f0f39SAzael Avalos exists = (drv->kbd_illum_supported) ? true : false; 2388360f0f39SAzael Avalos else if (attr == &dev_attr_kbd_backlight_timeout.attr) 2389360f0f39SAzael Avalos exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false; 23909d8658acSAzael Avalos else if (attr == &dev_attr_touchpad.attr) 23919d8658acSAzael Avalos exists = (drv->touchpad_supported) ? true : false; 2392e26ffe51SAzael Avalos else if (attr == &dev_attr_usb_sleep_charge.attr) 2393e26ffe51SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2394182bcaa5SAzael Avalos else if (attr == &dev_attr_sleep_functions_on_battery.attr) 2395182bcaa5SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2396bb3fe01fSAzael Avalos else if (attr == &dev_attr_usb_rapid_charge.attr) 2397bb3fe01fSAzael Avalos exists = (drv->usb_rapid_charge_supported) ? true : false; 2398172ce0a9SAzael Avalos else if (attr == &dev_attr_usb_sleep_music.attr) 2399172ce0a9SAzael Avalos exists = (drv->usb_sleep_music_supported) ? true : false; 2400bae84195SAzael Avalos else if (attr == &dev_attr_kbd_function_keys.attr) 2401bae84195SAzael Avalos exists = (drv->kbd_function_keys_supported) ? true : false; 240235d53ceaSAzael Avalos else if (attr == &dev_attr_panel_power_on.attr) 240335d53ceaSAzael Avalos exists = (drv->panel_power_on_supported) ? true : false; 240417fe4b3dSAzael Avalos else if (attr == &dev_attr_usb_three.attr) 240517fe4b3dSAzael Avalos exists = (drv->usb_three_supported) ? true : false; 2406b1009b91SAzael Avalos else if (attr == &dev_attr_cooling_method.attr) 2407b1009b91SAzael Avalos exists = (drv->cooling_method_supported) ? true : false; 2408360f0f39SAzael Avalos 2409360f0f39SAzael Avalos return exists ? attr->mode : 0; 2410360f0f39SAzael Avalos } 2411360f0f39SAzael Avalos 241244bd76d0SArvind Yadav static const struct attribute_group toshiba_attr_group = { 24139bd1213bSAzael Avalos .is_visible = toshiba_sysfs_is_visible, 24149bd1213bSAzael Avalos .attrs = toshiba_attributes, 24159bd1213bSAzael Avalos }; 24169bd1213bSAzael Avalos 241765e3cf9cSAzael Avalos static void toshiba_acpi_kbd_bl_work(struct work_struct *work) 241865e3cf9cSAzael Avalos { 241965e3cf9cSAzael Avalos /* Update the sysfs entries */ 2420147288e6SAzael Avalos if (sysfs_update_group(&toshiba_acpi->acpi_dev->dev.kobj, 242165e3cf9cSAzael Avalos &toshiba_attr_group)) 242265e3cf9cSAzael Avalos pr_err("Unable to update sysfs entries\n"); 242365e3cf9cSAzael Avalos 2424147288e6SAzael Avalos /* Notify LED subsystem about keyboard backlight change */ 2425147288e6SAzael Avalos if (toshiba_acpi->kbd_type == 2 && 2426147288e6SAzael Avalos toshiba_acpi->kbd_mode != SCI_KBD_MODE_AUTO) 2427147288e6SAzael Avalos led_classdev_notify_brightness_hw_changed(&toshiba_acpi->kbd_led, 2428147288e6SAzael Avalos (toshiba_acpi->kbd_mode == SCI_KBD_MODE_ON) ? 2429147288e6SAzael Avalos LED_FULL : LED_OFF); 2430147288e6SAzael Avalos 243165e3cf9cSAzael Avalos /* Emulate the keyboard backlight event */ 2432147288e6SAzael Avalos acpi_bus_generate_netlink_event(toshiba_acpi->acpi_dev->pnp.device_class, 2433147288e6SAzael Avalos dev_name(&toshiba_acpi->acpi_dev->dev), 243465e3cf9cSAzael Avalos 0x92, 0); 243565e3cf9cSAzael Avalos } 243665e3cf9cSAzael Avalos 24371f28f290SAzael Avalos /* 243898010f1eSAzael Avalos * IIO device 243998010f1eSAzael Avalos */ 244098010f1eSAzael Avalos 244198010f1eSAzael Avalos enum toshiba_iio_accel_chan { 244298010f1eSAzael Avalos AXIS_X, 244398010f1eSAzael Avalos AXIS_Y, 244498010f1eSAzael Avalos AXIS_Z 244598010f1eSAzael Avalos }; 244698010f1eSAzael Avalos 244798010f1eSAzael Avalos static int toshiba_iio_accel_get_axis(enum toshiba_iio_accel_chan chan) 244898010f1eSAzael Avalos { 244998010f1eSAzael Avalos u32 xyval, zval; 245098010f1eSAzael Avalos int ret; 245198010f1eSAzael Avalos 245298010f1eSAzael Avalos ret = toshiba_accelerometer_get(toshiba_acpi, &xyval, &zval); 245398010f1eSAzael Avalos if (ret < 0) 245498010f1eSAzael Avalos return ret; 245598010f1eSAzael Avalos 245698010f1eSAzael Avalos switch (chan) { 245798010f1eSAzael Avalos case AXIS_X: 245898010f1eSAzael Avalos return xyval & HCI_ACCEL_DIRECTION_MASK ? 245998010f1eSAzael Avalos -(xyval & HCI_ACCEL_MASK) : xyval & HCI_ACCEL_MASK; 246098010f1eSAzael Avalos case AXIS_Y: 246198010f1eSAzael Avalos return (xyval >> HCI_MISC_SHIFT) & HCI_ACCEL_DIRECTION_MASK ? 246298010f1eSAzael Avalos -((xyval >> HCI_MISC_SHIFT) & HCI_ACCEL_MASK) : 246398010f1eSAzael Avalos (xyval >> HCI_MISC_SHIFT) & HCI_ACCEL_MASK; 246498010f1eSAzael Avalos case AXIS_Z: 246598010f1eSAzael Avalos return zval & HCI_ACCEL_DIRECTION_MASK ? 246698010f1eSAzael Avalos -(zval & HCI_ACCEL_MASK) : zval & HCI_ACCEL_MASK; 246798010f1eSAzael Avalos } 246898010f1eSAzael Avalos 246998010f1eSAzael Avalos return ret; 247098010f1eSAzael Avalos } 247198010f1eSAzael Avalos 247298010f1eSAzael Avalos static int toshiba_iio_accel_read_raw(struct iio_dev *indio_dev, 247398010f1eSAzael Avalos struct iio_chan_spec const *chan, 247498010f1eSAzael Avalos int *val, int *val2, long mask) 247598010f1eSAzael Avalos { 247698010f1eSAzael Avalos int ret; 247798010f1eSAzael Avalos 247898010f1eSAzael Avalos switch (mask) { 247998010f1eSAzael Avalos case IIO_CHAN_INFO_RAW: 248098010f1eSAzael Avalos ret = toshiba_iio_accel_get_axis(chan->channel); 248198010f1eSAzael Avalos if (ret == -EIO || ret == -ENODEV) 248298010f1eSAzael Avalos return ret; 248398010f1eSAzael Avalos 248498010f1eSAzael Avalos *val = ret; 248598010f1eSAzael Avalos 248698010f1eSAzael Avalos return IIO_VAL_INT; 248798010f1eSAzael Avalos } 248898010f1eSAzael Avalos 248998010f1eSAzael Avalos return -EINVAL; 249098010f1eSAzael Avalos } 249198010f1eSAzael Avalos 249298010f1eSAzael Avalos #define TOSHIBA_IIO_ACCEL_CHANNEL(axis, chan) { \ 249398010f1eSAzael Avalos .type = IIO_ACCEL, \ 249498010f1eSAzael Avalos .modified = 1, \ 249598010f1eSAzael Avalos .channel = chan, \ 249698010f1eSAzael Avalos .channel2 = IIO_MOD_##axis, \ 249798010f1eSAzael Avalos .output = 1, \ 249898010f1eSAzael Avalos .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 249998010f1eSAzael Avalos } 250098010f1eSAzael Avalos 250198010f1eSAzael Avalos static const struct iio_chan_spec toshiba_iio_accel_channels[] = { 250298010f1eSAzael Avalos TOSHIBA_IIO_ACCEL_CHANNEL(X, AXIS_X), 250398010f1eSAzael Avalos TOSHIBA_IIO_ACCEL_CHANNEL(Y, AXIS_Y), 250498010f1eSAzael Avalos TOSHIBA_IIO_ACCEL_CHANNEL(Z, AXIS_Z), 250598010f1eSAzael Avalos }; 250698010f1eSAzael Avalos 250798010f1eSAzael Avalos static const struct iio_info toshiba_iio_accel_info = { 250898010f1eSAzael Avalos .read_raw = &toshiba_iio_accel_read_raw, 250998010f1eSAzael Avalos }; 251098010f1eSAzael Avalos 251198010f1eSAzael Avalos /* 2512fc5462f8SAzael Avalos * Misc device 2513fc5462f8SAzael Avalos */ 2514fc5462f8SAzael Avalos static int toshiba_acpi_smm_bridge(SMMRegisters *regs) 2515fc5462f8SAzael Avalos { 2516fc5462f8SAzael Avalos u32 in[TCI_WORDS] = { regs->eax, regs->ebx, regs->ecx, 2517fc5462f8SAzael Avalos regs->edx, regs->esi, regs->edi }; 2518fc5462f8SAzael Avalos u32 out[TCI_WORDS]; 2519fc5462f8SAzael Avalos acpi_status status; 2520fc5462f8SAzael Avalos 2521fc5462f8SAzael Avalos status = tci_raw(toshiba_acpi, in, out); 2522fc5462f8SAzael Avalos if (ACPI_FAILURE(status)) { 2523fc5462f8SAzael Avalos pr_err("ACPI call to query SMM registers failed\n"); 2524fc5462f8SAzael Avalos return -EIO; 2525fc5462f8SAzael Avalos } 2526fc5462f8SAzael Avalos 2527fc5462f8SAzael Avalos /* Fillout the SMM struct with the TCI call results */ 2528fc5462f8SAzael Avalos regs->eax = out[0]; 2529fc5462f8SAzael Avalos regs->ebx = out[1]; 2530fc5462f8SAzael Avalos regs->ecx = out[2]; 2531fc5462f8SAzael Avalos regs->edx = out[3]; 2532fc5462f8SAzael Avalos regs->esi = out[4]; 2533fc5462f8SAzael Avalos regs->edi = out[5]; 2534fc5462f8SAzael Avalos 2535fc5462f8SAzael Avalos return 0; 2536fc5462f8SAzael Avalos } 2537fc5462f8SAzael Avalos 2538fc5462f8SAzael Avalos static long toshiba_acpi_ioctl(struct file *fp, unsigned int cmd, 2539fc5462f8SAzael Avalos unsigned long arg) 2540fc5462f8SAzael Avalos { 2541fc5462f8SAzael Avalos SMMRegisters __user *argp = (SMMRegisters __user *)arg; 2542fc5462f8SAzael Avalos SMMRegisters regs; 2543fc5462f8SAzael Avalos int ret; 2544fc5462f8SAzael Avalos 2545fc5462f8SAzael Avalos if (!argp) 2546fc5462f8SAzael Avalos return -EINVAL; 2547fc5462f8SAzael Avalos 2548fc5462f8SAzael Avalos switch (cmd) { 2549fc5462f8SAzael Avalos case TOSH_SMM: 2550fc5462f8SAzael Avalos if (copy_from_user(®s, argp, sizeof(SMMRegisters))) 2551fc5462f8SAzael Avalos return -EFAULT; 2552fc5462f8SAzael Avalos ret = toshiba_acpi_smm_bridge(®s); 2553fc5462f8SAzael Avalos if (ret) 2554fc5462f8SAzael Avalos return ret; 2555fc5462f8SAzael Avalos if (copy_to_user(argp, ®s, sizeof(SMMRegisters))) 2556fc5462f8SAzael Avalos return -EFAULT; 2557fc5462f8SAzael Avalos break; 2558fc5462f8SAzael Avalos case TOSHIBA_ACPI_SCI: 2559fc5462f8SAzael Avalos if (copy_from_user(®s, argp, sizeof(SMMRegisters))) 2560fc5462f8SAzael Avalos return -EFAULT; 2561fc5462f8SAzael Avalos /* Ensure we are being called with a SCI_{GET, SET} register */ 2562fc5462f8SAzael Avalos if (regs.eax != SCI_GET && regs.eax != SCI_SET) 2563fc5462f8SAzael Avalos return -EINVAL; 2564fc5462f8SAzael Avalos if (!sci_open(toshiba_acpi)) 2565fc5462f8SAzael Avalos return -EIO; 2566fc5462f8SAzael Avalos ret = toshiba_acpi_smm_bridge(®s); 2567fc5462f8SAzael Avalos sci_close(toshiba_acpi); 2568fc5462f8SAzael Avalos if (ret) 2569fc5462f8SAzael Avalos return ret; 2570fc5462f8SAzael Avalos if (copy_to_user(argp, ®s, sizeof(SMMRegisters))) 2571fc5462f8SAzael Avalos return -EFAULT; 2572fc5462f8SAzael Avalos break; 2573fc5462f8SAzael Avalos default: 2574fc5462f8SAzael Avalos return -EINVAL; 2575fc5462f8SAzael Avalos } 2576fc5462f8SAzael Avalos 2577fc5462f8SAzael Avalos return 0; 2578fc5462f8SAzael Avalos } 2579fc5462f8SAzael Avalos 2580fc5462f8SAzael Avalos static const struct file_operations toshiba_acpi_fops = { 2581fc5462f8SAzael Avalos .owner = THIS_MODULE, 2582fc5462f8SAzael Avalos .unlocked_ioctl = toshiba_acpi_ioctl, 2583fc5462f8SAzael Avalos .llseek = noop_llseek, 2584fc5462f8SAzael Avalos }; 2585fc5462f8SAzael Avalos 2586fc5462f8SAzael Avalos /* 25872fdde834SAzael Avalos * WWAN RFKill handlers 25882fdde834SAzael Avalos */ 25892fdde834SAzael Avalos static int toshiba_acpi_wwan_set_block(void *data, bool blocked) 25902fdde834SAzael Avalos { 25912fdde834SAzael Avalos struct toshiba_acpi_dev *dev = data; 25922fdde834SAzael Avalos int ret; 25932fdde834SAzael Avalos 25942fdde834SAzael Avalos ret = toshiba_wireless_status(dev); 25952fdde834SAzael Avalos if (ret) 25962fdde834SAzael Avalos return ret; 25972fdde834SAzael Avalos 25982fdde834SAzael Avalos if (!dev->killswitch) 25992fdde834SAzael Avalos return 0; 26002fdde834SAzael Avalos 26012fdde834SAzael Avalos return toshiba_wwan_set(dev, !blocked); 26022fdde834SAzael Avalos } 26032fdde834SAzael Avalos 26042fdde834SAzael Avalos static void toshiba_acpi_wwan_poll(struct rfkill *rfkill, void *data) 26052fdde834SAzael Avalos { 26062fdde834SAzael Avalos struct toshiba_acpi_dev *dev = data; 26072fdde834SAzael Avalos 26082fdde834SAzael Avalos if (toshiba_wireless_status(dev)) 26092fdde834SAzael Avalos return; 26102fdde834SAzael Avalos 26112fdde834SAzael Avalos rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch); 26122fdde834SAzael Avalos } 26132fdde834SAzael Avalos 26142fdde834SAzael Avalos static const struct rfkill_ops wwan_rfk_ops = { 26152fdde834SAzael Avalos .set_block = toshiba_acpi_wwan_set_block, 26162fdde834SAzael Avalos .poll = toshiba_acpi_wwan_poll, 26172fdde834SAzael Avalos }; 26182fdde834SAzael Avalos 26192fdde834SAzael Avalos static int toshiba_acpi_setup_wwan_rfkill(struct toshiba_acpi_dev *dev) 26202fdde834SAzael Avalos { 26212fdde834SAzael Avalos int ret = toshiba_wireless_status(dev); 26222fdde834SAzael Avalos 26232fdde834SAzael Avalos if (ret) 26242fdde834SAzael Avalos return ret; 26252fdde834SAzael Avalos 26262fdde834SAzael Avalos dev->wwan_rfk = rfkill_alloc("Toshiba WWAN", 26272fdde834SAzael Avalos &dev->acpi_dev->dev, 26282fdde834SAzael Avalos RFKILL_TYPE_WWAN, 26292fdde834SAzael Avalos &wwan_rfk_ops, 26302fdde834SAzael Avalos dev); 26312fdde834SAzael Avalos if (!dev->wwan_rfk) { 26322fdde834SAzael Avalos pr_err("Unable to allocate WWAN rfkill device\n"); 26332fdde834SAzael Avalos return -ENOMEM; 26342fdde834SAzael Avalos } 26352fdde834SAzael Avalos 26362fdde834SAzael Avalos rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch); 26372fdde834SAzael Avalos 26382fdde834SAzael Avalos ret = rfkill_register(dev->wwan_rfk); 26392fdde834SAzael Avalos if (ret) { 26402fdde834SAzael Avalos pr_err("Unable to register WWAN rfkill device\n"); 26412fdde834SAzael Avalos rfkill_destroy(dev->wwan_rfk); 26422fdde834SAzael Avalos } 26432fdde834SAzael Avalos 26442fdde834SAzael Avalos return ret; 26452fdde834SAzael Avalos } 26462fdde834SAzael Avalos 26472fdde834SAzael Avalos /* 26481f28f290SAzael Avalos * Hotkeys 26491f28f290SAzael Avalos */ 26501f28f290SAzael Avalos static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev) 26511f28f290SAzael Avalos { 26521f28f290SAzael Avalos acpi_status status; 26531f28f290SAzael Avalos u32 result; 26541f28f290SAzael Avalos 26551f28f290SAzael Avalos status = acpi_evaluate_object(dev->acpi_dev->handle, 26561f28f290SAzael Avalos "ENAB", NULL, NULL); 26571f28f290SAzael Avalos if (ACPI_FAILURE(status)) 26581f28f290SAzael Avalos return -ENODEV; 26591f28f290SAzael Avalos 2660b116fd00SAzael Avalos /* 2661b116fd00SAzael Avalos * Enable the "Special Functions" mode only if they are 2662b116fd00SAzael Avalos * supported and if they are activated. 2663b116fd00SAzael Avalos */ 2664b116fd00SAzael Avalos if (dev->kbd_function_keys_supported && dev->special_functions) 2665b116fd00SAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, 2666b116fd00SAzael Avalos HCI_HOTKEY_SPECIAL_FUNCTIONS); 2667b116fd00SAzael Avalos else 2668d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE); 2669b116fd00SAzael Avalos 26701f28f290SAzael Avalos if (result == TOS_FAILURE) 26711f28f290SAzael Avalos return -EIO; 26721f28f290SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 26731f28f290SAzael Avalos return -ENODEV; 26741f28f290SAzael Avalos 26751f28f290SAzael Avalos return 0; 26761f28f290SAzael Avalos } 26771f28f290SAzael Avalos 267829cd293fSSeth Forshee static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, 267929cd293fSSeth Forshee struct serio *port) 268029cd293fSSeth Forshee { 268198280374SGiedrius Statkevičius if (str & I8042_STR_AUXDATA) 268229cd293fSSeth Forshee return false; 268329cd293fSSeth Forshee 268429cd293fSSeth Forshee if (unlikely(data == 0xe0)) 268529cd293fSSeth Forshee return false; 268629cd293fSSeth Forshee 268729cd293fSSeth Forshee if ((data & 0x7f) == TOS1900_FN_SCAN) { 268829cd293fSSeth Forshee schedule_work(&toshiba_acpi->hotkey_work); 268929cd293fSSeth Forshee return true; 269029cd293fSSeth Forshee } 269129cd293fSSeth Forshee 269229cd293fSSeth Forshee return false; 269329cd293fSSeth Forshee } 269429cd293fSSeth Forshee 269529cd293fSSeth Forshee static void toshiba_acpi_hotkey_work(struct work_struct *work) 269629cd293fSSeth Forshee { 269729cd293fSSeth Forshee acpi_handle ec_handle = ec_get_handle(); 269829cd293fSSeth Forshee acpi_status status; 269929cd293fSSeth Forshee 270029cd293fSSeth Forshee if (!ec_handle) 270129cd293fSSeth Forshee return; 270229cd293fSSeth Forshee 270329cd293fSSeth Forshee status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL); 270429cd293fSSeth Forshee if (ACPI_FAILURE(status)) 270529cd293fSSeth Forshee pr_err("ACPI NTFY method execution failed\n"); 270629cd293fSSeth Forshee } 270729cd293fSSeth Forshee 270829cd293fSSeth Forshee /* 270929cd293fSSeth Forshee * Returns hotkey scancode, or < 0 on failure. 271029cd293fSSeth Forshee */ 271129cd293fSSeth Forshee static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev) 271229cd293fSSeth Forshee { 271374facaf7SZhang Rui unsigned long long value; 271429cd293fSSeth Forshee acpi_status status; 271529cd293fSSeth Forshee 271674facaf7SZhang Rui status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO", 271774facaf7SZhang Rui NULL, &value); 271874facaf7SZhang Rui if (ACPI_FAILURE(status)) { 271929cd293fSSeth Forshee pr_err("ACPI INFO method execution failed\n"); 272029cd293fSSeth Forshee return -EIO; 272129cd293fSSeth Forshee } 272229cd293fSSeth Forshee 272374facaf7SZhang Rui return value; 272429cd293fSSeth Forshee } 272529cd293fSSeth Forshee 272629cd293fSSeth Forshee static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev, 272729cd293fSSeth Forshee int scancode) 272829cd293fSSeth Forshee { 272929cd293fSSeth Forshee if (scancode == 0x100) 273029cd293fSSeth Forshee return; 273129cd293fSSeth Forshee 2732e0769fe6SDarren Hart /* Act on key press; ignore key release */ 273329cd293fSSeth Forshee if (scancode & 0x80) 273429cd293fSSeth Forshee return; 273529cd293fSSeth Forshee 273629cd293fSSeth Forshee if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true)) 273729cd293fSSeth Forshee pr_info("Unknown key %x\n", scancode); 273829cd293fSSeth Forshee } 273929cd293fSSeth Forshee 274071454d78SAzael Avalos static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) 274171454d78SAzael Avalos { 274271454d78SAzael Avalos if (dev->info_supported) { 27437deef550SAzael Avalos int scancode = toshiba_acpi_query_hotkey(dev); 27447deef550SAzael Avalos 27457deef550SAzael Avalos if (scancode < 0) { 274671454d78SAzael Avalos pr_err("Failed to query hotkey event\n"); 27477deef550SAzael Avalos } else if (scancode != 0) { 274871454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, scancode); 27497deef550SAzael Avalos dev->key_event_valid = 1; 27507deef550SAzael Avalos dev->last_key_event = scancode; 27517deef550SAzael Avalos } 275271454d78SAzael Avalos } else if (dev->system_event_supported) { 27537deef550SAzael Avalos u32 result; 27547deef550SAzael Avalos u32 value; 27557deef550SAzael Avalos int retries = 3; 27567deef550SAzael Avalos 275771454d78SAzael Avalos do { 27587deef550SAzael Avalos result = hci_read(dev, HCI_SYSTEM_EVENT, &value); 27597deef550SAzael Avalos switch (result) { 276071454d78SAzael Avalos case TOS_SUCCESS: 276171454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, (int)value); 27627deef550SAzael Avalos dev->key_event_valid = 1; 27637deef550SAzael Avalos dev->last_key_event = value; 276471454d78SAzael Avalos break; 276571454d78SAzael Avalos case TOS_NOT_SUPPORTED: 276671454d78SAzael Avalos /* 276771454d78SAzael Avalos * This is a workaround for an unresolved 276871454d78SAzael Avalos * issue on some machines where system events 276971454d78SAzael Avalos * sporadically become disabled. 277071454d78SAzael Avalos */ 27717deef550SAzael Avalos result = hci_write(dev, HCI_SYSTEM_EVENT, 1); 27727deef550SAzael Avalos if (result == TOS_SUCCESS) 277371454d78SAzael Avalos pr_notice("Re-enabled hotkeys\n"); 2774df561f66SGustavo A. R. Silva fallthrough; 277571454d78SAzael Avalos default: 277671454d78SAzael Avalos retries--; 277771454d78SAzael Avalos break; 277871454d78SAzael Avalos } 27797deef550SAzael Avalos } while (retries && result != TOS_FIFO_EMPTY); 278071454d78SAzael Avalos } 278171454d78SAzael Avalos } 278271454d78SAzael Avalos 2783b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) 27846335e4d5SMatthew Garrett { 2785fe808bfbSTakashi Iwai const struct key_entry *keymap = toshiba_acpi_keymap; 2786a2b3471bSAzael Avalos acpi_handle ec_handle; 2787a2b3471bSAzael Avalos int error; 2788a2b3471bSAzael Avalos 27897faa6a37SAzael Avalos if (disable_hotkeys) { 27907faa6a37SAzael Avalos pr_info("Hotkeys disabled by module parameter\n"); 27917faa6a37SAzael Avalos return 0; 27927faa6a37SAzael Avalos } 27937faa6a37SAzael Avalos 2794a88bc06eSAzael Avalos if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) { 2795a88bc06eSAzael Avalos pr_info("WMI event detected, hotkeys will not be monitored\n"); 2796a88bc06eSAzael Avalos return 0; 2797a88bc06eSAzael Avalos } 2798a88bc06eSAzael Avalos 2799a2b3471bSAzael Avalos error = toshiba_acpi_enable_hotkeys(dev); 2800a2b3471bSAzael Avalos if (error) 2801a2b3471bSAzael Avalos return error; 2802a2b3471bSAzael Avalos 280310e6aaabSAzael Avalos if (toshiba_hotkey_event_type_get(dev, &dev->hotkey_event_type)) 280453147b6cSAzael Avalos pr_notice("Unable to query Hotkey Event Type\n"); 280553147b6cSAzael Avalos 2806135740deSSeth Forshee dev->hotkey_dev = input_allocate_device(); 2807b222cca6SJoe Perches if (!dev->hotkey_dev) 2808135740deSSeth Forshee return -ENOMEM; 2809135740deSSeth Forshee 2810135740deSSeth Forshee dev->hotkey_dev->name = "Toshiba input device"; 28116e02cc7eSSeth Forshee dev->hotkey_dev->phys = "toshiba_acpi/input0"; 2812135740deSSeth Forshee dev->hotkey_dev->id.bustype = BUS_HOST; 2813135740deSSeth Forshee 281410e6aaabSAzael Avalos if (dev->hotkey_event_type == HCI_SYSTEM_TYPE1 || 2815a2b3471bSAzael Avalos !dev->kbd_function_keys_supported) 2816a2b3471bSAzael Avalos keymap = toshiba_acpi_keymap; 281710e6aaabSAzael Avalos else if (dev->hotkey_event_type == HCI_SYSTEM_TYPE2 || 2818a2b3471bSAzael Avalos dev->kbd_function_keys_supported) 2819fe808bfbSTakashi Iwai keymap = toshiba_acpi_alt_keymap; 2820a2b3471bSAzael Avalos else 282110e6aaabSAzael Avalos pr_info("Unknown event type received %x\n", 282210e6aaabSAzael Avalos dev->hotkey_event_type); 2823fe808bfbSTakashi Iwai error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL); 2824135740deSSeth Forshee if (error) 2825135740deSSeth Forshee goto err_free_dev; 2826135740deSSeth Forshee 282729cd293fSSeth Forshee /* 282829cd293fSSeth Forshee * For some machines the SCI responsible for providing hotkey 282929cd293fSSeth Forshee * notification doesn't fire. We can trigger the notification 283029cd293fSSeth Forshee * whenever the Fn key is pressed using the NTFY method, if 283129cd293fSSeth Forshee * supported, so if it's present set up an i8042 key filter 283229cd293fSSeth Forshee * for this purpose. 283329cd293fSSeth Forshee */ 283429cd293fSSeth Forshee ec_handle = ec_get_handle(); 2835e2e19606SZhang Rui if (ec_handle && acpi_has_method(ec_handle, "NTFY")) { 283629cd293fSSeth Forshee INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work); 283729cd293fSSeth Forshee 283829cd293fSSeth Forshee error = i8042_install_filter(toshiba_acpi_i8042_filter); 283929cd293fSSeth Forshee if (error) { 284029cd293fSSeth Forshee pr_err("Error installing key filter\n"); 2841db8f95d0SMichał Kępień goto err_free_dev; 284229cd293fSSeth Forshee } 284329cd293fSSeth Forshee 284429cd293fSSeth Forshee dev->ntfy_supported = 1; 284529cd293fSSeth Forshee } 284629cd293fSSeth Forshee 284729cd293fSSeth Forshee /* 284829cd293fSSeth Forshee * Determine hotkey query interface. Prefer using the INFO 284929cd293fSSeth Forshee * method when it is available. 285029cd293fSSeth Forshee */ 2851e2e19606SZhang Rui if (acpi_has_method(dev->acpi_dev->handle, "INFO")) 285229cd293fSSeth Forshee dev->info_supported = 1; 285310e6aaabSAzael Avalos else if (hci_write(dev, HCI_SYSTEM_EVENT, 1) == TOS_SUCCESS) 285429cd293fSSeth Forshee dev->system_event_supported = 1; 285529cd293fSSeth Forshee 285629cd293fSSeth Forshee if (!dev->info_supported && !dev->system_event_supported) { 285729cd293fSSeth Forshee pr_warn("No hotkey query interface found\n"); 285828e36712SJiapeng Chong error = -EINVAL; 285929cd293fSSeth Forshee goto err_remove_filter; 286029cd293fSSeth Forshee } 286129cd293fSSeth Forshee 2862135740deSSeth Forshee error = input_register_device(dev->hotkey_dev); 2863135740deSSeth Forshee if (error) { 2864135740deSSeth Forshee pr_info("Unable to register input device\n"); 286529cd293fSSeth Forshee goto err_remove_filter; 2866135740deSSeth Forshee } 2867135740deSSeth Forshee 2868135740deSSeth Forshee return 0; 2869135740deSSeth Forshee 287029cd293fSSeth Forshee err_remove_filter: 287129cd293fSSeth Forshee if (dev->ntfy_supported) 287229cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 2873135740deSSeth Forshee err_free_dev: 2874135740deSSeth Forshee input_free_device(dev->hotkey_dev); 2875135740deSSeth Forshee dev->hotkey_dev = NULL; 2876135740deSSeth Forshee return error; 2877135740deSSeth Forshee } 2878135740deSSeth Forshee 2879b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) 288062cce752SSeth Forshee { 288162cce752SSeth Forshee struct backlight_properties props; 288262cce752SSeth Forshee int brightness; 288362cce752SSeth Forshee int ret; 288462cce752SSeth Forshee 288562cce752SSeth Forshee /* 288662cce752SSeth Forshee * Some machines don't support the backlight methods at all, and 288762cce752SSeth Forshee * others support it read-only. Either of these is pretty useless, 288862cce752SSeth Forshee * so only register the backlight device if the backlight method 288962cce752SSeth Forshee * supports both reads and writes. 289062cce752SSeth Forshee */ 289162cce752SSeth Forshee brightness = __get_lcd_brightness(dev); 289262cce752SSeth Forshee if (brightness < 0) 289362cce752SSeth Forshee return 0; 2894bae5336fSAzael Avalos /* 2895bae5336fSAzael Avalos * If transflective backlight is supported and the brightness is zero 2896bae5336fSAzael Avalos * (lowest brightness level), the set_lcd_brightness function will 2897bae5336fSAzael Avalos * activate the transflective backlight, making the LCD appear to be 2898bae5336fSAzael Avalos * turned off, simply increment the brightness level to avoid that. 2899bae5336fSAzael Avalos */ 2900bae5336fSAzael Avalos if (dev->tr_backlight_supported && brightness == 0) 2901bae5336fSAzael Avalos brightness++; 290262cce752SSeth Forshee ret = set_lcd_brightness(dev, brightness); 290362cce752SSeth Forshee if (ret) { 290462cce752SSeth Forshee pr_debug("Backlight method is read-only, disabling backlight support\n"); 290562cce752SSeth Forshee return 0; 290662cce752SSeth Forshee } 290762cce752SSeth Forshee 2908234b7cf8SHans de Goede if (acpi_video_get_backlight_type() != acpi_backlight_vendor) 2909358d6a2cSHans de Goede return 0; 2910358d6a2cSHans de Goede 291153039f22SMatthew Garrett memset(&props, 0, sizeof(props)); 291262cce752SSeth Forshee props.type = BACKLIGHT_PLATFORM; 291362cce752SSeth Forshee props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; 291462cce752SSeth Forshee 2915e0769fe6SDarren Hart /* Adding an extra level and having 0 change to transflective mode */ 2916121b7b0dSAkio Idehara if (dev->tr_backlight_supported) 2917121b7b0dSAkio Idehara props.max_brightness++; 2918121b7b0dSAkio Idehara 291962cce752SSeth Forshee dev->backlight_dev = backlight_device_register("toshiba", 292062cce752SSeth Forshee &dev->acpi_dev->dev, 292162cce752SSeth Forshee dev, 292262cce752SSeth Forshee &toshiba_backlight_data, 292362cce752SSeth Forshee &props); 292462cce752SSeth Forshee if (IS_ERR(dev->backlight_dev)) { 292562cce752SSeth Forshee ret = PTR_ERR(dev->backlight_dev); 292662cce752SSeth Forshee pr_err("Could not register toshiba backlight device\n"); 292762cce752SSeth Forshee dev->backlight_dev = NULL; 292862cce752SSeth Forshee return ret; 292962cce752SSeth Forshee } 293062cce752SSeth Forshee 293162cce752SSeth Forshee dev->backlight_dev->props.brightness = brightness; 293262cce752SSeth Forshee return 0; 293362cce752SSeth Forshee } 293462cce752SSeth Forshee 2935*c727ba4cSArvid Norlander /* HWMON support for fan */ 2936*c727ba4cSArvid Norlander #if IS_ENABLED(CONFIG_HWMON) 2937*c727ba4cSArvid Norlander static umode_t toshiba_acpi_hwmon_is_visible(const void *drvdata, 2938*c727ba4cSArvid Norlander enum hwmon_sensor_types type, 2939*c727ba4cSArvid Norlander u32 attr, int channel) 2940*c727ba4cSArvid Norlander { 2941*c727ba4cSArvid Norlander return 0444; 2942*c727ba4cSArvid Norlander } 2943*c727ba4cSArvid Norlander 2944*c727ba4cSArvid Norlander static int toshiba_acpi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, 2945*c727ba4cSArvid Norlander u32 attr, int channel, long *val) 2946*c727ba4cSArvid Norlander { 2947*c727ba4cSArvid Norlander /* 2948*c727ba4cSArvid Norlander * There is only a single channel and single attribute (for the 2949*c727ba4cSArvid Norlander * fan) at this point. 2950*c727ba4cSArvid Norlander * This can be replaced with more advanced logic in the future, 2951*c727ba4cSArvid Norlander * should the need arise. 2952*c727ba4cSArvid Norlander */ 2953*c727ba4cSArvid Norlander if (type == hwmon_fan && channel == 0 && attr == hwmon_fan_input) { 2954*c727ba4cSArvid Norlander u32 value; 2955*c727ba4cSArvid Norlander int ret; 2956*c727ba4cSArvid Norlander 2957*c727ba4cSArvid Norlander ret = get_fan_rpm(toshiba_acpi, &value); 2958*c727ba4cSArvid Norlander if (ret) 2959*c727ba4cSArvid Norlander return ret; 2960*c727ba4cSArvid Norlander 2961*c727ba4cSArvid Norlander *val = value; 2962*c727ba4cSArvid Norlander return 0; 2963*c727ba4cSArvid Norlander } 2964*c727ba4cSArvid Norlander return -EOPNOTSUPP; 2965*c727ba4cSArvid Norlander } 2966*c727ba4cSArvid Norlander 2967*c727ba4cSArvid Norlander static const struct hwmon_channel_info *toshiba_acpi_hwmon_info[] = { 2968*c727ba4cSArvid Norlander HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT), 2969*c727ba4cSArvid Norlander NULL 2970*c727ba4cSArvid Norlander }; 2971*c727ba4cSArvid Norlander 2972*c727ba4cSArvid Norlander static const struct hwmon_ops toshiba_acpi_hwmon_ops = { 2973*c727ba4cSArvid Norlander .is_visible = toshiba_acpi_hwmon_is_visible, 2974*c727ba4cSArvid Norlander .read = toshiba_acpi_hwmon_read, 2975*c727ba4cSArvid Norlander }; 2976*c727ba4cSArvid Norlander 2977*c727ba4cSArvid Norlander static const struct hwmon_chip_info toshiba_acpi_hwmon_chip_info = { 2978*c727ba4cSArvid Norlander .ops = &toshiba_acpi_hwmon_ops, 2979*c727ba4cSArvid Norlander .info = toshiba_acpi_hwmon_info, 2980*c727ba4cSArvid Norlander }; 2981*c727ba4cSArvid Norlander #endif 2982*c727ba4cSArvid Norlander 29830409cbceSAzael Avalos static void print_supported_features(struct toshiba_acpi_dev *dev) 29840409cbceSAzael Avalos { 29850409cbceSAzael Avalos pr_info("Supported laptop features:"); 29860409cbceSAzael Avalos 29870409cbceSAzael Avalos if (dev->hotkey_dev) 29880409cbceSAzael Avalos pr_cont(" hotkeys"); 29890409cbceSAzael Avalos if (dev->backlight_dev) 29900409cbceSAzael Avalos pr_cont(" backlight"); 29910409cbceSAzael Avalos if (dev->video_supported) 29920409cbceSAzael Avalos pr_cont(" video-out"); 29930409cbceSAzael Avalos if (dev->fan_supported) 29940409cbceSAzael Avalos pr_cont(" fan"); 2995dd193dcdSArvid Norlander if (dev->fan_rpm_supported) 2996dd193dcdSArvid Norlander pr_cont(" fan-rpm"); 29970409cbceSAzael Avalos if (dev->tr_backlight_supported) 29980409cbceSAzael Avalos pr_cont(" transflective-backlight"); 29990409cbceSAzael Avalos if (dev->illumination_supported) 30000409cbceSAzael Avalos pr_cont(" illumination"); 30010409cbceSAzael Avalos if (dev->kbd_illum_supported) 30020409cbceSAzael Avalos pr_cont(" keyboard-backlight"); 30030409cbceSAzael Avalos if (dev->touchpad_supported) 30040409cbceSAzael Avalos pr_cont(" touchpad"); 30050409cbceSAzael Avalos if (dev->eco_supported) 30060409cbceSAzael Avalos pr_cont(" eco-led"); 30070409cbceSAzael Avalos if (dev->accelerometer_supported) 30080409cbceSAzael Avalos pr_cont(" accelerometer-axes"); 30090409cbceSAzael Avalos if (dev->usb_sleep_charge_supported) 30100409cbceSAzael Avalos pr_cont(" usb-sleep-charge"); 30110409cbceSAzael Avalos if (dev->usb_rapid_charge_supported) 30120409cbceSAzael Avalos pr_cont(" usb-rapid-charge"); 30130409cbceSAzael Avalos if (dev->usb_sleep_music_supported) 30140409cbceSAzael Avalos pr_cont(" usb-sleep-music"); 30150409cbceSAzael Avalos if (dev->kbd_function_keys_supported) 30160409cbceSAzael Avalos pr_cont(" special-function-keys"); 30170409cbceSAzael Avalos if (dev->panel_power_on_supported) 30180409cbceSAzael Avalos pr_cont(" panel-power-on"); 30190409cbceSAzael Avalos if (dev->usb_three_supported) 30200409cbceSAzael Avalos pr_cont(" usb3"); 30216873f46aSAzael Avalos if (dev->wwan_supported) 30226873f46aSAzael Avalos pr_cont(" wwan"); 3023763ff32fSAzael Avalos if (dev->cooling_method_supported) 3024763ff32fSAzael Avalos pr_cont(" cooling-method"); 30250409cbceSAzael Avalos 30260409cbceSAzael Avalos pr_cont("\n"); 30270409cbceSAzael Avalos } 30280409cbceSAzael Avalos 302951fac838SRafael J. Wysocki static int toshiba_acpi_remove(struct acpi_device *acpi_dev) 3030135740deSSeth Forshee { 3031135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 3032135740deSSeth Forshee 3033fc5462f8SAzael Avalos misc_deregister(&dev->miscdev); 3034fc5462f8SAzael Avalos 303536d03f93SSeth Forshee remove_toshiba_proc_entries(dev); 3036135740deSSeth Forshee 3037*c727ba4cSArvid Norlander #if IS_ENABLED(CONFIG_HWMON) 3038*c727ba4cSArvid Norlander if (dev->hwmon_device) 3039*c727ba4cSArvid Norlander hwmon_device_unregister(dev->hwmon_device); 3040*c727ba4cSArvid Norlander #endif 3041*c727ba4cSArvid Norlander 304298010f1eSAzael Avalos if (dev->accelerometer_supported && dev->indio_dev) { 304398010f1eSAzael Avalos iio_device_unregister(dev->indio_dev); 304498010f1eSAzael Avalos iio_device_free(dev->indio_dev); 304598010f1eSAzael Avalos } 304698010f1eSAzael Avalos 3047360f0f39SAzael Avalos if (dev->sysfs_created) 3048360f0f39SAzael Avalos sysfs_remove_group(&dev->acpi_dev->dev.kobj, 3049360f0f39SAzael Avalos &toshiba_attr_group); 3050360f0f39SAzael Avalos 305129cd293fSSeth Forshee if (dev->ntfy_supported) { 305229cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 305329cd293fSSeth Forshee cancel_work_sync(&dev->hotkey_work); 305429cd293fSSeth Forshee } 305529cd293fSSeth Forshee 3056db8f95d0SMichał Kępień if (dev->hotkey_dev) 3057135740deSSeth Forshee input_unregister_device(dev->hotkey_dev); 3058135740deSSeth Forshee 3059135740deSSeth Forshee backlight_device_unregister(dev->backlight_dev); 3060135740deSSeth Forshee 3061135740deSSeth Forshee led_classdev_unregister(&dev->led_dev); 3062360f0f39SAzael Avalos led_classdev_unregister(&dev->kbd_led); 3063def6c4e2SAzael Avalos led_classdev_unregister(&dev->eco_led); 3064def6c4e2SAzael Avalos 30652fdde834SAzael Avalos if (dev->wwan_rfk) { 30662fdde834SAzael Avalos rfkill_unregister(dev->wwan_rfk); 30672fdde834SAzael Avalos rfkill_destroy(dev->wwan_rfk); 30682fdde834SAzael Avalos } 30692fdde834SAzael Avalos 307029cd293fSSeth Forshee if (toshiba_acpi) 307129cd293fSSeth Forshee toshiba_acpi = NULL; 307229cd293fSSeth Forshee 3073135740deSSeth Forshee kfree(dev); 3074135740deSSeth Forshee 3075135740deSSeth Forshee return 0; 3076135740deSSeth Forshee } 3077135740deSSeth Forshee 3078b859f159SGreg Kroah-Hartman static const char *find_hci_method(acpi_handle handle) 3079a540d6b5SSeth Forshee { 3080e2e19606SZhang Rui if (acpi_has_method(handle, "GHCI")) 3081a540d6b5SSeth Forshee return "GHCI"; 3082a540d6b5SSeth Forshee 3083e2e19606SZhang Rui if (acpi_has_method(handle, "SPFC")) 3084a540d6b5SSeth Forshee return "SPFC"; 3085a540d6b5SSeth Forshee 3086a540d6b5SSeth Forshee return NULL; 3087a540d6b5SSeth Forshee } 3088a540d6b5SSeth Forshee 3089b859f159SGreg Kroah-Hartman static int toshiba_acpi_add(struct acpi_device *acpi_dev) 3090135740deSSeth Forshee { 3091135740deSSeth Forshee struct toshiba_acpi_dev *dev; 3092a540d6b5SSeth Forshee const char *hci_method; 309336d03f93SSeth Forshee u32 dummy; 3094135740deSSeth Forshee int ret = 0; 3095135740deSSeth Forshee 309629cd293fSSeth Forshee if (toshiba_acpi) 309729cd293fSSeth Forshee return -EBUSY; 309829cd293fSSeth Forshee 3099135740deSSeth Forshee pr_info("Toshiba Laptop ACPI Extras version %s\n", 3100135740deSSeth Forshee TOSHIBA_ACPI_VERSION); 3101135740deSSeth Forshee 3102a540d6b5SSeth Forshee hci_method = find_hci_method(acpi_dev->handle); 3103a540d6b5SSeth Forshee if (!hci_method) { 3104a540d6b5SSeth Forshee pr_err("HCI interface not found\n"); 31056e02cc7eSSeth Forshee return -ENODEV; 3106a540d6b5SSeth Forshee } 31076e02cc7eSSeth Forshee 3108135740deSSeth Forshee dev = kzalloc(sizeof(*dev), GFP_KERNEL); 3109135740deSSeth Forshee if (!dev) 3110135740deSSeth Forshee return -ENOMEM; 3111135740deSSeth Forshee dev->acpi_dev = acpi_dev; 3112a540d6b5SSeth Forshee dev->method_hci = hci_method; 3113fc5462f8SAzael Avalos dev->miscdev.minor = MISC_DYNAMIC_MINOR; 3114fc5462f8SAzael Avalos dev->miscdev.name = "toshiba_acpi"; 3115fc5462f8SAzael Avalos dev->miscdev.fops = &toshiba_acpi_fops; 3116fc5462f8SAzael Avalos 3117fc5462f8SAzael Avalos ret = misc_register(&dev->miscdev); 3118fc5462f8SAzael Avalos if (ret) { 3119fc5462f8SAzael Avalos pr_err("Failed to register miscdevice\n"); 3120fc5462f8SAzael Avalos kfree(dev); 3121fc5462f8SAzael Avalos return ret; 3122fc5462f8SAzael Avalos } 3123fc5462f8SAzael Avalos 3124135740deSSeth Forshee acpi_dev->driver_data = dev; 3125360f0f39SAzael Avalos dev_set_drvdata(&acpi_dev->dev, dev); 3126135740deSSeth Forshee 3127a2b3471bSAzael Avalos /* Query the BIOS for supported features */ 3128a2b3471bSAzael Avalos 3129a2b3471bSAzael Avalos /* 3130a2b3471bSAzael Avalos * The "Special Functions" are always supported by the laptops 3131a2b3471bSAzael Avalos * with the new keyboard layout, query for its presence to help 3132a2b3471bSAzael Avalos * determine the keymap layout to use. 3133a2b3471bSAzael Avalos */ 3134b116fd00SAzael Avalos ret = toshiba_function_keys_get(dev, &dev->special_functions); 3135a2b3471bSAzael Avalos dev->kbd_function_keys_supported = !ret; 3136a2b3471bSAzael Avalos 3137d2f20619SAzael Avalos dev->hotkey_event_type = 0; 31386e02cc7eSSeth Forshee if (toshiba_acpi_setup_keyboard(dev)) 3139135740deSSeth Forshee pr_info("Unable to activate hotkeys\n"); 3140135740deSSeth Forshee 3141695f6060SAzael Avalos /* Determine whether or not BIOS supports transflective backlight */ 3142695f6060SAzael Avalos ret = get_tr_backlight_status(dev, &dummy); 3143695f6060SAzael Avalos dev->tr_backlight_supported = !ret; 3144695f6060SAzael Avalos 314562cce752SSeth Forshee ret = toshiba_acpi_setup_backlight(dev); 314662cce752SSeth Forshee if (ret) 3147135740deSSeth Forshee goto error; 3148135740deSSeth Forshee 3149ea215a3fSAzael Avalos toshiba_illumination_available(dev); 3150ea215a3fSAzael Avalos if (dev->illumination_supported) { 3151135740deSSeth Forshee dev->led_dev.name = "toshiba::illumination"; 3152135740deSSeth Forshee dev->led_dev.max_brightness = 1; 3153135740deSSeth Forshee dev->led_dev.brightness_set = toshiba_illumination_set; 3154135740deSSeth Forshee dev->led_dev.brightness_get = toshiba_illumination_get; 3155409f3aedSAndy Shevchenko led_classdev_register(&acpi_dev->dev, &dev->led_dev); 3156135740deSSeth Forshee } 3157135740deSSeth Forshee 3158ea215a3fSAzael Avalos toshiba_eco_mode_available(dev); 3159ea215a3fSAzael Avalos if (dev->eco_supported) { 3160def6c4e2SAzael Avalos dev->eco_led.name = "toshiba::eco_mode"; 3161def6c4e2SAzael Avalos dev->eco_led.max_brightness = 1; 3162def6c4e2SAzael Avalos dev->eco_led.brightness_set = toshiba_eco_mode_set_status; 3163def6c4e2SAzael Avalos dev->eco_led.brightness_get = toshiba_eco_mode_get_status; 3164409f3aedSAndy Shevchenko led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led); 3165def6c4e2SAzael Avalos } 3166def6c4e2SAzael Avalos 3167ea215a3fSAzael Avalos toshiba_kbd_illum_available(dev); 3168360f0f39SAzael Avalos /* 3169360f0f39SAzael Avalos * Only register the LED if KBD illumination is supported 3170360f0f39SAzael Avalos * and the keyboard backlight operation mode is set to FN-Z 3171147288e6SAzael Avalos * or we detect a second gen keyboard backlight 3172360f0f39SAzael Avalos */ 3173147288e6SAzael Avalos if (dev->kbd_illum_supported && 3174147288e6SAzael Avalos (dev->kbd_mode == SCI_KBD_MODE_FNZ || dev->kbd_type == 2)) { 3175360f0f39SAzael Avalos dev->kbd_led.name = "toshiba::kbd_backlight"; 3176147288e6SAzael Avalos dev->kbd_led.flags = LED_BRIGHT_HW_CHANGED; 3177360f0f39SAzael Avalos dev->kbd_led.max_brightness = 1; 3178360f0f39SAzael Avalos dev->kbd_led.brightness_set = toshiba_kbd_backlight_set; 3179360f0f39SAzael Avalos dev->kbd_led.brightness_get = toshiba_kbd_backlight_get; 3180409f3aedSAndy Shevchenko led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led); 3181360f0f39SAzael Avalos } 3182360f0f39SAzael Avalos 31839d8658acSAzael Avalos ret = toshiba_touchpad_get(dev, &dummy); 31849d8658acSAzael Avalos dev->touchpad_supported = !ret; 31859d8658acSAzael Avalos 3186ea215a3fSAzael Avalos toshiba_accelerometer_available(dev); 318798010f1eSAzael Avalos if (dev->accelerometer_supported) { 318878289b4aSAlexandru Ardelean dev->indio_dev = iio_device_alloc(&acpi_dev->dev, sizeof(*dev)); 318998010f1eSAzael Avalos if (!dev->indio_dev) { 319098010f1eSAzael Avalos pr_err("Unable to allocate iio device\n"); 319198010f1eSAzael Avalos goto iio_error; 319298010f1eSAzael Avalos } 319398010f1eSAzael Avalos 319498010f1eSAzael Avalos pr_info("Registering Toshiba accelerometer iio device\n"); 319598010f1eSAzael Avalos 319698010f1eSAzael Avalos dev->indio_dev->info = &toshiba_iio_accel_info; 319798010f1eSAzael Avalos dev->indio_dev->name = "Toshiba accelerometer"; 319898010f1eSAzael Avalos dev->indio_dev->modes = INDIO_DIRECT_MODE; 319998010f1eSAzael Avalos dev->indio_dev->channels = toshiba_iio_accel_channels; 320098010f1eSAzael Avalos dev->indio_dev->num_channels = 320198010f1eSAzael Avalos ARRAY_SIZE(toshiba_iio_accel_channels); 320298010f1eSAzael Avalos 320398010f1eSAzael Avalos ret = iio_device_register(dev->indio_dev); 320498010f1eSAzael Avalos if (ret < 0) { 320598010f1eSAzael Avalos pr_err("Unable to register iio device\n"); 320698010f1eSAzael Avalos iio_device_free(dev->indio_dev); 320798010f1eSAzael Avalos } 320898010f1eSAzael Avalos } 320998010f1eSAzael Avalos iio_error: 32105a2813e9SAzael Avalos 3211c8c91842SAzael Avalos toshiba_usb_sleep_charge_available(dev); 3212e26ffe51SAzael Avalos 3213bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(dev, &dummy); 3214bb3fe01fSAzael Avalos dev->usb_rapid_charge_supported = !ret; 3215bb3fe01fSAzael Avalos 3216172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(dev, &dummy); 3217172ce0a9SAzael Avalos dev->usb_sleep_music_supported = !ret; 3218172ce0a9SAzael Avalos 321935d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(dev, &dummy); 322035d53ceaSAzael Avalos dev->panel_power_on_supported = !ret; 322135d53ceaSAzael Avalos 322217fe4b3dSAzael Avalos ret = toshiba_usb_three_get(dev, &dummy); 322317fe4b3dSAzael Avalos dev->usb_three_supported = !ret; 322417fe4b3dSAzael Avalos 322536d03f93SSeth Forshee ret = get_video_status(dev, &dummy); 322636d03f93SSeth Forshee dev->video_supported = !ret; 322736d03f93SSeth Forshee 322836d03f93SSeth Forshee ret = get_fan_status(dev, &dummy); 322936d03f93SSeth Forshee dev->fan_supported = !ret; 323036d03f93SSeth Forshee 3231dd193dcdSArvid Norlander ret = get_fan_rpm(dev, &dummy); 3232dd193dcdSArvid Norlander dev->fan_rpm_supported = !ret; 3233dd193dcdSArvid Norlander 3234*c727ba4cSArvid Norlander #if IS_ENABLED(CONFIG_HWMON) 3235*c727ba4cSArvid Norlander if (dev->fan_rpm_supported) { 3236*c727ba4cSArvid Norlander dev->hwmon_device = hwmon_device_register_with_info( 3237*c727ba4cSArvid Norlander &dev->acpi_dev->dev, "toshiba_acpi_sensors", NULL, 3238*c727ba4cSArvid Norlander &toshiba_acpi_hwmon_chip_info, NULL); 3239*c727ba4cSArvid Norlander if (IS_ERR(dev->hwmon_device)) { 3240*c727ba4cSArvid Norlander dev->hwmon_device = NULL; 3241*c727ba4cSArvid Norlander pr_warn("unable to register hwmon device, skipping\n"); 3242*c727ba4cSArvid Norlander } 3243*c727ba4cSArvid Norlander } 3244*c727ba4cSArvid Norlander #endif 3245*c727ba4cSArvid Norlander 32466873f46aSAzael Avalos toshiba_wwan_available(dev); 32472fdde834SAzael Avalos if (dev->wwan_supported) 32482fdde834SAzael Avalos toshiba_acpi_setup_wwan_rfkill(dev); 32496873f46aSAzael Avalos 3250763ff32fSAzael Avalos toshiba_cooling_method_available(dev); 3251763ff32fSAzael Avalos 32520409cbceSAzael Avalos print_supported_features(dev); 32530409cbceSAzael Avalos 3254360f0f39SAzael Avalos ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, 3255360f0f39SAzael Avalos &toshiba_attr_group); 3256360f0f39SAzael Avalos if (ret) { 3257360f0f39SAzael Avalos dev->sysfs_created = 0; 3258360f0f39SAzael Avalos goto error; 3259360f0f39SAzael Avalos } 3260360f0f39SAzael Avalos dev->sysfs_created = !ret; 3261360f0f39SAzael Avalos 326236d03f93SSeth Forshee create_toshiba_proc_entries(dev); 326336d03f93SSeth Forshee 326429cd293fSSeth Forshee toshiba_acpi = dev; 326529cd293fSSeth Forshee 3266135740deSSeth Forshee return 0; 3267135740deSSeth Forshee 3268135740deSSeth Forshee error: 326951fac838SRafael J. Wysocki toshiba_acpi_remove(acpi_dev); 3270135740deSSeth Forshee return ret; 3271135740deSSeth Forshee } 3272135740deSSeth Forshee 3273135740deSSeth Forshee static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) 3274135740deSSeth Forshee { 3275135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 32766335e4d5SMatthew Garrett 327771454d78SAzael Avalos switch (event) { 327871454d78SAzael Avalos case 0x80: /* Hotkeys and some system events */ 3279a88bc06eSAzael Avalos /* 3280a88bc06eSAzael Avalos * Machines with this WMI GUID aren't supported due to bugs in 3281a88bc06eSAzael Avalos * their AML. 3282a88bc06eSAzael Avalos * 3283a88bc06eSAzael Avalos * Return silently to avoid triggering a netlink event. 3284a88bc06eSAzael Avalos */ 3285a88bc06eSAzael Avalos if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) 3286a88bc06eSAzael Avalos return; 328771454d78SAzael Avalos toshiba_acpi_process_hotkeys(dev); 328811948b93SSeth Forshee break; 3289bab09e23SAzael Avalos case 0x81: /* Dock events */ 3290bab09e23SAzael Avalos case 0x82: 3291bab09e23SAzael Avalos case 0x83: 3292bab09e23SAzael Avalos pr_info("Dock event received %x\n", event); 3293bab09e23SAzael Avalos break; 3294bab09e23SAzael Avalos case 0x88: /* Thermal events */ 3295bab09e23SAzael Avalos pr_info("Thermal event received\n"); 3296bab09e23SAzael Avalos break; 3297bab09e23SAzael Avalos case 0x8f: /* LID closed */ 3298bab09e23SAzael Avalos case 0x90: /* LID is closed and Dock has been ejected */ 3299bab09e23SAzael Avalos break; 3300bab09e23SAzael Avalos case 0x8c: /* SATA power events */ 3301bab09e23SAzael Avalos case 0x8b: 3302bab09e23SAzael Avalos pr_info("SATA power event received %x\n", event); 3303bab09e23SAzael Avalos break; 330480546905SAzael Avalos case 0x92: /* Keyboard backlight mode changed */ 3305147288e6SAzael Avalos dev->kbd_event_generated = true; 330680546905SAzael Avalos /* Update sysfs entries */ 330765e3cf9cSAzael Avalos if (sysfs_update_group(&acpi_dev->dev.kobj, 330865e3cf9cSAzael Avalos &toshiba_attr_group)) 330980546905SAzael Avalos pr_err("Unable to update sysfs entries\n"); 3310147288e6SAzael Avalos /* Notify LED subsystem about keyboard backlight change */ 3311147288e6SAzael Avalos if (dev->kbd_type == 2 && dev->kbd_mode != SCI_KBD_MODE_AUTO) 3312147288e6SAzael Avalos led_classdev_notify_brightness_hw_changed(&dev->kbd_led, 3313147288e6SAzael Avalos (dev->kbd_mode == SCI_KBD_MODE_ON) ? 3314147288e6SAzael Avalos LED_FULL : LED_OFF); 331580546905SAzael Avalos break; 3316bab09e23SAzael Avalos case 0x85: /* Unknown */ 3317bab09e23SAzael Avalos case 0x8d: /* Unknown */ 331871454d78SAzael Avalos case 0x8e: /* Unknown */ 3319bab09e23SAzael Avalos case 0x94: /* Unknown */ 3320bab09e23SAzael Avalos case 0x95: /* Unknown */ 332111948b93SSeth Forshee default: 332271454d78SAzael Avalos pr_info("Unknown event received %x\n", event); 332311948b93SSeth Forshee break; 33246335e4d5SMatthew Garrett } 3325bab09e23SAzael Avalos 3326bab09e23SAzael Avalos acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class, 3327bab09e23SAzael Avalos dev_name(&acpi_dev->dev), 332813ae84f9SAzael Avalos event, (event == 0x80) ? 332913ae84f9SAzael Avalos dev->last_key_event : 0); 333029cd293fSSeth Forshee } 33316335e4d5SMatthew Garrett 33323567a4e2SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 333343d2fd3bSRafael J. Wysocki static int toshiba_acpi_suspend(struct device *device) 333429cd293fSSeth Forshee { 333543d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 33361e574dbfSAzael Avalos 33371e574dbfSAzael Avalos if (dev->hotkey_dev) { 333829cd293fSSeth Forshee u32 result; 333929cd293fSSeth Forshee 3340d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE); 33411e574dbfSAzael Avalos if (result != TOS_SUCCESS) 33421e574dbfSAzael Avalos pr_info("Unable to disable hotkeys\n"); 33431e574dbfSAzael Avalos } 334429cd293fSSeth Forshee 334529cd293fSSeth Forshee return 0; 334629cd293fSSeth Forshee } 334729cd293fSSeth Forshee 334843d2fd3bSRafael J. Wysocki static int toshiba_acpi_resume(struct device *device) 334929cd293fSSeth Forshee { 335043d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 335129cd293fSSeth Forshee 3352e7fdb762SBenjamin Tissoires if (dev->hotkey_dev) { 33532fdde834SAzael Avalos if (toshiba_acpi_enable_hotkeys(dev)) 3354e7fdb762SBenjamin Tissoires pr_info("Unable to re-enable hotkeys\n"); 3355e7fdb762SBenjamin Tissoires } 335629cd293fSSeth Forshee 33572fdde834SAzael Avalos if (dev->wwan_rfk) { 33582fdde834SAzael Avalos if (!toshiba_wireless_status(dev)) 33592fdde834SAzael Avalos rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch); 33602fdde834SAzael Avalos } 33612fdde834SAzael Avalos 336229cd293fSSeth Forshee return 0; 336329cd293fSSeth Forshee } 33643567a4e2SRafael J. Wysocki #endif 33656335e4d5SMatthew Garrett 336643d2fd3bSRafael J. Wysocki static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm, 336743d2fd3bSRafael J. Wysocki toshiba_acpi_suspend, toshiba_acpi_resume); 336843d2fd3bSRafael J. Wysocki 3369135740deSSeth Forshee static struct acpi_driver toshiba_acpi_driver = { 3370135740deSSeth Forshee .name = "Toshiba ACPI driver", 3371135740deSSeth Forshee .owner = THIS_MODULE, 3372135740deSSeth Forshee .ids = toshiba_device_ids, 3373135740deSSeth Forshee .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, 3374135740deSSeth Forshee .ops = { 3375135740deSSeth Forshee .add = toshiba_acpi_add, 3376135740deSSeth Forshee .remove = toshiba_acpi_remove, 3377135740deSSeth Forshee .notify = toshiba_acpi_notify, 3378135740deSSeth Forshee }, 337943d2fd3bSRafael J. Wysocki .drv.pm = &toshiba_acpi_pm, 3380135740deSSeth Forshee }; 3381b4f9fe12SLen Brown 3382b4f9fe12SLen Brown static int __init toshiba_acpi_init(void) 3383b4f9fe12SLen Brown { 3384135740deSSeth Forshee int ret; 3385b4f9fe12SLen Brown 3386b4f9fe12SLen Brown toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); 3387b4f9fe12SLen Brown if (!toshiba_proc_dir) { 3388135740deSSeth Forshee pr_err("Unable to create proc dir " PROC_TOSHIBA "\n"); 3389b4f9fe12SLen Brown return -ENODEV; 3390b4f9fe12SLen Brown } 3391b4f9fe12SLen Brown 3392135740deSSeth Forshee ret = acpi_bus_register_driver(&toshiba_acpi_driver); 3393b4f9fe12SLen Brown if (ret) { 3394135740deSSeth Forshee pr_err("Failed to register ACPI driver: %d\n", ret); 3395135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 3396135740deSSeth Forshee } 3397135740deSSeth Forshee 3398b4f9fe12SLen Brown return ret; 3399b4f9fe12SLen Brown } 3400b4f9fe12SLen Brown 3401135740deSSeth Forshee static void __exit toshiba_acpi_exit(void) 3402135740deSSeth Forshee { 3403135740deSSeth Forshee acpi_bus_unregister_driver(&toshiba_acpi_driver); 3404135740deSSeth Forshee if (toshiba_proc_dir) 3405135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 3406b4f9fe12SLen Brown } 3407b4f9fe12SLen Brown 3408b4f9fe12SLen Brown module_init(toshiba_acpi_init); 3409b4f9fe12SLen Brown module_exit(toshiba_acpi_exit); 3410