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> 263cb1f40dSHans de Goede #include <linux/dmi.h> 27b4f9fe12SLen Brown #include <linux/kernel.h> 28b4f9fe12SLen Brown #include <linux/module.h> 297faa6a37SAzael Avalos #include <linux/moduleparam.h> 30b4f9fe12SLen Brown #include <linux/init.h> 31b4f9fe12SLen Brown #include <linux/types.h> 32b4f9fe12SLen Brown #include <linux/proc_fs.h> 33936c8bcdSAlexey Dobriyan #include <linux/seq_file.h> 34b4f9fe12SLen Brown #include <linux/backlight.h> 356335e4d5SMatthew Garrett #include <linux/input.h> 36384a7cd9SDmitry Torokhov #include <linux/input/sparse-keymap.h> 376c3f6e6cSPierre Ducroquet #include <linux/leds.h> 385a0e3ad6STejun Heo #include <linux/slab.h> 3929cd293fSSeth Forshee #include <linux/workqueue.h> 4029cd293fSSeth Forshee #include <linux/i8042.h> 418b48463fSLv Zheng #include <linux/acpi.h> 42b5163992SAzael Avalos #include <linux/uaccess.h> 43fc5462f8SAzael Avalos #include <linux/miscdevice.h> 442fdde834SAzael Avalos #include <linux/rfkill.h> 45c727ba4cSArvid Norlander #include <linux/hwmon.h> 4698010f1eSAzael Avalos #include <linux/iio/iio.h> 47fc5462f8SAzael Avalos #include <linux/toshiba.h> 488ef5db9eSArvid Norlander #include <acpi/battery.h> 49358d6a2cSHans de Goede #include <acpi/video.h> 50b4f9fe12SLen Brown 51b4f9fe12SLen Brown MODULE_AUTHOR("John Belmonte"); 52b4f9fe12SLen Brown MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); 53b4f9fe12SLen Brown MODULE_LICENSE("GPL"); 54b4f9fe12SLen Brown 5558900325SYang Yingliang static int turn_on_panel_on_resume = -1; 563cb1f40dSHans de Goede module_param(turn_on_panel_on_resume, int, 0644); 573cb1f40dSHans de Goede MODULE_PARM_DESC(turn_on_panel_on_resume, 583cb1f40dSHans de Goede "Call HCI_PANEL_POWER_ON on resume (-1 = auto, 0 = no, 1 = yes"); 593cb1f40dSHans de Goede 60f11f999eSSeth Forshee #define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100" 61f11f999eSSeth Forshee 6229cd293fSSeth Forshee /* Scan code for Fn key on TOS1900 models */ 6329cd293fSSeth Forshee #define TOS1900_FN_SCAN 0x6e 6429cd293fSSeth Forshee 65b4f9fe12SLen Brown /* Toshiba ACPI method paths */ 66b4f9fe12SLen Brown #define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX" 67b4f9fe12SLen Brown 68e0769fe6SDarren Hart /* 69e0769fe6SDarren Hart * The Toshiba configuration interface is composed of the HCI and the SCI, 70258c5903SAzael Avalos * which are defined as follows: 71b4f9fe12SLen Brown * 72b4f9fe12SLen Brown * HCI is Toshiba's "Hardware Control Interface" which is supposed to 73b4f9fe12SLen Brown * be uniform across all their models. Ideally we would just call 74b4f9fe12SLen Brown * dedicated ACPI methods instead of using this primitive interface. 75b4f9fe12SLen Brown * However the ACPI methods seem to be incomplete in some areas (for 76b4f9fe12SLen Brown * example they allow setting, but not reading, the LCD brightness value), 77b4f9fe12SLen Brown * so this is still useful. 7884a6273fSAzael Avalos * 7984a6273fSAzael Avalos * SCI stands for "System Configuration Interface" which aim is to 8084a6273fSAzael Avalos * conceal differences in hardware between different models. 81b4f9fe12SLen Brown */ 82b4f9fe12SLen Brown 83258c5903SAzael Avalos #define TCI_WORDS 6 84b4f9fe12SLen Brown 853f75bbe9SAzael Avalos /* Operations */ 86b4f9fe12SLen Brown #define HCI_SET 0xff00 87b4f9fe12SLen Brown #define HCI_GET 0xfe00 8884a6273fSAzael Avalos #define SCI_OPEN 0xf100 8984a6273fSAzael Avalos #define SCI_CLOSE 0xf200 9084a6273fSAzael Avalos #define SCI_GET 0xf300 9184a6273fSAzael Avalos #define SCI_SET 0xf400 92b4f9fe12SLen Brown 933f75bbe9SAzael Avalos /* Return codes */ 941864bbc2SAzael Avalos #define TOS_SUCCESS 0x0000 95e1a949c1SAzael Avalos #define TOS_SUCCESS2 0x0001 961864bbc2SAzael Avalos #define TOS_OPEN_CLOSE_OK 0x0044 971864bbc2SAzael Avalos #define TOS_FAILURE 0x1000 981864bbc2SAzael Avalos #define TOS_NOT_SUPPORTED 0x8000 991864bbc2SAzael Avalos #define TOS_ALREADY_OPEN 0x8100 1001864bbc2SAzael Avalos #define TOS_NOT_OPENED 0x8200 1011864bbc2SAzael Avalos #define TOS_INPUT_DATA_ERROR 0x8300 1021864bbc2SAzael Avalos #define TOS_WRITE_PROTECTED 0x8400 1031864bbc2SAzael Avalos #define TOS_NOT_PRESENT 0x8600 1041864bbc2SAzael Avalos #define TOS_FIFO_EMPTY 0x8c00 1051864bbc2SAzael Avalos #define TOS_DATA_NOT_AVAILABLE 0x8d20 1061864bbc2SAzael Avalos #define TOS_NOT_INITIALIZED 0x8d50 10798fc4ec6SAzael Avalos #define TOS_NOT_INSTALLED 0x8e00 108b4f9fe12SLen Brown 1093f75bbe9SAzael Avalos /* Registers */ 1103cb1f40dSHans de Goede #define HCI_PANEL_POWER_ON 0x0002 111b4f9fe12SLen Brown #define HCI_FAN 0x0004 112121b7b0dSAkio Idehara #define HCI_TR_BACKLIGHT 0x0005 113b4f9fe12SLen Brown #define HCI_SYSTEM_EVENT 0x0016 114b4f9fe12SLen Brown #define HCI_VIDEO_OUT 0x001c 115b4f9fe12SLen Brown #define HCI_HOTKEY_EVENT 0x001e 116b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS 0x002a 117dd193dcdSArvid Norlander #define HCI_FAN_RPM 0x0045 1186873f46aSAzael Avalos #define HCI_WIRELESS 0x0056 1195a2813e9SAzael Avalos #define HCI_ACCELEROMETER 0x006d 120763ff32fSAzael Avalos #define HCI_COOLING_METHOD 0x007f 121360f0f39SAzael Avalos #define HCI_KBD_ILLUMINATION 0x0095 122def6c4e2SAzael Avalos #define HCI_ECO_MODE 0x0097 1235a2813e9SAzael Avalos #define HCI_ACCELEROMETER2 0x00a6 12489655fbbSArvid Norlander #define HCI_BATTERY_CHARGE_MODE 0x00ba 12556e6b353SAzael Avalos #define HCI_SYSTEM_INFO 0xc000 12635d53ceaSAzael Avalos #define SCI_PANEL_POWER_ON 0x010d 127fdb79081SAzael Avalos #define SCI_ILLUMINATION 0x014e 128e26ffe51SAzael Avalos #define SCI_USB_SLEEP_CHARGE 0x0150 129360f0f39SAzael Avalos #define SCI_KBD_ILLUM_STATUS 0x015c 130172ce0a9SAzael Avalos #define SCI_USB_SLEEP_MUSIC 0x015e 13117fe4b3dSAzael Avalos #define SCI_USB_THREE 0x0169 1329d8658acSAzael Avalos #define SCI_TOUCHPAD 0x050e 133bae84195SAzael Avalos #define SCI_KBD_FUNCTION_KEYS 0x0522 134b4f9fe12SLen Brown 1353f75bbe9SAzael Avalos /* Field definitions */ 1365a2813e9SAzael Avalos #define HCI_ACCEL_MASK 0x7fff 13798010f1eSAzael Avalos #define HCI_ACCEL_DIRECTION_MASK 0x8000 13829cd293fSSeth Forshee #define HCI_HOTKEY_DISABLE 0x0b 139a30b8f81SAzael Avalos #define HCI_HOTKEY_ENABLE 0x09 140fb42d1f4SAzael Avalos #define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10 141b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_BITS 3 142b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) 143b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS) 144360f0f39SAzael Avalos #define HCI_MISC_SHIFT 0x10 14556e6b353SAzael Avalos #define HCI_SYSTEM_TYPE1 0x10 14656e6b353SAzael Avalos #define HCI_SYSTEM_TYPE2 0x11 147b4f9fe12SLen Brown #define HCI_VIDEO_OUT_LCD 0x1 148b4f9fe12SLen Brown #define HCI_VIDEO_OUT_CRT 0x2 149b4f9fe12SLen Brown #define HCI_VIDEO_OUT_TV 0x4 15093f8c16dSAzael Avalos #define SCI_KBD_MODE_MASK 0x1f 151360f0f39SAzael Avalos #define SCI_KBD_MODE_FNZ 0x1 152360f0f39SAzael Avalos #define SCI_KBD_MODE_AUTO 0x2 15393f8c16dSAzael Avalos #define SCI_KBD_MODE_ON 0x8 15493f8c16dSAzael Avalos #define SCI_KBD_MODE_OFF 0x10 15593f8c16dSAzael Avalos #define SCI_KBD_TIME_MAX 0x3c001a 1566873f46aSAzael Avalos #define HCI_WIRELESS_STATUS 0x1 1576873f46aSAzael Avalos #define HCI_WIRELESS_WWAN 0x3 1586873f46aSAzael Avalos #define HCI_WIRELESS_WWAN_STATUS 0x2000 1596873f46aSAzael Avalos #define HCI_WIRELESS_WWAN_POWER 0x4000 160e26ffe51SAzael Avalos #define SCI_USB_CHARGE_MODE_MASK 0xff 161c8c91842SAzael Avalos #define SCI_USB_CHARGE_DISABLED 0x00 162c8c91842SAzael Avalos #define SCI_USB_CHARGE_ALTERNATE 0x09 163c8c91842SAzael Avalos #define SCI_USB_CHARGE_TYPICAL 0x11 164c8c91842SAzael Avalos #define SCI_USB_CHARGE_AUTO 0x21 165182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_MASK 0x7 166182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_OFF 0x1 167182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_ON 0x4 168182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL 0x0200 169bb3fe01fSAzael Avalos #define SCI_USB_CHARGE_RAPID_DSP 0x0300 170b4f9fe12SLen Brown 171135740deSSeth Forshee struct toshiba_acpi_dev { 172135740deSSeth Forshee struct acpi_device *acpi_dev; 173135740deSSeth Forshee const char *method_hci; 174135740deSSeth Forshee struct input_dev *hotkey_dev; 17529cd293fSSeth Forshee struct work_struct hotkey_work; 176135740deSSeth Forshee struct backlight_device *backlight_dev; 177135740deSSeth Forshee struct led_classdev led_dev; 178360f0f39SAzael Avalos struct led_classdev kbd_led; 179def6c4e2SAzael Avalos struct led_classdev eco_led; 180fc5462f8SAzael Avalos struct miscdevice miscdev; 1812fdde834SAzael Avalos struct rfkill *wwan_rfk; 18298010f1eSAzael Avalos struct iio_dev *indio_dev; 183c727ba4cSArvid Norlander #if IS_ENABLED(CONFIG_HWMON) 184c727ba4cSArvid Norlander struct device *hwmon_device; 185c727ba4cSArvid Norlander #endif 18636d03f93SSeth Forshee 187135740deSSeth Forshee int force_fan; 188135740deSSeth Forshee int last_key_event; 189135740deSSeth Forshee int key_event_valid; 19093f8c16dSAzael Avalos int kbd_type; 191360f0f39SAzael Avalos int kbd_mode; 192360f0f39SAzael Avalos int kbd_time; 193182bcaa5SAzael Avalos int usbsc_bat_level; 194c8c91842SAzael Avalos int usbsc_mode_base; 195a2b3471bSAzael Avalos int hotkey_event_type; 196763ff32fSAzael Avalos int max_cooling_method; 197135740deSSeth Forshee 198592b746cSDan Carpenter unsigned int illumination_supported:1; 199592b746cSDan Carpenter unsigned int video_supported:1; 200592b746cSDan Carpenter unsigned int fan_supported:1; 201dd193dcdSArvid Norlander unsigned int fan_rpm_supported:1; 202592b746cSDan Carpenter unsigned int system_event_supported:1; 20329cd293fSSeth Forshee unsigned int ntfy_supported:1; 20429cd293fSSeth Forshee unsigned int info_supported:1; 205121b7b0dSAkio Idehara unsigned int tr_backlight_supported:1; 206360f0f39SAzael Avalos unsigned int kbd_illum_supported:1; 2079d8658acSAzael Avalos unsigned int touchpad_supported:1; 208def6c4e2SAzael Avalos unsigned int eco_supported:1; 2095a2813e9SAzael Avalos unsigned int accelerometer_supported:1; 210e26ffe51SAzael Avalos unsigned int usb_sleep_charge_supported:1; 211bb3fe01fSAzael Avalos unsigned int usb_rapid_charge_supported:1; 212172ce0a9SAzael Avalos unsigned int usb_sleep_music_supported:1; 213bae84195SAzael Avalos unsigned int kbd_function_keys_supported:1; 21435d53ceaSAzael Avalos unsigned int panel_power_on_supported:1; 21517fe4b3dSAzael Avalos unsigned int usb_three_supported:1; 2166873f46aSAzael Avalos unsigned int wwan_supported:1; 217763ff32fSAzael Avalos unsigned int cooling_method_supported:1; 21889655fbbSArvid Norlander unsigned int battery_charge_mode_supported:1; 219360f0f39SAzael Avalos unsigned int sysfs_created:1; 220b116fd00SAzael Avalos unsigned int special_functions; 221ea215a3fSAzael Avalos 22265e3cf9cSAzael Avalos bool kbd_event_generated; 2236873f46aSAzael Avalos bool killswitch; 224135740deSSeth Forshee }; 225135740deSSeth Forshee 22629cd293fSSeth Forshee static struct toshiba_acpi_dev *toshiba_acpi; 22729cd293fSSeth Forshee 2287faa6a37SAzael Avalos static bool disable_hotkeys; 2297faa6a37SAzael Avalos module_param(disable_hotkeys, bool, 0444); 2307faa6a37SAzael Avalos MODULE_PARM_DESC(disable_hotkeys, "Disables the hotkeys activation"); 2317faa6a37SAzael Avalos 232b4f9fe12SLen Brown static const struct acpi_device_id toshiba_device_ids[] = { 233b4f9fe12SLen Brown {"TOS6200", 0}, 23463a9e016SOndrej Zary {"TOS6207", 0}, 235b4f9fe12SLen Brown {"TOS6208", 0}, 236b4f9fe12SLen Brown {"TOS1900", 0}, 237b4f9fe12SLen Brown {"", 0}, 238b4f9fe12SLen Brown }; 239b4f9fe12SLen Brown MODULE_DEVICE_TABLE(acpi, toshiba_device_ids); 240b4f9fe12SLen Brown 241b859f159SGreg Kroah-Hartman static const struct key_entry toshiba_acpi_keymap[] = { 242fec278a1SUnai Uribarri { KE_KEY, 0x9e, { KEY_RFKILL } }, 243384a7cd9SDmitry Torokhov { KE_KEY, 0x101, { KEY_MUTE } }, 244384a7cd9SDmitry Torokhov { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 245384a7cd9SDmitry Torokhov { KE_KEY, 0x103, { KEY_ZOOMIN } }, 246408a5d13SAzael Avalos { KE_KEY, 0x10f, { KEY_TAB } }, 247af502837SAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 248af502837SAzael Avalos { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 249384a7cd9SDmitry Torokhov { KE_KEY, 0x13b, { KEY_COFFEE } }, 250384a7cd9SDmitry Torokhov { KE_KEY, 0x13c, { KEY_BATTERY } }, 251384a7cd9SDmitry Torokhov { KE_KEY, 0x13d, { KEY_SLEEP } }, 252384a7cd9SDmitry Torokhov { KE_KEY, 0x13e, { KEY_SUSPEND } }, 253384a7cd9SDmitry Torokhov { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } }, 254384a7cd9SDmitry Torokhov { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } }, 255384a7cd9SDmitry Torokhov { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } }, 256384a7cd9SDmitry Torokhov { KE_KEY, 0x142, { KEY_WLAN } }, 257af502837SAzael Avalos { KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } }, 258a49010f5SJon Dowland { KE_KEY, 0x17f, { KEY_FN } }, 259384a7cd9SDmitry Torokhov { KE_KEY, 0xb05, { KEY_PROG2 } }, 260384a7cd9SDmitry Torokhov { KE_KEY, 0xb06, { KEY_WWW } }, 261384a7cd9SDmitry Torokhov { KE_KEY, 0xb07, { KEY_MAIL } }, 262384a7cd9SDmitry Torokhov { KE_KEY, 0xb30, { KEY_STOP } }, 263384a7cd9SDmitry Torokhov { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } }, 264384a7cd9SDmitry Torokhov { KE_KEY, 0xb32, { KEY_NEXTSONG } }, 265384a7cd9SDmitry Torokhov { KE_KEY, 0xb33, { KEY_PLAYPAUSE } }, 266384a7cd9SDmitry Torokhov { KE_KEY, 0xb5a, { KEY_MEDIA } }, 267408a5d13SAzael Avalos { KE_IGNORE, 0x1430, { KEY_RESERVED } }, /* Wake from sleep */ 268408a5d13SAzael Avalos { KE_IGNORE, 0x1501, { KEY_RESERVED } }, /* Output changed */ 269408a5d13SAzael Avalos { KE_IGNORE, 0x1502, { KEY_RESERVED } }, /* HDMI plugged/unplugged */ 270408a5d13SAzael Avalos { KE_IGNORE, 0x1ABE, { KEY_RESERVED } }, /* Protection level set */ 271408a5d13SAzael Avalos { KE_IGNORE, 0x1ABF, { KEY_RESERVED } }, /* Protection level off */ 272384a7cd9SDmitry Torokhov { KE_END, 0 }, 2736335e4d5SMatthew Garrett }; 2746335e4d5SMatthew Garrett 275fe808bfbSTakashi Iwai static const struct key_entry toshiba_acpi_alt_keymap[] = { 276fe808bfbSTakashi Iwai { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 277fe808bfbSTakashi Iwai { KE_KEY, 0x103, { KEY_ZOOMIN } }, 278e6efad7fSAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 279fe808bfbSTakashi Iwai { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 280fe808bfbSTakashi Iwai { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } }, 281fe808bfbSTakashi Iwai { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } }, 282d50c9005SAzael Avalos { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } }, 283fe808bfbSTakashi Iwai { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } }, 284d50c9005SAzael Avalos { KE_KEY, 0x157, { KEY_MUTE } }, 285d50c9005SAzael Avalos { KE_KEY, 0x158, { KEY_WLAN } }, 286fe808bfbSTakashi Iwai { KE_END, 0 }, 287fe808bfbSTakashi Iwai }; 288fe808bfbSTakashi Iwai 289e0769fe6SDarren Hart /* 290e0769fe6SDarren Hart * Utility 291b4f9fe12SLen Brown */ 292b4f9fe12SLen Brown 293b5163992SAzael Avalos static inline void _set_bit(u32 *word, u32 mask, int value) 294b4f9fe12SLen Brown { 295b4f9fe12SLen Brown *word = (*word & ~mask) | (mask * value); 296b4f9fe12SLen Brown } 297b4f9fe12SLen Brown 298e0769fe6SDarren Hart /* 299e0769fe6SDarren Hart * ACPI interface wrappers 300b4f9fe12SLen Brown */ 301b4f9fe12SLen Brown 302b4f9fe12SLen Brown static int write_acpi_int(const char *methodName, int val) 303b4f9fe12SLen Brown { 304b4f9fe12SLen Brown acpi_status status; 305b4f9fe12SLen Brown 306619400daSZhang Rui status = acpi_execute_simple_method(NULL, (char *)methodName, val); 30732bcd5cbSSeth Forshee return (status == AE_OK) ? 0 : -EIO; 308b4f9fe12SLen Brown } 309b4f9fe12SLen Brown 310e0769fe6SDarren Hart /* 311e0769fe6SDarren Hart * Perform a raw configuration call. Here we don't care about input or output 312258c5903SAzael Avalos * buffer format. 313b4f9fe12SLen Brown */ 314258c5903SAzael Avalos static acpi_status tci_raw(struct toshiba_acpi_dev *dev, 315258c5903SAzael Avalos const u32 in[TCI_WORDS], u32 out[TCI_WORDS]) 316b4f9fe12SLen Brown { 31778429e55SAzael Avalos union acpi_object in_objs[TCI_WORDS], out_objs[TCI_WORDS + 1]; 318b4f9fe12SLen Brown struct acpi_object_list params; 319b4f9fe12SLen Brown struct acpi_buffer results; 320b4f9fe12SLen Brown acpi_status status; 321b4f9fe12SLen Brown int i; 322b4f9fe12SLen Brown 323258c5903SAzael Avalos params.count = TCI_WORDS; 324b4f9fe12SLen Brown params.pointer = in_objs; 325258c5903SAzael Avalos for (i = 0; i < TCI_WORDS; ++i) { 326b4f9fe12SLen Brown in_objs[i].type = ACPI_TYPE_INTEGER; 327b4f9fe12SLen Brown in_objs[i].integer.value = in[i]; 328b4f9fe12SLen Brown } 329b4f9fe12SLen Brown 330b4f9fe12SLen Brown results.length = sizeof(out_objs); 331b4f9fe12SLen Brown results.pointer = out_objs; 332b4f9fe12SLen Brown 3336e02cc7eSSeth Forshee status = acpi_evaluate_object(dev->acpi_dev->handle, 3346e02cc7eSSeth Forshee (char *)dev->method_hci, ¶ms, 335b4f9fe12SLen Brown &results); 336258c5903SAzael Avalos if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) { 337b5163992SAzael Avalos for (i = 0; i < out_objs->package.count; ++i) 338b4f9fe12SLen Brown out[i] = out_objs->package.elements[i].integer.value; 339b4f9fe12SLen Brown } 340b4f9fe12SLen Brown 341b4f9fe12SLen Brown return status; 342b4f9fe12SLen Brown } 343b4f9fe12SLen Brown 344e0769fe6SDarren Hart /* 345d37782bdSAzael Avalos * Common hci tasks 346b4f9fe12SLen Brown * 347b4f9fe12SLen Brown * In addition to the ACPI status, the HCI system returns a result which 348b4f9fe12SLen Brown * may be useful (such as "not supported"). 349b4f9fe12SLen Brown */ 350b4f9fe12SLen Brown 351d37782bdSAzael Avalos static u32 hci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 352b4f9fe12SLen Brown { 353258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 }; 354258c5903SAzael Avalos u32 out[TCI_WORDS]; 355258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 356893f3f62SAzael Avalos 357893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 358b4f9fe12SLen Brown } 359b4f9fe12SLen Brown 360d37782bdSAzael Avalos static u32 hci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 361b4f9fe12SLen Brown { 362258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 }; 363258c5903SAzael Avalos u32 out[TCI_WORDS]; 364258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 365b5163992SAzael Avalos 366893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 367893f3f62SAzael Avalos return TOS_FAILURE; 368893f3f62SAzael Avalos 369b4f9fe12SLen Brown *out1 = out[2]; 370893f3f62SAzael Avalos 371893f3f62SAzael Avalos return out[0]; 372b4f9fe12SLen Brown } 373b4f9fe12SLen Brown 374e0769fe6SDarren Hart /* 375e0769fe6SDarren Hart * Common sci tasks 37684a6273fSAzael Avalos */ 37784a6273fSAzael Avalos 37884a6273fSAzael Avalos static int sci_open(struct toshiba_acpi_dev *dev) 37984a6273fSAzael Avalos { 380258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 }; 381258c5903SAzael Avalos u32 out[TCI_WORDS]; 38278429e55SAzael Avalos acpi_status status = tci_raw(dev, in, out); 38384a6273fSAzael Avalos 3848baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 38584a6273fSAzael Avalos pr_err("ACPI call to open SCI failed\n"); 38684a6273fSAzael Avalos return 0; 38784a6273fSAzael Avalos } 38884a6273fSAzael Avalos 3891864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) { 39084a6273fSAzael Avalos return 1; 3911864bbc2SAzael Avalos } else if (out[0] == TOS_ALREADY_OPEN) { 39284a6273fSAzael Avalos pr_info("Toshiba SCI already opened\n"); 39384a6273fSAzael Avalos return 1; 394fa465739SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 395e0769fe6SDarren Hart /* 396e0769fe6SDarren Hart * Some BIOSes do not have the SCI open/close functions 397fa465739SAzael Avalos * implemented and return 0x8000 (Not Supported), failing to 398fa465739SAzael Avalos * register some supported features. 399fa465739SAzael Avalos * 400fa465739SAzael Avalos * Simply return 1 if we hit those affected laptops to make the 401fa465739SAzael Avalos * supported features work. 402fa465739SAzael Avalos * 403fa465739SAzael Avalos * In the case that some laptops really do not support the SCI, 404fa465739SAzael Avalos * all the SCI dependent functions check for TOS_NOT_SUPPORTED, 405fa465739SAzael Avalos * and thus, not registering support for the queried feature. 406fa465739SAzael Avalos */ 407fa465739SAzael Avalos return 1; 4081864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_PRESENT) { 40984a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 41084a6273fSAzael Avalos } 41184a6273fSAzael Avalos 41284a6273fSAzael Avalos return 0; 41384a6273fSAzael Avalos } 41484a6273fSAzael Avalos 41584a6273fSAzael Avalos static void sci_close(struct toshiba_acpi_dev *dev) 41684a6273fSAzael Avalos { 417258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 }; 418258c5903SAzael Avalos u32 out[TCI_WORDS]; 41978429e55SAzael Avalos acpi_status status = tci_raw(dev, in, out); 42084a6273fSAzael Avalos 4218baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 42284a6273fSAzael Avalos pr_err("ACPI call to close SCI failed\n"); 42384a6273fSAzael Avalos return; 42484a6273fSAzael Avalos } 42584a6273fSAzael Avalos 4261864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) 42784a6273fSAzael Avalos return; 4281864bbc2SAzael Avalos else if (out[0] == TOS_NOT_OPENED) 42984a6273fSAzael Avalos pr_info("Toshiba SCI not opened\n"); 4301864bbc2SAzael Avalos else if (out[0] == TOS_NOT_PRESENT) 43184a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 43284a6273fSAzael Avalos } 43384a6273fSAzael Avalos 434893f3f62SAzael Avalos static u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 43584a6273fSAzael Avalos { 436258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 }; 437258c5903SAzael Avalos u32 out[TCI_WORDS]; 438258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 439b5163992SAzael Avalos 440893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 441893f3f62SAzael Avalos return TOS_FAILURE; 442893f3f62SAzael Avalos 44384a6273fSAzael Avalos *out1 = out[2]; 444893f3f62SAzael Avalos 445893f3f62SAzael Avalos return out[0]; 44684a6273fSAzael Avalos } 44784a6273fSAzael Avalos 448893f3f62SAzael Avalos static u32 sci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 44984a6273fSAzael Avalos { 450258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 }; 451258c5903SAzael Avalos u32 out[TCI_WORDS]; 452258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 453893f3f62SAzael Avalos 454893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 45584a6273fSAzael Avalos } 45684a6273fSAzael Avalos 4576c3f6e6cSPierre Ducroquet /* Illumination support */ 458ea215a3fSAzael Avalos static void toshiba_illumination_available(struct toshiba_acpi_dev *dev) 4596c3f6e6cSPierre Ducroquet { 460258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 }; 461258c5903SAzael Avalos u32 out[TCI_WORDS]; 4626c3f6e6cSPierre Ducroquet acpi_status status; 4636c3f6e6cSPierre Ducroquet 464ea215a3fSAzael Avalos dev->illumination_supported = 0; 465ea215a3fSAzael Avalos 466fdb79081SAzael Avalos if (!sci_open(dev)) 467ea215a3fSAzael Avalos return; 468fdb79081SAzael Avalos 469258c5903SAzael Avalos status = tci_raw(dev, in, out); 470fdb79081SAzael Avalos sci_close(dev); 471513ee146SAzael Avalos if (ACPI_FAILURE(status)) { 472fdb79081SAzael Avalos pr_err("ACPI call to query Illumination support failed\n"); 473513ee146SAzael Avalos return; 474513ee146SAzael Avalos } 475513ee146SAzael Avalos 476513ee146SAzael Avalos if (out[0] != TOS_SUCCESS) 477513ee146SAzael Avalos return; 478513ee146SAzael Avalos 479ea215a3fSAzael Avalos dev->illumination_supported = 1; 4806c3f6e6cSPierre Ducroquet } 4816c3f6e6cSPierre Ducroquet 4826c3f6e6cSPierre Ducroquet static void toshiba_illumination_set(struct led_classdev *cdev, 4836c3f6e6cSPierre Ducroquet enum led_brightness brightness) 4846c3f6e6cSPierre Ducroquet { 485135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 486135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 487e1a949c1SAzael Avalos u32 result; 488e1a949c1SAzael Avalos u32 state; 4896c3f6e6cSPierre Ducroquet 4906c3f6e6cSPierre Ducroquet /* First request : initialize communication. */ 491fdb79081SAzael Avalos if (!sci_open(dev)) 4926c3f6e6cSPierre Ducroquet return; 4936c3f6e6cSPierre Ducroquet 494fdb79081SAzael Avalos /* Switch the illumination on/off */ 495fdb79081SAzael Avalos state = brightness ? 1 : 0; 496893f3f62SAzael Avalos result = sci_write(dev, SCI_ILLUMINATION, state); 497fdb79081SAzael Avalos sci_close(dev); 498a6b5354fSAzael Avalos if (result == TOS_FAILURE) 499fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 5006c3f6e6cSPierre Ducroquet } 5016c3f6e6cSPierre Ducroquet 5026c3f6e6cSPierre Ducroquet static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) 5036c3f6e6cSPierre Ducroquet { 504135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 505135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 50678429e55SAzael Avalos u32 result; 50778429e55SAzael Avalos u32 state; 5086c3f6e6cSPierre Ducroquet 5093f75bbe9SAzael Avalos /* First request : initialize communication. */ 510fdb79081SAzael Avalos if (!sci_open(dev)) 5116c3f6e6cSPierre Ducroquet return LED_OFF; 5126c3f6e6cSPierre Ducroquet 5136c3f6e6cSPierre Ducroquet /* Check the illumination */ 514893f3f62SAzael Avalos result = sci_read(dev, SCI_ILLUMINATION, &state); 515fdb79081SAzael Avalos sci_close(dev); 516a6b5354fSAzael Avalos if (result == TOS_FAILURE) { 517fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 518fdb79081SAzael Avalos return LED_OFF; 519e1a949c1SAzael Avalos } else if (result != TOS_SUCCESS) { 5206c3f6e6cSPierre Ducroquet return LED_OFF; 5216c3f6e6cSPierre Ducroquet } 5226c3f6e6cSPierre Ducroquet 523fdb79081SAzael Avalos return state ? LED_FULL : LED_OFF; 5246c3f6e6cSPierre Ducroquet } 5256c3f6e6cSPierre Ducroquet 526360f0f39SAzael Avalos /* KBD Illumination */ 527ea215a3fSAzael Avalos static void toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev) 52893f8c16dSAzael Avalos { 529258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 }; 530258c5903SAzael Avalos u32 out[TCI_WORDS]; 53193f8c16dSAzael Avalos acpi_status status; 53293f8c16dSAzael Avalos 533ea215a3fSAzael Avalos dev->kbd_illum_supported = 0; 53465e3cf9cSAzael Avalos dev->kbd_event_generated = false; 535ea215a3fSAzael Avalos 53693f8c16dSAzael Avalos if (!sci_open(dev)) 537ea215a3fSAzael Avalos return; 53893f8c16dSAzael Avalos 539258c5903SAzael Avalos status = tci_raw(dev, in, out); 54093f8c16dSAzael Avalos sci_close(dev); 541a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) { 54293f8c16dSAzael Avalos pr_err("ACPI call to query kbd illumination support failed\n"); 543513ee146SAzael Avalos return; 544513ee146SAzael Avalos } 545513ee146SAzael Avalos 546513ee146SAzael Avalos if (out[0] != TOS_SUCCESS) 547513ee146SAzael Avalos return; 548513ee146SAzael Avalos 549e0769fe6SDarren Hart /* 550e0769fe6SDarren Hart * Check for keyboard backlight timeout max value, 55193f8c16dSAzael Avalos * previous kbd backlight implementation set this to 55293f8c16dSAzael Avalos * 0x3c0003, and now the new implementation set this 553e0769fe6SDarren Hart * to 0x3c001a, use this to distinguish between them. 55493f8c16dSAzael Avalos */ 55593f8c16dSAzael Avalos if (out[3] == SCI_KBD_TIME_MAX) 55693f8c16dSAzael Avalos dev->kbd_type = 2; 55793f8c16dSAzael Avalos else 55893f8c16dSAzael Avalos dev->kbd_type = 1; 55993f8c16dSAzael Avalos /* Get the current keyboard backlight mode */ 56093f8c16dSAzael Avalos dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK; 56193f8c16dSAzael Avalos /* Get the current time (1-60 seconds) */ 56293f8c16dSAzael Avalos dev->kbd_time = out[2] >> HCI_MISC_SHIFT; 563ea215a3fSAzael Avalos /* Flag as supported */ 564ea215a3fSAzael Avalos dev->kbd_illum_supported = 1; 565ea215a3fSAzael Avalos } 56693f8c16dSAzael Avalos 567360f0f39SAzael Avalos static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time) 568360f0f39SAzael Avalos { 569360f0f39SAzael Avalos u32 result; 570360f0f39SAzael Avalos 571360f0f39SAzael Avalos if (!sci_open(dev)) 572360f0f39SAzael Avalos return -EIO; 573360f0f39SAzael Avalos 574893f3f62SAzael Avalos result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time); 575360f0f39SAzael Avalos sci_close(dev); 576a6b5354fSAzael Avalos if (result == TOS_FAILURE) 577360f0f39SAzael Avalos pr_err("ACPI call to set KBD backlight status failed\n"); 578a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 579360f0f39SAzael Avalos return -ENODEV; 580360f0f39SAzael Avalos 581e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 582360f0f39SAzael Avalos } 583360f0f39SAzael Avalos 584360f0f39SAzael Avalos static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time) 585360f0f39SAzael Avalos { 586360f0f39SAzael Avalos u32 result; 587360f0f39SAzael Avalos 588360f0f39SAzael Avalos if (!sci_open(dev)) 589360f0f39SAzael Avalos return -EIO; 590360f0f39SAzael Avalos 591893f3f62SAzael Avalos result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time); 592360f0f39SAzael Avalos sci_close(dev); 593a6b5354fSAzael Avalos if (result == TOS_FAILURE) 594360f0f39SAzael Avalos pr_err("ACPI call to get KBD backlight status failed\n"); 595a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 596360f0f39SAzael Avalos return -ENODEV; 597360f0f39SAzael Avalos 598e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 599360f0f39SAzael Avalos } 600360f0f39SAzael Avalos 601360f0f39SAzael Avalos static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev) 602360f0f39SAzael Avalos { 603360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 604360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 605e1a949c1SAzael Avalos u32 result; 606e1a949c1SAzael Avalos u32 state; 607360f0f39SAzael Avalos 608360f0f39SAzael Avalos /* Check the keyboard backlight state */ 609d37782bdSAzael Avalos result = hci_read(dev, HCI_KBD_ILLUMINATION, &state); 610a6b5354fSAzael Avalos if (result == TOS_FAILURE) { 611360f0f39SAzael Avalos pr_err("ACPI call to get the keyboard backlight failed\n"); 612360f0f39SAzael Avalos return LED_OFF; 613e1a949c1SAzael Avalos } else if (result != TOS_SUCCESS) { 614360f0f39SAzael Avalos return LED_OFF; 615360f0f39SAzael Avalos } 616360f0f39SAzael Avalos 617360f0f39SAzael Avalos return state ? LED_FULL : LED_OFF; 618360f0f39SAzael Avalos } 619360f0f39SAzael Avalos 620360f0f39SAzael Avalos static void toshiba_kbd_backlight_set(struct led_classdev *cdev, 621360f0f39SAzael Avalos enum led_brightness brightness) 622360f0f39SAzael Avalos { 623360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 624360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 625e1a949c1SAzael Avalos u32 result; 626e1a949c1SAzael Avalos u32 state; 627360f0f39SAzael Avalos 628360f0f39SAzael Avalos /* Set the keyboard backlight state */ 629360f0f39SAzael Avalos state = brightness ? 1 : 0; 630d37782bdSAzael Avalos result = hci_write(dev, HCI_KBD_ILLUMINATION, state); 631a6b5354fSAzael Avalos if (result == TOS_FAILURE) 632360f0f39SAzael Avalos pr_err("ACPI call to set KBD Illumination mode failed\n"); 633360f0f39SAzael Avalos } 634360f0f39SAzael Avalos 6359d8658acSAzael Avalos /* TouchPad support */ 6369d8658acSAzael Avalos static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state) 6379d8658acSAzael Avalos { 6389d8658acSAzael Avalos u32 result; 6399d8658acSAzael Avalos 6409d8658acSAzael Avalos if (!sci_open(dev)) 6419d8658acSAzael Avalos return -EIO; 6429d8658acSAzael Avalos 643893f3f62SAzael Avalos result = sci_write(dev, SCI_TOUCHPAD, state); 6449d8658acSAzael Avalos sci_close(dev); 645a6b5354fSAzael Avalos if (result == TOS_FAILURE) 6469d8658acSAzael Avalos pr_err("ACPI call to set the touchpad failed\n"); 647a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 6489d8658acSAzael Avalos return -ENODEV; 6499d8658acSAzael Avalos 650e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 6519d8658acSAzael Avalos } 6529d8658acSAzael Avalos 6539d8658acSAzael Avalos static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) 6549d8658acSAzael Avalos { 6559d8658acSAzael Avalos u32 result; 6569d8658acSAzael Avalos 6579d8658acSAzael Avalos if (!sci_open(dev)) 6589d8658acSAzael Avalos return -EIO; 6599d8658acSAzael Avalos 660893f3f62SAzael Avalos result = sci_read(dev, SCI_TOUCHPAD, state); 6619d8658acSAzael Avalos sci_close(dev); 662a6b5354fSAzael Avalos if (result == TOS_FAILURE) 6639d8658acSAzael Avalos pr_err("ACPI call to query the touchpad failed\n"); 664a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 6659d8658acSAzael Avalos return -ENODEV; 6669d8658acSAzael Avalos 667e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 6689d8658acSAzael Avalos } 6699d8658acSAzael Avalos 670def6c4e2SAzael Avalos /* Eco Mode support */ 671ea215a3fSAzael Avalos static void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) 672def6c4e2SAzael Avalos { 67398fc4ec6SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 }; 674258c5903SAzael Avalos u32 out[TCI_WORDS]; 67578429e55SAzael Avalos acpi_status status; 676def6c4e2SAzael Avalos 677ea215a3fSAzael Avalos dev->eco_supported = 0; 678ea215a3fSAzael Avalos 679258c5903SAzael Avalos status = tci_raw(dev, in, out); 6808baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 68198fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 682513ee146SAzael Avalos return; 683513ee146SAzael Avalos } 684513ee146SAzael Avalos 6854058ea22SArvid Norlander if (out[0] == TOS_INPUT_DATA_ERROR || out[0] == TOS_NOT_SUPPORTED) { 686e0769fe6SDarren Hart /* 687e0769fe6SDarren Hart * If we receive 0x8300 (Input Data Error), it means that the 68898fc4ec6SAzael Avalos * LED device is present, but that we just screwed the input 68998fc4ec6SAzael Avalos * parameters. 69098fc4ec6SAzael Avalos * 6914058ea22SArvid Norlander * On some laptops 0x8000 (Not supported) is also returned in 6924058ea22SArvid Norlander * this case, so we need to allow for that as well. 6934058ea22SArvid Norlander * 69498fc4ec6SAzael Avalos * Let's query the status of the LED to see if we really have a 69598fc4ec6SAzael Avalos * success response, indicating the actual presense of the LED, 69698fc4ec6SAzael Avalos * bail out otherwise. 69798fc4ec6SAzael Avalos */ 69898fc4ec6SAzael Avalos in[3] = 1; 69998fc4ec6SAzael Avalos status = tci_raw(dev, in, out); 700513ee146SAzael Avalos if (ACPI_FAILURE(status)) { 70198fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 702513ee146SAzael Avalos return; 703513ee146SAzael Avalos } 704513ee146SAzael Avalos 705513ee146SAzael Avalos if (out[0] != TOS_SUCCESS) 706513ee146SAzael Avalos return; 707513ee146SAzael Avalos 708ea215a3fSAzael Avalos dev->eco_supported = 1; 709def6c4e2SAzael Avalos } 710def6c4e2SAzael Avalos } 711def6c4e2SAzael Avalos 712b5163992SAzael Avalos static enum led_brightness 713b5163992SAzael Avalos toshiba_eco_mode_get_status(struct led_classdev *cdev) 714def6c4e2SAzael Avalos { 715def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 716def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 717258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 }; 718258c5903SAzael Avalos u32 out[TCI_WORDS]; 719def6c4e2SAzael Avalos acpi_status status; 720def6c4e2SAzael Avalos 721258c5903SAzael Avalos status = tci_raw(dev, in, out); 722a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) { 723def6c4e2SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 724def6c4e2SAzael Avalos return LED_OFF; 725def6c4e2SAzael Avalos } 726def6c4e2SAzael Avalos 727513ee146SAzael Avalos if (out[0] != TOS_SUCCESS) 728513ee146SAzael Avalos return LED_OFF; 729513ee146SAzael Avalos 730def6c4e2SAzael Avalos return out[2] ? LED_FULL : LED_OFF; 731def6c4e2SAzael Avalos } 732def6c4e2SAzael Avalos 733def6c4e2SAzael Avalos static void toshiba_eco_mode_set_status(struct led_classdev *cdev, 734def6c4e2SAzael Avalos enum led_brightness brightness) 735def6c4e2SAzael Avalos { 736def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 737def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 738258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 }; 739258c5903SAzael Avalos u32 out[TCI_WORDS]; 740def6c4e2SAzael Avalos acpi_status status; 741def6c4e2SAzael Avalos 742def6c4e2SAzael Avalos /* Switch the Eco Mode led on/off */ 743def6c4e2SAzael Avalos in[2] = (brightness) ? 1 : 0; 744258c5903SAzael Avalos status = tci_raw(dev, in, out); 745a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) 746def6c4e2SAzael Avalos pr_err("ACPI call to set ECO led failed\n"); 747def6c4e2SAzael Avalos } 748def6c4e2SAzael Avalos 7495a2813e9SAzael Avalos /* Accelerometer support */ 750ea215a3fSAzael Avalos static void toshiba_accelerometer_available(struct toshiba_acpi_dev *dev) 7515a2813e9SAzael Avalos { 752258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 }; 753258c5903SAzael Avalos u32 out[TCI_WORDS]; 7545a2813e9SAzael Avalos acpi_status status; 7555a2813e9SAzael Avalos 756ea215a3fSAzael Avalos dev->accelerometer_supported = 0; 757ea215a3fSAzael Avalos 758e0769fe6SDarren Hart /* 759e0769fe6SDarren Hart * Check if the accelerometer call exists, 7605a2813e9SAzael Avalos * this call also serves as initialization 7615a2813e9SAzael Avalos */ 762258c5903SAzael Avalos status = tci_raw(dev, in, out); 763513ee146SAzael Avalos if (ACPI_FAILURE(status)) { 7645a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 765513ee146SAzael Avalos return; 766513ee146SAzael Avalos } 767513ee146SAzael Avalos 768513ee146SAzael Avalos if (out[0] != TOS_SUCCESS) 769513ee146SAzael Avalos return; 770513ee146SAzael Avalos 771ea215a3fSAzael Avalos dev->accelerometer_supported = 1; 7725a2813e9SAzael Avalos } 7735a2813e9SAzael Avalos 7745a2813e9SAzael Avalos static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, 7755a2813e9SAzael Avalos u32 *xy, u32 *z) 7765a2813e9SAzael Avalos { 777258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 }; 778258c5903SAzael Avalos u32 out[TCI_WORDS]; 7795a2813e9SAzael Avalos acpi_status status; 7805a2813e9SAzael Avalos 7815a2813e9SAzael Avalos /* Check the Accelerometer status */ 782258c5903SAzael Avalos status = tci_raw(dev, in, out); 783a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) { 7845a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 7855a2813e9SAzael Avalos return -EIO; 7865a2813e9SAzael Avalos } 7875a2813e9SAzael Avalos 788513ee146SAzael Avalos if (out[0] == TOS_NOT_SUPPORTED) 789513ee146SAzael Avalos return -ENODEV; 790513ee146SAzael Avalos 791513ee146SAzael Avalos if (out[0] != TOS_SUCCESS) 792e1a949c1SAzael Avalos return -EIO; 793513ee146SAzael Avalos 794513ee146SAzael Avalos *xy = out[2]; 795513ee146SAzael Avalos *z = out[4]; 796513ee146SAzael Avalos 797513ee146SAzael Avalos return 0; 798e1a949c1SAzael Avalos } 799e1a949c1SAzael Avalos 800e26ffe51SAzael Avalos /* Sleep (Charge and Music) utilities support */ 801c8c91842SAzael Avalos static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev) 802c8c91842SAzael Avalos { 803c8c91842SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 804c8c91842SAzael Avalos u32 out[TCI_WORDS]; 805c8c91842SAzael Avalos acpi_status status; 806c8c91842SAzael Avalos 807c8c91842SAzael Avalos dev->usb_sleep_charge_supported = 0; 808c8c91842SAzael Avalos 809c8c91842SAzael Avalos if (!sci_open(dev)) 810c8c91842SAzael Avalos return; 811c8c91842SAzael Avalos 812c8c91842SAzael Avalos status = tci_raw(dev, in, out); 8138baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 814c8c91842SAzael Avalos pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); 815c8c91842SAzael Avalos sci_close(dev); 816c8c91842SAzael Avalos return; 817513ee146SAzael Avalos } 818513ee146SAzael Avalos 819513ee146SAzael Avalos if (out[0] != TOS_SUCCESS) { 820c8c91842SAzael Avalos sci_close(dev); 821c8c91842SAzael Avalos return; 822c8c91842SAzael Avalos } 823c8c91842SAzael Avalos 824513ee146SAzael Avalos dev->usbsc_mode_base = out[4]; 825513ee146SAzael Avalos 826c8c91842SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 827c8c91842SAzael Avalos status = tci_raw(dev, in, out); 828ea215a3fSAzael Avalos sci_close(dev); 8298baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 830c8c91842SAzael Avalos pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); 831513ee146SAzael Avalos return; 832513ee146SAzael Avalos } 833513ee146SAzael Avalos 834513ee146SAzael Avalos if (out[0] != TOS_SUCCESS) 835513ee146SAzael Avalos return; 836513ee146SAzael Avalos 837c8c91842SAzael Avalos dev->usbsc_bat_level = out[2]; 838ea215a3fSAzael Avalos /* Flag as supported */ 839c8c91842SAzael Avalos dev->usb_sleep_charge_supported = 1; 840c8c91842SAzael Avalos } 841c8c91842SAzael Avalos 842e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, 843e26ffe51SAzael Avalos u32 *mode) 844e26ffe51SAzael Avalos { 845e26ffe51SAzael Avalos u32 result; 846e26ffe51SAzael Avalos 847e26ffe51SAzael Avalos if (!sci_open(dev)) 848e26ffe51SAzael Avalos return -EIO; 849e26ffe51SAzael Avalos 850e26ffe51SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode); 851e26ffe51SAzael Avalos sci_close(dev); 852a6b5354fSAzael Avalos if (result == TOS_FAILURE) 853e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 854a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 855e26ffe51SAzael Avalos return -ENODEV; 856e26ffe51SAzael Avalos 857e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 858e26ffe51SAzael Avalos } 859e26ffe51SAzael Avalos 860e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev, 861e26ffe51SAzael Avalos u32 mode) 862e26ffe51SAzael Avalos { 863e26ffe51SAzael Avalos u32 result; 864e26ffe51SAzael Avalos 865e26ffe51SAzael Avalos if (!sci_open(dev)) 866e26ffe51SAzael Avalos return -EIO; 867e26ffe51SAzael Avalos 868e26ffe51SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode); 869e26ffe51SAzael Avalos sci_close(dev); 870a6b5354fSAzael Avalos if (result == TOS_FAILURE) 871e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 872a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 873e26ffe51SAzael Avalos return -ENODEV; 874e26ffe51SAzael Avalos 875e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 876e26ffe51SAzael Avalos } 877e26ffe51SAzael Avalos 878182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev, 879182bcaa5SAzael Avalos u32 *mode) 880182bcaa5SAzael Avalos { 881182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 882182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 883182bcaa5SAzael Avalos acpi_status status; 884182bcaa5SAzael Avalos 885182bcaa5SAzael Avalos if (!sci_open(dev)) 886182bcaa5SAzael Avalos return -EIO; 887182bcaa5SAzael Avalos 888182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 889182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 890182bcaa5SAzael Avalos sci_close(dev); 8918baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 892182bcaa5SAzael Avalos pr_err("ACPI call to get USB S&C battery level failed\n"); 893513ee146SAzael Avalos return -EIO; 894182bcaa5SAzael Avalos } 895182bcaa5SAzael Avalos 896513ee146SAzael Avalos if (out[0] == TOS_NOT_SUPPORTED) 897513ee146SAzael Avalos return -ENODEV; 898513ee146SAzael Avalos 899513ee146SAzael Avalos if (out[0] != TOS_SUCCESS) 900e1a949c1SAzael Avalos return -EIO; 901513ee146SAzael Avalos 902513ee146SAzael Avalos *mode = out[2]; 903513ee146SAzael Avalos 904513ee146SAzael Avalos return 0; 905513ee146SAzael Avalos 906182bcaa5SAzael Avalos } 907182bcaa5SAzael Avalos 908182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, 909182bcaa5SAzael Avalos u32 mode) 910182bcaa5SAzael Avalos { 911182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 912182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 913182bcaa5SAzael Avalos acpi_status status; 914182bcaa5SAzael Avalos 915182bcaa5SAzael Avalos if (!sci_open(dev)) 916182bcaa5SAzael Avalos return -EIO; 917182bcaa5SAzael Avalos 918182bcaa5SAzael Avalos in[2] = mode; 919182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 920182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 921182bcaa5SAzael Avalos sci_close(dev); 922513ee146SAzael Avalos if (ACPI_FAILURE(status)) { 923182bcaa5SAzael Avalos pr_err("ACPI call to set USB S&C battery level failed\n"); 924513ee146SAzael Avalos return -EIO; 925513ee146SAzael Avalos } 926513ee146SAzael Avalos 927513ee146SAzael Avalos if (out[0] == TOS_NOT_SUPPORTED) 928182bcaa5SAzael Avalos return -ENODEV; 929182bcaa5SAzael Avalos 930e1a949c1SAzael Avalos return out[0] == TOS_SUCCESS ? 0 : -EIO; 931182bcaa5SAzael Avalos } 932182bcaa5SAzael Avalos 933bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, 934bb3fe01fSAzael Avalos u32 *state) 935bb3fe01fSAzael Avalos { 936bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 937bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 938bb3fe01fSAzael Avalos acpi_status status; 939bb3fe01fSAzael Avalos 940bb3fe01fSAzael Avalos if (!sci_open(dev)) 941bb3fe01fSAzael Avalos return -EIO; 942bb3fe01fSAzael Avalos 943bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 944bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 945bb3fe01fSAzael Avalos sci_close(dev); 9468baec45dSAzael Avalos if (ACPI_FAILURE(status)) { 947bb26f189SAzael Avalos pr_err("ACPI call to get USB Rapid Charge failed\n"); 948513ee146SAzael Avalos return -EIO; 949bb3fe01fSAzael Avalos } 950bb3fe01fSAzael Avalos 951513ee146SAzael Avalos if (out[0] == TOS_NOT_SUPPORTED) 952513ee146SAzael Avalos return -ENODEV; 953513ee146SAzael Avalos 954513ee146SAzael Avalos if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2) 955e1a949c1SAzael Avalos return -EIO; 956513ee146SAzael Avalos 957513ee146SAzael Avalos *state = out[2]; 958513ee146SAzael Avalos 959513ee146SAzael Avalos return 0; 960bb3fe01fSAzael Avalos } 961bb3fe01fSAzael Avalos 962bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, 963bb3fe01fSAzael Avalos u32 state) 964bb3fe01fSAzael Avalos { 965bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 966bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 967bb3fe01fSAzael Avalos acpi_status status; 968bb3fe01fSAzael Avalos 969bb3fe01fSAzael Avalos if (!sci_open(dev)) 970bb3fe01fSAzael Avalos return -EIO; 971bb3fe01fSAzael Avalos 972bb3fe01fSAzael Avalos in[2] = state; 973bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 974bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 975bb3fe01fSAzael Avalos sci_close(dev); 976513ee146SAzael Avalos if (ACPI_FAILURE(status)) { 977bb26f189SAzael Avalos pr_err("ACPI call to set USB Rapid Charge failed\n"); 978513ee146SAzael Avalos return -EIO; 979513ee146SAzael Avalos } 980513ee146SAzael Avalos 981513ee146SAzael Avalos if (out[0] == TOS_NOT_SUPPORTED) 982bb3fe01fSAzael Avalos return -ENODEV; 983bb3fe01fSAzael Avalos 984e1a949c1SAzael Avalos return (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) ? 0 : -EIO; 985bb3fe01fSAzael Avalos } 986bb3fe01fSAzael Avalos 987172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state) 988172ce0a9SAzael Avalos { 989172ce0a9SAzael Avalos u32 result; 990172ce0a9SAzael Avalos 991172ce0a9SAzael Avalos if (!sci_open(dev)) 992172ce0a9SAzael Avalos return -EIO; 993172ce0a9SAzael Avalos 994172ce0a9SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state); 995172ce0a9SAzael Avalos sci_close(dev); 996a6b5354fSAzael Avalos if (result == TOS_FAILURE) 997bb26f189SAzael Avalos pr_err("ACPI call to get Sleep and Music failed\n"); 998a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 999172ce0a9SAzael Avalos return -ENODEV; 1000172ce0a9SAzael Avalos 1001cf680eaeSAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1002172ce0a9SAzael Avalos } 1003172ce0a9SAzael Avalos 1004172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state) 1005172ce0a9SAzael Avalos { 1006172ce0a9SAzael Avalos u32 result; 1007172ce0a9SAzael Avalos 1008172ce0a9SAzael Avalos if (!sci_open(dev)) 1009172ce0a9SAzael Avalos return -EIO; 1010172ce0a9SAzael Avalos 1011172ce0a9SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state); 1012172ce0a9SAzael Avalos sci_close(dev); 1013a6b5354fSAzael Avalos if (result == TOS_FAILURE) 1014bb26f189SAzael Avalos pr_err("ACPI call to set Sleep and Music failed\n"); 1015a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1016172ce0a9SAzael Avalos return -ENODEV; 1017172ce0a9SAzael Avalos 1018e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1019172ce0a9SAzael Avalos } 1020172ce0a9SAzael Avalos 1021bae84195SAzael Avalos /* Keyboard function keys */ 1022bae84195SAzael Avalos static int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode) 1023bae84195SAzael Avalos { 1024bae84195SAzael Avalos u32 result; 1025bae84195SAzael Avalos 1026bae84195SAzael Avalos if (!sci_open(dev)) 1027bae84195SAzael Avalos return -EIO; 1028bae84195SAzael Avalos 1029bae84195SAzael Avalos result = sci_read(dev, SCI_KBD_FUNCTION_KEYS, mode); 1030bae84195SAzael Avalos sci_close(dev); 1031a6b5354fSAzael Avalos if (result == TOS_FAILURE) 1032bae84195SAzael Avalos pr_err("ACPI call to get KBD function keys failed\n"); 1033a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1034bae84195SAzael Avalos return -ENODEV; 1035bae84195SAzael Avalos 1036e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 1037bae84195SAzael Avalos } 1038bae84195SAzael Avalos 1039bae84195SAzael Avalos static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode) 1040bae84195SAzael Avalos { 1041bae84195SAzael Avalos u32 result; 1042bae84195SAzael Avalos 1043bae84195SAzael Avalos if (!sci_open(dev)) 1044bae84195SAzael Avalos return -EIO; 1045bae84195SAzael Avalos 1046bae84195SAzael Avalos result = sci_write(dev, SCI_KBD_FUNCTION_KEYS, mode); 1047bae84195SAzael Avalos sci_close(dev); 1048a6b5354fSAzael Avalos if (result == TOS_FAILURE) 1049bae84195SAzael Avalos pr_err("ACPI call to set KBD function keys failed\n"); 1050a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1051bae84195SAzael Avalos return -ENODEV; 1052bae84195SAzael Avalos 1053e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 1054bae84195SAzael Avalos } 1055bae84195SAzael Avalos 105635d53ceaSAzael Avalos /* Panel Power ON */ 105735d53ceaSAzael Avalos static int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state) 105835d53ceaSAzael Avalos { 105935d53ceaSAzael Avalos u32 result; 106035d53ceaSAzael Avalos 106135d53ceaSAzael Avalos if (!sci_open(dev)) 106235d53ceaSAzael Avalos return -EIO; 106335d53ceaSAzael Avalos 106435d53ceaSAzael Avalos result = sci_read(dev, SCI_PANEL_POWER_ON, state); 106535d53ceaSAzael Avalos sci_close(dev); 1066a6b5354fSAzael Avalos if (result == TOS_FAILURE) 106735d53ceaSAzael Avalos pr_err("ACPI call to get Panel Power ON failed\n"); 1068a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 106935d53ceaSAzael Avalos return -ENODEV; 107035d53ceaSAzael Avalos 1071e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 107235d53ceaSAzael Avalos } 107335d53ceaSAzael Avalos 107435d53ceaSAzael Avalos static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state) 107535d53ceaSAzael Avalos { 107635d53ceaSAzael Avalos u32 result; 107735d53ceaSAzael Avalos 107835d53ceaSAzael Avalos if (!sci_open(dev)) 107935d53ceaSAzael Avalos return -EIO; 108035d53ceaSAzael Avalos 108135d53ceaSAzael Avalos result = sci_write(dev, SCI_PANEL_POWER_ON, state); 108235d53ceaSAzael Avalos sci_close(dev); 1083a6b5354fSAzael Avalos if (result == TOS_FAILURE) 108435d53ceaSAzael Avalos pr_err("ACPI call to set Panel Power ON failed\n"); 1085a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 108635d53ceaSAzael Avalos return -ENODEV; 108735d53ceaSAzael Avalos 1088e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 108935d53ceaSAzael Avalos } 109035d53ceaSAzael Avalos 109117fe4b3dSAzael Avalos /* USB Three */ 109217fe4b3dSAzael Avalos static int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state) 109317fe4b3dSAzael Avalos { 109417fe4b3dSAzael Avalos u32 result; 109517fe4b3dSAzael Avalos 109617fe4b3dSAzael Avalos if (!sci_open(dev)) 109717fe4b3dSAzael Avalos return -EIO; 109817fe4b3dSAzael Avalos 109917fe4b3dSAzael Avalos result = sci_read(dev, SCI_USB_THREE, state); 110017fe4b3dSAzael Avalos sci_close(dev); 1101a6b5354fSAzael Avalos if (result == TOS_FAILURE) 110217fe4b3dSAzael Avalos pr_err("ACPI call to get USB 3 failed\n"); 1103a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 110417fe4b3dSAzael Avalos return -ENODEV; 110517fe4b3dSAzael Avalos 1106e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 110717fe4b3dSAzael Avalos } 110817fe4b3dSAzael Avalos 110917fe4b3dSAzael Avalos static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state) 111017fe4b3dSAzael Avalos { 111117fe4b3dSAzael Avalos u32 result; 111217fe4b3dSAzael Avalos 111317fe4b3dSAzael Avalos if (!sci_open(dev)) 111417fe4b3dSAzael Avalos return -EIO; 111517fe4b3dSAzael Avalos 111617fe4b3dSAzael Avalos result = sci_write(dev, SCI_USB_THREE, state); 111717fe4b3dSAzael Avalos sci_close(dev); 1118a6b5354fSAzael Avalos if (result == TOS_FAILURE) 111917fe4b3dSAzael Avalos pr_err("ACPI call to set USB 3 failed\n"); 1120a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 112117fe4b3dSAzael Avalos return -ENODEV; 112217fe4b3dSAzael Avalos 1123e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 112417fe4b3dSAzael Avalos } 112517fe4b3dSAzael Avalos 112656e6b353SAzael Avalos /* Hotkey Event type */ 112756e6b353SAzael Avalos static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev, 112856e6b353SAzael Avalos u32 *type) 112956e6b353SAzael Avalos { 11303b876000SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_SYSTEM_INFO, 0x03, 0, 0, 0 }; 11313b876000SAzael Avalos u32 out[TCI_WORDS]; 11323b876000SAzael Avalos acpi_status status; 113356e6b353SAzael Avalos 11343b876000SAzael Avalos status = tci_raw(dev, in, out); 11353b876000SAzael Avalos if (ACPI_FAILURE(status)) { 113656e6b353SAzael Avalos pr_err("ACPI call to get System type failed\n"); 1137513ee146SAzael Avalos return -EIO; 113856e6b353SAzael Avalos } 113956e6b353SAzael Avalos 1140513ee146SAzael Avalos if (out[0] == TOS_NOT_SUPPORTED) 1141513ee146SAzael Avalos return -ENODEV; 1142513ee146SAzael Avalos 1143513ee146SAzael Avalos if (out[0] != TOS_SUCCESS) 1144e1a949c1SAzael Avalos return -EIO; 1145513ee146SAzael Avalos 1146513ee146SAzael Avalos *type = out[3]; 1147513ee146SAzael Avalos 1148513ee146SAzael Avalos return 0; 114956e6b353SAzael Avalos } 115056e6b353SAzael Avalos 11516873f46aSAzael Avalos /* Wireless status (RFKill, WLAN, BT, WWAN) */ 11526873f46aSAzael Avalos static int toshiba_wireless_status(struct toshiba_acpi_dev *dev) 11536873f46aSAzael Avalos { 11546873f46aSAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_WIRELESS, 0, 0, 0, 0 }; 11556873f46aSAzael Avalos u32 out[TCI_WORDS]; 11566873f46aSAzael Avalos acpi_status status; 11576873f46aSAzael Avalos 11586873f46aSAzael Avalos in[3] = HCI_WIRELESS_STATUS; 11596873f46aSAzael Avalos status = tci_raw(dev, in, out); 11606873f46aSAzael Avalos 11616873f46aSAzael Avalos if (ACPI_FAILURE(status)) { 11626873f46aSAzael Avalos pr_err("ACPI call to get Wireless status failed\n"); 11636873f46aSAzael Avalos return -EIO; 11646873f46aSAzael Avalos } 11656873f46aSAzael Avalos 11666873f46aSAzael Avalos if (out[0] == TOS_NOT_SUPPORTED) 11676873f46aSAzael Avalos return -ENODEV; 11686873f46aSAzael Avalos 11696873f46aSAzael Avalos if (out[0] != TOS_SUCCESS) 11706873f46aSAzael Avalos return -EIO; 11716873f46aSAzael Avalos 11726873f46aSAzael Avalos dev->killswitch = !!(out[2] & HCI_WIRELESS_STATUS); 11736873f46aSAzael Avalos 11746873f46aSAzael Avalos return 0; 11756873f46aSAzael Avalos } 11766873f46aSAzael Avalos 11776873f46aSAzael Avalos /* WWAN */ 11786873f46aSAzael Avalos static void toshiba_wwan_available(struct toshiba_acpi_dev *dev) 11796873f46aSAzael Avalos { 11806873f46aSAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_WIRELESS, 0, 0, 0, 0 }; 11816873f46aSAzael Avalos u32 out[TCI_WORDS]; 11826873f46aSAzael Avalos acpi_status status; 11836873f46aSAzael Avalos 11846873f46aSAzael Avalos dev->wwan_supported = 0; 11856873f46aSAzael Avalos 11866873f46aSAzael Avalos /* 11876873f46aSAzael Avalos * WWAN support can be queried by setting the in[3] value to 11886873f46aSAzael Avalos * HCI_WIRELESS_WWAN (0x03). 11896873f46aSAzael Avalos * 11906873f46aSAzael Avalos * If supported, out[0] contains TOS_SUCCESS and out[2] contains 11916873f46aSAzael Avalos * HCI_WIRELESS_WWAN_STATUS (0x2000). 11926873f46aSAzael Avalos * 11936873f46aSAzael Avalos * If not supported, out[0] contains TOS_INPUT_DATA_ERROR (0x8300) 11946873f46aSAzael Avalos * or TOS_NOT_SUPPORTED (0x8000). 11956873f46aSAzael Avalos */ 11966873f46aSAzael Avalos in[3] = HCI_WIRELESS_WWAN; 11976873f46aSAzael Avalos status = tci_raw(dev, in, out); 11986873f46aSAzael Avalos if (ACPI_FAILURE(status)) { 11996873f46aSAzael Avalos pr_err("ACPI call to get WWAN status failed\n"); 12006873f46aSAzael Avalos return; 12016873f46aSAzael Avalos } 12026873f46aSAzael Avalos 12036873f46aSAzael Avalos if (out[0] != TOS_SUCCESS) 12046873f46aSAzael Avalos return; 12056873f46aSAzael Avalos 12066873f46aSAzael Avalos dev->wwan_supported = (out[2] == HCI_WIRELESS_WWAN_STATUS); 12076873f46aSAzael Avalos } 12086873f46aSAzael Avalos 12096873f46aSAzael Avalos static int toshiba_wwan_set(struct toshiba_acpi_dev *dev, u32 state) 12106873f46aSAzael Avalos { 12116873f46aSAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, HCI_WIRELESS, state, 0, 0, 0 }; 12126873f46aSAzael Avalos u32 out[TCI_WORDS]; 12136873f46aSAzael Avalos acpi_status status; 12146873f46aSAzael Avalos 12156873f46aSAzael Avalos in[3] = HCI_WIRELESS_WWAN_STATUS; 12166873f46aSAzael Avalos status = tci_raw(dev, in, out); 12176873f46aSAzael Avalos if (ACPI_FAILURE(status)) { 12186873f46aSAzael Avalos pr_err("ACPI call to set WWAN status failed\n"); 12196873f46aSAzael Avalos return -EIO; 12206873f46aSAzael Avalos } 12216873f46aSAzael Avalos 12226873f46aSAzael Avalos if (out[0] == TOS_NOT_SUPPORTED) 12236873f46aSAzael Avalos return -ENODEV; 12246873f46aSAzael Avalos 12256873f46aSAzael Avalos if (out[0] != TOS_SUCCESS) 12266873f46aSAzael Avalos return -EIO; 12276873f46aSAzael Avalos 12286873f46aSAzael Avalos /* 12296873f46aSAzael Avalos * Some devices only need to call HCI_WIRELESS_WWAN_STATUS to 12306873f46aSAzael Avalos * (de)activate the device, but some others need the 12316873f46aSAzael Avalos * HCI_WIRELESS_WWAN_POWER call as well. 12326873f46aSAzael Avalos */ 12336873f46aSAzael Avalos in[3] = HCI_WIRELESS_WWAN_POWER; 12346873f46aSAzael Avalos status = tci_raw(dev, in, out); 12356873f46aSAzael Avalos if (ACPI_FAILURE(status)) { 12366873f46aSAzael Avalos pr_err("ACPI call to set WWAN power failed\n"); 12376873f46aSAzael Avalos return -EIO; 12386873f46aSAzael Avalos } 12396873f46aSAzael Avalos 12406873f46aSAzael Avalos if (out[0] == TOS_NOT_SUPPORTED) 12416873f46aSAzael Avalos return -ENODEV; 12426873f46aSAzael Avalos 12436873f46aSAzael Avalos return out[0] == TOS_SUCCESS ? 0 : -EIO; 12446873f46aSAzael Avalos } 12456873f46aSAzael Avalos 1246763ff32fSAzael Avalos /* Cooling Method */ 1247763ff32fSAzael Avalos static void toshiba_cooling_method_available(struct toshiba_acpi_dev *dev) 1248763ff32fSAzael Avalos { 1249763ff32fSAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_COOLING_METHOD, 0, 0, 0, 0 }; 1250763ff32fSAzael Avalos u32 out[TCI_WORDS]; 1251763ff32fSAzael Avalos acpi_status status; 1252763ff32fSAzael Avalos 1253763ff32fSAzael Avalos dev->cooling_method_supported = 0; 1254763ff32fSAzael Avalos dev->max_cooling_method = 0; 1255763ff32fSAzael Avalos 1256763ff32fSAzael Avalos status = tci_raw(dev, in, out); 1257513ee146SAzael Avalos if (ACPI_FAILURE(status)) { 1258763ff32fSAzael Avalos pr_err("ACPI call to get Cooling Method failed\n"); 1259513ee146SAzael Avalos return; 1260513ee146SAzael Avalos } 1261763ff32fSAzael Avalos 1262763ff32fSAzael Avalos if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2) 1263763ff32fSAzael Avalos return; 1264763ff32fSAzael Avalos 1265763ff32fSAzael Avalos dev->cooling_method_supported = 1; 1266763ff32fSAzael Avalos dev->max_cooling_method = out[3]; 1267763ff32fSAzael Avalos } 1268763ff32fSAzael Avalos 1269763ff32fSAzael Avalos static int toshiba_cooling_method_get(struct toshiba_acpi_dev *dev, u32 *state) 1270763ff32fSAzael Avalos { 1271763ff32fSAzael Avalos u32 result = hci_read(dev, HCI_COOLING_METHOD, state); 1272763ff32fSAzael Avalos 1273763ff32fSAzael Avalos if (result == TOS_FAILURE) 1274763ff32fSAzael Avalos pr_err("ACPI call to get Cooling Method failed\n"); 1275763ff32fSAzael Avalos 1276763ff32fSAzael Avalos if (result == TOS_NOT_SUPPORTED) 1277763ff32fSAzael Avalos return -ENODEV; 1278763ff32fSAzael Avalos 1279763ff32fSAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 1280763ff32fSAzael Avalos } 1281763ff32fSAzael Avalos 1282763ff32fSAzael Avalos static int toshiba_cooling_method_set(struct toshiba_acpi_dev *dev, u32 state) 1283763ff32fSAzael Avalos { 1284763ff32fSAzael Avalos u32 result = hci_write(dev, HCI_COOLING_METHOD, state); 1285763ff32fSAzael Avalos 1286763ff32fSAzael Avalos if (result == TOS_FAILURE) 1287fa1bc2a0SAzael Avalos pr_err("ACPI call to set Cooling Method failed\n"); 1288763ff32fSAzael Avalos 1289763ff32fSAzael Avalos if (result == TOS_NOT_SUPPORTED) 1290763ff32fSAzael Avalos return -ENODEV; 1291763ff32fSAzael Avalos 1292763ff32fSAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 1293763ff32fSAzael Avalos } 1294763ff32fSAzael Avalos 129589655fbbSArvid Norlander /* Battery charge control */ 129689655fbbSArvid Norlander static void toshiba_battery_charge_mode_available(struct toshiba_acpi_dev *dev) 129789655fbbSArvid Norlander { 129889655fbbSArvid Norlander u32 in[TCI_WORDS] = { HCI_GET, HCI_BATTERY_CHARGE_MODE, 0, 0, 0, 0 }; 129989655fbbSArvid Norlander u32 out[TCI_WORDS]; 130089655fbbSArvid Norlander acpi_status status; 130189655fbbSArvid Norlander 130289655fbbSArvid Norlander dev->battery_charge_mode_supported = 0; 130389655fbbSArvid Norlander 130489655fbbSArvid Norlander status = tci_raw(dev, in, out); 130589655fbbSArvid Norlander if (ACPI_FAILURE(status)) { 130689655fbbSArvid Norlander pr_err("ACPI call to get Battery Charge Mode failed\n"); 130789655fbbSArvid Norlander return; 130889655fbbSArvid Norlander } 130989655fbbSArvid Norlander 131089655fbbSArvid Norlander if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2) 131189655fbbSArvid Norlander return; 131289655fbbSArvid Norlander 131389655fbbSArvid Norlander dev->battery_charge_mode_supported = 1; 131489655fbbSArvid Norlander } 131589655fbbSArvid Norlander 131689655fbbSArvid Norlander static int toshiba_battery_charge_mode_get(struct toshiba_acpi_dev *dev, u32 *state) 131789655fbbSArvid Norlander { 131889655fbbSArvid Norlander u32 in[TCI_WORDS] = { HCI_GET, HCI_BATTERY_CHARGE_MODE, 0, 0, 0, 0x1 }; 131989655fbbSArvid Norlander u32 out[TCI_WORDS]; 132089655fbbSArvid Norlander int retries = 3; 132189655fbbSArvid Norlander 132289655fbbSArvid Norlander do { 132389655fbbSArvid Norlander acpi_status status = tci_raw(dev, in, out); 132489655fbbSArvid Norlander 132589655fbbSArvid Norlander if (ACPI_FAILURE(status)) 132689655fbbSArvid Norlander pr_err("ACPI call to get Battery Charge Mode failed\n"); 132789655fbbSArvid Norlander switch (out[0]) { 132889655fbbSArvid Norlander case TOS_SUCCESS: 132989655fbbSArvid Norlander case TOS_SUCCESS2: 133089655fbbSArvid Norlander *state = out[2]; 133189655fbbSArvid Norlander return 0; 133289655fbbSArvid Norlander case TOS_NOT_SUPPORTED: 133389655fbbSArvid Norlander return -ENODEV; 133489655fbbSArvid Norlander case TOS_DATA_NOT_AVAILABLE: 133589655fbbSArvid Norlander retries--; 133689655fbbSArvid Norlander break; 133789655fbbSArvid Norlander default: 133889655fbbSArvid Norlander return -EIO; 133989655fbbSArvid Norlander } 134089655fbbSArvid Norlander } while (retries); 134189655fbbSArvid Norlander 134289655fbbSArvid Norlander return -EIO; 134389655fbbSArvid Norlander } 134489655fbbSArvid Norlander 134589655fbbSArvid Norlander static int toshiba_battery_charge_mode_set(struct toshiba_acpi_dev *dev, u32 state) 134689655fbbSArvid Norlander { 134789655fbbSArvid Norlander u32 result = hci_write(dev, HCI_BATTERY_CHARGE_MODE, state); 134889655fbbSArvid Norlander 134989655fbbSArvid Norlander if (result == TOS_FAILURE) 135089655fbbSArvid Norlander pr_err("ACPI call to set Battery Charge Mode failed\n"); 135189655fbbSArvid Norlander 135289655fbbSArvid Norlander if (result == TOS_NOT_SUPPORTED) 135389655fbbSArvid Norlander return -ENODEV; 135489655fbbSArvid Norlander 135589655fbbSArvid Norlander return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 135689655fbbSArvid Norlander } 135789655fbbSArvid Norlander 13583f75bbe9SAzael Avalos /* Transflective Backlight */ 1359695f6060SAzael Avalos static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status) 1360121b7b0dSAkio Idehara { 1361e1a949c1SAzael Avalos u32 result = hci_read(dev, HCI_TR_BACKLIGHT, status); 1362121b7b0dSAkio Idehara 1363e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1364e1a949c1SAzael Avalos pr_err("ACPI call to get Transflective Backlight failed\n"); 1365e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1366e1a949c1SAzael Avalos return -ENODEV; 1367e1a949c1SAzael Avalos 1368e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1369121b7b0dSAkio Idehara } 1370121b7b0dSAkio Idehara 1371695f6060SAzael Avalos static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 status) 1372121b7b0dSAkio Idehara { 1373e1a949c1SAzael Avalos u32 result = hci_write(dev, HCI_TR_BACKLIGHT, !status); 1374121b7b0dSAkio Idehara 1375e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1376e1a949c1SAzael Avalos pr_err("ACPI call to set Transflective Backlight failed\n"); 1377e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1378e1a949c1SAzael Avalos return -ENODEV; 1379e1a949c1SAzael Avalos 1380e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1381121b7b0dSAkio Idehara } 1382121b7b0dSAkio Idehara 13833f75bbe9SAzael Avalos static struct proc_dir_entry *toshiba_proc_dir; 1384b4f9fe12SLen Brown 13853f75bbe9SAzael Avalos /* LCD Brightness */ 138662cce752SSeth Forshee static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) 1387b4f9fe12SLen Brown { 138878429e55SAzael Avalos int brightness = 0; 1389e1a949c1SAzael Avalos u32 result; 1390b4f9fe12SLen Brown u32 value; 1391121b7b0dSAkio Idehara 1392121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1393695f6060SAzael Avalos int ret = get_tr_backlight_status(dev, &value); 1394b5163992SAzael Avalos 1395121b7b0dSAkio Idehara if (ret) 1396121b7b0dSAkio Idehara return ret; 1397695f6060SAzael Avalos if (value) 1398121b7b0dSAkio Idehara return 0; 1399121b7b0dSAkio Idehara brightness++; 1400121b7b0dSAkio Idehara } 1401b4f9fe12SLen Brown 1402e1a949c1SAzael Avalos result = hci_read(dev, HCI_LCD_BRIGHTNESS, &value); 1403e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1404e1a949c1SAzael Avalos pr_err("ACPI call to get LCD Brightness failed\n"); 1405e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1406e1a949c1SAzael Avalos return -ENODEV; 140732bcd5cbSSeth Forshee 1408513ee146SAzael Avalos return result == TOS_SUCCESS ? 1409513ee146SAzael Avalos brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT) : 1410513ee146SAzael Avalos -EIO; 1411b4f9fe12SLen Brown } 1412b4f9fe12SLen Brown 141362cce752SSeth Forshee static int get_lcd_brightness(struct backlight_device *bd) 141462cce752SSeth Forshee { 141562cce752SSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 1416b5163992SAzael Avalos 141762cce752SSeth Forshee return __get_lcd_brightness(dev); 141862cce752SSeth Forshee } 141962cce752SSeth Forshee 1420936c8bcdSAlexey Dobriyan static int lcd_proc_show(struct seq_file *m, void *v) 1421b4f9fe12SLen Brown { 1422135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1423121b7b0dSAkio Idehara int levels; 1424e1a949c1SAzael Avalos int value; 1425b4f9fe12SLen Brown 1426135740deSSeth Forshee if (!dev->backlight_dev) 1427135740deSSeth Forshee return -ENODEV; 1428135740deSSeth Forshee 1429121b7b0dSAkio Idehara levels = dev->backlight_dev->props.max_brightness + 1; 143062cce752SSeth Forshee value = get_lcd_brightness(dev->backlight_dev); 1431513ee146SAzael Avalos if (value < 0) { 1432513ee146SAzael Avalos pr_err("Error reading LCD brightness\n"); 1433513ee146SAzael Avalos return value; 1434b4f9fe12SLen Brown } 1435b4f9fe12SLen Brown 1436513ee146SAzael Avalos seq_printf(m, "brightness: %d\n", value); 1437513ee146SAzael Avalos seq_printf(m, "brightness_levels: %d\n", levels); 1438e1a949c1SAzael Avalos 1439513ee146SAzael Avalos return 0; 1440936c8bcdSAlexey Dobriyan } 1441936c8bcdSAlexey Dobriyan 1442936c8bcdSAlexey Dobriyan static int lcd_proc_open(struct inode *inode, struct file *file) 1443936c8bcdSAlexey Dobriyan { 1444359745d7SMuchun Song return single_open(file, lcd_proc_show, pde_data(inode)); 1445b4f9fe12SLen Brown } 1446b4f9fe12SLen Brown 144762cce752SSeth Forshee static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) 1448b4f9fe12SLen Brown { 1449e1a949c1SAzael Avalos u32 result; 1450b4f9fe12SLen Brown 1451121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1452695f6060SAzael Avalos int ret = set_tr_backlight_status(dev, !value); 1453b5163992SAzael Avalos 1454121b7b0dSAkio Idehara if (ret) 1455121b7b0dSAkio Idehara return ret; 1456121b7b0dSAkio Idehara if (value) 1457121b7b0dSAkio Idehara value--; 1458121b7b0dSAkio Idehara } 1459121b7b0dSAkio Idehara 1460a39f46dfSAzael Avalos value = value << HCI_LCD_BRIGHTNESS_SHIFT; 1461e1a949c1SAzael Avalos result = hci_write(dev, HCI_LCD_BRIGHTNESS, value); 1462e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1463e1a949c1SAzael Avalos pr_err("ACPI call to set LCD Brightness failed\n"); 1464e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1465e1a949c1SAzael Avalos return -ENODEV; 1466e1a949c1SAzael Avalos 1467e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 1468b4f9fe12SLen Brown } 1469b4f9fe12SLen Brown 1470b4f9fe12SLen Brown static int set_lcd_status(struct backlight_device *bd) 1471b4f9fe12SLen Brown { 1472135740deSSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 1473b5163992SAzael Avalos 147462cce752SSeth Forshee return set_lcd_brightness(dev, bd->props.brightness); 1475b4f9fe12SLen Brown } 1476b4f9fe12SLen Brown 1477936c8bcdSAlexey Dobriyan static ssize_t lcd_proc_write(struct file *file, const char __user *buf, 1478936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1479b4f9fe12SLen Brown { 1480359745d7SMuchun Song struct toshiba_acpi_dev *dev = pde_data(file_inode(file)); 1481936c8bcdSAlexey Dobriyan char cmd[42]; 1482936c8bcdSAlexey Dobriyan size_t len; 148378429e55SAzael Avalos int levels; 1484e1a949c1SAzael Avalos int value; 1485b4f9fe12SLen Brown 1486936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1487936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1488936c8bcdSAlexey Dobriyan return -EFAULT; 1489936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1490936c8bcdSAlexey Dobriyan 149178429e55SAzael Avalos levels = dev->backlight_dev->props.max_brightness + 1; 1492e1a949c1SAzael Avalos if (sscanf(cmd, " brightness : %i", &value) != 1 && 1493e1a949c1SAzael Avalos value < 0 && value > levels) 1494e1a949c1SAzael Avalos return -EINVAL; 1495e1a949c1SAzael Avalos 1496e1a949c1SAzael Avalos if (set_lcd_brightness(dev, value)) 1497e1a949c1SAzael Avalos return -EIO; 1498e1a949c1SAzael Avalos 1499e1a949c1SAzael Avalos return count; 1500b4f9fe12SLen Brown } 1501b4f9fe12SLen Brown 150297a32539SAlexey Dobriyan static const struct proc_ops lcd_proc_ops = { 150397a32539SAlexey Dobriyan .proc_open = lcd_proc_open, 150497a32539SAlexey Dobriyan .proc_read = seq_read, 150597a32539SAlexey Dobriyan .proc_lseek = seq_lseek, 150697a32539SAlexey Dobriyan .proc_release = single_release, 150797a32539SAlexey Dobriyan .proc_write = lcd_proc_write, 1508936c8bcdSAlexey Dobriyan }; 1509936c8bcdSAlexey Dobriyan 1510e1a949c1SAzael Avalos /* Video-Out */ 151136d03f93SSeth Forshee static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status) 151236d03f93SSeth Forshee { 1513e1a949c1SAzael Avalos u32 result = hci_read(dev, HCI_VIDEO_OUT, status); 151436d03f93SSeth Forshee 1515e1a949c1SAzael Avalos if (result == TOS_FAILURE) 1516e1a949c1SAzael Avalos pr_err("ACPI call to get Video-Out failed\n"); 1517e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 1518e1a949c1SAzael Avalos return -ENODEV; 1519e1a949c1SAzael Avalos 1520e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 152136d03f93SSeth Forshee } 152236d03f93SSeth Forshee 1523936c8bcdSAlexey Dobriyan static int video_proc_show(struct seq_file *m, void *v) 1524b4f9fe12SLen Brown { 1525135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1526513ee146SAzael Avalos int is_lcd, is_crt, is_tv; 1527b4f9fe12SLen Brown u32 value; 1528b4f9fe12SLen Brown 1529513ee146SAzael Avalos if (get_video_status(dev, &value)) 1530513ee146SAzael Avalos return -EIO; 1531513ee146SAzael Avalos 1532513ee146SAzael Avalos is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; 1533513ee146SAzael Avalos is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; 1534513ee146SAzael Avalos is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; 1535b5163992SAzael Avalos 1536936c8bcdSAlexey Dobriyan seq_printf(m, "lcd_out: %d\n", is_lcd); 1537936c8bcdSAlexey Dobriyan seq_printf(m, "crt_out: %d\n", is_crt); 1538936c8bcdSAlexey Dobriyan seq_printf(m, "tv_out: %d\n", is_tv); 1539b4f9fe12SLen Brown 1540513ee146SAzael Avalos return 0; 1541b4f9fe12SLen Brown } 1542b4f9fe12SLen Brown 1543936c8bcdSAlexey Dobriyan static int video_proc_open(struct inode *inode, struct file *file) 1544b4f9fe12SLen Brown { 1545359745d7SMuchun Song return single_open(file, video_proc_show, pde_data(inode)); 1546936c8bcdSAlexey Dobriyan } 1547936c8bcdSAlexey Dobriyan 1548936c8bcdSAlexey Dobriyan static ssize_t video_proc_write(struct file *file, const char __user *buf, 1549936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1550936c8bcdSAlexey Dobriyan { 1551359745d7SMuchun Song struct toshiba_acpi_dev *dev = pde_data(file_inode(file)); 1552e1a949c1SAzael Avalos char *buffer; 1553e1a949c1SAzael Avalos char *cmd; 15542a72c46aSKaixu Xia int lcd_out = -1, crt_out = -1, tv_out = -1; 1555b4f9fe12SLen Brown int remain = count; 1556e1a949c1SAzael Avalos int value; 1557e1a949c1SAzael Avalos int ret; 1558b4f9fe12SLen Brown u32 video_out; 1559b4f9fe12SLen Brown 1560f0ee1a6dSGeliang Tang cmd = memdup_user_nul(buf, count); 1561f0ee1a6dSGeliang Tang if (IS_ERR(cmd)) 1562f0ee1a6dSGeliang Tang return PTR_ERR(cmd); 1563936c8bcdSAlexey Dobriyan 1564936c8bcdSAlexey Dobriyan buffer = cmd; 1565936c8bcdSAlexey Dobriyan 1566e0769fe6SDarren Hart /* 1567e0769fe6SDarren Hart * Scan expression. Multiple expressions may be delimited with ; 1568e0769fe6SDarren Hart * NOTE: To keep scanning simple, invalid fields are ignored. 1569b4f9fe12SLen Brown */ 1570b4f9fe12SLen Brown while (remain) { 1571b4f9fe12SLen Brown if (sscanf(buffer, " lcd_out : %i", &value) == 1) 1572b4f9fe12SLen Brown lcd_out = value & 1; 1573b4f9fe12SLen Brown else if (sscanf(buffer, " crt_out : %i", &value) == 1) 1574b4f9fe12SLen Brown crt_out = value & 1; 1575b4f9fe12SLen Brown else if (sscanf(buffer, " tv_out : %i", &value) == 1) 1576b4f9fe12SLen Brown tv_out = value & 1; 1577e0769fe6SDarren Hart /* Advance to one character past the next ; */ 1578b4f9fe12SLen Brown do { 1579b4f9fe12SLen Brown ++buffer; 1580b4f9fe12SLen Brown --remain; 1581b5163992SAzael Avalos } while (remain && *(buffer - 1) != ';'); 1582b4f9fe12SLen Brown } 1583b4f9fe12SLen Brown 1584936c8bcdSAlexey Dobriyan kfree(cmd); 1585936c8bcdSAlexey Dobriyan 158636d03f93SSeth Forshee ret = get_video_status(dev, &video_out); 158736d03f93SSeth Forshee if (!ret) { 1588b4f9fe12SLen Brown unsigned int new_video_out = video_out; 1589b5163992SAzael Avalos 1590b4f9fe12SLen Brown if (lcd_out != -1) 1591b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out); 1592b4f9fe12SLen Brown if (crt_out != -1) 1593b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out); 1594b4f9fe12SLen Brown if (tv_out != -1) 1595b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out); 1596e0769fe6SDarren Hart /* 1597e0769fe6SDarren Hart * To avoid unnecessary video disruption, only write the new 15983f75bbe9SAzael Avalos * video setting if something changed. 15993f75bbe9SAzael Avalos */ 1600b4f9fe12SLen Brown if (new_video_out != video_out) 160132bcd5cbSSeth Forshee ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out); 1602b4f9fe12SLen Brown } 1603b4f9fe12SLen Brown 1604e1a949c1SAzael Avalos return ret ? -EIO : count; 1605b4f9fe12SLen Brown } 1606b4f9fe12SLen Brown 160797a32539SAlexey Dobriyan static const struct proc_ops video_proc_ops = { 160897a32539SAlexey Dobriyan .proc_open = video_proc_open, 160997a32539SAlexey Dobriyan .proc_read = seq_read, 161097a32539SAlexey Dobriyan .proc_lseek = seq_lseek, 161197a32539SAlexey Dobriyan .proc_release = single_release, 161297a32539SAlexey Dobriyan .proc_write = video_proc_write, 1613936c8bcdSAlexey Dobriyan }; 1614936c8bcdSAlexey Dobriyan 16153e07e5baSAzael Avalos /* Fan status */ 161636d03f93SSeth Forshee static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status) 161736d03f93SSeth Forshee { 16183e07e5baSAzael Avalos u32 result = hci_read(dev, HCI_FAN, status); 161936d03f93SSeth Forshee 16203e07e5baSAzael Avalos if (result == TOS_FAILURE) 16213e07e5baSAzael Avalos pr_err("ACPI call to get Fan status failed\n"); 16223e07e5baSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 16233e07e5baSAzael Avalos return -ENODEV; 16243e07e5baSAzael Avalos 1625e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 16263e07e5baSAzael Avalos } 16273e07e5baSAzael Avalos 16283e07e5baSAzael Avalos static int set_fan_status(struct toshiba_acpi_dev *dev, u32 status) 16293e07e5baSAzael Avalos { 16303e07e5baSAzael Avalos u32 result = hci_write(dev, HCI_FAN, status); 16313e07e5baSAzael Avalos 16323e07e5baSAzael Avalos if (result == TOS_FAILURE) 16333e07e5baSAzael Avalos pr_err("ACPI call to set Fan status failed\n"); 16343e07e5baSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 16353e07e5baSAzael Avalos return -ENODEV; 16363e07e5baSAzael Avalos 1637e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO; 163836d03f93SSeth Forshee } 163936d03f93SSeth Forshee 1640936c8bcdSAlexey Dobriyan static int fan_proc_show(struct seq_file *m, void *v) 1641b4f9fe12SLen Brown { 1642135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1643b4f9fe12SLen Brown u32 value; 1644b4f9fe12SLen Brown 16453e07e5baSAzael Avalos if (get_fan_status(dev, &value)) 16463e07e5baSAzael Avalos return -EIO; 16473e07e5baSAzael Avalos 1648936c8bcdSAlexey Dobriyan seq_printf(m, "running: %d\n", (value > 0)); 1649135740deSSeth Forshee seq_printf(m, "force_on: %d\n", dev->force_fan); 1650b4f9fe12SLen Brown 16513e07e5baSAzael Avalos return 0; 1652b4f9fe12SLen Brown } 1653b4f9fe12SLen Brown 1654936c8bcdSAlexey Dobriyan static int fan_proc_open(struct inode *inode, struct file *file) 1655b4f9fe12SLen Brown { 1656359745d7SMuchun Song return single_open(file, fan_proc_show, pde_data(inode)); 1657936c8bcdSAlexey Dobriyan } 1658936c8bcdSAlexey Dobriyan 1659936c8bcdSAlexey Dobriyan static ssize_t fan_proc_write(struct file *file, const char __user *buf, 1660936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1661936c8bcdSAlexey Dobriyan { 1662359745d7SMuchun Song struct toshiba_acpi_dev *dev = pde_data(file_inode(file)); 1663936c8bcdSAlexey Dobriyan char cmd[42]; 1664936c8bcdSAlexey Dobriyan size_t len; 1665b4f9fe12SLen Brown int value; 1666b4f9fe12SLen Brown 1667936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1668936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1669936c8bcdSAlexey Dobriyan return -EFAULT; 1670936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1671936c8bcdSAlexey Dobriyan 16723e07e5baSAzael Avalos if (sscanf(cmd, " force_on : %i", &value) != 1 && 16733e07e5baSAzael Avalos value != 0 && value != 1) 1674b4f9fe12SLen Brown return -EINVAL; 16753e07e5baSAzael Avalos 16763e07e5baSAzael Avalos if (set_fan_status(dev, value)) 16773e07e5baSAzael Avalos return -EIO; 16783e07e5baSAzael Avalos 16793e07e5baSAzael Avalos dev->force_fan = value; 1680b4f9fe12SLen Brown 1681b4f9fe12SLen Brown return count; 1682b4f9fe12SLen Brown } 1683b4f9fe12SLen Brown 168497a32539SAlexey Dobriyan static const struct proc_ops fan_proc_ops = { 168597a32539SAlexey Dobriyan .proc_open = fan_proc_open, 168697a32539SAlexey Dobriyan .proc_read = seq_read, 168797a32539SAlexey Dobriyan .proc_lseek = seq_lseek, 168897a32539SAlexey Dobriyan .proc_release = single_release, 168997a32539SAlexey Dobriyan .proc_write = fan_proc_write, 1690936c8bcdSAlexey Dobriyan }; 1691936c8bcdSAlexey Dobriyan 1692dd193dcdSArvid Norlander /* Fan RPM */ 1693dd193dcdSArvid Norlander static int get_fan_rpm(struct toshiba_acpi_dev *dev, u32 *rpm) 1694dd193dcdSArvid Norlander { 1695dd193dcdSArvid Norlander u32 in[TCI_WORDS] = { HCI_GET, HCI_FAN_RPM, 0, 1, 0, 0 }; 1696dd193dcdSArvid Norlander u32 out[TCI_WORDS]; 1697dd193dcdSArvid Norlander acpi_status status = tci_raw(dev, in, out); 1698dd193dcdSArvid Norlander 1699dd193dcdSArvid Norlander if (ACPI_FAILURE(status)) { 1700dd193dcdSArvid Norlander pr_err("ACPI call to get Fan speed failed\n"); 1701dd193dcdSArvid Norlander return -EIO; 1702dd193dcdSArvid Norlander } 1703dd193dcdSArvid Norlander 1704dd193dcdSArvid Norlander if (out[0] == TOS_NOT_SUPPORTED) 1705dd193dcdSArvid Norlander return -ENODEV; 1706dd193dcdSArvid Norlander 1707dd193dcdSArvid Norlander if (out[0] == TOS_SUCCESS) { 1708dd193dcdSArvid Norlander *rpm = out[2]; 1709dd193dcdSArvid Norlander return 0; 1710dd193dcdSArvid Norlander } 1711dd193dcdSArvid Norlander 1712dd193dcdSArvid Norlander return -EIO; 1713dd193dcdSArvid Norlander } 1714dd193dcdSArvid Norlander 1715936c8bcdSAlexey Dobriyan static int keys_proc_show(struct seq_file *m, void *v) 1716b4f9fe12SLen Brown { 1717135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1718b4f9fe12SLen Brown 1719135740deSSeth Forshee seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid); 1720135740deSSeth Forshee seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event); 17217deef550SAzael Avalos 1722936c8bcdSAlexey Dobriyan return 0; 1723b4f9fe12SLen Brown } 1724b4f9fe12SLen Brown 1725936c8bcdSAlexey Dobriyan static int keys_proc_open(struct inode *inode, struct file *file) 1726b4f9fe12SLen Brown { 1727359745d7SMuchun Song return single_open(file, keys_proc_show, pde_data(inode)); 1728936c8bcdSAlexey Dobriyan } 1729936c8bcdSAlexey Dobriyan 1730936c8bcdSAlexey Dobriyan static ssize_t keys_proc_write(struct file *file, const char __user *buf, 1731936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1732936c8bcdSAlexey Dobriyan { 1733359745d7SMuchun Song struct toshiba_acpi_dev *dev = pde_data(file_inode(file)); 1734936c8bcdSAlexey Dobriyan char cmd[42]; 1735936c8bcdSAlexey Dobriyan size_t len; 1736b4f9fe12SLen Brown int value; 1737b4f9fe12SLen Brown 1738936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1739936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1740936c8bcdSAlexey Dobriyan return -EFAULT; 1741936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1742936c8bcdSAlexey Dobriyan 1743b5163992SAzael Avalos if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) 1744135740deSSeth Forshee dev->key_event_valid = 0; 1745b5163992SAzael Avalos else 1746b4f9fe12SLen Brown return -EINVAL; 1747b4f9fe12SLen Brown 1748b4f9fe12SLen Brown return count; 1749b4f9fe12SLen Brown } 1750b4f9fe12SLen Brown 175197a32539SAlexey Dobriyan static const struct proc_ops keys_proc_ops = { 175297a32539SAlexey Dobriyan .proc_open = keys_proc_open, 175397a32539SAlexey Dobriyan .proc_read = seq_read, 175497a32539SAlexey Dobriyan .proc_lseek = seq_lseek, 175597a32539SAlexey Dobriyan .proc_release = single_release, 175697a32539SAlexey Dobriyan .proc_write = keys_proc_write, 1757936c8bcdSAlexey Dobriyan }; 1758936c8bcdSAlexey Dobriyan 1759c2e2a618SRandy Dunlap static int __maybe_unused version_proc_show(struct seq_file *m, void *v) 1760b4f9fe12SLen Brown { 1761936c8bcdSAlexey Dobriyan seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION); 1762936c8bcdSAlexey Dobriyan seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION); 1763936c8bcdSAlexey Dobriyan return 0; 1764b4f9fe12SLen Brown } 1765b4f9fe12SLen Brown 1766e0769fe6SDarren Hart /* 1767e0769fe6SDarren Hart * Proc and module init 1768b4f9fe12SLen Brown */ 1769b4f9fe12SLen Brown 1770b4f9fe12SLen Brown #define PROC_TOSHIBA "toshiba" 1771b4f9fe12SLen Brown 1772b859f159SGreg Kroah-Hartman static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1773b4f9fe12SLen Brown { 177436d03f93SSeth Forshee if (dev->backlight_dev) 1775135740deSSeth Forshee proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, 177697a32539SAlexey Dobriyan &lcd_proc_ops, dev); 177736d03f93SSeth Forshee if (dev->video_supported) 1778135740deSSeth Forshee proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, 177997a32539SAlexey Dobriyan &video_proc_ops, dev); 178036d03f93SSeth Forshee if (dev->fan_supported) 1781135740deSSeth Forshee proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, 178297a32539SAlexey Dobriyan &fan_proc_ops, dev); 178336d03f93SSeth Forshee if (dev->hotkey_dev) 1784135740deSSeth Forshee proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, 178597a32539SAlexey Dobriyan &keys_proc_ops, dev); 17863f3942acSChristoph Hellwig proc_create_single_data("version", S_IRUGO, toshiba_proc_dir, 17873f3942acSChristoph Hellwig version_proc_show, dev); 1788b4f9fe12SLen Brown } 1789b4f9fe12SLen Brown 179036d03f93SSeth Forshee static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1791b4f9fe12SLen Brown { 179236d03f93SSeth Forshee if (dev->backlight_dev) 1793936c8bcdSAlexey Dobriyan remove_proc_entry("lcd", toshiba_proc_dir); 179436d03f93SSeth Forshee if (dev->video_supported) 1795936c8bcdSAlexey Dobriyan remove_proc_entry("video", toshiba_proc_dir); 179636d03f93SSeth Forshee if (dev->fan_supported) 1797936c8bcdSAlexey Dobriyan remove_proc_entry("fan", toshiba_proc_dir); 179836d03f93SSeth Forshee if (dev->hotkey_dev) 1799936c8bcdSAlexey Dobriyan remove_proc_entry("keys", toshiba_proc_dir); 1800936c8bcdSAlexey Dobriyan remove_proc_entry("version", toshiba_proc_dir); 1801b4f9fe12SLen Brown } 1802b4f9fe12SLen Brown 1803acc2472eSLionel Debroux static const struct backlight_ops toshiba_backlight_data = { 1804121b7b0dSAkio Idehara .options = BL_CORE_SUSPENDRESUME, 180562cce752SSeth Forshee .get_brightness = get_lcd_brightness, 1806b4f9fe12SLen Brown .update_status = set_lcd_status, 1807b4f9fe12SLen Brown }; 1808b4f9fe12SLen Brown 180965e3cf9cSAzael Avalos /* Keyboard backlight work */ 181065e3cf9cSAzael Avalos static void toshiba_acpi_kbd_bl_work(struct work_struct *work); 181165e3cf9cSAzael Avalos 181265e3cf9cSAzael Avalos static DECLARE_WORK(kbd_bl_work, toshiba_acpi_kbd_bl_work); 181365e3cf9cSAzael Avalos 1814360f0f39SAzael Avalos /* 1815360f0f39SAzael Avalos * Sysfs files 1816360f0f39SAzael Avalos */ 18179d309848SAzael Avalos static ssize_t version_show(struct device *dev, 1818c6c68ff8SAzael Avalos struct device_attribute *attr, char *buf) 1819c6c68ff8SAzael Avalos { 1820c6c68ff8SAzael Avalos return sprintf(buf, "%s\n", TOSHIBA_ACPI_VERSION); 1821c6c68ff8SAzael Avalos } 18220c3c0f10SAzael Avalos static DEVICE_ATTR_RO(version); 1823c6c68ff8SAzael Avalos 18249d309848SAzael Avalos static ssize_t fan_store(struct device *dev, 182594477d4cSAzael Avalos struct device_attribute *attr, 182694477d4cSAzael Avalos const char *buf, size_t count) 182794477d4cSAzael Avalos { 182894477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 182994477d4cSAzael Avalos int state; 183094477d4cSAzael Avalos int ret; 183194477d4cSAzael Avalos 183294477d4cSAzael Avalos ret = kstrtoint(buf, 0, &state); 183394477d4cSAzael Avalos if (ret) 183494477d4cSAzael Avalos return ret; 183594477d4cSAzael Avalos 183694477d4cSAzael Avalos if (state != 0 && state != 1) 183794477d4cSAzael Avalos return -EINVAL; 183894477d4cSAzael Avalos 18393e07e5baSAzael Avalos ret = set_fan_status(toshiba, state); 18403e07e5baSAzael Avalos if (ret) 18413e07e5baSAzael Avalos return ret; 184294477d4cSAzael Avalos 184394477d4cSAzael Avalos return count; 184494477d4cSAzael Avalos } 184594477d4cSAzael Avalos 18469d309848SAzael Avalos static ssize_t fan_show(struct device *dev, 184794477d4cSAzael Avalos struct device_attribute *attr, char *buf) 184894477d4cSAzael Avalos { 184994477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 185094477d4cSAzael Avalos u32 value; 185194477d4cSAzael Avalos int ret; 185294477d4cSAzael Avalos 185394477d4cSAzael Avalos ret = get_fan_status(toshiba, &value); 185494477d4cSAzael Avalos if (ret) 185594477d4cSAzael Avalos return ret; 185694477d4cSAzael Avalos 185794477d4cSAzael Avalos return sprintf(buf, "%d\n", value); 185894477d4cSAzael Avalos } 18590c3c0f10SAzael Avalos static DEVICE_ATTR_RW(fan); 186094477d4cSAzael Avalos 18619d309848SAzael Avalos static ssize_t kbd_backlight_mode_store(struct device *dev, 1862360f0f39SAzael Avalos struct device_attribute *attr, 1863360f0f39SAzael Avalos const char *buf, size_t count) 1864360f0f39SAzael Avalos { 1865360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1866aeaac098SDan Carpenter int mode; 1867aeaac098SDan Carpenter int ret; 1868360f0f39SAzael Avalos 1869aeaac098SDan Carpenter 1870aeaac098SDan Carpenter ret = kstrtoint(buf, 0, &mode); 1871aeaac098SDan Carpenter if (ret) 1872aeaac098SDan Carpenter return ret; 187393f8c16dSAzael Avalos 187493f8c16dSAzael Avalos /* Check for supported modes depending on keyboard backlight type */ 187593f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 187693f8c16dSAzael Avalos /* Type 1 supports SCI_KBD_MODE_FNZ and SCI_KBD_MODE_AUTO */ 1877aeaac098SDan Carpenter if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO) 1878360f0f39SAzael Avalos return -EINVAL; 187993f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 188093f8c16dSAzael Avalos /* Type 2 doesn't support SCI_KBD_MODE_FNZ */ 188193f8c16dSAzael Avalos if (mode != SCI_KBD_MODE_AUTO && mode != SCI_KBD_MODE_ON && 188293f8c16dSAzael Avalos mode != SCI_KBD_MODE_OFF) 188393f8c16dSAzael Avalos return -EINVAL; 188493f8c16dSAzael Avalos } 1885360f0f39SAzael Avalos 1886e0769fe6SDarren Hart /* 1887e0769fe6SDarren Hart * Set the Keyboard Backlight Mode where: 1888360f0f39SAzael Avalos * Auto - KBD backlight turns off automatically in given time 1889360f0f39SAzael Avalos * FN-Z - KBD backlight "toggles" when hotkey pressed 189093f8c16dSAzael Avalos * ON - KBD backlight is always on 189193f8c16dSAzael Avalos * OFF - KBD backlight is always off 1892360f0f39SAzael Avalos */ 189393f8c16dSAzael Avalos 189493f8c16dSAzael Avalos /* Only make a change if the actual mode has changed */ 1895aeaac098SDan Carpenter if (toshiba->kbd_mode != mode) { 189693f8c16dSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 18971e574dbfSAzael Avalos int time = toshiba->kbd_time << HCI_MISC_SHIFT; 189893f8c16dSAzael Avalos 189993f8c16dSAzael Avalos /* OR the "base time" to the actual method format */ 190093f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 190193f8c16dSAzael Avalos /* Type 1 requires the current mode */ 190293f8c16dSAzael Avalos time |= toshiba->kbd_mode; 190393f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 190493f8c16dSAzael Avalos /* Type 2 requires the desired mode */ 190593f8c16dSAzael Avalos time |= mode; 190693f8c16dSAzael Avalos } 190793f8c16dSAzael Avalos 1908aeaac098SDan Carpenter ret = toshiba_kbd_illum_status_set(toshiba, time); 1909aeaac098SDan Carpenter if (ret) 1910aeaac098SDan Carpenter return ret; 191193f8c16dSAzael Avalos 1912360f0f39SAzael Avalos toshiba->kbd_mode = mode; 1913147288e6SAzael Avalos toshiba_acpi->kbd_mode = mode; 191465e3cf9cSAzael Avalos 191565e3cf9cSAzael Avalos /* 191665e3cf9cSAzael Avalos * Some laptop models with the second generation backlit 191765e3cf9cSAzael Avalos * keyboard (type 2) do not generate the keyboard backlight 191865e3cf9cSAzael Avalos * changed event (0x92), and thus, the driver will never update 191965e3cf9cSAzael Avalos * the sysfs entries. 192065e3cf9cSAzael Avalos * 192165e3cf9cSAzael Avalos * The event is generated right when changing the keyboard 192265e3cf9cSAzael Avalos * backlight mode and the *notify function will set the 192365e3cf9cSAzael Avalos * kbd_event_generated to true. 192465e3cf9cSAzael Avalos * 192565e3cf9cSAzael Avalos * In case the event is not generated, schedule the keyboard 192665e3cf9cSAzael Avalos * backlight work to update the sysfs entries and emulate the 192765e3cf9cSAzael Avalos * event via genetlink. 192865e3cf9cSAzael Avalos */ 192965e3cf9cSAzael Avalos if (toshiba->kbd_type == 2 && 1930147288e6SAzael Avalos !toshiba->kbd_event_generated) 193165e3cf9cSAzael Avalos schedule_work(&kbd_bl_work); 1932360f0f39SAzael Avalos } 1933360f0f39SAzael Avalos 1934360f0f39SAzael Avalos return count; 1935360f0f39SAzael Avalos } 1936360f0f39SAzael Avalos 19379d309848SAzael Avalos static ssize_t kbd_backlight_mode_show(struct device *dev, 1938360f0f39SAzael Avalos struct device_attribute *attr, 1939360f0f39SAzael Avalos char *buf) 1940360f0f39SAzael Avalos { 1941360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1942360f0f39SAzael Avalos u32 time; 1943360f0f39SAzael Avalos 1944360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1945360f0f39SAzael Avalos return -EIO; 1946360f0f39SAzael Avalos 194793f8c16dSAzael Avalos return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK); 194893f8c16dSAzael Avalos } 19490c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_mode); 195093f8c16dSAzael Avalos 19519d309848SAzael Avalos static ssize_t kbd_type_show(struct device *dev, 19529d309848SAzael Avalos struct device_attribute *attr, char *buf) 195393f8c16dSAzael Avalos { 195493f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 195593f8c16dSAzael Avalos 195693f8c16dSAzael Avalos return sprintf(buf, "%d\n", toshiba->kbd_type); 195793f8c16dSAzael Avalos } 19580c3c0f10SAzael Avalos static DEVICE_ATTR_RO(kbd_type); 195993f8c16dSAzael Avalos 19609d309848SAzael Avalos static ssize_t available_kbd_modes_show(struct device *dev, 196193f8c16dSAzael Avalos struct device_attribute *attr, 196293f8c16dSAzael Avalos char *buf) 196393f8c16dSAzael Avalos { 196493f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 196593f8c16dSAzael Avalos 196693f8c16dSAzael Avalos if (toshiba->kbd_type == 1) 19670b498201SAzael Avalos return sprintf(buf, "0x%x 0x%x\n", 196893f8c16dSAzael Avalos SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO); 196993f8c16dSAzael Avalos 19700b498201SAzael Avalos return sprintf(buf, "0x%x 0x%x 0x%x\n", 197193f8c16dSAzael Avalos SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF); 1972360f0f39SAzael Avalos } 19730c3c0f10SAzael Avalos static DEVICE_ATTR_RO(available_kbd_modes); 1974360f0f39SAzael Avalos 19759d309848SAzael Avalos static ssize_t kbd_backlight_timeout_store(struct device *dev, 1976360f0f39SAzael Avalos struct device_attribute *attr, 1977360f0f39SAzael Avalos const char *buf, size_t count) 1978360f0f39SAzael Avalos { 1979360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1980eabde0faSAzael Avalos int time; 1981eabde0faSAzael Avalos int ret; 1982360f0f39SAzael Avalos 1983eabde0faSAzael Avalos ret = kstrtoint(buf, 0, &time); 1984eabde0faSAzael Avalos if (ret) 1985eabde0faSAzael Avalos return ret; 1986eabde0faSAzael Avalos 1987eabde0faSAzael Avalos /* Check for supported values depending on kbd_type */ 1988eabde0faSAzael Avalos if (toshiba->kbd_type == 1) { 1989eabde0faSAzael Avalos if (time < 0 || time > 60) 1990360f0f39SAzael Avalos return -EINVAL; 1991eabde0faSAzael Avalos } else if (toshiba->kbd_type == 2) { 1992eabde0faSAzael Avalos if (time < 1 || time > 60) 1993eabde0faSAzael Avalos return -EINVAL; 1994eabde0faSAzael Avalos } 1995360f0f39SAzael Avalos 1996eabde0faSAzael Avalos /* Set the Keyboard Backlight Timeout */ 1997eabde0faSAzael Avalos 1998eabde0faSAzael Avalos /* Only make a change if the actual timeout has changed */ 1999eabde0faSAzael Avalos if (toshiba->kbd_time != time) { 2000eabde0faSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 2001360f0f39SAzael Avalos time = time << HCI_MISC_SHIFT; 2002eabde0faSAzael Avalos /* OR the "base time" to the actual method format */ 2003eabde0faSAzael Avalos if (toshiba->kbd_type == 1) 2004eabde0faSAzael Avalos time |= SCI_KBD_MODE_FNZ; 2005eabde0faSAzael Avalos else if (toshiba->kbd_type == 2) 2006eabde0faSAzael Avalos time |= SCI_KBD_MODE_AUTO; 2007eabde0faSAzael Avalos 2008eabde0faSAzael Avalos ret = toshiba_kbd_illum_status_set(toshiba, time); 2009eabde0faSAzael Avalos if (ret) 2010eabde0faSAzael Avalos return ret; 2011eabde0faSAzael Avalos 2012360f0f39SAzael Avalos toshiba->kbd_time = time >> HCI_MISC_SHIFT; 2013360f0f39SAzael Avalos } 2014360f0f39SAzael Avalos 2015360f0f39SAzael Avalos return count; 2016360f0f39SAzael Avalos } 2017360f0f39SAzael Avalos 20189d309848SAzael Avalos static ssize_t kbd_backlight_timeout_show(struct device *dev, 2019360f0f39SAzael Avalos struct device_attribute *attr, 2020360f0f39SAzael Avalos char *buf) 2021360f0f39SAzael Avalos { 2022360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2023360f0f39SAzael Avalos u32 time; 2024360f0f39SAzael Avalos 2025360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 2026360f0f39SAzael Avalos return -EIO; 2027360f0f39SAzael Avalos 2028360f0f39SAzael Avalos return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT); 2029360f0f39SAzael Avalos } 20300c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_timeout); 2031360f0f39SAzael Avalos 20329d309848SAzael Avalos static ssize_t touchpad_store(struct device *dev, 20339d8658acSAzael Avalos struct device_attribute *attr, 20349d8658acSAzael Avalos const char *buf, size_t count) 20359d8658acSAzael Avalos { 20369d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 20379d8658acSAzael Avalos int state; 2038c8a41669SAzael Avalos int ret; 20399d8658acSAzael Avalos 20409d8658acSAzael Avalos /* Set the TouchPad on/off, 0 - Disable | 1 - Enable */ 2041c8a41669SAzael Avalos ret = kstrtoint(buf, 0, &state); 2042c8a41669SAzael Avalos if (ret) 2043c8a41669SAzael Avalos return ret; 2044c8a41669SAzael Avalos if (state != 0 && state != 1) 2045c8a41669SAzael Avalos return -EINVAL; 2046c8a41669SAzael Avalos 2047c8a41669SAzael Avalos ret = toshiba_touchpad_set(toshiba, state); 2048c8a41669SAzael Avalos if (ret) 2049c8a41669SAzael Avalos return ret; 20509d8658acSAzael Avalos 20519d8658acSAzael Avalos return count; 20529d8658acSAzael Avalos } 20539d8658acSAzael Avalos 20549d309848SAzael Avalos static ssize_t touchpad_show(struct device *dev, 20559d8658acSAzael Avalos struct device_attribute *attr, char *buf) 20569d8658acSAzael Avalos { 20579d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 20589d8658acSAzael Avalos u32 state; 20599d8658acSAzael Avalos int ret; 20609d8658acSAzael Avalos 20619d8658acSAzael Avalos ret = toshiba_touchpad_get(toshiba, &state); 20629d8658acSAzael Avalos if (ret < 0) 20639d8658acSAzael Avalos return ret; 20649d8658acSAzael Avalos 20659d8658acSAzael Avalos return sprintf(buf, "%i\n", state); 20669d8658acSAzael Avalos } 20670c3c0f10SAzael Avalos static DEVICE_ATTR_RW(touchpad); 20689d8658acSAzael Avalos 20699d309848SAzael Avalos static ssize_t usb_sleep_charge_show(struct device *dev, 20709d309848SAzael Avalos struct device_attribute *attr, char *buf) 2071e26ffe51SAzael Avalos { 2072e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2073e26ffe51SAzael Avalos u32 mode; 2074e26ffe51SAzael Avalos int ret; 2075e26ffe51SAzael Avalos 2076e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_get(toshiba, &mode); 2077e26ffe51SAzael Avalos if (ret < 0) 2078e26ffe51SAzael Avalos return ret; 2079e26ffe51SAzael Avalos 2080e26ffe51SAzael Avalos return sprintf(buf, "%x\n", mode & SCI_USB_CHARGE_MODE_MASK); 2081e26ffe51SAzael Avalos } 2082e26ffe51SAzael Avalos 20839d309848SAzael Avalos static ssize_t usb_sleep_charge_store(struct device *dev, 2084e26ffe51SAzael Avalos struct device_attribute *attr, 2085e26ffe51SAzael Avalos const char *buf, size_t count) 2086e26ffe51SAzael Avalos { 2087e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2088e26ffe51SAzael Avalos int state; 208978429e55SAzael Avalos u32 mode; 2090e26ffe51SAzael Avalos int ret; 2091e26ffe51SAzael Avalos 2092e26ffe51SAzael Avalos ret = kstrtoint(buf, 0, &state); 2093e26ffe51SAzael Avalos if (ret) 2094e26ffe51SAzael Avalos return ret; 2095e0769fe6SDarren Hart /* 2096e0769fe6SDarren Hart * Check for supported values, where: 2097e26ffe51SAzael Avalos * 0 - Disabled 2098e26ffe51SAzael Avalos * 1 - Alternate (Non USB conformant devices that require more power) 2099e26ffe51SAzael Avalos * 2 - Auto (USB conformant devices) 2100c8c91842SAzael Avalos * 3 - Typical 2101e26ffe51SAzael Avalos */ 2102c8c91842SAzael Avalos if (state != 0 && state != 1 && state != 2 && state != 3) 2103e26ffe51SAzael Avalos return -EINVAL; 2104e26ffe51SAzael Avalos 2105e26ffe51SAzael Avalos /* Set the USB charging mode to internal value */ 2106c8c91842SAzael Avalos mode = toshiba->usbsc_mode_base; 2107e26ffe51SAzael Avalos if (state == 0) 2108c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_DISABLED; 2109e26ffe51SAzael Avalos else if (state == 1) 2110c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_ALTERNATE; 2111e26ffe51SAzael Avalos else if (state == 2) 2112c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_AUTO; 2113c8c91842SAzael Avalos else if (state == 3) 2114c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_TYPICAL; 2115e26ffe51SAzael Avalos 2116e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_set(toshiba, mode); 2117e26ffe51SAzael Avalos if (ret) 2118e26ffe51SAzael Avalos return ret; 2119e26ffe51SAzael Avalos 2120e26ffe51SAzael Avalos return count; 2121e26ffe51SAzael Avalos } 21220c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_charge); 2123e26ffe51SAzael Avalos 2124182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_show(struct device *dev, 2125182bcaa5SAzael Avalos struct device_attribute *attr, 2126182bcaa5SAzael Avalos char *buf) 2127182bcaa5SAzael Avalos { 2128182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 212978429e55SAzael Avalos int bat_lvl, status; 2130182bcaa5SAzael Avalos u32 state; 2131182bcaa5SAzael Avalos int ret; 2132182bcaa5SAzael Avalos int tmp; 2133182bcaa5SAzael Avalos 2134182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_get(toshiba, &state); 2135182bcaa5SAzael Avalos if (ret < 0) 2136182bcaa5SAzael Avalos return ret; 2137182bcaa5SAzael Avalos 2138182bcaa5SAzael Avalos /* Determine the status: 0x4 - Enabled | 0x1 - Disabled */ 2139182bcaa5SAzael Avalos tmp = state & SCI_USB_CHARGE_BAT_MASK; 2140182bcaa5SAzael Avalos status = (tmp == 0x4) ? 1 : 0; 2141182bcaa5SAzael Avalos /* Determine the battery level set */ 2142182bcaa5SAzael Avalos bat_lvl = state >> HCI_MISC_SHIFT; 2143182bcaa5SAzael Avalos 2144182bcaa5SAzael Avalos return sprintf(buf, "%d %d\n", status, bat_lvl); 2145182bcaa5SAzael Avalos } 2146182bcaa5SAzael Avalos 2147182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_store(struct device *dev, 2148182bcaa5SAzael Avalos struct device_attribute *attr, 2149182bcaa5SAzael Avalos const char *buf, size_t count) 2150182bcaa5SAzael Avalos { 2151182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2152182bcaa5SAzael Avalos u32 status; 2153182bcaa5SAzael Avalos int value; 2154182bcaa5SAzael Avalos int ret; 2155182bcaa5SAzael Avalos int tmp; 2156182bcaa5SAzael Avalos 2157182bcaa5SAzael Avalos ret = kstrtoint(buf, 0, &value); 2158182bcaa5SAzael Avalos if (ret) 2159182bcaa5SAzael Avalos return ret; 2160182bcaa5SAzael Avalos 2161e0769fe6SDarren Hart /* 2162e0769fe6SDarren Hart * Set the status of the function: 2163182bcaa5SAzael Avalos * 0 - Disabled 2164182bcaa5SAzael Avalos * 1-100 - Enabled 2165182bcaa5SAzael Avalos */ 2166182bcaa5SAzael Avalos if (value < 0 || value > 100) 2167182bcaa5SAzael Avalos return -EINVAL; 2168182bcaa5SAzael Avalos 2169182bcaa5SAzael Avalos if (value == 0) { 2170182bcaa5SAzael Avalos tmp = toshiba->usbsc_bat_level << HCI_MISC_SHIFT; 2171182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_OFF; 2172182bcaa5SAzael Avalos } else { 2173182bcaa5SAzael Avalos tmp = value << HCI_MISC_SHIFT; 2174182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_ON; 2175182bcaa5SAzael Avalos } 2176182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_set(toshiba, status); 2177182bcaa5SAzael Avalos if (ret < 0) 2178182bcaa5SAzael Avalos return ret; 2179182bcaa5SAzael Avalos 2180182bcaa5SAzael Avalos toshiba->usbsc_bat_level = status >> HCI_MISC_SHIFT; 2181182bcaa5SAzael Avalos 2182182bcaa5SAzael Avalos return count; 2183182bcaa5SAzael Avalos } 21840c3c0f10SAzael Avalos static DEVICE_ATTR_RW(sleep_functions_on_battery); 2185182bcaa5SAzael Avalos 21869d309848SAzael Avalos static ssize_t usb_rapid_charge_show(struct device *dev, 21879d309848SAzael Avalos struct device_attribute *attr, char *buf) 2188bb3fe01fSAzael Avalos { 2189bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2190bb3fe01fSAzael Avalos u32 state; 2191bb3fe01fSAzael Avalos int ret; 2192bb3fe01fSAzael Avalos 2193bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(toshiba, &state); 2194bb3fe01fSAzael Avalos if (ret < 0) 2195bb3fe01fSAzael Avalos return ret; 2196bb3fe01fSAzael Avalos 2197bb3fe01fSAzael Avalos return sprintf(buf, "%d\n", state); 2198bb3fe01fSAzael Avalos } 2199bb3fe01fSAzael Avalos 22009d309848SAzael Avalos static ssize_t usb_rapid_charge_store(struct device *dev, 2201bb3fe01fSAzael Avalos struct device_attribute *attr, 2202bb3fe01fSAzael Avalos const char *buf, size_t count) 2203bb3fe01fSAzael Avalos { 2204bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2205bb3fe01fSAzael Avalos int state; 2206bb3fe01fSAzael Avalos int ret; 2207bb3fe01fSAzael Avalos 2208bb3fe01fSAzael Avalos ret = kstrtoint(buf, 0, &state); 2209bb3fe01fSAzael Avalos if (ret) 2210bb3fe01fSAzael Avalos return ret; 2211bb3fe01fSAzael Avalos if (state != 0 && state != 1) 2212bb3fe01fSAzael Avalos return -EINVAL; 2213bb3fe01fSAzael Avalos 2214bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_set(toshiba, state); 2215bb3fe01fSAzael Avalos if (ret) 2216bb3fe01fSAzael Avalos return ret; 2217bb3fe01fSAzael Avalos 2218bb3fe01fSAzael Avalos return count; 2219bb3fe01fSAzael Avalos } 22200c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_rapid_charge); 2221bb3fe01fSAzael Avalos 22229d309848SAzael Avalos static ssize_t usb_sleep_music_show(struct device *dev, 22239d309848SAzael Avalos struct device_attribute *attr, char *buf) 2224172ce0a9SAzael Avalos { 2225172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2226172ce0a9SAzael Avalos u32 state; 2227172ce0a9SAzael Avalos int ret; 2228172ce0a9SAzael Avalos 2229172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(toshiba, &state); 2230172ce0a9SAzael Avalos if (ret < 0) 2231172ce0a9SAzael Avalos return ret; 2232172ce0a9SAzael Avalos 2233172ce0a9SAzael Avalos return sprintf(buf, "%d\n", state); 2234172ce0a9SAzael Avalos } 2235172ce0a9SAzael Avalos 22369d309848SAzael Avalos static ssize_t usb_sleep_music_store(struct device *dev, 2237172ce0a9SAzael Avalos struct device_attribute *attr, 2238172ce0a9SAzael Avalos const char *buf, size_t count) 2239172ce0a9SAzael Avalos { 2240172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2241172ce0a9SAzael Avalos int state; 2242172ce0a9SAzael Avalos int ret; 2243172ce0a9SAzael Avalos 2244172ce0a9SAzael Avalos ret = kstrtoint(buf, 0, &state); 2245172ce0a9SAzael Avalos if (ret) 2246172ce0a9SAzael Avalos return ret; 2247172ce0a9SAzael Avalos if (state != 0 && state != 1) 2248172ce0a9SAzael Avalos return -EINVAL; 2249172ce0a9SAzael Avalos 2250172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_set(toshiba, state); 2251172ce0a9SAzael Avalos if (ret) 2252172ce0a9SAzael Avalos return ret; 2253172ce0a9SAzael Avalos 2254172ce0a9SAzael Avalos return count; 2255172ce0a9SAzael Avalos } 22560c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_music); 2257172ce0a9SAzael Avalos 22589d309848SAzael Avalos static ssize_t kbd_function_keys_show(struct device *dev, 22599d309848SAzael Avalos struct device_attribute *attr, char *buf) 2260bae84195SAzael Avalos { 2261bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2262bae84195SAzael Avalos int mode; 2263bae84195SAzael Avalos int ret; 2264bae84195SAzael Avalos 2265bae84195SAzael Avalos ret = toshiba_function_keys_get(toshiba, &mode); 2266bae84195SAzael Avalos if (ret < 0) 2267bae84195SAzael Avalos return ret; 2268bae84195SAzael Avalos 2269bae84195SAzael Avalos return sprintf(buf, "%d\n", mode); 2270bae84195SAzael Avalos } 2271bae84195SAzael Avalos 22729d309848SAzael Avalos static ssize_t kbd_function_keys_store(struct device *dev, 2273bae84195SAzael Avalos struct device_attribute *attr, 2274bae84195SAzael Avalos const char *buf, size_t count) 2275bae84195SAzael Avalos { 2276bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2277bae84195SAzael Avalos int mode; 2278bae84195SAzael Avalos int ret; 2279bae84195SAzael Avalos 2280bae84195SAzael Avalos ret = kstrtoint(buf, 0, &mode); 2281bae84195SAzael Avalos if (ret) 2282bae84195SAzael Avalos return ret; 2283e0769fe6SDarren Hart /* 2284e0769fe6SDarren Hart * Check for the function keys mode where: 2285bae84195SAzael Avalos * 0 - Normal operation (F{1-12} as usual and hotkeys via FN-F{1-12}) 2286bae84195SAzael Avalos * 1 - Special functions (Opposite of the above setting) 2287bae84195SAzael Avalos */ 2288bae84195SAzael Avalos if (mode != 0 && mode != 1) 2289bae84195SAzael Avalos return -EINVAL; 2290bae84195SAzael Avalos 2291bae84195SAzael Avalos ret = toshiba_function_keys_set(toshiba, mode); 2292bae84195SAzael Avalos if (ret) 2293bae84195SAzael Avalos return ret; 2294bae84195SAzael Avalos 2295bae84195SAzael Avalos pr_info("Reboot for changes to KBD Function Keys to take effect"); 2296bae84195SAzael Avalos 2297bae84195SAzael Avalos return count; 2298bae84195SAzael Avalos } 22990c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_function_keys); 2300bae84195SAzael Avalos 23019d309848SAzael Avalos static ssize_t panel_power_on_show(struct device *dev, 23029d309848SAzael Avalos struct device_attribute *attr, char *buf) 230335d53ceaSAzael Avalos { 230435d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 230535d53ceaSAzael Avalos u32 state; 230635d53ceaSAzael Avalos int ret; 230735d53ceaSAzael Avalos 230835d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(toshiba, &state); 230935d53ceaSAzael Avalos if (ret < 0) 231035d53ceaSAzael Avalos return ret; 231135d53ceaSAzael Avalos 231235d53ceaSAzael Avalos return sprintf(buf, "%d\n", state); 231335d53ceaSAzael Avalos } 231435d53ceaSAzael Avalos 23159d309848SAzael Avalos static ssize_t panel_power_on_store(struct device *dev, 231635d53ceaSAzael Avalos struct device_attribute *attr, 231735d53ceaSAzael Avalos const char *buf, size_t count) 231835d53ceaSAzael Avalos { 231935d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 232035d53ceaSAzael Avalos int state; 232135d53ceaSAzael Avalos int ret; 232235d53ceaSAzael Avalos 232335d53ceaSAzael Avalos ret = kstrtoint(buf, 0, &state); 232435d53ceaSAzael Avalos if (ret) 232535d53ceaSAzael Avalos return ret; 232635d53ceaSAzael Avalos if (state != 0 && state != 1) 232735d53ceaSAzael Avalos return -EINVAL; 232835d53ceaSAzael Avalos 232935d53ceaSAzael Avalos ret = toshiba_panel_power_on_set(toshiba, state); 233035d53ceaSAzael Avalos if (ret) 233135d53ceaSAzael Avalos return ret; 233235d53ceaSAzael Avalos 233335d53ceaSAzael Avalos pr_info("Reboot for changes to Panel Power ON to take effect"); 233435d53ceaSAzael Avalos 233535d53ceaSAzael Avalos return count; 233635d53ceaSAzael Avalos } 23370c3c0f10SAzael Avalos static DEVICE_ATTR_RW(panel_power_on); 233835d53ceaSAzael Avalos 23399d309848SAzael Avalos static ssize_t usb_three_show(struct device *dev, 23409d309848SAzael Avalos struct device_attribute *attr, char *buf) 234117fe4b3dSAzael Avalos { 234217fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 234317fe4b3dSAzael Avalos u32 state; 234417fe4b3dSAzael Avalos int ret; 234517fe4b3dSAzael Avalos 234617fe4b3dSAzael Avalos ret = toshiba_usb_three_get(toshiba, &state); 234717fe4b3dSAzael Avalos if (ret < 0) 234817fe4b3dSAzael Avalos return ret; 234917fe4b3dSAzael Avalos 235017fe4b3dSAzael Avalos return sprintf(buf, "%d\n", state); 235117fe4b3dSAzael Avalos } 235217fe4b3dSAzael Avalos 23539d309848SAzael Avalos static ssize_t usb_three_store(struct device *dev, 235417fe4b3dSAzael Avalos struct device_attribute *attr, 235517fe4b3dSAzael Avalos const char *buf, size_t count) 235617fe4b3dSAzael Avalos { 235717fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 235817fe4b3dSAzael Avalos int state; 235917fe4b3dSAzael Avalos int ret; 236017fe4b3dSAzael Avalos 236117fe4b3dSAzael Avalos ret = kstrtoint(buf, 0, &state); 236217fe4b3dSAzael Avalos if (ret) 236317fe4b3dSAzael Avalos return ret; 2364e0769fe6SDarren Hart /* 2365e0769fe6SDarren Hart * Check for USB 3 mode where: 236617fe4b3dSAzael Avalos * 0 - Disabled (Acts like a USB 2 port, saving power) 236717fe4b3dSAzael Avalos * 1 - Enabled 236817fe4b3dSAzael Avalos */ 236917fe4b3dSAzael Avalos if (state != 0 && state != 1) 237017fe4b3dSAzael Avalos return -EINVAL; 237117fe4b3dSAzael Avalos 237217fe4b3dSAzael Avalos ret = toshiba_usb_three_set(toshiba, state); 237317fe4b3dSAzael Avalos if (ret) 237417fe4b3dSAzael Avalos return ret; 237517fe4b3dSAzael Avalos 237617fe4b3dSAzael Avalos pr_info("Reboot for changes to USB 3 to take effect"); 237717fe4b3dSAzael Avalos 237817fe4b3dSAzael Avalos return count; 237917fe4b3dSAzael Avalos } 23800c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_three); 23819bd1213bSAzael Avalos 2382b1009b91SAzael Avalos static ssize_t cooling_method_show(struct device *dev, 2383b1009b91SAzael Avalos struct device_attribute *attr, char *buf) 2384b1009b91SAzael Avalos { 2385b1009b91SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2386b1009b91SAzael Avalos int state; 2387b1009b91SAzael Avalos int ret; 2388b1009b91SAzael Avalos 2389b1009b91SAzael Avalos ret = toshiba_cooling_method_get(toshiba, &state); 2390b1009b91SAzael Avalos if (ret < 0) 2391b1009b91SAzael Avalos return ret; 2392b1009b91SAzael Avalos 2393b1009b91SAzael Avalos return sprintf(buf, "%d %d\n", state, toshiba->max_cooling_method); 2394b1009b91SAzael Avalos } 2395b1009b91SAzael Avalos 2396b1009b91SAzael Avalos static ssize_t cooling_method_store(struct device *dev, 2397b1009b91SAzael Avalos struct device_attribute *attr, 2398b1009b91SAzael Avalos const char *buf, size_t count) 2399b1009b91SAzael Avalos { 2400b1009b91SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2401b1009b91SAzael Avalos int state; 2402b1009b91SAzael Avalos int ret; 2403b1009b91SAzael Avalos 2404b1009b91SAzael Avalos ret = kstrtoint(buf, 0, &state); 2405b1009b91SAzael Avalos if (ret) 2406b1009b91SAzael Avalos return ret; 2407b1009b91SAzael Avalos 2408b1009b91SAzael Avalos /* 2409b1009b91SAzael Avalos * Check for supported values 2410b1009b91SAzael Avalos * Depending on the laptop model, some only support these two: 2411b1009b91SAzael Avalos * 0 - Maximum Performance 2412b1009b91SAzael Avalos * 1 - Battery Optimized 2413b1009b91SAzael Avalos * 2414b1009b91SAzael Avalos * While some others support all three methods: 2415b1009b91SAzael Avalos * 0 - Maximum Performance 2416b1009b91SAzael Avalos * 1 - Performance 2417b1009b91SAzael Avalos * 2 - Battery Optimized 2418b1009b91SAzael Avalos */ 2419b1009b91SAzael Avalos if (state < 0 || state > toshiba->max_cooling_method) 2420b1009b91SAzael Avalos return -EINVAL; 2421b1009b91SAzael Avalos 2422b1009b91SAzael Avalos ret = toshiba_cooling_method_set(toshiba, state); 2423b1009b91SAzael Avalos if (ret) 2424b1009b91SAzael Avalos return ret; 2425b1009b91SAzael Avalos 2426b1009b91SAzael Avalos return count; 2427b1009b91SAzael Avalos } 2428b1009b91SAzael Avalos static DEVICE_ATTR_RW(cooling_method); 2429b1009b91SAzael Avalos 24309bd1213bSAzael Avalos static struct attribute *toshiba_attributes[] = { 24319bd1213bSAzael Avalos &dev_attr_version.attr, 24329bd1213bSAzael Avalos &dev_attr_fan.attr, 24339bd1213bSAzael Avalos &dev_attr_kbd_backlight_mode.attr, 24349bd1213bSAzael Avalos &dev_attr_kbd_type.attr, 24359bd1213bSAzael Avalos &dev_attr_available_kbd_modes.attr, 24369bd1213bSAzael Avalos &dev_attr_kbd_backlight_timeout.attr, 24379bd1213bSAzael Avalos &dev_attr_touchpad.attr, 24389bd1213bSAzael Avalos &dev_attr_usb_sleep_charge.attr, 24399bd1213bSAzael Avalos &dev_attr_sleep_functions_on_battery.attr, 24409bd1213bSAzael Avalos &dev_attr_usb_rapid_charge.attr, 24419bd1213bSAzael Avalos &dev_attr_usb_sleep_music.attr, 24429bd1213bSAzael Avalos &dev_attr_kbd_function_keys.attr, 24439bd1213bSAzael Avalos &dev_attr_panel_power_on.attr, 24449bd1213bSAzael Avalos &dev_attr_usb_three.attr, 2445b1009b91SAzael Avalos &dev_attr_cooling_method.attr, 24469bd1213bSAzael Avalos NULL, 24479bd1213bSAzael Avalos }; 24489bd1213bSAzael Avalos 2449360f0f39SAzael Avalos static umode_t toshiba_sysfs_is_visible(struct kobject *kobj, 2450360f0f39SAzael Avalos struct attribute *attr, int idx) 2451360f0f39SAzael Avalos { 245246ecf720SMinghao Chi struct device *dev = kobj_to_dev(kobj); 2453360f0f39SAzael Avalos struct toshiba_acpi_dev *drv = dev_get_drvdata(dev); 2454360f0f39SAzael Avalos bool exists = true; 2455360f0f39SAzael Avalos 245694477d4cSAzael Avalos if (attr == &dev_attr_fan.attr) 245794477d4cSAzael Avalos exists = (drv->fan_supported) ? true : false; 245894477d4cSAzael Avalos else if (attr == &dev_attr_kbd_backlight_mode.attr) 2459360f0f39SAzael Avalos exists = (drv->kbd_illum_supported) ? true : false; 2460360f0f39SAzael Avalos else if (attr == &dev_attr_kbd_backlight_timeout.attr) 2461360f0f39SAzael Avalos exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false; 24629d8658acSAzael Avalos else if (attr == &dev_attr_touchpad.attr) 24639d8658acSAzael Avalos exists = (drv->touchpad_supported) ? true : false; 2464e26ffe51SAzael Avalos else if (attr == &dev_attr_usb_sleep_charge.attr) 2465e26ffe51SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2466182bcaa5SAzael Avalos else if (attr == &dev_attr_sleep_functions_on_battery.attr) 2467182bcaa5SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2468bb3fe01fSAzael Avalos else if (attr == &dev_attr_usb_rapid_charge.attr) 2469bb3fe01fSAzael Avalos exists = (drv->usb_rapid_charge_supported) ? true : false; 2470172ce0a9SAzael Avalos else if (attr == &dev_attr_usb_sleep_music.attr) 2471172ce0a9SAzael Avalos exists = (drv->usb_sleep_music_supported) ? true : false; 2472bae84195SAzael Avalos else if (attr == &dev_attr_kbd_function_keys.attr) 2473bae84195SAzael Avalos exists = (drv->kbd_function_keys_supported) ? true : false; 247435d53ceaSAzael Avalos else if (attr == &dev_attr_panel_power_on.attr) 247535d53ceaSAzael Avalos exists = (drv->panel_power_on_supported) ? true : false; 247617fe4b3dSAzael Avalos else if (attr == &dev_attr_usb_three.attr) 247717fe4b3dSAzael Avalos exists = (drv->usb_three_supported) ? true : false; 2478b1009b91SAzael Avalos else if (attr == &dev_attr_cooling_method.attr) 2479b1009b91SAzael Avalos exists = (drv->cooling_method_supported) ? true : false; 2480360f0f39SAzael Avalos 2481360f0f39SAzael Avalos return exists ? attr->mode : 0; 2482360f0f39SAzael Avalos } 2483360f0f39SAzael Avalos 248444bd76d0SArvind Yadav static const struct attribute_group toshiba_attr_group = { 24859bd1213bSAzael Avalos .is_visible = toshiba_sysfs_is_visible, 24869bd1213bSAzael Avalos .attrs = toshiba_attributes, 24879bd1213bSAzael Avalos }; 24889bd1213bSAzael Avalos 248965e3cf9cSAzael Avalos static void toshiba_acpi_kbd_bl_work(struct work_struct *work) 249065e3cf9cSAzael Avalos { 249165e3cf9cSAzael Avalos /* Update the sysfs entries */ 2492147288e6SAzael Avalos if (sysfs_update_group(&toshiba_acpi->acpi_dev->dev.kobj, 249365e3cf9cSAzael Avalos &toshiba_attr_group)) 249465e3cf9cSAzael Avalos pr_err("Unable to update sysfs entries\n"); 249565e3cf9cSAzael Avalos 2496147288e6SAzael Avalos /* Notify LED subsystem about keyboard backlight change */ 2497147288e6SAzael Avalos if (toshiba_acpi->kbd_type == 2 && 2498147288e6SAzael Avalos toshiba_acpi->kbd_mode != SCI_KBD_MODE_AUTO) 2499147288e6SAzael Avalos led_classdev_notify_brightness_hw_changed(&toshiba_acpi->kbd_led, 2500147288e6SAzael Avalos (toshiba_acpi->kbd_mode == SCI_KBD_MODE_ON) ? 2501147288e6SAzael Avalos LED_FULL : LED_OFF); 2502147288e6SAzael Avalos 250365e3cf9cSAzael Avalos /* Emulate the keyboard backlight event */ 2504147288e6SAzael Avalos acpi_bus_generate_netlink_event(toshiba_acpi->acpi_dev->pnp.device_class, 2505147288e6SAzael Avalos dev_name(&toshiba_acpi->acpi_dev->dev), 250665e3cf9cSAzael Avalos 0x92, 0); 250765e3cf9cSAzael Avalos } 250865e3cf9cSAzael Avalos 25091f28f290SAzael Avalos /* 251098010f1eSAzael Avalos * IIO device 251198010f1eSAzael Avalos */ 251298010f1eSAzael Avalos 251398010f1eSAzael Avalos enum toshiba_iio_accel_chan { 251498010f1eSAzael Avalos AXIS_X, 251598010f1eSAzael Avalos AXIS_Y, 251698010f1eSAzael Avalos AXIS_Z 251798010f1eSAzael Avalos }; 251898010f1eSAzael Avalos 251998010f1eSAzael Avalos static int toshiba_iio_accel_get_axis(enum toshiba_iio_accel_chan chan) 252098010f1eSAzael Avalos { 252198010f1eSAzael Avalos u32 xyval, zval; 252298010f1eSAzael Avalos int ret; 252398010f1eSAzael Avalos 252498010f1eSAzael Avalos ret = toshiba_accelerometer_get(toshiba_acpi, &xyval, &zval); 252598010f1eSAzael Avalos if (ret < 0) 252698010f1eSAzael Avalos return ret; 252798010f1eSAzael Avalos 252898010f1eSAzael Avalos switch (chan) { 252998010f1eSAzael Avalos case AXIS_X: 253098010f1eSAzael Avalos return xyval & HCI_ACCEL_DIRECTION_MASK ? 253198010f1eSAzael Avalos -(xyval & HCI_ACCEL_MASK) : xyval & HCI_ACCEL_MASK; 253298010f1eSAzael Avalos case AXIS_Y: 253398010f1eSAzael Avalos return (xyval >> HCI_MISC_SHIFT) & HCI_ACCEL_DIRECTION_MASK ? 253498010f1eSAzael Avalos -((xyval >> HCI_MISC_SHIFT) & HCI_ACCEL_MASK) : 253598010f1eSAzael Avalos (xyval >> HCI_MISC_SHIFT) & HCI_ACCEL_MASK; 253698010f1eSAzael Avalos case AXIS_Z: 253798010f1eSAzael Avalos return zval & HCI_ACCEL_DIRECTION_MASK ? 253898010f1eSAzael Avalos -(zval & HCI_ACCEL_MASK) : zval & HCI_ACCEL_MASK; 253998010f1eSAzael Avalos } 254098010f1eSAzael Avalos 254198010f1eSAzael Avalos return ret; 254298010f1eSAzael Avalos } 254398010f1eSAzael Avalos 254498010f1eSAzael Avalos static int toshiba_iio_accel_read_raw(struct iio_dev *indio_dev, 254598010f1eSAzael Avalos struct iio_chan_spec const *chan, 254698010f1eSAzael Avalos int *val, int *val2, long mask) 254798010f1eSAzael Avalos { 254898010f1eSAzael Avalos int ret; 254998010f1eSAzael Avalos 255098010f1eSAzael Avalos switch (mask) { 255198010f1eSAzael Avalos case IIO_CHAN_INFO_RAW: 255298010f1eSAzael Avalos ret = toshiba_iio_accel_get_axis(chan->channel); 255398010f1eSAzael Avalos if (ret == -EIO || ret == -ENODEV) 255498010f1eSAzael Avalos return ret; 255598010f1eSAzael Avalos 255698010f1eSAzael Avalos *val = ret; 255798010f1eSAzael Avalos 255898010f1eSAzael Avalos return IIO_VAL_INT; 255998010f1eSAzael Avalos } 256098010f1eSAzael Avalos 256198010f1eSAzael Avalos return -EINVAL; 256298010f1eSAzael Avalos } 256398010f1eSAzael Avalos 256498010f1eSAzael Avalos #define TOSHIBA_IIO_ACCEL_CHANNEL(axis, chan) { \ 256598010f1eSAzael Avalos .type = IIO_ACCEL, \ 256698010f1eSAzael Avalos .modified = 1, \ 256798010f1eSAzael Avalos .channel = chan, \ 256898010f1eSAzael Avalos .channel2 = IIO_MOD_##axis, \ 256998010f1eSAzael Avalos .output = 1, \ 257098010f1eSAzael Avalos .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 257198010f1eSAzael Avalos } 257298010f1eSAzael Avalos 257398010f1eSAzael Avalos static const struct iio_chan_spec toshiba_iio_accel_channels[] = { 257498010f1eSAzael Avalos TOSHIBA_IIO_ACCEL_CHANNEL(X, AXIS_X), 257598010f1eSAzael Avalos TOSHIBA_IIO_ACCEL_CHANNEL(Y, AXIS_Y), 257698010f1eSAzael Avalos TOSHIBA_IIO_ACCEL_CHANNEL(Z, AXIS_Z), 257798010f1eSAzael Avalos }; 257898010f1eSAzael Avalos 257998010f1eSAzael Avalos static const struct iio_info toshiba_iio_accel_info = { 258098010f1eSAzael Avalos .read_raw = &toshiba_iio_accel_read_raw, 258198010f1eSAzael Avalos }; 258298010f1eSAzael Avalos 258398010f1eSAzael Avalos /* 2584fc5462f8SAzael Avalos * Misc device 2585fc5462f8SAzael Avalos */ 2586fc5462f8SAzael Avalos static int toshiba_acpi_smm_bridge(SMMRegisters *regs) 2587fc5462f8SAzael Avalos { 2588fc5462f8SAzael Avalos u32 in[TCI_WORDS] = { regs->eax, regs->ebx, regs->ecx, 2589fc5462f8SAzael Avalos regs->edx, regs->esi, regs->edi }; 2590fc5462f8SAzael Avalos u32 out[TCI_WORDS]; 2591fc5462f8SAzael Avalos acpi_status status; 2592fc5462f8SAzael Avalos 2593fc5462f8SAzael Avalos status = tci_raw(toshiba_acpi, in, out); 2594fc5462f8SAzael Avalos if (ACPI_FAILURE(status)) { 2595fc5462f8SAzael Avalos pr_err("ACPI call to query SMM registers failed\n"); 2596fc5462f8SAzael Avalos return -EIO; 2597fc5462f8SAzael Avalos } 2598fc5462f8SAzael Avalos 2599fc5462f8SAzael Avalos /* Fillout the SMM struct with the TCI call results */ 2600fc5462f8SAzael Avalos regs->eax = out[0]; 2601fc5462f8SAzael Avalos regs->ebx = out[1]; 2602fc5462f8SAzael Avalos regs->ecx = out[2]; 2603fc5462f8SAzael Avalos regs->edx = out[3]; 2604fc5462f8SAzael Avalos regs->esi = out[4]; 2605fc5462f8SAzael Avalos regs->edi = out[5]; 2606fc5462f8SAzael Avalos 2607fc5462f8SAzael Avalos return 0; 2608fc5462f8SAzael Avalos } 2609fc5462f8SAzael Avalos 2610fc5462f8SAzael Avalos static long toshiba_acpi_ioctl(struct file *fp, unsigned int cmd, 2611fc5462f8SAzael Avalos unsigned long arg) 2612fc5462f8SAzael Avalos { 2613fc5462f8SAzael Avalos SMMRegisters __user *argp = (SMMRegisters __user *)arg; 2614fc5462f8SAzael Avalos SMMRegisters regs; 2615fc5462f8SAzael Avalos int ret; 2616fc5462f8SAzael Avalos 2617fc5462f8SAzael Avalos if (!argp) 2618fc5462f8SAzael Avalos return -EINVAL; 2619fc5462f8SAzael Avalos 2620fc5462f8SAzael Avalos switch (cmd) { 2621fc5462f8SAzael Avalos case TOSH_SMM: 2622fc5462f8SAzael Avalos if (copy_from_user(®s, argp, sizeof(SMMRegisters))) 2623fc5462f8SAzael Avalos return -EFAULT; 2624fc5462f8SAzael Avalos ret = toshiba_acpi_smm_bridge(®s); 2625fc5462f8SAzael Avalos if (ret) 2626fc5462f8SAzael Avalos return ret; 2627fc5462f8SAzael Avalos if (copy_to_user(argp, ®s, sizeof(SMMRegisters))) 2628fc5462f8SAzael Avalos return -EFAULT; 2629fc5462f8SAzael Avalos break; 2630fc5462f8SAzael Avalos case TOSHIBA_ACPI_SCI: 2631fc5462f8SAzael Avalos if (copy_from_user(®s, argp, sizeof(SMMRegisters))) 2632fc5462f8SAzael Avalos return -EFAULT; 2633fc5462f8SAzael Avalos /* Ensure we are being called with a SCI_{GET, SET} register */ 2634fc5462f8SAzael Avalos if (regs.eax != SCI_GET && regs.eax != SCI_SET) 2635fc5462f8SAzael Avalos return -EINVAL; 2636fc5462f8SAzael Avalos if (!sci_open(toshiba_acpi)) 2637fc5462f8SAzael Avalos return -EIO; 2638fc5462f8SAzael Avalos ret = toshiba_acpi_smm_bridge(®s); 2639fc5462f8SAzael Avalos sci_close(toshiba_acpi); 2640fc5462f8SAzael Avalos if (ret) 2641fc5462f8SAzael Avalos return ret; 2642fc5462f8SAzael Avalos if (copy_to_user(argp, ®s, sizeof(SMMRegisters))) 2643fc5462f8SAzael Avalos return -EFAULT; 2644fc5462f8SAzael Avalos break; 2645fc5462f8SAzael Avalos default: 2646fc5462f8SAzael Avalos return -EINVAL; 2647fc5462f8SAzael Avalos } 2648fc5462f8SAzael Avalos 2649fc5462f8SAzael Avalos return 0; 2650fc5462f8SAzael Avalos } 2651fc5462f8SAzael Avalos 2652fc5462f8SAzael Avalos static const struct file_operations toshiba_acpi_fops = { 2653fc5462f8SAzael Avalos .owner = THIS_MODULE, 2654fc5462f8SAzael Avalos .unlocked_ioctl = toshiba_acpi_ioctl, 2655fc5462f8SAzael Avalos .llseek = noop_llseek, 2656fc5462f8SAzael Avalos }; 2657fc5462f8SAzael Avalos 2658fc5462f8SAzael Avalos /* 26592fdde834SAzael Avalos * WWAN RFKill handlers 26602fdde834SAzael Avalos */ 26612fdde834SAzael Avalos static int toshiba_acpi_wwan_set_block(void *data, bool blocked) 26622fdde834SAzael Avalos { 26632fdde834SAzael Avalos struct toshiba_acpi_dev *dev = data; 26642fdde834SAzael Avalos int ret; 26652fdde834SAzael Avalos 26662fdde834SAzael Avalos ret = toshiba_wireless_status(dev); 26672fdde834SAzael Avalos if (ret) 26682fdde834SAzael Avalos return ret; 26692fdde834SAzael Avalos 26702fdde834SAzael Avalos if (!dev->killswitch) 26712fdde834SAzael Avalos return 0; 26722fdde834SAzael Avalos 26732fdde834SAzael Avalos return toshiba_wwan_set(dev, !blocked); 26742fdde834SAzael Avalos } 26752fdde834SAzael Avalos 26762fdde834SAzael Avalos static void toshiba_acpi_wwan_poll(struct rfkill *rfkill, void *data) 26772fdde834SAzael Avalos { 26782fdde834SAzael Avalos struct toshiba_acpi_dev *dev = data; 26792fdde834SAzael Avalos 26802fdde834SAzael Avalos if (toshiba_wireless_status(dev)) 26812fdde834SAzael Avalos return; 26822fdde834SAzael Avalos 26832fdde834SAzael Avalos rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch); 26842fdde834SAzael Avalos } 26852fdde834SAzael Avalos 26862fdde834SAzael Avalos static const struct rfkill_ops wwan_rfk_ops = { 26872fdde834SAzael Avalos .set_block = toshiba_acpi_wwan_set_block, 26882fdde834SAzael Avalos .poll = toshiba_acpi_wwan_poll, 26892fdde834SAzael Avalos }; 26902fdde834SAzael Avalos 26912fdde834SAzael Avalos static int toshiba_acpi_setup_wwan_rfkill(struct toshiba_acpi_dev *dev) 26922fdde834SAzael Avalos { 26932fdde834SAzael Avalos int ret = toshiba_wireless_status(dev); 26942fdde834SAzael Avalos 26952fdde834SAzael Avalos if (ret) 26962fdde834SAzael Avalos return ret; 26972fdde834SAzael Avalos 26982fdde834SAzael Avalos dev->wwan_rfk = rfkill_alloc("Toshiba WWAN", 26992fdde834SAzael Avalos &dev->acpi_dev->dev, 27002fdde834SAzael Avalos RFKILL_TYPE_WWAN, 27012fdde834SAzael Avalos &wwan_rfk_ops, 27022fdde834SAzael Avalos dev); 27032fdde834SAzael Avalos if (!dev->wwan_rfk) { 27042fdde834SAzael Avalos pr_err("Unable to allocate WWAN rfkill device\n"); 27052fdde834SAzael Avalos return -ENOMEM; 27062fdde834SAzael Avalos } 27072fdde834SAzael Avalos 27082fdde834SAzael Avalos rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch); 27092fdde834SAzael Avalos 27102fdde834SAzael Avalos ret = rfkill_register(dev->wwan_rfk); 27112fdde834SAzael Avalos if (ret) { 27122fdde834SAzael Avalos pr_err("Unable to register WWAN rfkill device\n"); 27132fdde834SAzael Avalos rfkill_destroy(dev->wwan_rfk); 27142fdde834SAzael Avalos } 27152fdde834SAzael Avalos 27162fdde834SAzael Avalos return ret; 27172fdde834SAzael Avalos } 27182fdde834SAzael Avalos 27192fdde834SAzael Avalos /* 27201f28f290SAzael Avalos * Hotkeys 27211f28f290SAzael Avalos */ 27221f28f290SAzael Avalos static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev) 27231f28f290SAzael Avalos { 27241f28f290SAzael Avalos acpi_status status; 27251f28f290SAzael Avalos u32 result; 27261f28f290SAzael Avalos 27271f28f290SAzael Avalos status = acpi_evaluate_object(dev->acpi_dev->handle, 27281f28f290SAzael Avalos "ENAB", NULL, NULL); 27291f28f290SAzael Avalos if (ACPI_FAILURE(status)) 27301f28f290SAzael Avalos return -ENODEV; 27311f28f290SAzael Avalos 2732b116fd00SAzael Avalos /* 2733b116fd00SAzael Avalos * Enable the "Special Functions" mode only if they are 2734b116fd00SAzael Avalos * supported and if they are activated. 2735b116fd00SAzael Avalos */ 2736b116fd00SAzael Avalos if (dev->kbd_function_keys_supported && dev->special_functions) 2737b116fd00SAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, 2738b116fd00SAzael Avalos HCI_HOTKEY_SPECIAL_FUNCTIONS); 2739b116fd00SAzael Avalos else 2740d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE); 2741b116fd00SAzael Avalos 27421f28f290SAzael Avalos if (result == TOS_FAILURE) 27431f28f290SAzael Avalos return -EIO; 27441f28f290SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 27451f28f290SAzael Avalos return -ENODEV; 27461f28f290SAzael Avalos 27471f28f290SAzael Avalos return 0; 27481f28f290SAzael Avalos } 27491f28f290SAzael Avalos 275029cd293fSSeth Forshee static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, 275129cd293fSSeth Forshee struct serio *port) 275229cd293fSSeth Forshee { 275398280374SGiedrius Statkevičius if (str & I8042_STR_AUXDATA) 275429cd293fSSeth Forshee return false; 275529cd293fSSeth Forshee 275629cd293fSSeth Forshee if (unlikely(data == 0xe0)) 275729cd293fSSeth Forshee return false; 275829cd293fSSeth Forshee 275929cd293fSSeth Forshee if ((data & 0x7f) == TOS1900_FN_SCAN) { 276029cd293fSSeth Forshee schedule_work(&toshiba_acpi->hotkey_work); 276129cd293fSSeth Forshee return true; 276229cd293fSSeth Forshee } 276329cd293fSSeth Forshee 276429cd293fSSeth Forshee return false; 276529cd293fSSeth Forshee } 276629cd293fSSeth Forshee 276729cd293fSSeth Forshee static void toshiba_acpi_hotkey_work(struct work_struct *work) 276829cd293fSSeth Forshee { 276929cd293fSSeth Forshee acpi_handle ec_handle = ec_get_handle(); 277029cd293fSSeth Forshee acpi_status status; 277129cd293fSSeth Forshee 277229cd293fSSeth Forshee if (!ec_handle) 277329cd293fSSeth Forshee return; 277429cd293fSSeth Forshee 277529cd293fSSeth Forshee status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL); 277629cd293fSSeth Forshee if (ACPI_FAILURE(status)) 277729cd293fSSeth Forshee pr_err("ACPI NTFY method execution failed\n"); 277829cd293fSSeth Forshee } 277929cd293fSSeth Forshee 278029cd293fSSeth Forshee /* 278129cd293fSSeth Forshee * Returns hotkey scancode, or < 0 on failure. 278229cd293fSSeth Forshee */ 278329cd293fSSeth Forshee static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev) 278429cd293fSSeth Forshee { 278574facaf7SZhang Rui unsigned long long value; 278629cd293fSSeth Forshee acpi_status status; 278729cd293fSSeth Forshee 278874facaf7SZhang Rui status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO", 278974facaf7SZhang Rui NULL, &value); 279074facaf7SZhang Rui if (ACPI_FAILURE(status)) { 279129cd293fSSeth Forshee pr_err("ACPI INFO method execution failed\n"); 279229cd293fSSeth Forshee return -EIO; 279329cd293fSSeth Forshee } 279429cd293fSSeth Forshee 279574facaf7SZhang Rui return value; 279629cd293fSSeth Forshee } 279729cd293fSSeth Forshee 279829cd293fSSeth Forshee static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev, 279929cd293fSSeth Forshee int scancode) 280029cd293fSSeth Forshee { 280129cd293fSSeth Forshee if (scancode == 0x100) 280229cd293fSSeth Forshee return; 280329cd293fSSeth Forshee 2804e0769fe6SDarren Hart /* Act on key press; ignore key release */ 280529cd293fSSeth Forshee if (scancode & 0x80) 280629cd293fSSeth Forshee return; 280729cd293fSSeth Forshee 280829cd293fSSeth Forshee if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true)) 280929cd293fSSeth Forshee pr_info("Unknown key %x\n", scancode); 281029cd293fSSeth Forshee } 281129cd293fSSeth Forshee 281271454d78SAzael Avalos static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) 281371454d78SAzael Avalos { 281471454d78SAzael Avalos if (dev->info_supported) { 28157deef550SAzael Avalos int scancode = toshiba_acpi_query_hotkey(dev); 28167deef550SAzael Avalos 28177deef550SAzael Avalos if (scancode < 0) { 281871454d78SAzael Avalos pr_err("Failed to query hotkey event\n"); 28197deef550SAzael Avalos } else if (scancode != 0) { 282071454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, scancode); 28217deef550SAzael Avalos dev->key_event_valid = 1; 28227deef550SAzael Avalos dev->last_key_event = scancode; 28237deef550SAzael Avalos } 282471454d78SAzael Avalos } else if (dev->system_event_supported) { 28257deef550SAzael Avalos u32 result; 28267deef550SAzael Avalos u32 value; 28277deef550SAzael Avalos int retries = 3; 28287deef550SAzael Avalos 282971454d78SAzael Avalos do { 28307deef550SAzael Avalos result = hci_read(dev, HCI_SYSTEM_EVENT, &value); 28317deef550SAzael Avalos switch (result) { 283271454d78SAzael Avalos case TOS_SUCCESS: 283371454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, (int)value); 28347deef550SAzael Avalos dev->key_event_valid = 1; 28357deef550SAzael Avalos dev->last_key_event = value; 283671454d78SAzael Avalos break; 283771454d78SAzael Avalos case TOS_NOT_SUPPORTED: 283871454d78SAzael Avalos /* 283971454d78SAzael Avalos * This is a workaround for an unresolved 284071454d78SAzael Avalos * issue on some machines where system events 284171454d78SAzael Avalos * sporadically become disabled. 284271454d78SAzael Avalos */ 28437deef550SAzael Avalos result = hci_write(dev, HCI_SYSTEM_EVENT, 1); 28447deef550SAzael Avalos if (result == TOS_SUCCESS) 284571454d78SAzael Avalos pr_notice("Re-enabled hotkeys\n"); 2846df561f66SGustavo A. R. Silva fallthrough; 284771454d78SAzael Avalos default: 284871454d78SAzael Avalos retries--; 284971454d78SAzael Avalos break; 285071454d78SAzael Avalos } 28517deef550SAzael Avalos } while (retries && result != TOS_FIFO_EMPTY); 285271454d78SAzael Avalos } 285371454d78SAzael Avalos } 285471454d78SAzael Avalos 2855b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) 28566335e4d5SMatthew Garrett { 2857fe808bfbSTakashi Iwai const struct key_entry *keymap = toshiba_acpi_keymap; 2858a2b3471bSAzael Avalos acpi_handle ec_handle; 2859a2b3471bSAzael Avalos int error; 2860a2b3471bSAzael Avalos 28617faa6a37SAzael Avalos if (disable_hotkeys) { 28627faa6a37SAzael Avalos pr_info("Hotkeys disabled by module parameter\n"); 28637faa6a37SAzael Avalos return 0; 28647faa6a37SAzael Avalos } 28657faa6a37SAzael Avalos 2866a88bc06eSAzael Avalos if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) { 2867a88bc06eSAzael Avalos pr_info("WMI event detected, hotkeys will not be monitored\n"); 2868a88bc06eSAzael Avalos return 0; 2869a88bc06eSAzael Avalos } 2870a88bc06eSAzael Avalos 2871a2b3471bSAzael Avalos error = toshiba_acpi_enable_hotkeys(dev); 2872a2b3471bSAzael Avalos if (error) 2873a2b3471bSAzael Avalos return error; 2874a2b3471bSAzael Avalos 287510e6aaabSAzael Avalos if (toshiba_hotkey_event_type_get(dev, &dev->hotkey_event_type)) 287653147b6cSAzael Avalos pr_notice("Unable to query Hotkey Event Type\n"); 287753147b6cSAzael Avalos 2878135740deSSeth Forshee dev->hotkey_dev = input_allocate_device(); 2879b222cca6SJoe Perches if (!dev->hotkey_dev) 2880135740deSSeth Forshee return -ENOMEM; 2881135740deSSeth Forshee 2882135740deSSeth Forshee dev->hotkey_dev->name = "Toshiba input device"; 28836e02cc7eSSeth Forshee dev->hotkey_dev->phys = "toshiba_acpi/input0"; 2884135740deSSeth Forshee dev->hotkey_dev->id.bustype = BUS_HOST; 28854b93c6eaSArvid Norlander dev->hotkey_dev->dev.parent = &dev->acpi_dev->dev; 2886135740deSSeth Forshee 288710e6aaabSAzael Avalos if (dev->hotkey_event_type == HCI_SYSTEM_TYPE1 || 2888a2b3471bSAzael Avalos !dev->kbd_function_keys_supported) 2889a2b3471bSAzael Avalos keymap = toshiba_acpi_keymap; 289010e6aaabSAzael Avalos else if (dev->hotkey_event_type == HCI_SYSTEM_TYPE2 || 2891a2b3471bSAzael Avalos dev->kbd_function_keys_supported) 2892fe808bfbSTakashi Iwai keymap = toshiba_acpi_alt_keymap; 2893a2b3471bSAzael Avalos else 289410e6aaabSAzael Avalos pr_info("Unknown event type received %x\n", 289510e6aaabSAzael Avalos dev->hotkey_event_type); 2896fe808bfbSTakashi Iwai error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL); 2897135740deSSeth Forshee if (error) 2898135740deSSeth Forshee goto err_free_dev; 2899135740deSSeth Forshee 290029cd293fSSeth Forshee /* 290129cd293fSSeth Forshee * For some machines the SCI responsible for providing hotkey 290229cd293fSSeth Forshee * notification doesn't fire. We can trigger the notification 290329cd293fSSeth Forshee * whenever the Fn key is pressed using the NTFY method, if 290429cd293fSSeth Forshee * supported, so if it's present set up an i8042 key filter 290529cd293fSSeth Forshee * for this purpose. 290629cd293fSSeth Forshee */ 290729cd293fSSeth Forshee ec_handle = ec_get_handle(); 2908e2e19606SZhang Rui if (ec_handle && acpi_has_method(ec_handle, "NTFY")) { 290929cd293fSSeth Forshee INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work); 291029cd293fSSeth Forshee 291129cd293fSSeth Forshee error = i8042_install_filter(toshiba_acpi_i8042_filter); 291229cd293fSSeth Forshee if (error) { 291329cd293fSSeth Forshee pr_err("Error installing key filter\n"); 2914db8f95d0SMichał Kępień goto err_free_dev; 291529cd293fSSeth Forshee } 291629cd293fSSeth Forshee 291729cd293fSSeth Forshee dev->ntfy_supported = 1; 291829cd293fSSeth Forshee } 291929cd293fSSeth Forshee 292029cd293fSSeth Forshee /* 292129cd293fSSeth Forshee * Determine hotkey query interface. Prefer using the INFO 292229cd293fSSeth Forshee * method when it is available. 292329cd293fSSeth Forshee */ 2924e2e19606SZhang Rui if (acpi_has_method(dev->acpi_dev->handle, "INFO")) 292529cd293fSSeth Forshee dev->info_supported = 1; 292610e6aaabSAzael Avalos else if (hci_write(dev, HCI_SYSTEM_EVENT, 1) == TOS_SUCCESS) 292729cd293fSSeth Forshee dev->system_event_supported = 1; 292829cd293fSSeth Forshee 292929cd293fSSeth Forshee if (!dev->info_supported && !dev->system_event_supported) { 293029cd293fSSeth Forshee pr_warn("No hotkey query interface found\n"); 293128e36712SJiapeng Chong error = -EINVAL; 293229cd293fSSeth Forshee goto err_remove_filter; 293329cd293fSSeth Forshee } 293429cd293fSSeth Forshee 2935135740deSSeth Forshee error = input_register_device(dev->hotkey_dev); 2936135740deSSeth Forshee if (error) { 2937135740deSSeth Forshee pr_info("Unable to register input device\n"); 293829cd293fSSeth Forshee goto err_remove_filter; 2939135740deSSeth Forshee } 2940135740deSSeth Forshee 2941135740deSSeth Forshee return 0; 2942135740deSSeth Forshee 294329cd293fSSeth Forshee err_remove_filter: 294429cd293fSSeth Forshee if (dev->ntfy_supported) 294529cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 2946135740deSSeth Forshee err_free_dev: 2947135740deSSeth Forshee input_free_device(dev->hotkey_dev); 2948135740deSSeth Forshee dev->hotkey_dev = NULL; 2949135740deSSeth Forshee return error; 2950135740deSSeth Forshee } 2951135740deSSeth Forshee 2952b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) 295362cce752SSeth Forshee { 295462cce752SSeth Forshee struct backlight_properties props; 295562cce752SSeth Forshee int brightness; 295662cce752SSeth Forshee int ret; 295762cce752SSeth Forshee 295862cce752SSeth Forshee /* 295962cce752SSeth Forshee * Some machines don't support the backlight methods at all, and 296062cce752SSeth Forshee * others support it read-only. Either of these is pretty useless, 296162cce752SSeth Forshee * so only register the backlight device if the backlight method 296262cce752SSeth Forshee * supports both reads and writes. 296362cce752SSeth Forshee */ 296462cce752SSeth Forshee brightness = __get_lcd_brightness(dev); 296562cce752SSeth Forshee if (brightness < 0) 296662cce752SSeth Forshee return 0; 2967bae5336fSAzael Avalos /* 2968bae5336fSAzael Avalos * If transflective backlight is supported and the brightness is zero 2969bae5336fSAzael Avalos * (lowest brightness level), the set_lcd_brightness function will 2970bae5336fSAzael Avalos * activate the transflective backlight, making the LCD appear to be 2971bae5336fSAzael Avalos * turned off, simply increment the brightness level to avoid that. 2972bae5336fSAzael Avalos */ 2973bae5336fSAzael Avalos if (dev->tr_backlight_supported && brightness == 0) 2974bae5336fSAzael Avalos brightness++; 297562cce752SSeth Forshee ret = set_lcd_brightness(dev, brightness); 297662cce752SSeth Forshee if (ret) { 297762cce752SSeth Forshee pr_debug("Backlight method is read-only, disabling backlight support\n"); 297862cce752SSeth Forshee return 0; 297962cce752SSeth Forshee } 298062cce752SSeth Forshee 2981234b7cf8SHans de Goede if (acpi_video_get_backlight_type() != acpi_backlight_vendor) 2982358d6a2cSHans de Goede return 0; 2983358d6a2cSHans de Goede 298453039f22SMatthew Garrett memset(&props, 0, sizeof(props)); 298562cce752SSeth Forshee props.type = BACKLIGHT_PLATFORM; 298662cce752SSeth Forshee props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; 298762cce752SSeth Forshee 2988e0769fe6SDarren Hart /* Adding an extra level and having 0 change to transflective mode */ 2989121b7b0dSAkio Idehara if (dev->tr_backlight_supported) 2990121b7b0dSAkio Idehara props.max_brightness++; 2991121b7b0dSAkio Idehara 299262cce752SSeth Forshee dev->backlight_dev = backlight_device_register("toshiba", 299362cce752SSeth Forshee &dev->acpi_dev->dev, 299462cce752SSeth Forshee dev, 299562cce752SSeth Forshee &toshiba_backlight_data, 299662cce752SSeth Forshee &props); 299762cce752SSeth Forshee if (IS_ERR(dev->backlight_dev)) { 299862cce752SSeth Forshee ret = PTR_ERR(dev->backlight_dev); 299962cce752SSeth Forshee pr_err("Could not register toshiba backlight device\n"); 300062cce752SSeth Forshee dev->backlight_dev = NULL; 300162cce752SSeth Forshee return ret; 300262cce752SSeth Forshee } 300362cce752SSeth Forshee 300462cce752SSeth Forshee dev->backlight_dev->props.brightness = brightness; 300562cce752SSeth Forshee return 0; 300662cce752SSeth Forshee } 300762cce752SSeth Forshee 3008c727ba4cSArvid Norlander /* HWMON support for fan */ 3009c727ba4cSArvid Norlander #if IS_ENABLED(CONFIG_HWMON) 3010c727ba4cSArvid Norlander static umode_t toshiba_acpi_hwmon_is_visible(const void *drvdata, 3011c727ba4cSArvid Norlander enum hwmon_sensor_types type, 3012c727ba4cSArvid Norlander u32 attr, int channel) 3013c727ba4cSArvid Norlander { 3014c727ba4cSArvid Norlander return 0444; 3015c727ba4cSArvid Norlander } 3016c727ba4cSArvid Norlander 3017c727ba4cSArvid Norlander static int toshiba_acpi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, 3018c727ba4cSArvid Norlander u32 attr, int channel, long *val) 3019c727ba4cSArvid Norlander { 3020c727ba4cSArvid Norlander /* 3021c727ba4cSArvid Norlander * There is only a single channel and single attribute (for the 3022c727ba4cSArvid Norlander * fan) at this point. 3023c727ba4cSArvid Norlander * This can be replaced with more advanced logic in the future, 3024c727ba4cSArvid Norlander * should the need arise. 3025c727ba4cSArvid Norlander */ 3026c727ba4cSArvid Norlander if (type == hwmon_fan && channel == 0 && attr == hwmon_fan_input) { 3027c727ba4cSArvid Norlander u32 value; 3028c727ba4cSArvid Norlander int ret; 3029c727ba4cSArvid Norlander 3030c727ba4cSArvid Norlander ret = get_fan_rpm(toshiba_acpi, &value); 3031c727ba4cSArvid Norlander if (ret) 3032c727ba4cSArvid Norlander return ret; 3033c727ba4cSArvid Norlander 3034c727ba4cSArvid Norlander *val = value; 3035c727ba4cSArvid Norlander return 0; 3036c727ba4cSArvid Norlander } 3037c727ba4cSArvid Norlander return -EOPNOTSUPP; 3038c727ba4cSArvid Norlander } 3039c727ba4cSArvid Norlander 3040c727ba4cSArvid Norlander static const struct hwmon_channel_info *toshiba_acpi_hwmon_info[] = { 3041c727ba4cSArvid Norlander HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT), 3042c727ba4cSArvid Norlander NULL 3043c727ba4cSArvid Norlander }; 3044c727ba4cSArvid Norlander 3045c727ba4cSArvid Norlander static const struct hwmon_ops toshiba_acpi_hwmon_ops = { 3046c727ba4cSArvid Norlander .is_visible = toshiba_acpi_hwmon_is_visible, 3047c727ba4cSArvid Norlander .read = toshiba_acpi_hwmon_read, 3048c727ba4cSArvid Norlander }; 3049c727ba4cSArvid Norlander 3050c727ba4cSArvid Norlander static const struct hwmon_chip_info toshiba_acpi_hwmon_chip_info = { 3051c727ba4cSArvid Norlander .ops = &toshiba_acpi_hwmon_ops, 3052c727ba4cSArvid Norlander .info = toshiba_acpi_hwmon_info, 3053c727ba4cSArvid Norlander }; 3054c727ba4cSArvid Norlander #endif 3055c727ba4cSArvid Norlander 30568ef5db9eSArvid Norlander /* ACPI battery hooking */ 30578ef5db9eSArvid Norlander static ssize_t charge_control_end_threshold_show(struct device *device, 30588ef5db9eSArvid Norlander struct device_attribute *attr, 30598ef5db9eSArvid Norlander char *buf) 30608ef5db9eSArvid Norlander { 30618ef5db9eSArvid Norlander u32 state; 30628ef5db9eSArvid Norlander int status; 30638ef5db9eSArvid Norlander 30648ef5db9eSArvid Norlander if (toshiba_acpi == NULL) { 30658ef5db9eSArvid Norlander pr_err("Toshiba ACPI object invalid\n"); 30668ef5db9eSArvid Norlander return -ENODEV; 30678ef5db9eSArvid Norlander } 30688ef5db9eSArvid Norlander 30698ef5db9eSArvid Norlander status = toshiba_battery_charge_mode_get(toshiba_acpi, &state); 30708ef5db9eSArvid Norlander 30718ef5db9eSArvid Norlander if (status != 0) 30728ef5db9eSArvid Norlander return status; 30738ef5db9eSArvid Norlander 30748ef5db9eSArvid Norlander if (state == 1) 30758ef5db9eSArvid Norlander return sprintf(buf, "80\n"); 30768ef5db9eSArvid Norlander else 30778ef5db9eSArvid Norlander return sprintf(buf, "100\n"); 30788ef5db9eSArvid Norlander } 30798ef5db9eSArvid Norlander 30808ef5db9eSArvid Norlander static ssize_t charge_control_end_threshold_store(struct device *dev, 30818ef5db9eSArvid Norlander struct device_attribute *attr, 30828ef5db9eSArvid Norlander const char *buf, 30838ef5db9eSArvid Norlander size_t count) 30848ef5db9eSArvid Norlander { 30858ef5db9eSArvid Norlander u32 value; 30868ef5db9eSArvid Norlander int rval; 30878ef5db9eSArvid Norlander 30888ef5db9eSArvid Norlander if (toshiba_acpi == NULL) { 30898ef5db9eSArvid Norlander pr_err("Toshiba ACPI object invalid\n"); 30908ef5db9eSArvid Norlander return -ENODEV; 30918ef5db9eSArvid Norlander } 30928ef5db9eSArvid Norlander 30938ef5db9eSArvid Norlander rval = kstrtou32(buf, 10, &value); 30948ef5db9eSArvid Norlander if (rval) 30958ef5db9eSArvid Norlander return rval; 30968ef5db9eSArvid Norlander 30978ef5db9eSArvid Norlander if (value < 1 || value > 100) 30988ef5db9eSArvid Norlander return -EINVAL; 30998ef5db9eSArvid Norlander rval = toshiba_battery_charge_mode_set(toshiba_acpi, 31008ef5db9eSArvid Norlander (value < 90) ? 1 : 0); 31018ef5db9eSArvid Norlander if (rval < 0) 31028ef5db9eSArvid Norlander return rval; 31038ef5db9eSArvid Norlander else 31048ef5db9eSArvid Norlander return count; 31058ef5db9eSArvid Norlander } 31068ef5db9eSArvid Norlander 31078ef5db9eSArvid Norlander static DEVICE_ATTR_RW(charge_control_end_threshold); 31088ef5db9eSArvid Norlander 31098ef5db9eSArvid Norlander static struct attribute *toshiba_acpi_battery_attrs[] = { 31108ef5db9eSArvid Norlander &dev_attr_charge_control_end_threshold.attr, 31118ef5db9eSArvid Norlander NULL, 31128ef5db9eSArvid Norlander }; 31138ef5db9eSArvid Norlander 31148ef5db9eSArvid Norlander ATTRIBUTE_GROUPS(toshiba_acpi_battery); 31158ef5db9eSArvid Norlander 31168ef5db9eSArvid Norlander static int toshiba_acpi_battery_add(struct power_supply *battery) 31178ef5db9eSArvid Norlander { 31188ef5db9eSArvid Norlander if (toshiba_acpi == NULL) { 31198ef5db9eSArvid Norlander pr_err("Init order issue\n"); 31208ef5db9eSArvid Norlander return -ENODEV; 31218ef5db9eSArvid Norlander } 31228ef5db9eSArvid Norlander if (!toshiba_acpi->battery_charge_mode_supported) 31238ef5db9eSArvid Norlander return -ENODEV; 31248ef5db9eSArvid Norlander if (device_add_groups(&battery->dev, toshiba_acpi_battery_groups)) 31258ef5db9eSArvid Norlander return -ENODEV; 31268ef5db9eSArvid Norlander return 0; 31278ef5db9eSArvid Norlander } 31288ef5db9eSArvid Norlander 31298ef5db9eSArvid Norlander static int toshiba_acpi_battery_remove(struct power_supply *battery) 31308ef5db9eSArvid Norlander { 31318ef5db9eSArvid Norlander device_remove_groups(&battery->dev, toshiba_acpi_battery_groups); 31328ef5db9eSArvid Norlander return 0; 31338ef5db9eSArvid Norlander } 31348ef5db9eSArvid Norlander 31358ef5db9eSArvid Norlander static struct acpi_battery_hook battery_hook = { 31368ef5db9eSArvid Norlander .add_battery = toshiba_acpi_battery_add, 31378ef5db9eSArvid Norlander .remove_battery = toshiba_acpi_battery_remove, 31388ef5db9eSArvid Norlander .name = "Toshiba Battery Extension", 31398ef5db9eSArvid Norlander }; 31408ef5db9eSArvid Norlander 31410409cbceSAzael Avalos static void print_supported_features(struct toshiba_acpi_dev *dev) 31420409cbceSAzael Avalos { 31430409cbceSAzael Avalos pr_info("Supported laptop features:"); 31440409cbceSAzael Avalos 31450409cbceSAzael Avalos if (dev->hotkey_dev) 31460409cbceSAzael Avalos pr_cont(" hotkeys"); 31470409cbceSAzael Avalos if (dev->backlight_dev) 31480409cbceSAzael Avalos pr_cont(" backlight"); 31490409cbceSAzael Avalos if (dev->video_supported) 31500409cbceSAzael Avalos pr_cont(" video-out"); 31510409cbceSAzael Avalos if (dev->fan_supported) 31520409cbceSAzael Avalos pr_cont(" fan"); 3153dd193dcdSArvid Norlander if (dev->fan_rpm_supported) 3154dd193dcdSArvid Norlander pr_cont(" fan-rpm"); 31550409cbceSAzael Avalos if (dev->tr_backlight_supported) 31560409cbceSAzael Avalos pr_cont(" transflective-backlight"); 31570409cbceSAzael Avalos if (dev->illumination_supported) 31580409cbceSAzael Avalos pr_cont(" illumination"); 31590409cbceSAzael Avalos if (dev->kbd_illum_supported) 31600409cbceSAzael Avalos pr_cont(" keyboard-backlight"); 31610409cbceSAzael Avalos if (dev->touchpad_supported) 31620409cbceSAzael Avalos pr_cont(" touchpad"); 31630409cbceSAzael Avalos if (dev->eco_supported) 31640409cbceSAzael Avalos pr_cont(" eco-led"); 31650409cbceSAzael Avalos if (dev->accelerometer_supported) 31660409cbceSAzael Avalos pr_cont(" accelerometer-axes"); 31670409cbceSAzael Avalos if (dev->usb_sleep_charge_supported) 31680409cbceSAzael Avalos pr_cont(" usb-sleep-charge"); 31690409cbceSAzael Avalos if (dev->usb_rapid_charge_supported) 31700409cbceSAzael Avalos pr_cont(" usb-rapid-charge"); 31710409cbceSAzael Avalos if (dev->usb_sleep_music_supported) 31720409cbceSAzael Avalos pr_cont(" usb-sleep-music"); 31730409cbceSAzael Avalos if (dev->kbd_function_keys_supported) 31740409cbceSAzael Avalos pr_cont(" special-function-keys"); 31750409cbceSAzael Avalos if (dev->panel_power_on_supported) 31760409cbceSAzael Avalos pr_cont(" panel-power-on"); 31770409cbceSAzael Avalos if (dev->usb_three_supported) 31780409cbceSAzael Avalos pr_cont(" usb3"); 31796873f46aSAzael Avalos if (dev->wwan_supported) 31806873f46aSAzael Avalos pr_cont(" wwan"); 3181763ff32fSAzael Avalos if (dev->cooling_method_supported) 3182763ff32fSAzael Avalos pr_cont(" cooling-method"); 318389655fbbSArvid Norlander if (dev->battery_charge_mode_supported) 318489655fbbSArvid Norlander pr_cont(" battery-charge-mode"); 31850409cbceSAzael Avalos 31860409cbceSAzael Avalos pr_cont("\n"); 31870409cbceSAzael Avalos } 31880409cbceSAzael Avalos 3189*6c0eb5baSDawei Li static void toshiba_acpi_remove(struct acpi_device *acpi_dev) 3190135740deSSeth Forshee { 3191135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 3192135740deSSeth Forshee 3193fc5462f8SAzael Avalos misc_deregister(&dev->miscdev); 3194fc5462f8SAzael Avalos 319536d03f93SSeth Forshee remove_toshiba_proc_entries(dev); 3196135740deSSeth Forshee 3197c727ba4cSArvid Norlander #if IS_ENABLED(CONFIG_HWMON) 3198c727ba4cSArvid Norlander if (dev->hwmon_device) 3199c727ba4cSArvid Norlander hwmon_device_unregister(dev->hwmon_device); 3200c727ba4cSArvid Norlander #endif 3201c727ba4cSArvid Norlander 320298010f1eSAzael Avalos if (dev->accelerometer_supported && dev->indio_dev) { 320398010f1eSAzael Avalos iio_device_unregister(dev->indio_dev); 320498010f1eSAzael Avalos iio_device_free(dev->indio_dev); 320598010f1eSAzael Avalos } 320698010f1eSAzael Avalos 3207360f0f39SAzael Avalos if (dev->sysfs_created) 3208360f0f39SAzael Avalos sysfs_remove_group(&dev->acpi_dev->dev.kobj, 3209360f0f39SAzael Avalos &toshiba_attr_group); 3210360f0f39SAzael Avalos 321129cd293fSSeth Forshee if (dev->ntfy_supported) { 321229cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 321329cd293fSSeth Forshee cancel_work_sync(&dev->hotkey_work); 321429cd293fSSeth Forshee } 321529cd293fSSeth Forshee 3216db8f95d0SMichał Kępień if (dev->hotkey_dev) 3217135740deSSeth Forshee input_unregister_device(dev->hotkey_dev); 3218135740deSSeth Forshee 3219135740deSSeth Forshee backlight_device_unregister(dev->backlight_dev); 3220135740deSSeth Forshee 3221135740deSSeth Forshee led_classdev_unregister(&dev->led_dev); 3222360f0f39SAzael Avalos led_classdev_unregister(&dev->kbd_led); 3223def6c4e2SAzael Avalos led_classdev_unregister(&dev->eco_led); 3224def6c4e2SAzael Avalos 32252fdde834SAzael Avalos if (dev->wwan_rfk) { 32262fdde834SAzael Avalos rfkill_unregister(dev->wwan_rfk); 32272fdde834SAzael Avalos rfkill_destroy(dev->wwan_rfk); 32282fdde834SAzael Avalos } 32292fdde834SAzael Avalos 32308ef5db9eSArvid Norlander if (dev->battery_charge_mode_supported) 32318ef5db9eSArvid Norlander battery_hook_unregister(&battery_hook); 32328ef5db9eSArvid Norlander 323329cd293fSSeth Forshee if (toshiba_acpi) 323429cd293fSSeth Forshee toshiba_acpi = NULL; 323529cd293fSSeth Forshee 3236135740deSSeth Forshee kfree(dev); 3237135740deSSeth Forshee } 3238135740deSSeth Forshee 3239b859f159SGreg Kroah-Hartman static const char *find_hci_method(acpi_handle handle) 3240a540d6b5SSeth Forshee { 3241e2e19606SZhang Rui if (acpi_has_method(handle, "GHCI")) 3242a540d6b5SSeth Forshee return "GHCI"; 3243a540d6b5SSeth Forshee 3244e2e19606SZhang Rui if (acpi_has_method(handle, "SPFC")) 3245a540d6b5SSeth Forshee return "SPFC"; 3246a540d6b5SSeth Forshee 3247a540d6b5SSeth Forshee return NULL; 3248a540d6b5SSeth Forshee } 3249a540d6b5SSeth Forshee 32503cb1f40dSHans de Goede /* 32513cb1f40dSHans de Goede * Some Toshibas have a broken acpi-video interface for brightness control, 32523cb1f40dSHans de Goede * these are quirked in drivers/acpi/video_detect.c to use the GPU native 32533cb1f40dSHans de Goede * (/sys/class/backlight/intel_backlight) instead. 32543cb1f40dSHans de Goede * But these need a HCI_SET call to actually turn the panel back on at resume, 32553cb1f40dSHans de Goede * without this call the screen stays black at resume. 32563cb1f40dSHans de Goede * Either HCI_LCD_BRIGHTNESS (used by acpi_video's _BCM) or HCI_PANEL_POWER_ON 32573cb1f40dSHans de Goede * works. toshiba_acpi_resume() uses HCI_PANEL_POWER_ON to avoid changing 32583cb1f40dSHans de Goede * the configured brightness level. 32593cb1f40dSHans de Goede */ 32603cb1f40dSHans de Goede static const struct dmi_system_id turn_on_panel_on_resume_dmi_ids[] = { 32613cb1f40dSHans de Goede { 32623cb1f40dSHans de Goede /* Toshiba Portégé R700 */ 32633cb1f40dSHans de Goede /* https://bugzilla.kernel.org/show_bug.cgi?id=21012 */ 32643cb1f40dSHans de Goede .matches = { 32653cb1f40dSHans de Goede DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 32663cb1f40dSHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R700"), 32673cb1f40dSHans de Goede }, 32683cb1f40dSHans de Goede }, 32693cb1f40dSHans de Goede { 32703cb1f40dSHans de Goede /* Toshiba Satellite/Portégé R830 */ 32713cb1f40dSHans de Goede /* Portégé: https://bugs.freedesktop.org/show_bug.cgi?id=82634 */ 32723cb1f40dSHans de Goede /* Satellite: https://bugzilla.kernel.org/show_bug.cgi?id=21012 */ 32733cb1f40dSHans de Goede .matches = { 32743cb1f40dSHans de Goede DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 32753cb1f40dSHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "R830"), 32763cb1f40dSHans de Goede }, 32773cb1f40dSHans de Goede }, 32783cb1f40dSHans de Goede { 32793cb1f40dSHans de Goede /* Toshiba Satellite/Portégé Z830 */ 32803cb1f40dSHans de Goede .matches = { 32813cb1f40dSHans de Goede DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 32823cb1f40dSHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "Z830"), 32833cb1f40dSHans de Goede }, 32843cb1f40dSHans de Goede }, 32853cb1f40dSHans de Goede }; 32863cb1f40dSHans de Goede 3287b859f159SGreg Kroah-Hartman static int toshiba_acpi_add(struct acpi_device *acpi_dev) 3288135740deSSeth Forshee { 3289135740deSSeth Forshee struct toshiba_acpi_dev *dev; 3290a540d6b5SSeth Forshee const char *hci_method; 329136d03f93SSeth Forshee u32 dummy; 3292135740deSSeth Forshee int ret = 0; 3293135740deSSeth Forshee 329429cd293fSSeth Forshee if (toshiba_acpi) 329529cd293fSSeth Forshee return -EBUSY; 329629cd293fSSeth Forshee 3297135740deSSeth Forshee pr_info("Toshiba Laptop ACPI Extras version %s\n", 3298135740deSSeth Forshee TOSHIBA_ACPI_VERSION); 3299135740deSSeth Forshee 3300a540d6b5SSeth Forshee hci_method = find_hci_method(acpi_dev->handle); 3301a540d6b5SSeth Forshee if (!hci_method) { 3302a540d6b5SSeth Forshee pr_err("HCI interface not found\n"); 33036e02cc7eSSeth Forshee return -ENODEV; 3304a540d6b5SSeth Forshee } 33056e02cc7eSSeth Forshee 3306135740deSSeth Forshee dev = kzalloc(sizeof(*dev), GFP_KERNEL); 3307135740deSSeth Forshee if (!dev) 3308135740deSSeth Forshee return -ENOMEM; 3309135740deSSeth Forshee dev->acpi_dev = acpi_dev; 3310a540d6b5SSeth Forshee dev->method_hci = hci_method; 3311fc5462f8SAzael Avalos dev->miscdev.minor = MISC_DYNAMIC_MINOR; 3312fc5462f8SAzael Avalos dev->miscdev.name = "toshiba_acpi"; 3313fc5462f8SAzael Avalos dev->miscdev.fops = &toshiba_acpi_fops; 3314fc5462f8SAzael Avalos 3315fc5462f8SAzael Avalos ret = misc_register(&dev->miscdev); 3316fc5462f8SAzael Avalos if (ret) { 3317fc5462f8SAzael Avalos pr_err("Failed to register miscdevice\n"); 3318fc5462f8SAzael Avalos kfree(dev); 3319fc5462f8SAzael Avalos return ret; 3320fc5462f8SAzael Avalos } 3321fc5462f8SAzael Avalos 3322135740deSSeth Forshee acpi_dev->driver_data = dev; 3323360f0f39SAzael Avalos dev_set_drvdata(&acpi_dev->dev, dev); 3324135740deSSeth Forshee 3325a2b3471bSAzael Avalos /* Query the BIOS for supported features */ 3326a2b3471bSAzael Avalos 3327a2b3471bSAzael Avalos /* 3328a2b3471bSAzael Avalos * The "Special Functions" are always supported by the laptops 3329a2b3471bSAzael Avalos * with the new keyboard layout, query for its presence to help 3330a2b3471bSAzael Avalos * determine the keymap layout to use. 3331a2b3471bSAzael Avalos */ 3332b116fd00SAzael Avalos ret = toshiba_function_keys_get(dev, &dev->special_functions); 3333a2b3471bSAzael Avalos dev->kbd_function_keys_supported = !ret; 3334a2b3471bSAzael Avalos 3335d2f20619SAzael Avalos dev->hotkey_event_type = 0; 33366e02cc7eSSeth Forshee if (toshiba_acpi_setup_keyboard(dev)) 3337135740deSSeth Forshee pr_info("Unable to activate hotkeys\n"); 3338135740deSSeth Forshee 3339695f6060SAzael Avalos /* Determine whether or not BIOS supports transflective backlight */ 3340695f6060SAzael Avalos ret = get_tr_backlight_status(dev, &dummy); 3341695f6060SAzael Avalos dev->tr_backlight_supported = !ret; 3342695f6060SAzael Avalos 334362cce752SSeth Forshee ret = toshiba_acpi_setup_backlight(dev); 334462cce752SSeth Forshee if (ret) 3345135740deSSeth Forshee goto error; 3346135740deSSeth Forshee 3347ea215a3fSAzael Avalos toshiba_illumination_available(dev); 3348ea215a3fSAzael Avalos if (dev->illumination_supported) { 3349135740deSSeth Forshee dev->led_dev.name = "toshiba::illumination"; 3350135740deSSeth Forshee dev->led_dev.max_brightness = 1; 3351135740deSSeth Forshee dev->led_dev.brightness_set = toshiba_illumination_set; 3352135740deSSeth Forshee dev->led_dev.brightness_get = toshiba_illumination_get; 3353409f3aedSAndy Shevchenko led_classdev_register(&acpi_dev->dev, &dev->led_dev); 3354135740deSSeth Forshee } 3355135740deSSeth Forshee 3356ea215a3fSAzael Avalos toshiba_eco_mode_available(dev); 3357ea215a3fSAzael Avalos if (dev->eco_supported) { 3358def6c4e2SAzael Avalos dev->eco_led.name = "toshiba::eco_mode"; 3359def6c4e2SAzael Avalos dev->eco_led.max_brightness = 1; 3360def6c4e2SAzael Avalos dev->eco_led.brightness_set = toshiba_eco_mode_set_status; 3361def6c4e2SAzael Avalos dev->eco_led.brightness_get = toshiba_eco_mode_get_status; 3362409f3aedSAndy Shevchenko led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led); 3363def6c4e2SAzael Avalos } 3364def6c4e2SAzael Avalos 3365ea215a3fSAzael Avalos toshiba_kbd_illum_available(dev); 3366360f0f39SAzael Avalos /* 3367360f0f39SAzael Avalos * Only register the LED if KBD illumination is supported 3368360f0f39SAzael Avalos * and the keyboard backlight operation mode is set to FN-Z 3369147288e6SAzael Avalos * or we detect a second gen keyboard backlight 3370360f0f39SAzael Avalos */ 3371147288e6SAzael Avalos if (dev->kbd_illum_supported && 3372147288e6SAzael Avalos (dev->kbd_mode == SCI_KBD_MODE_FNZ || dev->kbd_type == 2)) { 3373360f0f39SAzael Avalos dev->kbd_led.name = "toshiba::kbd_backlight"; 3374147288e6SAzael Avalos dev->kbd_led.flags = LED_BRIGHT_HW_CHANGED; 3375360f0f39SAzael Avalos dev->kbd_led.max_brightness = 1; 3376360f0f39SAzael Avalos dev->kbd_led.brightness_set = toshiba_kbd_backlight_set; 3377360f0f39SAzael Avalos dev->kbd_led.brightness_get = toshiba_kbd_backlight_get; 3378409f3aedSAndy Shevchenko led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led); 3379360f0f39SAzael Avalos } 3380360f0f39SAzael Avalos 33819d8658acSAzael Avalos ret = toshiba_touchpad_get(dev, &dummy); 33829d8658acSAzael Avalos dev->touchpad_supported = !ret; 33839d8658acSAzael Avalos 3384ea215a3fSAzael Avalos toshiba_accelerometer_available(dev); 338598010f1eSAzael Avalos if (dev->accelerometer_supported) { 338678289b4aSAlexandru Ardelean dev->indio_dev = iio_device_alloc(&acpi_dev->dev, sizeof(*dev)); 338798010f1eSAzael Avalos if (!dev->indio_dev) { 338898010f1eSAzael Avalos pr_err("Unable to allocate iio device\n"); 338998010f1eSAzael Avalos goto iio_error; 339098010f1eSAzael Avalos } 339198010f1eSAzael Avalos 339298010f1eSAzael Avalos pr_info("Registering Toshiba accelerometer iio device\n"); 339398010f1eSAzael Avalos 339498010f1eSAzael Avalos dev->indio_dev->info = &toshiba_iio_accel_info; 339598010f1eSAzael Avalos dev->indio_dev->name = "Toshiba accelerometer"; 339698010f1eSAzael Avalos dev->indio_dev->modes = INDIO_DIRECT_MODE; 339798010f1eSAzael Avalos dev->indio_dev->channels = toshiba_iio_accel_channels; 339898010f1eSAzael Avalos dev->indio_dev->num_channels = 339998010f1eSAzael Avalos ARRAY_SIZE(toshiba_iio_accel_channels); 340098010f1eSAzael Avalos 340198010f1eSAzael Avalos ret = iio_device_register(dev->indio_dev); 340298010f1eSAzael Avalos if (ret < 0) { 340398010f1eSAzael Avalos pr_err("Unable to register iio device\n"); 340498010f1eSAzael Avalos iio_device_free(dev->indio_dev); 340598010f1eSAzael Avalos } 340698010f1eSAzael Avalos } 340798010f1eSAzael Avalos iio_error: 34085a2813e9SAzael Avalos 3409c8c91842SAzael Avalos toshiba_usb_sleep_charge_available(dev); 3410e26ffe51SAzael Avalos 3411bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(dev, &dummy); 3412bb3fe01fSAzael Avalos dev->usb_rapid_charge_supported = !ret; 3413bb3fe01fSAzael Avalos 3414172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(dev, &dummy); 3415172ce0a9SAzael Avalos dev->usb_sleep_music_supported = !ret; 3416172ce0a9SAzael Avalos 341735d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(dev, &dummy); 341835d53ceaSAzael Avalos dev->panel_power_on_supported = !ret; 341935d53ceaSAzael Avalos 342017fe4b3dSAzael Avalos ret = toshiba_usb_three_get(dev, &dummy); 342117fe4b3dSAzael Avalos dev->usb_three_supported = !ret; 342217fe4b3dSAzael Avalos 342336d03f93SSeth Forshee ret = get_video_status(dev, &dummy); 342436d03f93SSeth Forshee dev->video_supported = !ret; 342536d03f93SSeth Forshee 342636d03f93SSeth Forshee ret = get_fan_status(dev, &dummy); 342736d03f93SSeth Forshee dev->fan_supported = !ret; 342836d03f93SSeth Forshee 3429dd193dcdSArvid Norlander ret = get_fan_rpm(dev, &dummy); 3430dd193dcdSArvid Norlander dev->fan_rpm_supported = !ret; 3431dd193dcdSArvid Norlander 3432c727ba4cSArvid Norlander #if IS_ENABLED(CONFIG_HWMON) 3433c727ba4cSArvid Norlander if (dev->fan_rpm_supported) { 3434c727ba4cSArvid Norlander dev->hwmon_device = hwmon_device_register_with_info( 3435c727ba4cSArvid Norlander &dev->acpi_dev->dev, "toshiba_acpi_sensors", NULL, 3436c727ba4cSArvid Norlander &toshiba_acpi_hwmon_chip_info, NULL); 3437c727ba4cSArvid Norlander if (IS_ERR(dev->hwmon_device)) { 3438c727ba4cSArvid Norlander dev->hwmon_device = NULL; 3439c727ba4cSArvid Norlander pr_warn("unable to register hwmon device, skipping\n"); 3440c727ba4cSArvid Norlander } 3441c727ba4cSArvid Norlander } 3442c727ba4cSArvid Norlander #endif 3443c727ba4cSArvid Norlander 34443cb1f40dSHans de Goede if (turn_on_panel_on_resume == -1) 34453cb1f40dSHans de Goede turn_on_panel_on_resume = dmi_check_system(turn_on_panel_on_resume_dmi_ids); 34463cb1f40dSHans de Goede 34476873f46aSAzael Avalos toshiba_wwan_available(dev); 34482fdde834SAzael Avalos if (dev->wwan_supported) 34492fdde834SAzael Avalos toshiba_acpi_setup_wwan_rfkill(dev); 34506873f46aSAzael Avalos 3451763ff32fSAzael Avalos toshiba_cooling_method_available(dev); 3452763ff32fSAzael Avalos 345389655fbbSArvid Norlander toshiba_battery_charge_mode_available(dev); 345489655fbbSArvid Norlander 34550409cbceSAzael Avalos print_supported_features(dev); 34560409cbceSAzael Avalos 3457360f0f39SAzael Avalos ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, 3458360f0f39SAzael Avalos &toshiba_attr_group); 3459360f0f39SAzael Avalos if (ret) { 3460360f0f39SAzael Avalos dev->sysfs_created = 0; 3461360f0f39SAzael Avalos goto error; 3462360f0f39SAzael Avalos } 3463360f0f39SAzael Avalos dev->sysfs_created = !ret; 3464360f0f39SAzael Avalos 346536d03f93SSeth Forshee create_toshiba_proc_entries(dev); 346636d03f93SSeth Forshee 346729cd293fSSeth Forshee toshiba_acpi = dev; 346829cd293fSSeth Forshee 34698ef5db9eSArvid Norlander /* 34708ef5db9eSArvid Norlander * As the battery hook relies on the static variable toshiba_acpi being 34718ef5db9eSArvid Norlander * set, this must be done after toshiba_acpi is assigned. 34728ef5db9eSArvid Norlander */ 34738ef5db9eSArvid Norlander if (dev->battery_charge_mode_supported) 34748ef5db9eSArvid Norlander battery_hook_register(&battery_hook); 34758ef5db9eSArvid Norlander 3476135740deSSeth Forshee return 0; 3477135740deSSeth Forshee 3478135740deSSeth Forshee error: 347951fac838SRafael J. Wysocki toshiba_acpi_remove(acpi_dev); 3480135740deSSeth Forshee return ret; 3481135740deSSeth Forshee } 3482135740deSSeth Forshee 3483135740deSSeth Forshee static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) 3484135740deSSeth Forshee { 3485135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 34866335e4d5SMatthew Garrett 348771454d78SAzael Avalos switch (event) { 348871454d78SAzael Avalos case 0x80: /* Hotkeys and some system events */ 3489a88bc06eSAzael Avalos /* 3490a88bc06eSAzael Avalos * Machines with this WMI GUID aren't supported due to bugs in 3491a88bc06eSAzael Avalos * their AML. 3492a88bc06eSAzael Avalos * 3493a88bc06eSAzael Avalos * Return silently to avoid triggering a netlink event. 3494a88bc06eSAzael Avalos */ 3495a88bc06eSAzael Avalos if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) 3496a88bc06eSAzael Avalos return; 349771454d78SAzael Avalos toshiba_acpi_process_hotkeys(dev); 349811948b93SSeth Forshee break; 3499bab09e23SAzael Avalos case 0x81: /* Dock events */ 3500bab09e23SAzael Avalos case 0x82: 3501bab09e23SAzael Avalos case 0x83: 3502bab09e23SAzael Avalos pr_info("Dock event received %x\n", event); 3503bab09e23SAzael Avalos break; 3504bab09e23SAzael Avalos case 0x88: /* Thermal events */ 3505bab09e23SAzael Avalos pr_info("Thermal event received\n"); 3506bab09e23SAzael Avalos break; 3507bab09e23SAzael Avalos case 0x8f: /* LID closed */ 3508bab09e23SAzael Avalos case 0x90: /* LID is closed and Dock has been ejected */ 3509bab09e23SAzael Avalos break; 3510bab09e23SAzael Avalos case 0x8c: /* SATA power events */ 3511bab09e23SAzael Avalos case 0x8b: 3512bab09e23SAzael Avalos pr_info("SATA power event received %x\n", event); 3513bab09e23SAzael Avalos break; 351480546905SAzael Avalos case 0x92: /* Keyboard backlight mode changed */ 3515147288e6SAzael Avalos dev->kbd_event_generated = true; 351680546905SAzael Avalos /* Update sysfs entries */ 351765e3cf9cSAzael Avalos if (sysfs_update_group(&acpi_dev->dev.kobj, 351865e3cf9cSAzael Avalos &toshiba_attr_group)) 351980546905SAzael Avalos pr_err("Unable to update sysfs entries\n"); 3520147288e6SAzael Avalos /* Notify LED subsystem about keyboard backlight change */ 3521147288e6SAzael Avalos if (dev->kbd_type == 2 && dev->kbd_mode != SCI_KBD_MODE_AUTO) 3522147288e6SAzael Avalos led_classdev_notify_brightness_hw_changed(&dev->kbd_led, 3523147288e6SAzael Avalos (dev->kbd_mode == SCI_KBD_MODE_ON) ? 3524147288e6SAzael Avalos LED_FULL : LED_OFF); 352580546905SAzael Avalos break; 3526bab09e23SAzael Avalos case 0x85: /* Unknown */ 3527bab09e23SAzael Avalos case 0x8d: /* Unknown */ 352871454d78SAzael Avalos case 0x8e: /* Unknown */ 3529bab09e23SAzael Avalos case 0x94: /* Unknown */ 3530bab09e23SAzael Avalos case 0x95: /* Unknown */ 353111948b93SSeth Forshee default: 353271454d78SAzael Avalos pr_info("Unknown event received %x\n", event); 353311948b93SSeth Forshee break; 35346335e4d5SMatthew Garrett } 3535bab09e23SAzael Avalos 3536bab09e23SAzael Avalos acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class, 3537bab09e23SAzael Avalos dev_name(&acpi_dev->dev), 353813ae84f9SAzael Avalos event, (event == 0x80) ? 353913ae84f9SAzael Avalos dev->last_key_event : 0); 354029cd293fSSeth Forshee } 35416335e4d5SMatthew Garrett 35423567a4e2SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 354343d2fd3bSRafael J. Wysocki static int toshiba_acpi_suspend(struct device *device) 354429cd293fSSeth Forshee { 354543d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 35461e574dbfSAzael Avalos 35471e574dbfSAzael Avalos if (dev->hotkey_dev) { 354829cd293fSSeth Forshee u32 result; 354929cd293fSSeth Forshee 3550d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE); 35511e574dbfSAzael Avalos if (result != TOS_SUCCESS) 35521e574dbfSAzael Avalos pr_info("Unable to disable hotkeys\n"); 35531e574dbfSAzael Avalos } 355429cd293fSSeth Forshee 355529cd293fSSeth Forshee return 0; 355629cd293fSSeth Forshee } 355729cd293fSSeth Forshee 355843d2fd3bSRafael J. Wysocki static int toshiba_acpi_resume(struct device *device) 355929cd293fSSeth Forshee { 356043d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 356129cd293fSSeth Forshee 3562e7fdb762SBenjamin Tissoires if (dev->hotkey_dev) { 35632fdde834SAzael Avalos if (toshiba_acpi_enable_hotkeys(dev)) 3564e7fdb762SBenjamin Tissoires pr_info("Unable to re-enable hotkeys\n"); 3565e7fdb762SBenjamin Tissoires } 356629cd293fSSeth Forshee 35672fdde834SAzael Avalos if (dev->wwan_rfk) { 35682fdde834SAzael Avalos if (!toshiba_wireless_status(dev)) 35692fdde834SAzael Avalos rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch); 35702fdde834SAzael Avalos } 35712fdde834SAzael Avalos 35723cb1f40dSHans de Goede if (turn_on_panel_on_resume) 35733cb1f40dSHans de Goede hci_write(dev, HCI_PANEL_POWER_ON, 1); 35743cb1f40dSHans de Goede 357529cd293fSSeth Forshee return 0; 357629cd293fSSeth Forshee } 35773567a4e2SRafael J. Wysocki #endif 35786335e4d5SMatthew Garrett 357943d2fd3bSRafael J. Wysocki static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm, 358043d2fd3bSRafael J. Wysocki toshiba_acpi_suspend, toshiba_acpi_resume); 358143d2fd3bSRafael J. Wysocki 3582135740deSSeth Forshee static struct acpi_driver toshiba_acpi_driver = { 3583135740deSSeth Forshee .name = "Toshiba ACPI driver", 3584135740deSSeth Forshee .owner = THIS_MODULE, 3585135740deSSeth Forshee .ids = toshiba_device_ids, 3586135740deSSeth Forshee .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, 3587135740deSSeth Forshee .ops = { 3588135740deSSeth Forshee .add = toshiba_acpi_add, 3589135740deSSeth Forshee .remove = toshiba_acpi_remove, 3590135740deSSeth Forshee .notify = toshiba_acpi_notify, 3591135740deSSeth Forshee }, 359243d2fd3bSRafael J. Wysocki .drv.pm = &toshiba_acpi_pm, 3593135740deSSeth Forshee }; 3594b4f9fe12SLen Brown 3595b4f9fe12SLen Brown static int __init toshiba_acpi_init(void) 3596b4f9fe12SLen Brown { 3597135740deSSeth Forshee int ret; 3598b4f9fe12SLen Brown 3599b4f9fe12SLen Brown toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); 3600b4f9fe12SLen Brown if (!toshiba_proc_dir) { 3601135740deSSeth Forshee pr_err("Unable to create proc dir " PROC_TOSHIBA "\n"); 3602b4f9fe12SLen Brown return -ENODEV; 3603b4f9fe12SLen Brown } 3604b4f9fe12SLen Brown 3605135740deSSeth Forshee ret = acpi_bus_register_driver(&toshiba_acpi_driver); 3606b4f9fe12SLen Brown if (ret) { 3607135740deSSeth Forshee pr_err("Failed to register ACPI driver: %d\n", ret); 3608135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 3609135740deSSeth Forshee } 3610135740deSSeth Forshee 3611b4f9fe12SLen Brown return ret; 3612b4f9fe12SLen Brown } 3613b4f9fe12SLen Brown 3614135740deSSeth Forshee static void __exit toshiba_acpi_exit(void) 3615135740deSSeth Forshee { 3616135740deSSeth Forshee acpi_bus_unregister_driver(&toshiba_acpi_driver); 3617135740deSSeth Forshee if (toshiba_proc_dir) 3618135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 3619b4f9fe12SLen Brown } 3620b4f9fe12SLen Brown 3621b4f9fe12SLen Brown module_init(toshiba_acpi_init); 3622b4f9fe12SLen Brown module_exit(toshiba_acpi_exit); 3623