1b4f9fe12SLen Brown /* 2b4f9fe12SLen Brown * toshiba_acpi.c - Toshiba Laptop ACPI Extras 3b4f9fe12SLen Brown * 4b4f9fe12SLen Brown * Copyright (C) 2002-2004 John Belmonte 5b4f9fe12SLen Brown * Copyright (C) 2008 Philip Langdale 66c3f6e6cSPierre Ducroquet * Copyright (C) 2010 Pierre Ducroquet 77216d702SAzael Avalos * Copyright (C) 2014-2015 Azael Avalos 8b4f9fe12SLen Brown * 9b4f9fe12SLen Brown * This program is free software; you can redistribute it and/or modify 10b4f9fe12SLen Brown * it under the terms of the GNU General Public License as published by 11b4f9fe12SLen Brown * the Free Software Foundation; either version 2 of the License, or 12b4f9fe12SLen Brown * (at your option) any later version. 13b4f9fe12SLen Brown * 14b4f9fe12SLen Brown * This program is distributed in the hope that it will be useful, 15b4f9fe12SLen Brown * but WITHOUT ANY WARRANTY; without even the implied warranty of 16b4f9fe12SLen Brown * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17b4f9fe12SLen Brown * GNU General Public License for more details. 18b4f9fe12SLen Brown * 19c57c0fa4SDarren Hart * The full GNU General Public License is included in this distribution in 20c57c0fa4SDarren Hart * the file called "COPYING". 21b4f9fe12SLen Brown * 22b4f9fe12SLen Brown * The devolpment page for this driver is located at 23b4f9fe12SLen Brown * http://memebeam.org/toys/ToshibaAcpiDriver. 24b4f9fe12SLen Brown * 25b4f9fe12SLen Brown * Credits: 26b4f9fe12SLen Brown * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse 27b4f9fe12SLen Brown * engineering the Windows drivers 28b4f9fe12SLen Brown * Yasushi Nagato - changes for linux kernel 2.4 -> 2.5 29b4f9fe12SLen Brown * Rob Miller - TV out and hotkeys help 30b4f9fe12SLen Brown */ 31b4f9fe12SLen Brown 327e33460dSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 337e33460dSJoe Perches 347216d702SAzael Avalos #define TOSHIBA_ACPI_VERSION "0.21" 35b4f9fe12SLen Brown #define PROC_INTERFACE_VERSION 1 36b4f9fe12SLen Brown 37b4f9fe12SLen Brown #include <linux/kernel.h> 38b4f9fe12SLen Brown #include <linux/module.h> 39b4f9fe12SLen Brown #include <linux/init.h> 40b4f9fe12SLen Brown #include <linux/types.h> 41b4f9fe12SLen Brown #include <linux/proc_fs.h> 42936c8bcdSAlexey Dobriyan #include <linux/seq_file.h> 43b4f9fe12SLen Brown #include <linux/backlight.h> 44b4f9fe12SLen Brown #include <linux/rfkill.h> 456335e4d5SMatthew Garrett #include <linux/input.h> 46384a7cd9SDmitry Torokhov #include <linux/input/sparse-keymap.h> 476c3f6e6cSPierre Ducroquet #include <linux/leds.h> 485a0e3ad6STejun Heo #include <linux/slab.h> 4929cd293fSSeth Forshee #include <linux/workqueue.h> 5029cd293fSSeth Forshee #include <linux/i8042.h> 518b48463fSLv Zheng #include <linux/acpi.h> 52*358d6a2cSHans de Goede #include <linux/dmi.h> 53b5163992SAzael Avalos #include <linux/uaccess.h> 54*358d6a2cSHans de Goede #include <acpi/video.h> 55b4f9fe12SLen Brown 56b4f9fe12SLen Brown MODULE_AUTHOR("John Belmonte"); 57b4f9fe12SLen Brown MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); 58b4f9fe12SLen Brown MODULE_LICENSE("GPL"); 59b4f9fe12SLen Brown 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 85b4f9fe12SLen Brown /* 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 93b4f9fe12SLen Brown /* return codes */ 941864bbc2SAzael Avalos #define TOS_SUCCESS 0x0000 951864bbc2SAzael Avalos #define TOS_OPEN_CLOSE_OK 0x0044 961864bbc2SAzael Avalos #define TOS_FAILURE 0x1000 971864bbc2SAzael Avalos #define TOS_NOT_SUPPORTED 0x8000 981864bbc2SAzael Avalos #define TOS_ALREADY_OPEN 0x8100 991864bbc2SAzael Avalos #define TOS_NOT_OPENED 0x8200 1001864bbc2SAzael Avalos #define TOS_INPUT_DATA_ERROR 0x8300 1011864bbc2SAzael Avalos #define TOS_WRITE_PROTECTED 0x8400 1021864bbc2SAzael Avalos #define TOS_NOT_PRESENT 0x8600 1031864bbc2SAzael Avalos #define TOS_FIFO_EMPTY 0x8c00 1041864bbc2SAzael Avalos #define TOS_DATA_NOT_AVAILABLE 0x8d20 1051864bbc2SAzael Avalos #define TOS_NOT_INITIALIZED 0x8d50 10698fc4ec6SAzael Avalos #define TOS_NOT_INSTALLED 0x8e00 107b4f9fe12SLen Brown 108b4f9fe12SLen Brown /* registers */ 109b4f9fe12SLen Brown #define HCI_FAN 0x0004 110121b7b0dSAkio Idehara #define HCI_TR_BACKLIGHT 0x0005 111b4f9fe12SLen Brown #define HCI_SYSTEM_EVENT 0x0016 112b4f9fe12SLen Brown #define HCI_VIDEO_OUT 0x001c 113b4f9fe12SLen Brown #define HCI_HOTKEY_EVENT 0x001e 114b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS 0x002a 115b4f9fe12SLen Brown #define HCI_WIRELESS 0x0056 1165a2813e9SAzael Avalos #define HCI_ACCELEROMETER 0x006d 117360f0f39SAzael Avalos #define HCI_KBD_ILLUMINATION 0x0095 118def6c4e2SAzael Avalos #define HCI_ECO_MODE 0x0097 1195a2813e9SAzael Avalos #define HCI_ACCELEROMETER2 0x00a6 12056e6b353SAzael Avalos #define HCI_SYSTEM_INFO 0xc000 12135d53ceaSAzael Avalos #define SCI_PANEL_POWER_ON 0x010d 122fdb79081SAzael Avalos #define SCI_ILLUMINATION 0x014e 123e26ffe51SAzael Avalos #define SCI_USB_SLEEP_CHARGE 0x0150 124360f0f39SAzael Avalos #define SCI_KBD_ILLUM_STATUS 0x015c 125172ce0a9SAzael Avalos #define SCI_USB_SLEEP_MUSIC 0x015e 12617fe4b3dSAzael Avalos #define SCI_USB_THREE 0x0169 1279d8658acSAzael Avalos #define SCI_TOUCHPAD 0x050e 128bae84195SAzael Avalos #define SCI_KBD_FUNCTION_KEYS 0x0522 129b4f9fe12SLen Brown 130b4f9fe12SLen Brown /* field definitions */ 1315a2813e9SAzael Avalos #define HCI_ACCEL_MASK 0x7fff 13229cd293fSSeth Forshee #define HCI_HOTKEY_DISABLE 0x0b 13329cd293fSSeth Forshee #define HCI_HOTKEY_ENABLE 0x09 134fb42d1f4SAzael Avalos #define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10 135b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_BITS 3 136b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) 137b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS) 138360f0f39SAzael Avalos #define HCI_MISC_SHIFT 0x10 13956e6b353SAzael Avalos #define HCI_SYSTEM_TYPE1 0x10 14056e6b353SAzael Avalos #define HCI_SYSTEM_TYPE2 0x11 141b4f9fe12SLen Brown #define HCI_VIDEO_OUT_LCD 0x1 142b4f9fe12SLen Brown #define HCI_VIDEO_OUT_CRT 0x2 143b4f9fe12SLen Brown #define HCI_VIDEO_OUT_TV 0x4 144b4f9fe12SLen Brown #define HCI_WIRELESS_KILL_SWITCH 0x01 145b4f9fe12SLen Brown #define HCI_WIRELESS_BT_PRESENT 0x0f 146b4f9fe12SLen Brown #define HCI_WIRELESS_BT_ATTACH 0x40 147b4f9fe12SLen Brown #define HCI_WIRELESS_BT_POWER 0x80 14893f8c16dSAzael Avalos #define SCI_KBD_MODE_MASK 0x1f 149360f0f39SAzael Avalos #define SCI_KBD_MODE_FNZ 0x1 150360f0f39SAzael Avalos #define SCI_KBD_MODE_AUTO 0x2 15193f8c16dSAzael Avalos #define SCI_KBD_MODE_ON 0x8 15293f8c16dSAzael Avalos #define SCI_KBD_MODE_OFF 0x10 15393f8c16dSAzael Avalos #define SCI_KBD_TIME_MAX 0x3c001a 154e26ffe51SAzael Avalos #define SCI_USB_CHARGE_MODE_MASK 0xff 155c8c91842SAzael Avalos #define SCI_USB_CHARGE_DISABLED 0x00 156c8c91842SAzael Avalos #define SCI_USB_CHARGE_ALTERNATE 0x09 157c8c91842SAzael Avalos #define SCI_USB_CHARGE_TYPICAL 0x11 158c8c91842SAzael Avalos #define SCI_USB_CHARGE_AUTO 0x21 159182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_MASK 0x7 160182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_OFF 0x1 161182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_ON 0x4 162182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL 0x0200 163bb3fe01fSAzael Avalos #define SCI_USB_CHARGE_RAPID_DSP 0x0300 164b4f9fe12SLen Brown 165135740deSSeth Forshee struct toshiba_acpi_dev { 166135740deSSeth Forshee struct acpi_device *acpi_dev; 167135740deSSeth Forshee const char *method_hci; 168135740deSSeth Forshee struct rfkill *bt_rfk; 169135740deSSeth Forshee struct input_dev *hotkey_dev; 17029cd293fSSeth Forshee struct work_struct hotkey_work; 171135740deSSeth Forshee struct backlight_device *backlight_dev; 172135740deSSeth Forshee struct led_classdev led_dev; 173360f0f39SAzael Avalos struct led_classdev kbd_led; 174def6c4e2SAzael Avalos struct led_classdev eco_led; 17536d03f93SSeth Forshee 176135740deSSeth Forshee int force_fan; 177135740deSSeth Forshee int last_key_event; 178135740deSSeth Forshee int key_event_valid; 17993f8c16dSAzael Avalos int kbd_type; 180360f0f39SAzael Avalos int kbd_mode; 181360f0f39SAzael Avalos int kbd_time; 182182bcaa5SAzael Avalos int usbsc_bat_level; 183c8c91842SAzael Avalos int usbsc_mode_base; 184a2b3471bSAzael Avalos int hotkey_event_type; 185135740deSSeth Forshee 186592b746cSDan Carpenter unsigned int illumination_supported:1; 187592b746cSDan Carpenter unsigned int video_supported:1; 188592b746cSDan Carpenter unsigned int fan_supported:1; 189592b746cSDan Carpenter unsigned int system_event_supported:1; 19029cd293fSSeth Forshee unsigned int ntfy_supported:1; 19129cd293fSSeth Forshee unsigned int info_supported:1; 192121b7b0dSAkio Idehara unsigned int tr_backlight_supported:1; 193360f0f39SAzael Avalos unsigned int kbd_illum_supported:1; 194360f0f39SAzael Avalos unsigned int kbd_led_registered:1; 1959d8658acSAzael Avalos unsigned int touchpad_supported:1; 196def6c4e2SAzael Avalos unsigned int eco_supported:1; 1975a2813e9SAzael Avalos unsigned int accelerometer_supported:1; 198e26ffe51SAzael Avalos unsigned int usb_sleep_charge_supported:1; 199bb3fe01fSAzael Avalos unsigned int usb_rapid_charge_supported:1; 200172ce0a9SAzael Avalos unsigned int usb_sleep_music_supported:1; 201bae84195SAzael Avalos unsigned int kbd_function_keys_supported:1; 20235d53ceaSAzael Avalos unsigned int panel_power_on_supported:1; 20317fe4b3dSAzael Avalos unsigned int usb_three_supported:1; 204360f0f39SAzael Avalos unsigned int sysfs_created:1; 20536d03f93SSeth Forshee 206135740deSSeth Forshee struct mutex mutex; 207135740deSSeth Forshee }; 208135740deSSeth Forshee 20929cd293fSSeth Forshee static struct toshiba_acpi_dev *toshiba_acpi; 21029cd293fSSeth Forshee 211b4f9fe12SLen Brown static const struct acpi_device_id toshiba_device_ids[] = { 212b4f9fe12SLen Brown {"TOS6200", 0}, 21363a9e016SOndrej Zary {"TOS6207", 0}, 214b4f9fe12SLen Brown {"TOS6208", 0}, 215b4f9fe12SLen Brown {"TOS1900", 0}, 216b4f9fe12SLen Brown {"", 0}, 217b4f9fe12SLen Brown }; 218b4f9fe12SLen Brown MODULE_DEVICE_TABLE(acpi, toshiba_device_ids); 219b4f9fe12SLen Brown 220b859f159SGreg Kroah-Hartman static const struct key_entry toshiba_acpi_keymap[] = { 221fec278a1SUnai Uribarri { KE_KEY, 0x9e, { KEY_RFKILL } }, 222384a7cd9SDmitry Torokhov { KE_KEY, 0x101, { KEY_MUTE } }, 223384a7cd9SDmitry Torokhov { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 224384a7cd9SDmitry Torokhov { KE_KEY, 0x103, { KEY_ZOOMIN } }, 225408a5d13SAzael Avalos { KE_KEY, 0x10f, { KEY_TAB } }, 226af502837SAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 227af502837SAzael Avalos { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 228384a7cd9SDmitry Torokhov { KE_KEY, 0x13b, { KEY_COFFEE } }, 229384a7cd9SDmitry Torokhov { KE_KEY, 0x13c, { KEY_BATTERY } }, 230384a7cd9SDmitry Torokhov { KE_KEY, 0x13d, { KEY_SLEEP } }, 231384a7cd9SDmitry Torokhov { KE_KEY, 0x13e, { KEY_SUSPEND } }, 232384a7cd9SDmitry Torokhov { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } }, 233384a7cd9SDmitry Torokhov { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } }, 234384a7cd9SDmitry Torokhov { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } }, 235384a7cd9SDmitry Torokhov { KE_KEY, 0x142, { KEY_WLAN } }, 236af502837SAzael Avalos { KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } }, 237a49010f5SJon Dowland { KE_KEY, 0x17f, { KEY_FN } }, 238384a7cd9SDmitry Torokhov { KE_KEY, 0xb05, { KEY_PROG2 } }, 239384a7cd9SDmitry Torokhov { KE_KEY, 0xb06, { KEY_WWW } }, 240384a7cd9SDmitry Torokhov { KE_KEY, 0xb07, { KEY_MAIL } }, 241384a7cd9SDmitry Torokhov { KE_KEY, 0xb30, { KEY_STOP } }, 242384a7cd9SDmitry Torokhov { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } }, 243384a7cd9SDmitry Torokhov { KE_KEY, 0xb32, { KEY_NEXTSONG } }, 244384a7cd9SDmitry Torokhov { KE_KEY, 0xb33, { KEY_PLAYPAUSE } }, 245384a7cd9SDmitry Torokhov { KE_KEY, 0xb5a, { KEY_MEDIA } }, 246408a5d13SAzael Avalos { KE_IGNORE, 0x1430, { KEY_RESERVED } }, /* Wake from sleep */ 247408a5d13SAzael Avalos { KE_IGNORE, 0x1501, { KEY_RESERVED } }, /* Output changed */ 248408a5d13SAzael Avalos { KE_IGNORE, 0x1502, { KEY_RESERVED } }, /* HDMI plugged/unplugged */ 249408a5d13SAzael Avalos { KE_IGNORE, 0x1ABE, { KEY_RESERVED } }, /* Protection level set */ 250408a5d13SAzael Avalos { KE_IGNORE, 0x1ABF, { KEY_RESERVED } }, /* Protection level off */ 251384a7cd9SDmitry Torokhov { KE_END, 0 }, 2526335e4d5SMatthew Garrett }; 2536335e4d5SMatthew Garrett 254fe808bfbSTakashi Iwai static const struct key_entry toshiba_acpi_alt_keymap[] = { 255fe808bfbSTakashi Iwai { KE_KEY, 0x157, { KEY_MUTE } }, 256fe808bfbSTakashi Iwai { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 257fe808bfbSTakashi Iwai { KE_KEY, 0x103, { KEY_ZOOMIN } }, 258e6efad7fSAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 259fe808bfbSTakashi Iwai { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 260fe808bfbSTakashi Iwai { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } }, 261fe808bfbSTakashi Iwai { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } }, 262fe808bfbSTakashi Iwai { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } }, 263fe808bfbSTakashi Iwai { KE_KEY, 0x158, { KEY_WLAN } }, 264fe808bfbSTakashi Iwai { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } }, 265fe808bfbSTakashi Iwai { KE_END, 0 }, 266fe808bfbSTakashi Iwai }; 267fe808bfbSTakashi Iwai 268e0769fe6SDarren Hart /* 269*358d6a2cSHans de Goede * List of models which have a broken acpi-video backlight interface and thus 270*358d6a2cSHans de Goede * need to use the toshiba (vendor) interface instead. 271*358d6a2cSHans de Goede */ 272*358d6a2cSHans de Goede static const struct dmi_system_id toshiba_vendor_backlight_dmi[] = { 273*358d6a2cSHans de Goede {} 274*358d6a2cSHans de Goede }; 275*358d6a2cSHans de Goede 276*358d6a2cSHans de Goede /* 277e0769fe6SDarren Hart * Utility 278b4f9fe12SLen Brown */ 279b4f9fe12SLen Brown 280b5163992SAzael Avalos static inline void _set_bit(u32 *word, u32 mask, int value) 281b4f9fe12SLen Brown { 282b4f9fe12SLen Brown *word = (*word & ~mask) | (mask * value); 283b4f9fe12SLen Brown } 284b4f9fe12SLen Brown 285e0769fe6SDarren Hart /* 286e0769fe6SDarren Hart * ACPI interface wrappers 287b4f9fe12SLen Brown */ 288b4f9fe12SLen Brown 289b4f9fe12SLen Brown static int write_acpi_int(const char *methodName, int val) 290b4f9fe12SLen Brown { 291b4f9fe12SLen Brown acpi_status status; 292b4f9fe12SLen Brown 293619400daSZhang Rui status = acpi_execute_simple_method(NULL, (char *)methodName, val); 29432bcd5cbSSeth Forshee return (status == AE_OK) ? 0 : -EIO; 295b4f9fe12SLen Brown } 296b4f9fe12SLen Brown 297e0769fe6SDarren Hart /* 298e0769fe6SDarren Hart * Perform a raw configuration call. Here we don't care about input or output 299258c5903SAzael Avalos * buffer format. 300b4f9fe12SLen Brown */ 301258c5903SAzael Avalos static acpi_status tci_raw(struct toshiba_acpi_dev *dev, 302258c5903SAzael Avalos const u32 in[TCI_WORDS], u32 out[TCI_WORDS]) 303b4f9fe12SLen Brown { 304b4f9fe12SLen Brown struct acpi_object_list params; 305258c5903SAzael Avalos union acpi_object in_objs[TCI_WORDS]; 306b4f9fe12SLen Brown struct acpi_buffer results; 307258c5903SAzael Avalos union acpi_object out_objs[TCI_WORDS + 1]; 308b4f9fe12SLen Brown acpi_status status; 309b4f9fe12SLen Brown int i; 310b4f9fe12SLen Brown 311258c5903SAzael Avalos params.count = TCI_WORDS; 312b4f9fe12SLen Brown params.pointer = in_objs; 313258c5903SAzael Avalos for (i = 0; i < TCI_WORDS; ++i) { 314b4f9fe12SLen Brown in_objs[i].type = ACPI_TYPE_INTEGER; 315b4f9fe12SLen Brown in_objs[i].integer.value = in[i]; 316b4f9fe12SLen Brown } 317b4f9fe12SLen Brown 318b4f9fe12SLen Brown results.length = sizeof(out_objs); 319b4f9fe12SLen Brown results.pointer = out_objs; 320b4f9fe12SLen Brown 3216e02cc7eSSeth Forshee status = acpi_evaluate_object(dev->acpi_dev->handle, 3226e02cc7eSSeth Forshee (char *)dev->method_hci, ¶ms, 323b4f9fe12SLen Brown &results); 324258c5903SAzael Avalos if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) { 325b5163992SAzael Avalos for (i = 0; i < out_objs->package.count; ++i) 326b4f9fe12SLen Brown out[i] = out_objs->package.elements[i].integer.value; 327b4f9fe12SLen Brown } 328b4f9fe12SLen Brown 329b4f9fe12SLen Brown return status; 330b4f9fe12SLen Brown } 331b4f9fe12SLen Brown 332e0769fe6SDarren Hart /* 333e0769fe6SDarren Hart * Common hci tasks (get or set one or two value) 334b4f9fe12SLen Brown * 335b4f9fe12SLen Brown * In addition to the ACPI status, the HCI system returns a result which 336b4f9fe12SLen Brown * may be useful (such as "not supported"). 337b4f9fe12SLen Brown */ 338b4f9fe12SLen Brown 339893f3f62SAzael Avalos static u32 hci_write1(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 340b4f9fe12SLen Brown { 341258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 }; 342258c5903SAzael Avalos u32 out[TCI_WORDS]; 343258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 344893f3f62SAzael Avalos 345893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 346b4f9fe12SLen Brown } 347b4f9fe12SLen Brown 348893f3f62SAzael Avalos static u32 hci_read1(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 349b4f9fe12SLen Brown { 350258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 }; 351258c5903SAzael Avalos u32 out[TCI_WORDS]; 352258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 353b5163992SAzael Avalos 354893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 355893f3f62SAzael Avalos return TOS_FAILURE; 356893f3f62SAzael Avalos 357b4f9fe12SLen Brown *out1 = out[2]; 358893f3f62SAzael Avalos 359893f3f62SAzael Avalos return out[0]; 360b4f9fe12SLen Brown } 361b4f9fe12SLen Brown 362893f3f62SAzael Avalos static u32 hci_write2(struct toshiba_acpi_dev *dev, u32 reg, u32 in1, u32 in2) 363b4f9fe12SLen Brown { 364258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, reg, in1, in2, 0, 0 }; 365258c5903SAzael Avalos u32 out[TCI_WORDS]; 366258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 367893f3f62SAzael Avalos 368893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 369b4f9fe12SLen Brown } 370b4f9fe12SLen Brown 371b5163992SAzael Avalos static u32 hci_read2(struct toshiba_acpi_dev *dev, 372b5163992SAzael Avalos u32 reg, u32 *out1, u32 *out2) 373b4f9fe12SLen Brown { 374258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 }; 375258c5903SAzael Avalos u32 out[TCI_WORDS]; 376258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 377b5163992SAzael Avalos 378893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 379893f3f62SAzael Avalos return TOS_FAILURE; 380893f3f62SAzael Avalos 381b4f9fe12SLen Brown *out1 = out[2]; 382b4f9fe12SLen Brown *out2 = out[3]; 383893f3f62SAzael Avalos 384893f3f62SAzael Avalos return out[0]; 385b4f9fe12SLen Brown } 386b4f9fe12SLen Brown 387e0769fe6SDarren Hart /* 388e0769fe6SDarren Hart * Common sci tasks 38984a6273fSAzael Avalos */ 39084a6273fSAzael Avalos 39184a6273fSAzael Avalos static int sci_open(struct toshiba_acpi_dev *dev) 39284a6273fSAzael Avalos { 393258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 }; 394258c5903SAzael Avalos u32 out[TCI_WORDS]; 39584a6273fSAzael Avalos acpi_status status; 39684a6273fSAzael Avalos 397258c5903SAzael Avalos status = tci_raw(dev, in, out); 3981864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 39984a6273fSAzael Avalos pr_err("ACPI call to open SCI failed\n"); 40084a6273fSAzael Avalos return 0; 40184a6273fSAzael Avalos } 40284a6273fSAzael Avalos 4031864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) { 40484a6273fSAzael Avalos return 1; 4051864bbc2SAzael Avalos } else if (out[0] == TOS_ALREADY_OPEN) { 40684a6273fSAzael Avalos pr_info("Toshiba SCI already opened\n"); 40784a6273fSAzael Avalos return 1; 408fa465739SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 409e0769fe6SDarren Hart /* 410e0769fe6SDarren Hart * Some BIOSes do not have the SCI open/close functions 411fa465739SAzael Avalos * implemented and return 0x8000 (Not Supported), failing to 412fa465739SAzael Avalos * register some supported features. 413fa465739SAzael Avalos * 414fa465739SAzael Avalos * Simply return 1 if we hit those affected laptops to make the 415fa465739SAzael Avalos * supported features work. 416fa465739SAzael Avalos * 417fa465739SAzael Avalos * In the case that some laptops really do not support the SCI, 418fa465739SAzael Avalos * all the SCI dependent functions check for TOS_NOT_SUPPORTED, 419fa465739SAzael Avalos * and thus, not registering support for the queried feature. 420fa465739SAzael Avalos */ 421fa465739SAzael Avalos return 1; 4221864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_PRESENT) { 42384a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 42484a6273fSAzael Avalos } 42584a6273fSAzael Avalos 42684a6273fSAzael Avalos return 0; 42784a6273fSAzael Avalos } 42884a6273fSAzael Avalos 42984a6273fSAzael Avalos static void sci_close(struct toshiba_acpi_dev *dev) 43084a6273fSAzael Avalos { 431258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 }; 432258c5903SAzael Avalos u32 out[TCI_WORDS]; 43384a6273fSAzael Avalos acpi_status status; 43484a6273fSAzael Avalos 435258c5903SAzael Avalos status = tci_raw(dev, in, out); 4361864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 43784a6273fSAzael Avalos pr_err("ACPI call to close SCI failed\n"); 43884a6273fSAzael Avalos return; 43984a6273fSAzael Avalos } 44084a6273fSAzael Avalos 4411864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) 44284a6273fSAzael Avalos return; 4431864bbc2SAzael Avalos else if (out[0] == TOS_NOT_OPENED) 44484a6273fSAzael Avalos pr_info("Toshiba SCI not opened\n"); 4451864bbc2SAzael Avalos else if (out[0] == TOS_NOT_PRESENT) 44684a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 44784a6273fSAzael Avalos } 44884a6273fSAzael Avalos 449893f3f62SAzael Avalos static u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 45084a6273fSAzael Avalos { 451258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 }; 452258c5903SAzael Avalos u32 out[TCI_WORDS]; 453258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 454b5163992SAzael Avalos 455893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 456893f3f62SAzael Avalos return TOS_FAILURE; 457893f3f62SAzael Avalos 45884a6273fSAzael Avalos *out1 = out[2]; 459893f3f62SAzael Avalos 460893f3f62SAzael Avalos return out[0]; 46184a6273fSAzael Avalos } 46284a6273fSAzael Avalos 463893f3f62SAzael Avalos static u32 sci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 46484a6273fSAzael Avalos { 465258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 }; 466258c5903SAzael Avalos u32 out[TCI_WORDS]; 467258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 468893f3f62SAzael Avalos 469893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 47084a6273fSAzael Avalos } 47184a6273fSAzael Avalos 4726c3f6e6cSPierre Ducroquet /* Illumination support */ 473135740deSSeth Forshee static int toshiba_illumination_available(struct toshiba_acpi_dev *dev) 4746c3f6e6cSPierre Ducroquet { 475258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 }; 476258c5903SAzael Avalos u32 out[TCI_WORDS]; 4776c3f6e6cSPierre Ducroquet acpi_status status; 4786c3f6e6cSPierre Ducroquet 479fdb79081SAzael Avalos if (!sci_open(dev)) 480fdb79081SAzael Avalos return 0; 481fdb79081SAzael Avalos 482258c5903SAzael Avalos status = tci_raw(dev, in, out); 483fdb79081SAzael Avalos sci_close(dev); 4841864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 485fdb79081SAzael Avalos pr_err("ACPI call to query Illumination support failed\n"); 486fdb79081SAzael Avalos return 0; 4871864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 4887e33460dSJoe Perches pr_info("Illumination device not available\n"); 4896c3f6e6cSPierre Ducroquet return 0; 4906c3f6e6cSPierre Ducroquet } 491fdb79081SAzael Avalos 4926c3f6e6cSPierre Ducroquet return 1; 4936c3f6e6cSPierre Ducroquet } 4946c3f6e6cSPierre Ducroquet 4956c3f6e6cSPierre Ducroquet static void toshiba_illumination_set(struct led_classdev *cdev, 4966c3f6e6cSPierre Ducroquet enum led_brightness brightness) 4976c3f6e6cSPierre Ducroquet { 498135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 499135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 500fdb79081SAzael Avalos u32 state, result; 5016c3f6e6cSPierre Ducroquet 5026c3f6e6cSPierre Ducroquet /* First request : initialize communication. */ 503fdb79081SAzael Avalos if (!sci_open(dev)) 5046c3f6e6cSPierre Ducroquet return; 5056c3f6e6cSPierre Ducroquet 506fdb79081SAzael Avalos /* Switch the illumination on/off */ 507fdb79081SAzael Avalos state = brightness ? 1 : 0; 508893f3f62SAzael Avalos result = sci_write(dev, SCI_ILLUMINATION, state); 509fdb79081SAzael Avalos sci_close(dev); 510893f3f62SAzael Avalos if (result == TOS_FAILURE) { 511fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 512fdb79081SAzael Avalos return; 5131864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 514fdb79081SAzael Avalos pr_info("Illumination not supported\n"); 5156c3f6e6cSPierre Ducroquet return; 5166c3f6e6cSPierre Ducroquet } 5176c3f6e6cSPierre Ducroquet } 5186c3f6e6cSPierre Ducroquet 5196c3f6e6cSPierre Ducroquet static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) 5206c3f6e6cSPierre Ducroquet { 521135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev, 522135740deSSeth Forshee struct toshiba_acpi_dev, led_dev); 523fdb79081SAzael Avalos u32 state, result; 5246c3f6e6cSPierre Ducroquet 5256c3f6e6cSPierre Ducroquet /* First request : initialize communication. */ 526fdb79081SAzael Avalos if (!sci_open(dev)) 5276c3f6e6cSPierre Ducroquet return LED_OFF; 5286c3f6e6cSPierre Ducroquet 5296c3f6e6cSPierre Ducroquet /* Check the illumination */ 530893f3f62SAzael Avalos result = sci_read(dev, SCI_ILLUMINATION, &state); 531fdb79081SAzael Avalos sci_close(dev); 532893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 533fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n"); 534fdb79081SAzael Avalos return LED_OFF; 5351864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 536fdb79081SAzael Avalos pr_info("Illumination not supported\n"); 5376c3f6e6cSPierre Ducroquet return LED_OFF; 5386c3f6e6cSPierre Ducroquet } 5396c3f6e6cSPierre Ducroquet 540fdb79081SAzael Avalos return state ? LED_FULL : LED_OFF; 5416c3f6e6cSPierre Ducroquet } 5426c3f6e6cSPierre Ducroquet 543360f0f39SAzael Avalos /* KBD Illumination */ 54493f8c16dSAzael Avalos static int toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev) 54593f8c16dSAzael Avalos { 546258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 }; 547258c5903SAzael Avalos u32 out[TCI_WORDS]; 54893f8c16dSAzael Avalos acpi_status status; 54993f8c16dSAzael Avalos 55093f8c16dSAzael Avalos if (!sci_open(dev)) 55193f8c16dSAzael Avalos return 0; 55293f8c16dSAzael Avalos 553258c5903SAzael Avalos status = tci_raw(dev, in, out); 55493f8c16dSAzael Avalos sci_close(dev); 5551864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 55693f8c16dSAzael Avalos pr_err("ACPI call to query kbd illumination support failed\n"); 55793f8c16dSAzael Avalos return 0; 5581864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 55993f8c16dSAzael Avalos pr_info("Keyboard illumination not available\n"); 56093f8c16dSAzael Avalos return 0; 56193f8c16dSAzael Avalos } 56293f8c16dSAzael Avalos 563e0769fe6SDarren Hart /* 564e0769fe6SDarren Hart * Check for keyboard backlight timeout max value, 56593f8c16dSAzael Avalos * previous kbd backlight implementation set this to 56693f8c16dSAzael Avalos * 0x3c0003, and now the new implementation set this 567e0769fe6SDarren Hart * to 0x3c001a, use this to distinguish between them. 56893f8c16dSAzael Avalos */ 56993f8c16dSAzael Avalos if (out[3] == SCI_KBD_TIME_MAX) 57093f8c16dSAzael Avalos dev->kbd_type = 2; 57193f8c16dSAzael Avalos else 57293f8c16dSAzael Avalos dev->kbd_type = 1; 57393f8c16dSAzael Avalos /* Get the current keyboard backlight mode */ 57493f8c16dSAzael Avalos dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK; 57593f8c16dSAzael Avalos /* Get the current time (1-60 seconds) */ 57693f8c16dSAzael Avalos dev->kbd_time = out[2] >> HCI_MISC_SHIFT; 57793f8c16dSAzael Avalos 57893f8c16dSAzael Avalos return 1; 57993f8c16dSAzael Avalos } 58093f8c16dSAzael Avalos 581360f0f39SAzael Avalos static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time) 582360f0f39SAzael Avalos { 583360f0f39SAzael Avalos u32 result; 584360f0f39SAzael Avalos 585360f0f39SAzael Avalos if (!sci_open(dev)) 586360f0f39SAzael Avalos return -EIO; 587360f0f39SAzael Avalos 588893f3f62SAzael Avalos result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time); 589360f0f39SAzael Avalos sci_close(dev); 590893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 591360f0f39SAzael Avalos pr_err("ACPI call to set KBD backlight status failed\n"); 592360f0f39SAzael Avalos return -EIO; 5931864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 594360f0f39SAzael Avalos pr_info("Keyboard backlight status not supported\n"); 595360f0f39SAzael Avalos return -ENODEV; 596360f0f39SAzael Avalos } 597360f0f39SAzael Avalos 598360f0f39SAzael Avalos return 0; 599360f0f39SAzael Avalos } 600360f0f39SAzael Avalos 601360f0f39SAzael Avalos static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time) 602360f0f39SAzael Avalos { 603360f0f39SAzael Avalos u32 result; 604360f0f39SAzael Avalos 605360f0f39SAzael Avalos if (!sci_open(dev)) 606360f0f39SAzael Avalos return -EIO; 607360f0f39SAzael Avalos 608893f3f62SAzael Avalos result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time); 609360f0f39SAzael Avalos sci_close(dev); 610893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 611360f0f39SAzael Avalos pr_err("ACPI call to get KBD backlight status failed\n"); 612360f0f39SAzael Avalos return -EIO; 6131864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 614360f0f39SAzael Avalos pr_info("Keyboard backlight status not supported\n"); 615360f0f39SAzael Avalos return -ENODEV; 616360f0f39SAzael Avalos } 617360f0f39SAzael Avalos 618360f0f39SAzael Avalos return 0; 619360f0f39SAzael Avalos } 620360f0f39SAzael Avalos 621360f0f39SAzael Avalos static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev) 622360f0f39SAzael Avalos { 623360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 624360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 625360f0f39SAzael Avalos u32 state, result; 626360f0f39SAzael Avalos 627360f0f39SAzael Avalos /* Check the keyboard backlight state */ 628893f3f62SAzael Avalos result = hci_read1(dev, HCI_KBD_ILLUMINATION, &state); 629893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 630360f0f39SAzael Avalos pr_err("ACPI call to get the keyboard backlight failed\n"); 631360f0f39SAzael Avalos return LED_OFF; 6321864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 633360f0f39SAzael Avalos pr_info("Keyboard backlight not supported\n"); 634360f0f39SAzael Avalos return LED_OFF; 635360f0f39SAzael Avalos } 636360f0f39SAzael Avalos 637360f0f39SAzael Avalos return state ? LED_FULL : LED_OFF; 638360f0f39SAzael Avalos } 639360f0f39SAzael Avalos 640360f0f39SAzael Avalos static void toshiba_kbd_backlight_set(struct led_classdev *cdev, 641360f0f39SAzael Avalos enum led_brightness brightness) 642360f0f39SAzael Avalos { 643360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 644360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 645360f0f39SAzael Avalos u32 state, result; 646360f0f39SAzael Avalos 647360f0f39SAzael Avalos /* Set the keyboard backlight state */ 648360f0f39SAzael Avalos state = brightness ? 1 : 0; 649893f3f62SAzael Avalos result = hci_write1(dev, HCI_KBD_ILLUMINATION, state); 650893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 651360f0f39SAzael Avalos pr_err("ACPI call to set KBD Illumination mode failed\n"); 652360f0f39SAzael Avalos return; 6531864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 654360f0f39SAzael Avalos pr_info("Keyboard backlight not supported\n"); 655360f0f39SAzael Avalos return; 656360f0f39SAzael Avalos } 657360f0f39SAzael Avalos } 658360f0f39SAzael Avalos 6599d8658acSAzael Avalos /* TouchPad support */ 6609d8658acSAzael Avalos static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state) 6619d8658acSAzael Avalos { 6629d8658acSAzael Avalos u32 result; 6639d8658acSAzael Avalos 6649d8658acSAzael Avalos if (!sci_open(dev)) 6659d8658acSAzael Avalos return -EIO; 6669d8658acSAzael Avalos 667893f3f62SAzael Avalos result = sci_write(dev, SCI_TOUCHPAD, state); 6689d8658acSAzael Avalos sci_close(dev); 669893f3f62SAzael Avalos if (result == TOS_FAILURE) { 6709d8658acSAzael Avalos pr_err("ACPI call to set the touchpad failed\n"); 6719d8658acSAzael Avalos return -EIO; 6721864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 6739d8658acSAzael Avalos return -ENODEV; 6749d8658acSAzael Avalos } 6759d8658acSAzael Avalos 6769d8658acSAzael Avalos return 0; 6779d8658acSAzael Avalos } 6789d8658acSAzael Avalos 6799d8658acSAzael Avalos static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) 6809d8658acSAzael Avalos { 6819d8658acSAzael Avalos u32 result; 6829d8658acSAzael Avalos 6839d8658acSAzael Avalos if (!sci_open(dev)) 6849d8658acSAzael Avalos return -EIO; 6859d8658acSAzael Avalos 686893f3f62SAzael Avalos result = sci_read(dev, SCI_TOUCHPAD, state); 6879d8658acSAzael Avalos sci_close(dev); 688893f3f62SAzael Avalos if (result == TOS_FAILURE) { 6899d8658acSAzael Avalos pr_err("ACPI call to query the touchpad failed\n"); 6909d8658acSAzael Avalos return -EIO; 6911864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 6929d8658acSAzael Avalos return -ENODEV; 6939d8658acSAzael Avalos } 6949d8658acSAzael Avalos 6959d8658acSAzael Avalos return 0; 6969d8658acSAzael Avalos } 6979d8658acSAzael Avalos 698def6c4e2SAzael Avalos /* Eco Mode support */ 699def6c4e2SAzael Avalos static int toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) 700def6c4e2SAzael Avalos { 701def6c4e2SAzael Avalos acpi_status status; 70298fc4ec6SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 }; 703258c5903SAzael Avalos u32 out[TCI_WORDS]; 704def6c4e2SAzael Avalos 705258c5903SAzael Avalos status = tci_raw(dev, in, out); 70698fc4ec6SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 70798fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 70898fc4ec6SAzael Avalos } else if (out[0] == TOS_NOT_INSTALLED) { 70998fc4ec6SAzael Avalos pr_info("ECO led not installed"); 71098fc4ec6SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 711e0769fe6SDarren Hart /* 712e0769fe6SDarren Hart * If we receive 0x8300 (Input Data Error), it means that the 71398fc4ec6SAzael Avalos * LED device is present, but that we just screwed the input 71498fc4ec6SAzael Avalos * parameters. 71598fc4ec6SAzael Avalos * 71698fc4ec6SAzael Avalos * Let's query the status of the LED to see if we really have a 71798fc4ec6SAzael Avalos * success response, indicating the actual presense of the LED, 71898fc4ec6SAzael Avalos * bail out otherwise. 71998fc4ec6SAzael Avalos */ 72098fc4ec6SAzael Avalos in[3] = 1; 72198fc4ec6SAzael Avalos status = tci_raw(dev, in, out); 72298fc4ec6SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) 72398fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 72498fc4ec6SAzael Avalos else if (out[0] == TOS_SUCCESS) 72598fc4ec6SAzael Avalos return 1; 726def6c4e2SAzael Avalos } 727def6c4e2SAzael Avalos 72898fc4ec6SAzael Avalos return 0; 729def6c4e2SAzael Avalos } 730def6c4e2SAzael Avalos 731b5163992SAzael Avalos static enum led_brightness 732b5163992SAzael Avalos toshiba_eco_mode_get_status(struct led_classdev *cdev) 733def6c4e2SAzael Avalos { 734def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 735def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 736258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 }; 737258c5903SAzael Avalos u32 out[TCI_WORDS]; 738def6c4e2SAzael Avalos acpi_status status; 739def6c4e2SAzael Avalos 740258c5903SAzael Avalos status = tci_raw(dev, in, out); 7411864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 742def6c4e2SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 743def6c4e2SAzael Avalos return LED_OFF; 744def6c4e2SAzael Avalos } 745def6c4e2SAzael Avalos 746def6c4e2SAzael Avalos return out[2] ? LED_FULL : LED_OFF; 747def6c4e2SAzael Avalos } 748def6c4e2SAzael Avalos 749def6c4e2SAzael Avalos static void toshiba_eco_mode_set_status(struct led_classdev *cdev, 750def6c4e2SAzael Avalos enum led_brightness brightness) 751def6c4e2SAzael Avalos { 752def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 753def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 754258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 }; 755258c5903SAzael Avalos u32 out[TCI_WORDS]; 756def6c4e2SAzael Avalos acpi_status status; 757def6c4e2SAzael Avalos 758def6c4e2SAzael Avalos /* Switch the Eco Mode led on/off */ 759def6c4e2SAzael Avalos in[2] = (brightness) ? 1 : 0; 760258c5903SAzael Avalos status = tci_raw(dev, in, out); 7611864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 762def6c4e2SAzael Avalos pr_err("ACPI call to set ECO led failed\n"); 763def6c4e2SAzael Avalos return; 764def6c4e2SAzael Avalos } 765def6c4e2SAzael Avalos } 766def6c4e2SAzael Avalos 7675a2813e9SAzael Avalos /* Accelerometer support */ 7685a2813e9SAzael Avalos static int toshiba_accelerometer_supported(struct toshiba_acpi_dev *dev) 7695a2813e9SAzael Avalos { 770258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 }; 771258c5903SAzael Avalos u32 out[TCI_WORDS]; 7725a2813e9SAzael Avalos acpi_status status; 7735a2813e9SAzael Avalos 774e0769fe6SDarren Hart /* 775e0769fe6SDarren Hart * Check if the accelerometer call exists, 7765a2813e9SAzael Avalos * this call also serves as initialization 7775a2813e9SAzael Avalos */ 778258c5903SAzael Avalos status = tci_raw(dev, in, out); 7791864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 7805a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 7815a2813e9SAzael Avalos return -EIO; 7821864bbc2SAzael Avalos } else if (out[0] == TOS_DATA_NOT_AVAILABLE || 7831864bbc2SAzael Avalos out[0] == TOS_NOT_INITIALIZED) { 7845a2813e9SAzael Avalos pr_err("Accelerometer not initialized\n"); 7855a2813e9SAzael Avalos return -EIO; 7861864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 7875a2813e9SAzael Avalos pr_info("Accelerometer not supported\n"); 7885a2813e9SAzael Avalos return -ENODEV; 7895a2813e9SAzael Avalos } 7905a2813e9SAzael Avalos 7915a2813e9SAzael Avalos return 0; 7925a2813e9SAzael Avalos } 7935a2813e9SAzael Avalos 7945a2813e9SAzael Avalos static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, 7955a2813e9SAzael Avalos u32 *xy, u32 *z) 7965a2813e9SAzael Avalos { 797258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 }; 798258c5903SAzael Avalos u32 out[TCI_WORDS]; 7995a2813e9SAzael Avalos acpi_status status; 8005a2813e9SAzael Avalos 8015a2813e9SAzael Avalos /* Check the Accelerometer status */ 802258c5903SAzael Avalos status = tci_raw(dev, in, out); 8031864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 8045a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 8055a2813e9SAzael Avalos return -EIO; 8065a2813e9SAzael Avalos } 8075a2813e9SAzael Avalos 8085a2813e9SAzael Avalos *xy = out[2]; 8095a2813e9SAzael Avalos *z = out[4]; 8105a2813e9SAzael Avalos 8115a2813e9SAzael Avalos return 0; 8125a2813e9SAzael Avalos } 8135a2813e9SAzael Avalos 814e26ffe51SAzael Avalos /* Sleep (Charge and Music) utilities support */ 815c8c91842SAzael Avalos static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev) 816c8c91842SAzael Avalos { 817c8c91842SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 818c8c91842SAzael Avalos u32 out[TCI_WORDS]; 819c8c91842SAzael Avalos acpi_status status; 820c8c91842SAzael Avalos 821c8c91842SAzael Avalos /* Set the feature to "not supported" in case of error */ 822c8c91842SAzael Avalos dev->usb_sleep_charge_supported = 0; 823c8c91842SAzael Avalos 824c8c91842SAzael Avalos if (!sci_open(dev)) 825c8c91842SAzael Avalos return; 826c8c91842SAzael Avalos 827c8c91842SAzael Avalos status = tci_raw(dev, in, out); 828c8c91842SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 829c8c91842SAzael Avalos pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); 830c8c91842SAzael Avalos sci_close(dev); 831c8c91842SAzael Avalos return; 832c8c91842SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 833c8c91842SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 834c8c91842SAzael Avalos sci_close(dev); 835c8c91842SAzael Avalos return; 836c8c91842SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 837c8c91842SAzael Avalos dev->usbsc_mode_base = out[4]; 838c8c91842SAzael Avalos } 839c8c91842SAzael Avalos 840c8c91842SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 841c8c91842SAzael Avalos status = tci_raw(dev, in, out); 842c8c91842SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 843c8c91842SAzael Avalos pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); 844c8c91842SAzael Avalos sci_close(dev); 845c8c91842SAzael Avalos return; 846c8c91842SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 847c8c91842SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 848c8c91842SAzael Avalos sci_close(dev); 849c8c91842SAzael Avalos return; 850c8c91842SAzael Avalos } else if (out[0] == TOS_SUCCESS) { 851c8c91842SAzael Avalos dev->usbsc_bat_level = out[2]; 852c8c91842SAzael Avalos /* 853c8c91842SAzael Avalos * If we reach this point, it means that the laptop has support 854c8c91842SAzael Avalos * for this feature and all values are initialized. 855c8c91842SAzael Avalos * Set it as supported. 856c8c91842SAzael Avalos */ 857c8c91842SAzael Avalos dev->usb_sleep_charge_supported = 1; 858c8c91842SAzael Avalos } 859c8c91842SAzael Avalos 860c8c91842SAzael Avalos sci_close(dev); 861c8c91842SAzael Avalos } 862c8c91842SAzael Avalos 863e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, 864e26ffe51SAzael Avalos u32 *mode) 865e26ffe51SAzael Avalos { 866e26ffe51SAzael Avalos u32 result; 867e26ffe51SAzael Avalos 868e26ffe51SAzael Avalos if (!sci_open(dev)) 869e26ffe51SAzael Avalos return -EIO; 870e26ffe51SAzael Avalos 871e26ffe51SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode); 872e26ffe51SAzael Avalos sci_close(dev); 873e26ffe51SAzael Avalos if (result == TOS_FAILURE) { 874e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 875e26ffe51SAzael Avalos return -EIO; 876e26ffe51SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 877e26ffe51SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 878e26ffe51SAzael Avalos return -ENODEV; 879e26ffe51SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 880e26ffe51SAzael Avalos return -EIO; 881e26ffe51SAzael Avalos } 882e26ffe51SAzael Avalos 883e26ffe51SAzael Avalos return 0; 884e26ffe51SAzael Avalos } 885e26ffe51SAzael Avalos 886e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev, 887e26ffe51SAzael Avalos u32 mode) 888e26ffe51SAzael Avalos { 889e26ffe51SAzael Avalos u32 result; 890e26ffe51SAzael Avalos 891e26ffe51SAzael Avalos if (!sci_open(dev)) 892e26ffe51SAzael Avalos return -EIO; 893e26ffe51SAzael Avalos 894e26ffe51SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode); 895e26ffe51SAzael Avalos sci_close(dev); 896e26ffe51SAzael Avalos if (result == TOS_FAILURE) { 897e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 898e26ffe51SAzael Avalos return -EIO; 899e26ffe51SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 900e26ffe51SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 901e26ffe51SAzael Avalos return -ENODEV; 902e26ffe51SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 903e26ffe51SAzael Avalos return -EIO; 904e26ffe51SAzael Avalos } 905e26ffe51SAzael Avalos 906e26ffe51SAzael Avalos return 0; 907e26ffe51SAzael Avalos } 908e26ffe51SAzael Avalos 909182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev, 910182bcaa5SAzael Avalos u32 *mode) 911182bcaa5SAzael Avalos { 912182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 913182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 914182bcaa5SAzael Avalos acpi_status status; 915182bcaa5SAzael Avalos 916182bcaa5SAzael Avalos if (!sci_open(dev)) 917182bcaa5SAzael Avalos return -EIO; 918182bcaa5SAzael Avalos 919182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 920182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 921182bcaa5SAzael Avalos sci_close(dev); 922182bcaa5SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 923182bcaa5SAzael Avalos pr_err("ACPI call to get USB S&C battery level failed\n"); 924182bcaa5SAzael Avalos return -EIO; 925182bcaa5SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 926182bcaa5SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 927182bcaa5SAzael Avalos return -ENODEV; 928182bcaa5SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 929182bcaa5SAzael Avalos return -EIO; 930182bcaa5SAzael Avalos } 931182bcaa5SAzael Avalos 932182bcaa5SAzael Avalos *mode = out[2]; 933182bcaa5SAzael Avalos 934182bcaa5SAzael Avalos return 0; 935182bcaa5SAzael Avalos } 936182bcaa5SAzael Avalos 937182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, 938182bcaa5SAzael Avalos u32 mode) 939182bcaa5SAzael Avalos { 940182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 941182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 942182bcaa5SAzael Avalos acpi_status status; 943182bcaa5SAzael Avalos 944182bcaa5SAzael Avalos if (!sci_open(dev)) 945182bcaa5SAzael Avalos return -EIO; 946182bcaa5SAzael Avalos 947182bcaa5SAzael Avalos in[2] = mode; 948182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 949182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 950182bcaa5SAzael Avalos sci_close(dev); 951182bcaa5SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 952182bcaa5SAzael Avalos pr_err("ACPI call to set USB S&C battery level failed\n"); 953182bcaa5SAzael Avalos return -EIO; 954182bcaa5SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 955182bcaa5SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 956182bcaa5SAzael Avalos return -ENODEV; 957182bcaa5SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 958182bcaa5SAzael Avalos return -EIO; 959182bcaa5SAzael Avalos } 960182bcaa5SAzael Avalos 961182bcaa5SAzael Avalos return 0; 962182bcaa5SAzael Avalos } 963182bcaa5SAzael Avalos 964bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, 965bb3fe01fSAzael Avalos u32 *state) 966bb3fe01fSAzael Avalos { 967bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 968bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 969bb3fe01fSAzael Avalos acpi_status status; 970bb3fe01fSAzael Avalos 971bb3fe01fSAzael Avalos if (!sci_open(dev)) 972bb3fe01fSAzael Avalos return -EIO; 973bb3fe01fSAzael Avalos 974bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 975bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 976bb3fe01fSAzael Avalos sci_close(dev); 977bb3fe01fSAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 978bb26f189SAzael Avalos pr_err("ACPI call to get USB Rapid Charge failed\n"); 979bb3fe01fSAzael Avalos return -EIO; 980bb3fe01fSAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED || 981bb3fe01fSAzael Avalos out[0] == TOS_INPUT_DATA_ERROR) { 982bb26f189SAzael Avalos pr_info("USB Rapid Charge not supported\n"); 983bb3fe01fSAzael Avalos return -ENODEV; 984bb3fe01fSAzael Avalos } 985bb3fe01fSAzael Avalos 986bb3fe01fSAzael Avalos *state = out[2]; 987bb3fe01fSAzael Avalos 988bb3fe01fSAzael Avalos return 0; 989bb3fe01fSAzael Avalos } 990bb3fe01fSAzael Avalos 991bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, 992bb3fe01fSAzael Avalos u32 state) 993bb3fe01fSAzael Avalos { 994bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 995bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 996bb3fe01fSAzael Avalos acpi_status status; 997bb3fe01fSAzael Avalos 998bb3fe01fSAzael Avalos if (!sci_open(dev)) 999bb3fe01fSAzael Avalos return -EIO; 1000bb3fe01fSAzael Avalos 1001bb3fe01fSAzael Avalos in[2] = state; 1002bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 1003bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 1004bb3fe01fSAzael Avalos sci_close(dev); 1005bb3fe01fSAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 1006bb26f189SAzael Avalos pr_err("ACPI call to set USB Rapid Charge failed\n"); 1007bb3fe01fSAzael Avalos return -EIO; 1008bb3fe01fSAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 1009bb26f189SAzael Avalos pr_info("USB Rapid Charge not supported\n"); 1010bb3fe01fSAzael Avalos return -ENODEV; 1011bb3fe01fSAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 1012bb3fe01fSAzael Avalos return -EIO; 1013bb3fe01fSAzael Avalos } 1014bb3fe01fSAzael Avalos 1015bb3fe01fSAzael Avalos return 0; 1016bb3fe01fSAzael Avalos } 1017bb3fe01fSAzael Avalos 1018172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state) 1019172ce0a9SAzael Avalos { 1020172ce0a9SAzael Avalos u32 result; 1021172ce0a9SAzael Avalos 1022172ce0a9SAzael Avalos if (!sci_open(dev)) 1023172ce0a9SAzael Avalos return -EIO; 1024172ce0a9SAzael Avalos 1025172ce0a9SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state); 1026172ce0a9SAzael Avalos sci_close(dev); 1027172ce0a9SAzael Avalos if (result == TOS_FAILURE) { 1028bb26f189SAzael Avalos pr_err("ACPI call to get Sleep and Music failed\n"); 1029172ce0a9SAzael Avalos return -EIO; 1030172ce0a9SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1031bb26f189SAzael Avalos pr_info("Sleep and Music not supported\n"); 1032172ce0a9SAzael Avalos return -ENODEV; 1033172ce0a9SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 1034172ce0a9SAzael Avalos return -EIO; 1035172ce0a9SAzael Avalos } 1036172ce0a9SAzael Avalos 1037172ce0a9SAzael Avalos return 0; 1038172ce0a9SAzael Avalos } 1039172ce0a9SAzael Avalos 1040172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state) 1041172ce0a9SAzael Avalos { 1042172ce0a9SAzael Avalos u32 result; 1043172ce0a9SAzael Avalos 1044172ce0a9SAzael Avalos if (!sci_open(dev)) 1045172ce0a9SAzael Avalos return -EIO; 1046172ce0a9SAzael Avalos 1047172ce0a9SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state); 1048172ce0a9SAzael Avalos sci_close(dev); 1049172ce0a9SAzael Avalos if (result == TOS_FAILURE) { 1050bb26f189SAzael Avalos pr_err("ACPI call to set Sleep and Music failed\n"); 1051172ce0a9SAzael Avalos return -EIO; 1052172ce0a9SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1053bb26f189SAzael Avalos pr_info("Sleep and Music not supported\n"); 1054172ce0a9SAzael Avalos return -ENODEV; 1055172ce0a9SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 1056172ce0a9SAzael Avalos return -EIO; 1057172ce0a9SAzael Avalos } 1058172ce0a9SAzael Avalos 1059172ce0a9SAzael Avalos return 0; 1060172ce0a9SAzael Avalos } 1061172ce0a9SAzael Avalos 1062bae84195SAzael Avalos /* Keyboard function keys */ 1063bae84195SAzael Avalos static int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode) 1064bae84195SAzael Avalos { 1065bae84195SAzael Avalos u32 result; 1066bae84195SAzael Avalos 1067bae84195SAzael Avalos if (!sci_open(dev)) 1068bae84195SAzael Avalos return -EIO; 1069bae84195SAzael Avalos 1070bae84195SAzael Avalos result = sci_read(dev, SCI_KBD_FUNCTION_KEYS, mode); 1071bae84195SAzael Avalos sci_close(dev); 1072bae84195SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 1073bae84195SAzael Avalos pr_err("ACPI call to get KBD function keys failed\n"); 1074bae84195SAzael Avalos return -EIO; 1075bae84195SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1076bae84195SAzael Avalos pr_info("KBD function keys not supported\n"); 1077bae84195SAzael Avalos return -ENODEV; 1078bae84195SAzael Avalos } 1079bae84195SAzael Avalos 1080bae84195SAzael Avalos return 0; 1081bae84195SAzael Avalos } 1082bae84195SAzael Avalos 1083bae84195SAzael Avalos static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode) 1084bae84195SAzael Avalos { 1085bae84195SAzael Avalos u32 result; 1086bae84195SAzael Avalos 1087bae84195SAzael Avalos if (!sci_open(dev)) 1088bae84195SAzael Avalos return -EIO; 1089bae84195SAzael Avalos 1090bae84195SAzael Avalos result = sci_write(dev, SCI_KBD_FUNCTION_KEYS, mode); 1091bae84195SAzael Avalos sci_close(dev); 1092bae84195SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 1093bae84195SAzael Avalos pr_err("ACPI call to set KBD function keys failed\n"); 1094bae84195SAzael Avalos return -EIO; 1095bae84195SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1096bae84195SAzael Avalos pr_info("KBD function keys not supported\n"); 1097bae84195SAzael Avalos return -ENODEV; 1098bae84195SAzael Avalos } 1099bae84195SAzael Avalos 1100bae84195SAzael Avalos return 0; 1101bae84195SAzael Avalos } 1102bae84195SAzael Avalos 110335d53ceaSAzael Avalos /* Panel Power ON */ 110435d53ceaSAzael Avalos static int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state) 110535d53ceaSAzael Avalos { 110635d53ceaSAzael Avalos u32 result; 110735d53ceaSAzael Avalos 110835d53ceaSAzael Avalos if (!sci_open(dev)) 110935d53ceaSAzael Avalos return -EIO; 111035d53ceaSAzael Avalos 111135d53ceaSAzael Avalos result = sci_read(dev, SCI_PANEL_POWER_ON, state); 111235d53ceaSAzael Avalos sci_close(dev); 111335d53ceaSAzael Avalos if (result == TOS_FAILURE) { 111435d53ceaSAzael Avalos pr_err("ACPI call to get Panel Power ON failed\n"); 111535d53ceaSAzael Avalos return -EIO; 111635d53ceaSAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 111735d53ceaSAzael Avalos pr_info("Panel Power on not supported\n"); 111835d53ceaSAzael Avalos return -ENODEV; 111935d53ceaSAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 112035d53ceaSAzael Avalos return -EIO; 112135d53ceaSAzael Avalos } 112235d53ceaSAzael Avalos 112335d53ceaSAzael Avalos return 0; 112435d53ceaSAzael Avalos } 112535d53ceaSAzael Avalos 112635d53ceaSAzael Avalos static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state) 112735d53ceaSAzael Avalos { 112835d53ceaSAzael Avalos u32 result; 112935d53ceaSAzael Avalos 113035d53ceaSAzael Avalos if (!sci_open(dev)) 113135d53ceaSAzael Avalos return -EIO; 113235d53ceaSAzael Avalos 113335d53ceaSAzael Avalos result = sci_write(dev, SCI_PANEL_POWER_ON, state); 113435d53ceaSAzael Avalos sci_close(dev); 113535d53ceaSAzael Avalos if (result == TOS_FAILURE) { 113635d53ceaSAzael Avalos pr_err("ACPI call to set Panel Power ON failed\n"); 113735d53ceaSAzael Avalos return -EIO; 113835d53ceaSAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 113935d53ceaSAzael Avalos pr_info("Panel Power ON not supported\n"); 114035d53ceaSAzael Avalos return -ENODEV; 114135d53ceaSAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 114235d53ceaSAzael Avalos return -EIO; 114335d53ceaSAzael Avalos } 114435d53ceaSAzael Avalos 114535d53ceaSAzael Avalos return 0; 114635d53ceaSAzael Avalos } 114735d53ceaSAzael Avalos 114817fe4b3dSAzael Avalos /* USB Three */ 114917fe4b3dSAzael Avalos static int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state) 115017fe4b3dSAzael Avalos { 115117fe4b3dSAzael Avalos u32 result; 115217fe4b3dSAzael Avalos 115317fe4b3dSAzael Avalos if (!sci_open(dev)) 115417fe4b3dSAzael Avalos return -EIO; 115517fe4b3dSAzael Avalos 115617fe4b3dSAzael Avalos result = sci_read(dev, SCI_USB_THREE, state); 115717fe4b3dSAzael Avalos sci_close(dev); 115817fe4b3dSAzael Avalos if (result == TOS_FAILURE) { 115917fe4b3dSAzael Avalos pr_err("ACPI call to get USB 3 failed\n"); 116017fe4b3dSAzael Avalos return -EIO; 116117fe4b3dSAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 116217fe4b3dSAzael Avalos pr_info("USB 3 not supported\n"); 116317fe4b3dSAzael Avalos return -ENODEV; 116417fe4b3dSAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 116517fe4b3dSAzael Avalos return -EIO; 116617fe4b3dSAzael Avalos } 116717fe4b3dSAzael Avalos 116817fe4b3dSAzael Avalos return 0; 116917fe4b3dSAzael Avalos } 117017fe4b3dSAzael Avalos 117117fe4b3dSAzael Avalos static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state) 117217fe4b3dSAzael Avalos { 117317fe4b3dSAzael Avalos u32 result; 117417fe4b3dSAzael Avalos 117517fe4b3dSAzael Avalos if (!sci_open(dev)) 117617fe4b3dSAzael Avalos return -EIO; 117717fe4b3dSAzael Avalos 117817fe4b3dSAzael Avalos result = sci_write(dev, SCI_USB_THREE, state); 117917fe4b3dSAzael Avalos sci_close(dev); 118017fe4b3dSAzael Avalos if (result == TOS_FAILURE) { 118117fe4b3dSAzael Avalos pr_err("ACPI call to set USB 3 failed\n"); 118217fe4b3dSAzael Avalos return -EIO; 118317fe4b3dSAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 118417fe4b3dSAzael Avalos pr_info("USB 3 not supported\n"); 118517fe4b3dSAzael Avalos return -ENODEV; 118617fe4b3dSAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 118717fe4b3dSAzael Avalos return -EIO; 118817fe4b3dSAzael Avalos } 118917fe4b3dSAzael Avalos 119017fe4b3dSAzael Avalos return 0; 119117fe4b3dSAzael Avalos } 119217fe4b3dSAzael Avalos 119356e6b353SAzael Avalos /* Hotkey Event type */ 119456e6b353SAzael Avalos static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev, 119556e6b353SAzael Avalos u32 *type) 119656e6b353SAzael Avalos { 119756e6b353SAzael Avalos u32 val1 = 0x03; 119856e6b353SAzael Avalos u32 val2 = 0; 119956e6b353SAzael Avalos u32 result; 120056e6b353SAzael Avalos 120156e6b353SAzael Avalos result = hci_read2(dev, HCI_SYSTEM_INFO, &val1, &val2); 120256e6b353SAzael Avalos if (result == TOS_FAILURE) { 120356e6b353SAzael Avalos pr_err("ACPI call to get System type failed\n"); 120456e6b353SAzael Avalos return -EIO; 120556e6b353SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 120656e6b353SAzael Avalos pr_info("System type not supported\n"); 120756e6b353SAzael Avalos return -ENODEV; 120856e6b353SAzael Avalos } 120956e6b353SAzael Avalos 121056e6b353SAzael Avalos *type = val2; 121156e6b353SAzael Avalos 121256e6b353SAzael Avalos return 0; 121356e6b353SAzael Avalos } 121456e6b353SAzael Avalos 1215b4f9fe12SLen Brown /* Bluetooth rfkill handlers */ 1216b4f9fe12SLen Brown 1217135740deSSeth Forshee static u32 hci_get_bt_present(struct toshiba_acpi_dev *dev, bool *present) 1218b4f9fe12SLen Brown { 1219b4f9fe12SLen Brown u32 hci_result; 1220b4f9fe12SLen Brown u32 value, value2; 1221b4f9fe12SLen Brown 1222b4f9fe12SLen Brown value = 0; 1223b4f9fe12SLen Brown value2 = 0; 1224893f3f62SAzael Avalos hci_result = hci_read2(dev, HCI_WIRELESS, &value, &value2); 12251864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) 1226b4f9fe12SLen Brown *present = (value & HCI_WIRELESS_BT_PRESENT) ? true : false; 1227b4f9fe12SLen Brown 1228b4f9fe12SLen Brown return hci_result; 1229b4f9fe12SLen Brown } 1230b4f9fe12SLen Brown 1231135740deSSeth Forshee static u32 hci_get_radio_state(struct toshiba_acpi_dev *dev, bool *radio_state) 1232b4f9fe12SLen Brown { 1233b4f9fe12SLen Brown u32 hci_result; 1234b4f9fe12SLen Brown u32 value, value2; 1235b4f9fe12SLen Brown 1236b4f9fe12SLen Brown value = 0; 1237b4f9fe12SLen Brown value2 = 0x0001; 1238893f3f62SAzael Avalos hci_result = hci_read2(dev, HCI_WIRELESS, &value, &value2); 1239b4f9fe12SLen Brown 1240b4f9fe12SLen Brown *radio_state = value & HCI_WIRELESS_KILL_SWITCH; 1241b4f9fe12SLen Brown return hci_result; 1242b4f9fe12SLen Brown } 1243b4f9fe12SLen Brown 124419d337dfSJohannes Berg static int bt_rfkill_set_block(void *data, bool blocked) 1245b4f9fe12SLen Brown { 124619d337dfSJohannes Berg struct toshiba_acpi_dev *dev = data; 1247b4f9fe12SLen Brown u32 result1, result2; 1248b4f9fe12SLen Brown u32 value; 124919d337dfSJohannes Berg int err; 1250b4f9fe12SLen Brown bool radio_state; 1251b4f9fe12SLen Brown 125219d337dfSJohannes Berg value = (blocked == false); 1253b4f9fe12SLen Brown 1254b4f9fe12SLen Brown mutex_lock(&dev->mutex); 12551864bbc2SAzael Avalos if (hci_get_radio_state(dev, &radio_state) != TOS_SUCCESS) { 125632bcd5cbSSeth Forshee err = -EIO; 125719d337dfSJohannes Berg goto out; 1258b4f9fe12SLen Brown } 1259b4f9fe12SLen Brown 126019d337dfSJohannes Berg if (!radio_state) { 126119d337dfSJohannes Berg err = 0; 126219d337dfSJohannes Berg goto out; 126319d337dfSJohannes Berg } 126419d337dfSJohannes Berg 1265893f3f62SAzael Avalos result1 = hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER); 1266893f3f62SAzael Avalos result2 = hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH); 126719d337dfSJohannes Berg 12681864bbc2SAzael Avalos if (result1 != TOS_SUCCESS || result2 != TOS_SUCCESS) 126932bcd5cbSSeth Forshee err = -EIO; 127019d337dfSJohannes Berg else 127119d337dfSJohannes Berg err = 0; 127219d337dfSJohannes Berg out: 127319d337dfSJohannes Berg mutex_unlock(&dev->mutex); 127419d337dfSJohannes Berg return err; 127519d337dfSJohannes Berg } 127619d337dfSJohannes Berg 127719d337dfSJohannes Berg static void bt_rfkill_poll(struct rfkill *rfkill, void *data) 1278b4f9fe12SLen Brown { 1279b4f9fe12SLen Brown bool new_rfk_state; 1280b4f9fe12SLen Brown bool value; 1281b4f9fe12SLen Brown u32 hci_result; 128219d337dfSJohannes Berg struct toshiba_acpi_dev *dev = data; 128319d337dfSJohannes Berg 128419d337dfSJohannes Berg mutex_lock(&dev->mutex); 1285b4f9fe12SLen Brown 1286135740deSSeth Forshee hci_result = hci_get_radio_state(dev, &value); 12871864bbc2SAzael Avalos if (hci_result != TOS_SUCCESS) { 128819d337dfSJohannes Berg /* Can't do anything useful */ 128919d337dfSJohannes Berg mutex_unlock(&dev->mutex); 129082e7784fSJiri Slaby return; 129119d337dfSJohannes Berg } 1292b4f9fe12SLen Brown 1293b4f9fe12SLen Brown new_rfk_state = value; 1294b4f9fe12SLen Brown 1295b4f9fe12SLen Brown mutex_unlock(&dev->mutex); 1296b4f9fe12SLen Brown 129719d337dfSJohannes Berg if (rfkill_set_hw_state(rfkill, !new_rfk_state)) 129819d337dfSJohannes Berg bt_rfkill_set_block(data, true); 1299b4f9fe12SLen Brown } 130019d337dfSJohannes Berg 130119d337dfSJohannes Berg static const struct rfkill_ops toshiba_rfk_ops = { 130219d337dfSJohannes Berg .set_block = bt_rfkill_set_block, 130319d337dfSJohannes Berg .poll = bt_rfkill_poll, 130419d337dfSJohannes Berg }; 1305b4f9fe12SLen Brown 1306121b7b0dSAkio Idehara static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled) 1307121b7b0dSAkio Idehara { 1308121b7b0dSAkio Idehara u32 hci_result; 1309121b7b0dSAkio Idehara u32 status; 1310121b7b0dSAkio Idehara 1311893f3f62SAzael Avalos hci_result = hci_read1(dev, HCI_TR_BACKLIGHT, &status); 1312121b7b0dSAkio Idehara *enabled = !status; 13131864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 1314121b7b0dSAkio Idehara } 1315121b7b0dSAkio Idehara 1316121b7b0dSAkio Idehara static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable) 1317121b7b0dSAkio Idehara { 1318121b7b0dSAkio Idehara u32 hci_result; 1319121b7b0dSAkio Idehara u32 value = !enable; 1320121b7b0dSAkio Idehara 1321893f3f62SAzael Avalos hci_result = hci_write1(dev, HCI_TR_BACKLIGHT, value); 13221864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 1323121b7b0dSAkio Idehara } 1324121b7b0dSAkio Idehara 1325b4f9fe12SLen Brown static struct proc_dir_entry *toshiba_proc_dir /*= 0*/; 1326b4f9fe12SLen Brown 132762cce752SSeth Forshee static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) 1328b4f9fe12SLen Brown { 1329b4f9fe12SLen Brown u32 hci_result; 1330b4f9fe12SLen Brown u32 value; 1331121b7b0dSAkio Idehara int brightness = 0; 1332121b7b0dSAkio Idehara 1333121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1334121b7b0dSAkio Idehara bool enabled; 1335121b7b0dSAkio Idehara int ret = get_tr_backlight_status(dev, &enabled); 1336b5163992SAzael Avalos 1337121b7b0dSAkio Idehara if (ret) 1338121b7b0dSAkio Idehara return ret; 1339121b7b0dSAkio Idehara if (enabled) 1340121b7b0dSAkio Idehara return 0; 1341121b7b0dSAkio Idehara brightness++; 1342121b7b0dSAkio Idehara } 1343b4f9fe12SLen Brown 1344893f3f62SAzael Avalos hci_result = hci_read1(dev, HCI_LCD_BRIGHTNESS, &value); 13451864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) 1346121b7b0dSAkio Idehara return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT); 134732bcd5cbSSeth Forshee 134832bcd5cbSSeth Forshee return -EIO; 1349b4f9fe12SLen Brown } 1350b4f9fe12SLen Brown 135162cce752SSeth Forshee static int get_lcd_brightness(struct backlight_device *bd) 135262cce752SSeth Forshee { 135362cce752SSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 1354b5163992SAzael Avalos 135562cce752SSeth Forshee return __get_lcd_brightness(dev); 135662cce752SSeth Forshee } 135762cce752SSeth Forshee 1358936c8bcdSAlexey Dobriyan static int lcd_proc_show(struct seq_file *m, void *v) 1359b4f9fe12SLen Brown { 1360135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1361135740deSSeth Forshee int value; 1362121b7b0dSAkio Idehara int levels; 1363b4f9fe12SLen Brown 1364135740deSSeth Forshee if (!dev->backlight_dev) 1365135740deSSeth Forshee return -ENODEV; 1366135740deSSeth Forshee 1367121b7b0dSAkio Idehara levels = dev->backlight_dev->props.max_brightness + 1; 136862cce752SSeth Forshee value = get_lcd_brightness(dev->backlight_dev); 1369b4f9fe12SLen Brown if (value >= 0) { 1370936c8bcdSAlexey Dobriyan seq_printf(m, "brightness: %d\n", value); 1371121b7b0dSAkio Idehara seq_printf(m, "brightness_levels: %d\n", levels); 137232bcd5cbSSeth Forshee return 0; 1373b4f9fe12SLen Brown } 1374b4f9fe12SLen Brown 137532bcd5cbSSeth Forshee pr_err("Error reading LCD brightness\n"); 137632bcd5cbSSeth Forshee return -EIO; 1377936c8bcdSAlexey Dobriyan } 1378936c8bcdSAlexey Dobriyan 1379936c8bcdSAlexey Dobriyan static int lcd_proc_open(struct inode *inode, struct file *file) 1380936c8bcdSAlexey Dobriyan { 1381d9dda78bSAl Viro return single_open(file, lcd_proc_show, PDE_DATA(inode)); 1382b4f9fe12SLen Brown } 1383b4f9fe12SLen Brown 138462cce752SSeth Forshee static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) 1385b4f9fe12SLen Brown { 1386a39f46dfSAzael Avalos u32 hci_result; 1387b4f9fe12SLen Brown 1388121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1389121b7b0dSAkio Idehara bool enable = !value; 1390121b7b0dSAkio Idehara int ret = set_tr_backlight_status(dev, enable); 1391b5163992SAzael Avalos 1392121b7b0dSAkio Idehara if (ret) 1393121b7b0dSAkio Idehara return ret; 1394121b7b0dSAkio Idehara if (value) 1395121b7b0dSAkio Idehara value--; 1396121b7b0dSAkio Idehara } 1397121b7b0dSAkio Idehara 1398a39f46dfSAzael Avalos value = value << HCI_LCD_BRIGHTNESS_SHIFT; 1399a39f46dfSAzael Avalos hci_result = hci_write1(dev, HCI_LCD_BRIGHTNESS, value); 1400a39f46dfSAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 1401b4f9fe12SLen Brown } 1402b4f9fe12SLen Brown 1403b4f9fe12SLen Brown static int set_lcd_status(struct backlight_device *bd) 1404b4f9fe12SLen Brown { 1405135740deSSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 1406b5163992SAzael Avalos 140762cce752SSeth Forshee return set_lcd_brightness(dev, bd->props.brightness); 1408b4f9fe12SLen Brown } 1409b4f9fe12SLen Brown 1410936c8bcdSAlexey Dobriyan static ssize_t lcd_proc_write(struct file *file, const char __user *buf, 1411936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1412b4f9fe12SLen Brown { 1413d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1414936c8bcdSAlexey Dobriyan char cmd[42]; 1415936c8bcdSAlexey Dobriyan size_t len; 1416b4f9fe12SLen Brown int value; 1417b4f9fe12SLen Brown int ret; 1418121b7b0dSAkio Idehara int levels = dev->backlight_dev->props.max_brightness + 1; 1419b4f9fe12SLen Brown 1420936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1421936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1422936c8bcdSAlexey Dobriyan return -EFAULT; 1423936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1424936c8bcdSAlexey Dobriyan 1425936c8bcdSAlexey Dobriyan if (sscanf(cmd, " brightness : %i", &value) == 1 && 1426121b7b0dSAkio Idehara value >= 0 && value < levels) { 142762cce752SSeth Forshee ret = set_lcd_brightness(dev, value); 1428b4f9fe12SLen Brown if (ret == 0) 1429b4f9fe12SLen Brown ret = count; 1430b4f9fe12SLen Brown } else { 1431b4f9fe12SLen Brown ret = -EINVAL; 1432b4f9fe12SLen Brown } 1433b4f9fe12SLen Brown return ret; 1434b4f9fe12SLen Brown } 1435b4f9fe12SLen Brown 1436936c8bcdSAlexey Dobriyan static const struct file_operations lcd_proc_fops = { 1437936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1438936c8bcdSAlexey Dobriyan .open = lcd_proc_open, 1439936c8bcdSAlexey Dobriyan .read = seq_read, 1440936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1441936c8bcdSAlexey Dobriyan .release = single_release, 1442936c8bcdSAlexey Dobriyan .write = lcd_proc_write, 1443936c8bcdSAlexey Dobriyan }; 1444936c8bcdSAlexey Dobriyan 144536d03f93SSeth Forshee static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status) 144636d03f93SSeth Forshee { 144736d03f93SSeth Forshee u32 hci_result; 144836d03f93SSeth Forshee 1449893f3f62SAzael Avalos hci_result = hci_read1(dev, HCI_VIDEO_OUT, status); 14501864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 145136d03f93SSeth Forshee } 145236d03f93SSeth Forshee 1453936c8bcdSAlexey Dobriyan static int video_proc_show(struct seq_file *m, void *v) 1454b4f9fe12SLen Brown { 1455135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1456b4f9fe12SLen Brown u32 value; 145736d03f93SSeth Forshee int ret; 1458b4f9fe12SLen Brown 145936d03f93SSeth Forshee ret = get_video_status(dev, &value); 146036d03f93SSeth Forshee if (!ret) { 1461b4f9fe12SLen Brown int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; 1462b4f9fe12SLen Brown int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; 1463b4f9fe12SLen Brown int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; 1464b5163992SAzael Avalos 1465936c8bcdSAlexey Dobriyan seq_printf(m, "lcd_out: %d\n", is_lcd); 1466936c8bcdSAlexey Dobriyan seq_printf(m, "crt_out: %d\n", is_crt); 1467936c8bcdSAlexey Dobriyan seq_printf(m, "tv_out: %d\n", is_tv); 1468b4f9fe12SLen Brown } 1469b4f9fe12SLen Brown 147036d03f93SSeth Forshee return ret; 1471b4f9fe12SLen Brown } 1472b4f9fe12SLen Brown 1473936c8bcdSAlexey Dobriyan static int video_proc_open(struct inode *inode, struct file *file) 1474b4f9fe12SLen Brown { 1475d9dda78bSAl Viro return single_open(file, video_proc_show, PDE_DATA(inode)); 1476936c8bcdSAlexey Dobriyan } 1477936c8bcdSAlexey Dobriyan 1478936c8bcdSAlexey Dobriyan static ssize_t video_proc_write(struct file *file, const char __user *buf, 1479936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1480936c8bcdSAlexey Dobriyan { 1481d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1482936c8bcdSAlexey Dobriyan char *cmd, *buffer; 148336d03f93SSeth Forshee int ret; 1484b4f9fe12SLen Brown int value; 1485b4f9fe12SLen Brown int remain = count; 1486b4f9fe12SLen Brown int lcd_out = -1; 1487b4f9fe12SLen Brown int crt_out = -1; 1488b4f9fe12SLen Brown int tv_out = -1; 1489b4f9fe12SLen Brown u32 video_out; 1490b4f9fe12SLen Brown 1491936c8bcdSAlexey Dobriyan cmd = kmalloc(count + 1, GFP_KERNEL); 1492936c8bcdSAlexey Dobriyan if (!cmd) 1493936c8bcdSAlexey Dobriyan return -ENOMEM; 1494936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, count)) { 1495936c8bcdSAlexey Dobriyan kfree(cmd); 1496936c8bcdSAlexey Dobriyan return -EFAULT; 1497936c8bcdSAlexey Dobriyan } 1498936c8bcdSAlexey Dobriyan cmd[count] = '\0'; 1499936c8bcdSAlexey Dobriyan 1500936c8bcdSAlexey Dobriyan buffer = cmd; 1501936c8bcdSAlexey Dobriyan 1502e0769fe6SDarren Hart /* 1503e0769fe6SDarren Hart * Scan expression. Multiple expressions may be delimited with ; 1504e0769fe6SDarren Hart * NOTE: To keep scanning simple, invalid fields are ignored. 1505b4f9fe12SLen Brown */ 1506b4f9fe12SLen Brown while (remain) { 1507b4f9fe12SLen Brown if (sscanf(buffer, " lcd_out : %i", &value) == 1) 1508b4f9fe12SLen Brown lcd_out = value & 1; 1509b4f9fe12SLen Brown else if (sscanf(buffer, " crt_out : %i", &value) == 1) 1510b4f9fe12SLen Brown crt_out = value & 1; 1511b4f9fe12SLen Brown else if (sscanf(buffer, " tv_out : %i", &value) == 1) 1512b4f9fe12SLen Brown tv_out = value & 1; 1513e0769fe6SDarren Hart /* Advance to one character past the next ; */ 1514b4f9fe12SLen Brown do { 1515b4f9fe12SLen Brown ++buffer; 1516b4f9fe12SLen Brown --remain; 1517b5163992SAzael Avalos } while (remain && *(buffer - 1) != ';'); 1518b4f9fe12SLen Brown } 1519b4f9fe12SLen Brown 1520936c8bcdSAlexey Dobriyan kfree(cmd); 1521936c8bcdSAlexey Dobriyan 152236d03f93SSeth Forshee ret = get_video_status(dev, &video_out); 152336d03f93SSeth Forshee if (!ret) { 1524b4f9fe12SLen Brown unsigned int new_video_out = video_out; 1525b5163992SAzael Avalos 1526b4f9fe12SLen Brown if (lcd_out != -1) 1527b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out); 1528b4f9fe12SLen Brown if (crt_out != -1) 1529b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out); 1530b4f9fe12SLen Brown if (tv_out != -1) 1531b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out); 1532e0769fe6SDarren Hart /* 1533e0769fe6SDarren Hart * To avoid unnecessary video disruption, only write the new 1534b4f9fe12SLen Brown * video setting if something changed. */ 1535b4f9fe12SLen Brown if (new_video_out != video_out) 153632bcd5cbSSeth Forshee ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out); 1537b4f9fe12SLen Brown } 1538b4f9fe12SLen Brown 153932bcd5cbSSeth Forshee return ret ? ret : count; 1540b4f9fe12SLen Brown } 1541b4f9fe12SLen Brown 1542936c8bcdSAlexey Dobriyan static const struct file_operations video_proc_fops = { 1543936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1544936c8bcdSAlexey Dobriyan .open = video_proc_open, 1545936c8bcdSAlexey Dobriyan .read = seq_read, 1546936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1547936c8bcdSAlexey Dobriyan .release = single_release, 1548936c8bcdSAlexey Dobriyan .write = video_proc_write, 1549936c8bcdSAlexey Dobriyan }; 1550936c8bcdSAlexey Dobriyan 155136d03f93SSeth Forshee static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status) 155236d03f93SSeth Forshee { 155336d03f93SSeth Forshee u32 hci_result; 155436d03f93SSeth Forshee 1555893f3f62SAzael Avalos hci_result = hci_read1(dev, HCI_FAN, status); 15561864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 155736d03f93SSeth Forshee } 155836d03f93SSeth Forshee 1559936c8bcdSAlexey Dobriyan static int fan_proc_show(struct seq_file *m, void *v) 1560b4f9fe12SLen Brown { 1561135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 156236d03f93SSeth Forshee int ret; 1563b4f9fe12SLen Brown u32 value; 1564b4f9fe12SLen Brown 156536d03f93SSeth Forshee ret = get_fan_status(dev, &value); 156636d03f93SSeth Forshee if (!ret) { 1567936c8bcdSAlexey Dobriyan seq_printf(m, "running: %d\n", (value > 0)); 1568135740deSSeth Forshee seq_printf(m, "force_on: %d\n", dev->force_fan); 1569b4f9fe12SLen Brown } 1570b4f9fe12SLen Brown 157136d03f93SSeth Forshee return ret; 1572b4f9fe12SLen Brown } 1573b4f9fe12SLen Brown 1574936c8bcdSAlexey Dobriyan static int fan_proc_open(struct inode *inode, struct file *file) 1575b4f9fe12SLen Brown { 1576d9dda78bSAl Viro return single_open(file, fan_proc_show, PDE_DATA(inode)); 1577936c8bcdSAlexey Dobriyan } 1578936c8bcdSAlexey Dobriyan 1579936c8bcdSAlexey Dobriyan static ssize_t fan_proc_write(struct file *file, const char __user *buf, 1580936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1581936c8bcdSAlexey Dobriyan { 1582d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1583936c8bcdSAlexey Dobriyan char cmd[42]; 1584936c8bcdSAlexey Dobriyan size_t len; 1585b4f9fe12SLen Brown int value; 1586b4f9fe12SLen Brown u32 hci_result; 1587b4f9fe12SLen Brown 1588936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1589936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1590936c8bcdSAlexey Dobriyan return -EFAULT; 1591936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1592936c8bcdSAlexey Dobriyan 1593936c8bcdSAlexey Dobriyan if (sscanf(cmd, " force_on : %i", &value) == 1 && 1594b4f9fe12SLen Brown value >= 0 && value <= 1) { 1595893f3f62SAzael Avalos hci_result = hci_write1(dev, HCI_FAN, value); 1596b5163992SAzael Avalos if (hci_result == TOS_SUCCESS) 1597135740deSSeth Forshee dev->force_fan = value; 1598b5163992SAzael Avalos else 1599b5163992SAzael Avalos return -EIO; 1600b4f9fe12SLen Brown } else { 1601b4f9fe12SLen Brown return -EINVAL; 1602b4f9fe12SLen Brown } 1603b4f9fe12SLen Brown 1604b4f9fe12SLen Brown return count; 1605b4f9fe12SLen Brown } 1606b4f9fe12SLen Brown 1607936c8bcdSAlexey Dobriyan static const struct file_operations fan_proc_fops = { 1608936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1609936c8bcdSAlexey Dobriyan .open = fan_proc_open, 1610936c8bcdSAlexey Dobriyan .read = seq_read, 1611936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1612936c8bcdSAlexey Dobriyan .release = single_release, 1613936c8bcdSAlexey Dobriyan .write = fan_proc_write, 1614936c8bcdSAlexey Dobriyan }; 1615936c8bcdSAlexey Dobriyan 1616936c8bcdSAlexey Dobriyan static int keys_proc_show(struct seq_file *m, void *v) 1617b4f9fe12SLen Brown { 1618135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1619b4f9fe12SLen Brown u32 hci_result; 1620b4f9fe12SLen Brown u32 value; 1621b4f9fe12SLen Brown 162211948b93SSeth Forshee if (!dev->key_event_valid && dev->system_event_supported) { 1623893f3f62SAzael Avalos hci_result = hci_read1(dev, HCI_SYSTEM_EVENT, &value); 16241864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) { 1625135740deSSeth Forshee dev->key_event_valid = 1; 1626135740deSSeth Forshee dev->last_key_event = value; 16271864bbc2SAzael Avalos } else if (hci_result == TOS_FIFO_EMPTY) { 1628e0769fe6SDarren Hart /* Better luck next time */ 16291864bbc2SAzael Avalos } else if (hci_result == TOS_NOT_SUPPORTED) { 1630e0769fe6SDarren Hart /* 1631e0769fe6SDarren Hart * This is a workaround for an unresolved issue on 1632b4f9fe12SLen Brown * some machines where system events sporadically 1633e0769fe6SDarren Hart * become disabled. 1634e0769fe6SDarren Hart */ 1635893f3f62SAzael Avalos hci_result = hci_write1(dev, HCI_SYSTEM_EVENT, 1); 16367e33460dSJoe Perches pr_notice("Re-enabled hotkeys\n"); 1637b4f9fe12SLen Brown } else { 16387e33460dSJoe Perches pr_err("Error reading hotkey status\n"); 163932bcd5cbSSeth Forshee return -EIO; 1640b4f9fe12SLen Brown } 1641b4f9fe12SLen Brown } 1642b4f9fe12SLen Brown 1643135740deSSeth Forshee seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid); 1644135740deSSeth Forshee seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event); 1645936c8bcdSAlexey Dobriyan return 0; 1646b4f9fe12SLen Brown } 1647b4f9fe12SLen Brown 1648936c8bcdSAlexey Dobriyan static int keys_proc_open(struct inode *inode, struct file *file) 1649b4f9fe12SLen Brown { 1650d9dda78bSAl Viro return single_open(file, keys_proc_show, PDE_DATA(inode)); 1651936c8bcdSAlexey Dobriyan } 1652936c8bcdSAlexey Dobriyan 1653936c8bcdSAlexey Dobriyan static ssize_t keys_proc_write(struct file *file, const char __user *buf, 1654936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1655936c8bcdSAlexey Dobriyan { 1656d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1657936c8bcdSAlexey Dobriyan char cmd[42]; 1658936c8bcdSAlexey Dobriyan size_t len; 1659b4f9fe12SLen Brown int value; 1660b4f9fe12SLen Brown 1661936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1662936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1663936c8bcdSAlexey Dobriyan return -EFAULT; 1664936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1665936c8bcdSAlexey Dobriyan 1666b5163992SAzael Avalos if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) 1667135740deSSeth Forshee dev->key_event_valid = 0; 1668b5163992SAzael Avalos else 1669b4f9fe12SLen Brown return -EINVAL; 1670b4f9fe12SLen Brown 1671b4f9fe12SLen Brown return count; 1672b4f9fe12SLen Brown } 1673b4f9fe12SLen Brown 1674936c8bcdSAlexey Dobriyan static const struct file_operations keys_proc_fops = { 1675936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1676936c8bcdSAlexey Dobriyan .open = keys_proc_open, 1677936c8bcdSAlexey Dobriyan .read = seq_read, 1678936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1679936c8bcdSAlexey Dobriyan .release = single_release, 1680936c8bcdSAlexey Dobriyan .write = keys_proc_write, 1681936c8bcdSAlexey Dobriyan }; 1682936c8bcdSAlexey Dobriyan 1683936c8bcdSAlexey Dobriyan static int version_proc_show(struct seq_file *m, void *v) 1684b4f9fe12SLen Brown { 1685936c8bcdSAlexey Dobriyan seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION); 1686936c8bcdSAlexey Dobriyan seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION); 1687936c8bcdSAlexey Dobriyan return 0; 1688b4f9fe12SLen Brown } 1689b4f9fe12SLen Brown 1690936c8bcdSAlexey Dobriyan static int version_proc_open(struct inode *inode, struct file *file) 1691936c8bcdSAlexey Dobriyan { 1692d9dda78bSAl Viro return single_open(file, version_proc_show, PDE_DATA(inode)); 1693936c8bcdSAlexey Dobriyan } 1694936c8bcdSAlexey Dobriyan 1695936c8bcdSAlexey Dobriyan static const struct file_operations version_proc_fops = { 1696936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1697936c8bcdSAlexey Dobriyan .open = version_proc_open, 1698936c8bcdSAlexey Dobriyan .read = seq_read, 1699936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1700936c8bcdSAlexey Dobriyan .release = single_release, 1701936c8bcdSAlexey Dobriyan }; 1702936c8bcdSAlexey Dobriyan 1703e0769fe6SDarren Hart /* 1704e0769fe6SDarren Hart * Proc and module init 1705b4f9fe12SLen Brown */ 1706b4f9fe12SLen Brown 1707b4f9fe12SLen Brown #define PROC_TOSHIBA "toshiba" 1708b4f9fe12SLen Brown 1709b859f159SGreg Kroah-Hartman static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1710b4f9fe12SLen Brown { 171136d03f93SSeth Forshee if (dev->backlight_dev) 1712135740deSSeth Forshee proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1713135740deSSeth Forshee &lcd_proc_fops, dev); 171436d03f93SSeth Forshee if (dev->video_supported) 1715135740deSSeth Forshee proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1716135740deSSeth Forshee &video_proc_fops, dev); 171736d03f93SSeth Forshee if (dev->fan_supported) 1718135740deSSeth Forshee proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1719135740deSSeth Forshee &fan_proc_fops, dev); 172036d03f93SSeth Forshee if (dev->hotkey_dev) 1721135740deSSeth Forshee proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1722135740deSSeth Forshee &keys_proc_fops, dev); 1723135740deSSeth Forshee proc_create_data("version", S_IRUGO, toshiba_proc_dir, 1724135740deSSeth Forshee &version_proc_fops, dev); 1725b4f9fe12SLen Brown } 1726b4f9fe12SLen Brown 172736d03f93SSeth Forshee static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1728b4f9fe12SLen Brown { 172936d03f93SSeth Forshee if (dev->backlight_dev) 1730936c8bcdSAlexey Dobriyan remove_proc_entry("lcd", toshiba_proc_dir); 173136d03f93SSeth Forshee if (dev->video_supported) 1732936c8bcdSAlexey Dobriyan remove_proc_entry("video", toshiba_proc_dir); 173336d03f93SSeth Forshee if (dev->fan_supported) 1734936c8bcdSAlexey Dobriyan remove_proc_entry("fan", toshiba_proc_dir); 173536d03f93SSeth Forshee if (dev->hotkey_dev) 1736936c8bcdSAlexey Dobriyan remove_proc_entry("keys", toshiba_proc_dir); 1737936c8bcdSAlexey Dobriyan remove_proc_entry("version", toshiba_proc_dir); 1738b4f9fe12SLen Brown } 1739b4f9fe12SLen Brown 1740acc2472eSLionel Debroux static const struct backlight_ops toshiba_backlight_data = { 1741121b7b0dSAkio Idehara .options = BL_CORE_SUSPENDRESUME, 174262cce752SSeth Forshee .get_brightness = get_lcd_brightness, 1743b4f9fe12SLen Brown .update_status = set_lcd_status, 1744b4f9fe12SLen Brown }; 1745b4f9fe12SLen Brown 1746360f0f39SAzael Avalos /* 1747360f0f39SAzael Avalos * Sysfs files 1748360f0f39SAzael Avalos */ 17499d309848SAzael Avalos static ssize_t version_show(struct device *dev, 1750c6c68ff8SAzael Avalos struct device_attribute *attr, char *buf) 1751c6c68ff8SAzael Avalos { 1752c6c68ff8SAzael Avalos return sprintf(buf, "%s\n", TOSHIBA_ACPI_VERSION); 1753c6c68ff8SAzael Avalos } 17540c3c0f10SAzael Avalos static DEVICE_ATTR_RO(version); 1755c6c68ff8SAzael Avalos 17569d309848SAzael Avalos static ssize_t fan_store(struct device *dev, 175794477d4cSAzael Avalos struct device_attribute *attr, 175894477d4cSAzael Avalos const char *buf, size_t count) 175994477d4cSAzael Avalos { 176094477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 176194477d4cSAzael Avalos u32 result; 176294477d4cSAzael Avalos int state; 176394477d4cSAzael Avalos int ret; 176494477d4cSAzael Avalos 176594477d4cSAzael Avalos ret = kstrtoint(buf, 0, &state); 176694477d4cSAzael Avalos if (ret) 176794477d4cSAzael Avalos return ret; 176894477d4cSAzael Avalos 176994477d4cSAzael Avalos if (state != 0 && state != 1) 177094477d4cSAzael Avalos return -EINVAL; 177194477d4cSAzael Avalos 177294477d4cSAzael Avalos result = hci_write1(toshiba, HCI_FAN, state); 177394477d4cSAzael Avalos if (result == TOS_FAILURE) 177494477d4cSAzael Avalos return -EIO; 177594477d4cSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 177694477d4cSAzael Avalos return -ENODEV; 177794477d4cSAzael Avalos 177894477d4cSAzael Avalos return count; 177994477d4cSAzael Avalos } 178094477d4cSAzael Avalos 17819d309848SAzael Avalos static ssize_t fan_show(struct device *dev, 178294477d4cSAzael Avalos struct device_attribute *attr, char *buf) 178394477d4cSAzael Avalos { 178494477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 178594477d4cSAzael Avalos u32 value; 178694477d4cSAzael Avalos int ret; 178794477d4cSAzael Avalos 178894477d4cSAzael Avalos ret = get_fan_status(toshiba, &value); 178994477d4cSAzael Avalos if (ret) 179094477d4cSAzael Avalos return ret; 179194477d4cSAzael Avalos 179294477d4cSAzael Avalos return sprintf(buf, "%d\n", value); 179394477d4cSAzael Avalos } 17940c3c0f10SAzael Avalos static DEVICE_ATTR_RW(fan); 179594477d4cSAzael Avalos 17969d309848SAzael Avalos static ssize_t kbd_backlight_mode_store(struct device *dev, 1797360f0f39SAzael Avalos struct device_attribute *attr, 1798360f0f39SAzael Avalos const char *buf, size_t count) 1799360f0f39SAzael Avalos { 1800360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1801aeaac098SDan Carpenter int mode; 1802aeaac098SDan Carpenter int time; 1803aeaac098SDan Carpenter int ret; 1804360f0f39SAzael Avalos 1805aeaac098SDan Carpenter 1806aeaac098SDan Carpenter ret = kstrtoint(buf, 0, &mode); 1807aeaac098SDan Carpenter if (ret) 1808aeaac098SDan Carpenter return ret; 180993f8c16dSAzael Avalos 181093f8c16dSAzael Avalos /* Check for supported modes depending on keyboard backlight type */ 181193f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 181293f8c16dSAzael Avalos /* Type 1 supports SCI_KBD_MODE_FNZ and SCI_KBD_MODE_AUTO */ 1813aeaac098SDan Carpenter if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO) 1814360f0f39SAzael Avalos return -EINVAL; 181593f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 181693f8c16dSAzael Avalos /* Type 2 doesn't support SCI_KBD_MODE_FNZ */ 181793f8c16dSAzael Avalos if (mode != SCI_KBD_MODE_AUTO && mode != SCI_KBD_MODE_ON && 181893f8c16dSAzael Avalos mode != SCI_KBD_MODE_OFF) 181993f8c16dSAzael Avalos return -EINVAL; 182093f8c16dSAzael Avalos } 1821360f0f39SAzael Avalos 1822e0769fe6SDarren Hart /* 1823e0769fe6SDarren Hart * Set the Keyboard Backlight Mode where: 1824360f0f39SAzael Avalos * Auto - KBD backlight turns off automatically in given time 1825360f0f39SAzael Avalos * FN-Z - KBD backlight "toggles" when hotkey pressed 182693f8c16dSAzael Avalos * ON - KBD backlight is always on 182793f8c16dSAzael Avalos * OFF - KBD backlight is always off 1828360f0f39SAzael Avalos */ 182993f8c16dSAzael Avalos 183093f8c16dSAzael Avalos /* Only make a change if the actual mode has changed */ 1831aeaac098SDan Carpenter if (toshiba->kbd_mode != mode) { 183293f8c16dSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 1833360f0f39SAzael Avalos time = toshiba->kbd_time << HCI_MISC_SHIFT; 183493f8c16dSAzael Avalos 183593f8c16dSAzael Avalos /* OR the "base time" to the actual method format */ 183693f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 183793f8c16dSAzael Avalos /* Type 1 requires the current mode */ 183893f8c16dSAzael Avalos time |= toshiba->kbd_mode; 183993f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 184093f8c16dSAzael Avalos /* Type 2 requires the desired mode */ 184193f8c16dSAzael Avalos time |= mode; 184293f8c16dSAzael Avalos } 184393f8c16dSAzael Avalos 1844aeaac098SDan Carpenter ret = toshiba_kbd_illum_status_set(toshiba, time); 1845aeaac098SDan Carpenter if (ret) 1846aeaac098SDan Carpenter return ret; 184793f8c16dSAzael Avalos 1848360f0f39SAzael Avalos toshiba->kbd_mode = mode; 1849360f0f39SAzael Avalos } 1850360f0f39SAzael Avalos 1851360f0f39SAzael Avalos return count; 1852360f0f39SAzael Avalos } 1853360f0f39SAzael Avalos 18549d309848SAzael Avalos static ssize_t kbd_backlight_mode_show(struct device *dev, 1855360f0f39SAzael Avalos struct device_attribute *attr, 1856360f0f39SAzael Avalos char *buf) 1857360f0f39SAzael Avalos { 1858360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1859360f0f39SAzael Avalos u32 time; 1860360f0f39SAzael Avalos 1861360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1862360f0f39SAzael Avalos return -EIO; 1863360f0f39SAzael Avalos 186493f8c16dSAzael Avalos return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK); 186593f8c16dSAzael Avalos } 18660c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_mode); 186793f8c16dSAzael Avalos 18689d309848SAzael Avalos static ssize_t kbd_type_show(struct device *dev, 18699d309848SAzael Avalos struct device_attribute *attr, char *buf) 187093f8c16dSAzael Avalos { 187193f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 187293f8c16dSAzael Avalos 187393f8c16dSAzael Avalos return sprintf(buf, "%d\n", toshiba->kbd_type); 187493f8c16dSAzael Avalos } 18750c3c0f10SAzael Avalos static DEVICE_ATTR_RO(kbd_type); 187693f8c16dSAzael Avalos 18779d309848SAzael Avalos static ssize_t available_kbd_modes_show(struct device *dev, 187893f8c16dSAzael Avalos struct device_attribute *attr, 187993f8c16dSAzael Avalos char *buf) 188093f8c16dSAzael Avalos { 188193f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 188293f8c16dSAzael Avalos 188393f8c16dSAzael Avalos if (toshiba->kbd_type == 1) 188493f8c16dSAzael Avalos return sprintf(buf, "%x %x\n", 188593f8c16dSAzael Avalos SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO); 188693f8c16dSAzael Avalos 188793f8c16dSAzael Avalos return sprintf(buf, "%x %x %x\n", 188893f8c16dSAzael Avalos SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF); 1889360f0f39SAzael Avalos } 18900c3c0f10SAzael Avalos static DEVICE_ATTR_RO(available_kbd_modes); 1891360f0f39SAzael Avalos 18929d309848SAzael Avalos static ssize_t kbd_backlight_timeout_store(struct device *dev, 1893360f0f39SAzael Avalos struct device_attribute *attr, 1894360f0f39SAzael Avalos const char *buf, size_t count) 1895360f0f39SAzael Avalos { 1896360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1897eabde0faSAzael Avalos int time; 1898eabde0faSAzael Avalos int ret; 1899360f0f39SAzael Avalos 1900eabde0faSAzael Avalos ret = kstrtoint(buf, 0, &time); 1901eabde0faSAzael Avalos if (ret) 1902eabde0faSAzael Avalos return ret; 1903eabde0faSAzael Avalos 1904eabde0faSAzael Avalos /* Check for supported values depending on kbd_type */ 1905eabde0faSAzael Avalos if (toshiba->kbd_type == 1) { 1906eabde0faSAzael Avalos if (time < 0 || time > 60) 1907360f0f39SAzael Avalos return -EINVAL; 1908eabde0faSAzael Avalos } else if (toshiba->kbd_type == 2) { 1909eabde0faSAzael Avalos if (time < 1 || time > 60) 1910eabde0faSAzael Avalos return -EINVAL; 1911eabde0faSAzael Avalos } 1912360f0f39SAzael Avalos 1913eabde0faSAzael Avalos /* Set the Keyboard Backlight Timeout */ 1914eabde0faSAzael Avalos 1915eabde0faSAzael Avalos /* Only make a change if the actual timeout has changed */ 1916eabde0faSAzael Avalos if (toshiba->kbd_time != time) { 1917eabde0faSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 1918360f0f39SAzael Avalos time = time << HCI_MISC_SHIFT; 1919eabde0faSAzael Avalos /* OR the "base time" to the actual method format */ 1920eabde0faSAzael Avalos if (toshiba->kbd_type == 1) 1921eabde0faSAzael Avalos time |= SCI_KBD_MODE_FNZ; 1922eabde0faSAzael Avalos else if (toshiba->kbd_type == 2) 1923eabde0faSAzael Avalos time |= SCI_KBD_MODE_AUTO; 1924eabde0faSAzael Avalos 1925eabde0faSAzael Avalos ret = toshiba_kbd_illum_status_set(toshiba, time); 1926eabde0faSAzael Avalos if (ret) 1927eabde0faSAzael Avalos return ret; 1928eabde0faSAzael Avalos 1929360f0f39SAzael Avalos toshiba->kbd_time = time >> HCI_MISC_SHIFT; 1930360f0f39SAzael Avalos } 1931360f0f39SAzael Avalos 1932360f0f39SAzael Avalos return count; 1933360f0f39SAzael Avalos } 1934360f0f39SAzael Avalos 19359d309848SAzael Avalos static ssize_t kbd_backlight_timeout_show(struct device *dev, 1936360f0f39SAzael Avalos struct device_attribute *attr, 1937360f0f39SAzael Avalos char *buf) 1938360f0f39SAzael Avalos { 1939360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1940360f0f39SAzael Avalos u32 time; 1941360f0f39SAzael Avalos 1942360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1943360f0f39SAzael Avalos return -EIO; 1944360f0f39SAzael Avalos 1945360f0f39SAzael Avalos return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT); 1946360f0f39SAzael Avalos } 19470c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_timeout); 1948360f0f39SAzael Avalos 19499d309848SAzael Avalos static ssize_t touchpad_store(struct device *dev, 19509d8658acSAzael Avalos struct device_attribute *attr, 19519d8658acSAzael Avalos const char *buf, size_t count) 19529d8658acSAzael Avalos { 19539d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 19549d8658acSAzael Avalos int state; 1955c8a41669SAzael Avalos int ret; 19569d8658acSAzael Avalos 19579d8658acSAzael Avalos /* Set the TouchPad on/off, 0 - Disable | 1 - Enable */ 1958c8a41669SAzael Avalos ret = kstrtoint(buf, 0, &state); 1959c8a41669SAzael Avalos if (ret) 1960c8a41669SAzael Avalos return ret; 1961c8a41669SAzael Avalos if (state != 0 && state != 1) 1962c8a41669SAzael Avalos return -EINVAL; 1963c8a41669SAzael Avalos 1964c8a41669SAzael Avalos ret = toshiba_touchpad_set(toshiba, state); 1965c8a41669SAzael Avalos if (ret) 1966c8a41669SAzael Avalos return ret; 19679d8658acSAzael Avalos 19689d8658acSAzael Avalos return count; 19699d8658acSAzael Avalos } 19709d8658acSAzael Avalos 19719d309848SAzael Avalos static ssize_t touchpad_show(struct device *dev, 19729d8658acSAzael Avalos struct device_attribute *attr, char *buf) 19739d8658acSAzael Avalos { 19749d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 19759d8658acSAzael Avalos u32 state; 19769d8658acSAzael Avalos int ret; 19779d8658acSAzael Avalos 19789d8658acSAzael Avalos ret = toshiba_touchpad_get(toshiba, &state); 19799d8658acSAzael Avalos if (ret < 0) 19809d8658acSAzael Avalos return ret; 19819d8658acSAzael Avalos 19829d8658acSAzael Avalos return sprintf(buf, "%i\n", state); 19839d8658acSAzael Avalos } 19840c3c0f10SAzael Avalos static DEVICE_ATTR_RW(touchpad); 19859d8658acSAzael Avalos 19869d309848SAzael Avalos static ssize_t position_show(struct device *dev, 19875a2813e9SAzael Avalos struct device_attribute *attr, char *buf) 19885a2813e9SAzael Avalos { 19895a2813e9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 19905a2813e9SAzael Avalos u32 xyval, zval, tmp; 19915a2813e9SAzael Avalos u16 x, y, z; 19925a2813e9SAzael Avalos int ret; 19935a2813e9SAzael Avalos 19945a2813e9SAzael Avalos xyval = zval = 0; 19955a2813e9SAzael Avalos ret = toshiba_accelerometer_get(toshiba, &xyval, &zval); 19965a2813e9SAzael Avalos if (ret < 0) 19975a2813e9SAzael Avalos return ret; 19985a2813e9SAzael Avalos 19995a2813e9SAzael Avalos x = xyval & HCI_ACCEL_MASK; 20005a2813e9SAzael Avalos tmp = xyval >> HCI_MISC_SHIFT; 20015a2813e9SAzael Avalos y = tmp & HCI_ACCEL_MASK; 20025a2813e9SAzael Avalos z = zval & HCI_ACCEL_MASK; 20035a2813e9SAzael Avalos 20045a2813e9SAzael Avalos return sprintf(buf, "%d %d %d\n", x, y, z); 20055a2813e9SAzael Avalos } 20060c3c0f10SAzael Avalos static DEVICE_ATTR_RO(position); 20075a2813e9SAzael Avalos 20089d309848SAzael Avalos static ssize_t usb_sleep_charge_show(struct device *dev, 20099d309848SAzael Avalos struct device_attribute *attr, char *buf) 2010e26ffe51SAzael Avalos { 2011e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2012e26ffe51SAzael Avalos u32 mode; 2013e26ffe51SAzael Avalos int ret; 2014e26ffe51SAzael Avalos 2015e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_get(toshiba, &mode); 2016e26ffe51SAzael Avalos if (ret < 0) 2017e26ffe51SAzael Avalos return ret; 2018e26ffe51SAzael Avalos 2019e26ffe51SAzael Avalos return sprintf(buf, "%x\n", mode & SCI_USB_CHARGE_MODE_MASK); 2020e26ffe51SAzael Avalos } 2021e26ffe51SAzael Avalos 20229d309848SAzael Avalos static ssize_t usb_sleep_charge_store(struct device *dev, 2023e26ffe51SAzael Avalos struct device_attribute *attr, 2024e26ffe51SAzael Avalos const char *buf, size_t count) 2025e26ffe51SAzael Avalos { 2026e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2027e26ffe51SAzael Avalos u32 mode; 2028e26ffe51SAzael Avalos int state; 2029e26ffe51SAzael Avalos int ret; 2030e26ffe51SAzael Avalos 2031e26ffe51SAzael Avalos ret = kstrtoint(buf, 0, &state); 2032e26ffe51SAzael Avalos if (ret) 2033e26ffe51SAzael Avalos return ret; 2034e0769fe6SDarren Hart /* 2035e0769fe6SDarren Hart * Check for supported values, where: 2036e26ffe51SAzael Avalos * 0 - Disabled 2037e26ffe51SAzael Avalos * 1 - Alternate (Non USB conformant devices that require more power) 2038e26ffe51SAzael Avalos * 2 - Auto (USB conformant devices) 2039c8c91842SAzael Avalos * 3 - Typical 2040e26ffe51SAzael Avalos */ 2041c8c91842SAzael Avalos if (state != 0 && state != 1 && state != 2 && state != 3) 2042e26ffe51SAzael Avalos return -EINVAL; 2043e26ffe51SAzael Avalos 2044e26ffe51SAzael Avalos /* Set the USB charging mode to internal value */ 2045c8c91842SAzael Avalos mode = toshiba->usbsc_mode_base; 2046e26ffe51SAzael Avalos if (state == 0) 2047c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_DISABLED; 2048e26ffe51SAzael Avalos else if (state == 1) 2049c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_ALTERNATE; 2050e26ffe51SAzael Avalos else if (state == 2) 2051c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_AUTO; 2052c8c91842SAzael Avalos else if (state == 3) 2053c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_TYPICAL; 2054e26ffe51SAzael Avalos 2055e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_set(toshiba, mode); 2056e26ffe51SAzael Avalos if (ret) 2057e26ffe51SAzael Avalos return ret; 2058e26ffe51SAzael Avalos 2059e26ffe51SAzael Avalos return count; 2060e26ffe51SAzael Avalos } 20610c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_charge); 2062e26ffe51SAzael Avalos 2063182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_show(struct device *dev, 2064182bcaa5SAzael Avalos struct device_attribute *attr, 2065182bcaa5SAzael Avalos char *buf) 2066182bcaa5SAzael Avalos { 2067182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2068182bcaa5SAzael Avalos u32 state; 2069182bcaa5SAzael Avalos int bat_lvl; 2070182bcaa5SAzael Avalos int status; 2071182bcaa5SAzael Avalos int ret; 2072182bcaa5SAzael Avalos int tmp; 2073182bcaa5SAzael Avalos 2074182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_get(toshiba, &state); 2075182bcaa5SAzael Avalos if (ret < 0) 2076182bcaa5SAzael Avalos return ret; 2077182bcaa5SAzael Avalos 2078182bcaa5SAzael Avalos /* Determine the status: 0x4 - Enabled | 0x1 - Disabled */ 2079182bcaa5SAzael Avalos tmp = state & SCI_USB_CHARGE_BAT_MASK; 2080182bcaa5SAzael Avalos status = (tmp == 0x4) ? 1 : 0; 2081182bcaa5SAzael Avalos /* Determine the battery level set */ 2082182bcaa5SAzael Avalos bat_lvl = state >> HCI_MISC_SHIFT; 2083182bcaa5SAzael Avalos 2084182bcaa5SAzael Avalos return sprintf(buf, "%d %d\n", status, bat_lvl); 2085182bcaa5SAzael Avalos } 2086182bcaa5SAzael Avalos 2087182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_store(struct device *dev, 2088182bcaa5SAzael Avalos struct device_attribute *attr, 2089182bcaa5SAzael Avalos const char *buf, size_t count) 2090182bcaa5SAzael Avalos { 2091182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2092182bcaa5SAzael Avalos u32 status; 2093182bcaa5SAzael Avalos int value; 2094182bcaa5SAzael Avalos int ret; 2095182bcaa5SAzael Avalos int tmp; 2096182bcaa5SAzael Avalos 2097182bcaa5SAzael Avalos ret = kstrtoint(buf, 0, &value); 2098182bcaa5SAzael Avalos if (ret) 2099182bcaa5SAzael Avalos return ret; 2100182bcaa5SAzael Avalos 2101e0769fe6SDarren Hart /* 2102e0769fe6SDarren Hart * Set the status of the function: 2103182bcaa5SAzael Avalos * 0 - Disabled 2104182bcaa5SAzael Avalos * 1-100 - Enabled 2105182bcaa5SAzael Avalos */ 2106182bcaa5SAzael Avalos if (value < 0 || value > 100) 2107182bcaa5SAzael Avalos return -EINVAL; 2108182bcaa5SAzael Avalos 2109182bcaa5SAzael Avalos if (value == 0) { 2110182bcaa5SAzael Avalos tmp = toshiba->usbsc_bat_level << HCI_MISC_SHIFT; 2111182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_OFF; 2112182bcaa5SAzael Avalos } else { 2113182bcaa5SAzael Avalos tmp = value << HCI_MISC_SHIFT; 2114182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_ON; 2115182bcaa5SAzael Avalos } 2116182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_set(toshiba, status); 2117182bcaa5SAzael Avalos if (ret < 0) 2118182bcaa5SAzael Avalos return ret; 2119182bcaa5SAzael Avalos 2120182bcaa5SAzael Avalos toshiba->usbsc_bat_level = status >> HCI_MISC_SHIFT; 2121182bcaa5SAzael Avalos 2122182bcaa5SAzael Avalos return count; 2123182bcaa5SAzael Avalos } 21240c3c0f10SAzael Avalos static DEVICE_ATTR_RW(sleep_functions_on_battery); 2125182bcaa5SAzael Avalos 21269d309848SAzael Avalos static ssize_t usb_rapid_charge_show(struct device *dev, 21279d309848SAzael Avalos struct device_attribute *attr, char *buf) 2128bb3fe01fSAzael Avalos { 2129bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2130bb3fe01fSAzael Avalos u32 state; 2131bb3fe01fSAzael Avalos int ret; 2132bb3fe01fSAzael Avalos 2133bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(toshiba, &state); 2134bb3fe01fSAzael Avalos if (ret < 0) 2135bb3fe01fSAzael Avalos return ret; 2136bb3fe01fSAzael Avalos 2137bb3fe01fSAzael Avalos return sprintf(buf, "%d\n", state); 2138bb3fe01fSAzael Avalos } 2139bb3fe01fSAzael Avalos 21409d309848SAzael Avalos static ssize_t usb_rapid_charge_store(struct device *dev, 2141bb3fe01fSAzael Avalos struct device_attribute *attr, 2142bb3fe01fSAzael Avalos const char *buf, size_t count) 2143bb3fe01fSAzael Avalos { 2144bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2145bb3fe01fSAzael Avalos int state; 2146bb3fe01fSAzael Avalos int ret; 2147bb3fe01fSAzael Avalos 2148bb3fe01fSAzael Avalos ret = kstrtoint(buf, 0, &state); 2149bb3fe01fSAzael Avalos if (ret) 2150bb3fe01fSAzael Avalos return ret; 2151bb3fe01fSAzael Avalos if (state != 0 && state != 1) 2152bb3fe01fSAzael Avalos return -EINVAL; 2153bb3fe01fSAzael Avalos 2154bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_set(toshiba, state); 2155bb3fe01fSAzael Avalos if (ret) 2156bb3fe01fSAzael Avalos return ret; 2157bb3fe01fSAzael Avalos 2158bb3fe01fSAzael Avalos return count; 2159bb3fe01fSAzael Avalos } 21600c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_rapid_charge); 2161bb3fe01fSAzael Avalos 21629d309848SAzael Avalos static ssize_t usb_sleep_music_show(struct device *dev, 21639d309848SAzael Avalos struct device_attribute *attr, char *buf) 2164172ce0a9SAzael Avalos { 2165172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2166172ce0a9SAzael Avalos u32 state; 2167172ce0a9SAzael Avalos int ret; 2168172ce0a9SAzael Avalos 2169172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(toshiba, &state); 2170172ce0a9SAzael Avalos if (ret < 0) 2171172ce0a9SAzael Avalos return ret; 2172172ce0a9SAzael Avalos 2173172ce0a9SAzael Avalos return sprintf(buf, "%d\n", state); 2174172ce0a9SAzael Avalos } 2175172ce0a9SAzael Avalos 21769d309848SAzael Avalos static ssize_t usb_sleep_music_store(struct device *dev, 2177172ce0a9SAzael Avalos struct device_attribute *attr, 2178172ce0a9SAzael Avalos const char *buf, size_t count) 2179172ce0a9SAzael Avalos { 2180172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2181172ce0a9SAzael Avalos int state; 2182172ce0a9SAzael Avalos int ret; 2183172ce0a9SAzael Avalos 2184172ce0a9SAzael Avalos ret = kstrtoint(buf, 0, &state); 2185172ce0a9SAzael Avalos if (ret) 2186172ce0a9SAzael Avalos return ret; 2187172ce0a9SAzael Avalos if (state != 0 && state != 1) 2188172ce0a9SAzael Avalos return -EINVAL; 2189172ce0a9SAzael Avalos 2190172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_set(toshiba, state); 2191172ce0a9SAzael Avalos if (ret) 2192172ce0a9SAzael Avalos return ret; 2193172ce0a9SAzael Avalos 2194172ce0a9SAzael Avalos return count; 2195172ce0a9SAzael Avalos } 21960c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_music); 2197172ce0a9SAzael Avalos 21989d309848SAzael Avalos static ssize_t kbd_function_keys_show(struct device *dev, 21999d309848SAzael Avalos struct device_attribute *attr, char *buf) 2200bae84195SAzael Avalos { 2201bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2202bae84195SAzael Avalos int mode; 2203bae84195SAzael Avalos int ret; 2204bae84195SAzael Avalos 2205bae84195SAzael Avalos ret = toshiba_function_keys_get(toshiba, &mode); 2206bae84195SAzael Avalos if (ret < 0) 2207bae84195SAzael Avalos return ret; 2208bae84195SAzael Avalos 2209bae84195SAzael Avalos return sprintf(buf, "%d\n", mode); 2210bae84195SAzael Avalos } 2211bae84195SAzael Avalos 22129d309848SAzael Avalos static ssize_t kbd_function_keys_store(struct device *dev, 2213bae84195SAzael Avalos struct device_attribute *attr, 2214bae84195SAzael Avalos const char *buf, size_t count) 2215bae84195SAzael Avalos { 2216bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2217bae84195SAzael Avalos int mode; 2218bae84195SAzael Avalos int ret; 2219bae84195SAzael Avalos 2220bae84195SAzael Avalos ret = kstrtoint(buf, 0, &mode); 2221bae84195SAzael Avalos if (ret) 2222bae84195SAzael Avalos return ret; 2223e0769fe6SDarren Hart /* 2224e0769fe6SDarren Hart * Check for the function keys mode where: 2225bae84195SAzael Avalos * 0 - Normal operation (F{1-12} as usual and hotkeys via FN-F{1-12}) 2226bae84195SAzael Avalos * 1 - Special functions (Opposite of the above setting) 2227bae84195SAzael Avalos */ 2228bae84195SAzael Avalos if (mode != 0 && mode != 1) 2229bae84195SAzael Avalos return -EINVAL; 2230bae84195SAzael Avalos 2231bae84195SAzael Avalos ret = toshiba_function_keys_set(toshiba, mode); 2232bae84195SAzael Avalos if (ret) 2233bae84195SAzael Avalos return ret; 2234bae84195SAzael Avalos 2235bae84195SAzael Avalos pr_info("Reboot for changes to KBD Function Keys to take effect"); 2236bae84195SAzael Avalos 2237bae84195SAzael Avalos return count; 2238bae84195SAzael Avalos } 22390c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_function_keys); 2240bae84195SAzael Avalos 22419d309848SAzael Avalos static ssize_t panel_power_on_show(struct device *dev, 22429d309848SAzael Avalos struct device_attribute *attr, char *buf) 224335d53ceaSAzael Avalos { 224435d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 224535d53ceaSAzael Avalos u32 state; 224635d53ceaSAzael Avalos int ret; 224735d53ceaSAzael Avalos 224835d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(toshiba, &state); 224935d53ceaSAzael Avalos if (ret < 0) 225035d53ceaSAzael Avalos return ret; 225135d53ceaSAzael Avalos 225235d53ceaSAzael Avalos return sprintf(buf, "%d\n", state); 225335d53ceaSAzael Avalos } 225435d53ceaSAzael Avalos 22559d309848SAzael Avalos static ssize_t panel_power_on_store(struct device *dev, 225635d53ceaSAzael Avalos struct device_attribute *attr, 225735d53ceaSAzael Avalos const char *buf, size_t count) 225835d53ceaSAzael Avalos { 225935d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 226035d53ceaSAzael Avalos int state; 226135d53ceaSAzael Avalos int ret; 226235d53ceaSAzael Avalos 226335d53ceaSAzael Avalos ret = kstrtoint(buf, 0, &state); 226435d53ceaSAzael Avalos if (ret) 226535d53ceaSAzael Avalos return ret; 226635d53ceaSAzael Avalos if (state != 0 && state != 1) 226735d53ceaSAzael Avalos return -EINVAL; 226835d53ceaSAzael Avalos 226935d53ceaSAzael Avalos ret = toshiba_panel_power_on_set(toshiba, state); 227035d53ceaSAzael Avalos if (ret) 227135d53ceaSAzael Avalos return ret; 227235d53ceaSAzael Avalos 227335d53ceaSAzael Avalos pr_info("Reboot for changes to Panel Power ON to take effect"); 227435d53ceaSAzael Avalos 227535d53ceaSAzael Avalos return count; 227635d53ceaSAzael Avalos } 22770c3c0f10SAzael Avalos static DEVICE_ATTR_RW(panel_power_on); 227835d53ceaSAzael Avalos 22799d309848SAzael Avalos static ssize_t usb_three_show(struct device *dev, 22809d309848SAzael Avalos struct device_attribute *attr, char *buf) 228117fe4b3dSAzael Avalos { 228217fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 228317fe4b3dSAzael Avalos u32 state; 228417fe4b3dSAzael Avalos int ret; 228517fe4b3dSAzael Avalos 228617fe4b3dSAzael Avalos ret = toshiba_usb_three_get(toshiba, &state); 228717fe4b3dSAzael Avalos if (ret < 0) 228817fe4b3dSAzael Avalos return ret; 228917fe4b3dSAzael Avalos 229017fe4b3dSAzael Avalos return sprintf(buf, "%d\n", state); 229117fe4b3dSAzael Avalos } 229217fe4b3dSAzael Avalos 22939d309848SAzael Avalos static ssize_t usb_three_store(struct device *dev, 229417fe4b3dSAzael Avalos struct device_attribute *attr, 229517fe4b3dSAzael Avalos const char *buf, size_t count) 229617fe4b3dSAzael Avalos { 229717fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 229817fe4b3dSAzael Avalos int state; 229917fe4b3dSAzael Avalos int ret; 230017fe4b3dSAzael Avalos 230117fe4b3dSAzael Avalos ret = kstrtoint(buf, 0, &state); 230217fe4b3dSAzael Avalos if (ret) 230317fe4b3dSAzael Avalos return ret; 2304e0769fe6SDarren Hart /* 2305e0769fe6SDarren Hart * Check for USB 3 mode where: 230617fe4b3dSAzael Avalos * 0 - Disabled (Acts like a USB 2 port, saving power) 230717fe4b3dSAzael Avalos * 1 - Enabled 230817fe4b3dSAzael Avalos */ 230917fe4b3dSAzael Avalos if (state != 0 && state != 1) 231017fe4b3dSAzael Avalos return -EINVAL; 231117fe4b3dSAzael Avalos 231217fe4b3dSAzael Avalos ret = toshiba_usb_three_set(toshiba, state); 231317fe4b3dSAzael Avalos if (ret) 231417fe4b3dSAzael Avalos return ret; 231517fe4b3dSAzael Avalos 231617fe4b3dSAzael Avalos pr_info("Reboot for changes to USB 3 to take effect"); 231717fe4b3dSAzael Avalos 231817fe4b3dSAzael Avalos return count; 231917fe4b3dSAzael Avalos } 23200c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_three); 23219bd1213bSAzael Avalos 23229bd1213bSAzael Avalos static struct attribute *toshiba_attributes[] = { 23239bd1213bSAzael Avalos &dev_attr_version.attr, 23249bd1213bSAzael Avalos &dev_attr_fan.attr, 23259bd1213bSAzael Avalos &dev_attr_kbd_backlight_mode.attr, 23269bd1213bSAzael Avalos &dev_attr_kbd_type.attr, 23279bd1213bSAzael Avalos &dev_attr_available_kbd_modes.attr, 23289bd1213bSAzael Avalos &dev_attr_kbd_backlight_timeout.attr, 23299bd1213bSAzael Avalos &dev_attr_touchpad.attr, 23309bd1213bSAzael Avalos &dev_attr_position.attr, 23319bd1213bSAzael Avalos &dev_attr_usb_sleep_charge.attr, 23329bd1213bSAzael Avalos &dev_attr_sleep_functions_on_battery.attr, 23339bd1213bSAzael Avalos &dev_attr_usb_rapid_charge.attr, 23349bd1213bSAzael Avalos &dev_attr_usb_sleep_music.attr, 23359bd1213bSAzael Avalos &dev_attr_kbd_function_keys.attr, 23369bd1213bSAzael Avalos &dev_attr_panel_power_on.attr, 23379bd1213bSAzael Avalos &dev_attr_usb_three.attr, 23389bd1213bSAzael Avalos NULL, 23399bd1213bSAzael Avalos }; 23409bd1213bSAzael Avalos 2341360f0f39SAzael Avalos static umode_t toshiba_sysfs_is_visible(struct kobject *kobj, 2342360f0f39SAzael Avalos struct attribute *attr, int idx) 2343360f0f39SAzael Avalos { 2344360f0f39SAzael Avalos struct device *dev = container_of(kobj, struct device, kobj); 2345360f0f39SAzael Avalos struct toshiba_acpi_dev *drv = dev_get_drvdata(dev); 2346360f0f39SAzael Avalos bool exists = true; 2347360f0f39SAzael Avalos 234894477d4cSAzael Avalos if (attr == &dev_attr_fan.attr) 234994477d4cSAzael Avalos exists = (drv->fan_supported) ? true : false; 235094477d4cSAzael Avalos else if (attr == &dev_attr_kbd_backlight_mode.attr) 2351360f0f39SAzael Avalos exists = (drv->kbd_illum_supported) ? true : false; 2352360f0f39SAzael Avalos else if (attr == &dev_attr_kbd_backlight_timeout.attr) 2353360f0f39SAzael Avalos exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false; 23549d8658acSAzael Avalos else if (attr == &dev_attr_touchpad.attr) 23559d8658acSAzael Avalos exists = (drv->touchpad_supported) ? true : false; 23565a2813e9SAzael Avalos else if (attr == &dev_attr_position.attr) 23575a2813e9SAzael Avalos exists = (drv->accelerometer_supported) ? true : false; 2358e26ffe51SAzael Avalos else if (attr == &dev_attr_usb_sleep_charge.attr) 2359e26ffe51SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2360182bcaa5SAzael Avalos else if (attr == &dev_attr_sleep_functions_on_battery.attr) 2361182bcaa5SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2362bb3fe01fSAzael Avalos else if (attr == &dev_attr_usb_rapid_charge.attr) 2363bb3fe01fSAzael Avalos exists = (drv->usb_rapid_charge_supported) ? true : false; 2364172ce0a9SAzael Avalos else if (attr == &dev_attr_usb_sleep_music.attr) 2365172ce0a9SAzael Avalos exists = (drv->usb_sleep_music_supported) ? true : false; 2366bae84195SAzael Avalos else if (attr == &dev_attr_kbd_function_keys.attr) 2367bae84195SAzael Avalos exists = (drv->kbd_function_keys_supported) ? true : false; 236835d53ceaSAzael Avalos else if (attr == &dev_attr_panel_power_on.attr) 236935d53ceaSAzael Avalos exists = (drv->panel_power_on_supported) ? true : false; 237017fe4b3dSAzael Avalos else if (attr == &dev_attr_usb_three.attr) 237117fe4b3dSAzael Avalos exists = (drv->usb_three_supported) ? true : false; 2372360f0f39SAzael Avalos 2373360f0f39SAzael Avalos return exists ? attr->mode : 0; 2374360f0f39SAzael Avalos } 2375360f0f39SAzael Avalos 23769bd1213bSAzael Avalos static struct attribute_group toshiba_attr_group = { 23779bd1213bSAzael Avalos .is_visible = toshiba_sysfs_is_visible, 23789bd1213bSAzael Avalos .attrs = toshiba_attributes, 23799bd1213bSAzael Avalos }; 23809bd1213bSAzael Avalos 23811f28f290SAzael Avalos /* 23821f28f290SAzael Avalos * Hotkeys 23831f28f290SAzael Avalos */ 23841f28f290SAzael Avalos static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev) 23851f28f290SAzael Avalos { 23861f28f290SAzael Avalos acpi_status status; 23871f28f290SAzael Avalos u32 result; 23881f28f290SAzael Avalos 23891f28f290SAzael Avalos status = acpi_evaluate_object(dev->acpi_dev->handle, 23901f28f290SAzael Avalos "ENAB", NULL, NULL); 23911f28f290SAzael Avalos if (ACPI_FAILURE(status)) 23921f28f290SAzael Avalos return -ENODEV; 23931f28f290SAzael Avalos 23941f28f290SAzael Avalos result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE); 23951f28f290SAzael Avalos if (result == TOS_FAILURE) 23961f28f290SAzael Avalos return -EIO; 23971f28f290SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 23981f28f290SAzael Avalos return -ENODEV; 23991f28f290SAzael Avalos 24001f28f290SAzael Avalos return 0; 24011f28f290SAzael Avalos } 24021f28f290SAzael Avalos 2403fb42d1f4SAzael Avalos static void toshiba_acpi_enable_special_functions(struct toshiba_acpi_dev *dev) 2404fb42d1f4SAzael Avalos { 2405fb42d1f4SAzael Avalos u32 result; 2406fb42d1f4SAzael Avalos 2407fb42d1f4SAzael Avalos /* 2408fb42d1f4SAzael Avalos * Re-activate the hotkeys, but this time, we are using the 2409fb42d1f4SAzael Avalos * "Special Functions" mode. 2410fb42d1f4SAzael Avalos */ 2411fb42d1f4SAzael Avalos result = hci_write1(dev, HCI_HOTKEY_EVENT, 2412fb42d1f4SAzael Avalos HCI_HOTKEY_SPECIAL_FUNCTIONS); 2413fb42d1f4SAzael Avalos if (result != TOS_SUCCESS) 2414fb42d1f4SAzael Avalos pr_err("Could not enable the Special Function mode\n"); 2415fb42d1f4SAzael Avalos } 2416fb42d1f4SAzael Avalos 241729cd293fSSeth Forshee static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, 241829cd293fSSeth Forshee struct serio *port) 241929cd293fSSeth Forshee { 242098280374SGiedrius Statkevičius if (str & I8042_STR_AUXDATA) 242129cd293fSSeth Forshee return false; 242229cd293fSSeth Forshee 242329cd293fSSeth Forshee if (unlikely(data == 0xe0)) 242429cd293fSSeth Forshee return false; 242529cd293fSSeth Forshee 242629cd293fSSeth Forshee if ((data & 0x7f) == TOS1900_FN_SCAN) { 242729cd293fSSeth Forshee schedule_work(&toshiba_acpi->hotkey_work); 242829cd293fSSeth Forshee return true; 242929cd293fSSeth Forshee } 243029cd293fSSeth Forshee 243129cd293fSSeth Forshee return false; 243229cd293fSSeth Forshee } 243329cd293fSSeth Forshee 243429cd293fSSeth Forshee static void toshiba_acpi_hotkey_work(struct work_struct *work) 243529cd293fSSeth Forshee { 243629cd293fSSeth Forshee acpi_handle ec_handle = ec_get_handle(); 243729cd293fSSeth Forshee acpi_status status; 243829cd293fSSeth Forshee 243929cd293fSSeth Forshee if (!ec_handle) 244029cd293fSSeth Forshee return; 244129cd293fSSeth Forshee 244229cd293fSSeth Forshee status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL); 244329cd293fSSeth Forshee if (ACPI_FAILURE(status)) 244429cd293fSSeth Forshee pr_err("ACPI NTFY method execution failed\n"); 244529cd293fSSeth Forshee } 244629cd293fSSeth Forshee 244729cd293fSSeth Forshee /* 244829cd293fSSeth Forshee * Returns hotkey scancode, or < 0 on failure. 244929cd293fSSeth Forshee */ 245029cd293fSSeth Forshee static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev) 245129cd293fSSeth Forshee { 245274facaf7SZhang Rui unsigned long long value; 245329cd293fSSeth Forshee acpi_status status; 245429cd293fSSeth Forshee 245574facaf7SZhang Rui status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO", 245674facaf7SZhang Rui NULL, &value); 245774facaf7SZhang Rui if (ACPI_FAILURE(status)) { 245829cd293fSSeth Forshee pr_err("ACPI INFO method execution failed\n"); 245929cd293fSSeth Forshee return -EIO; 246029cd293fSSeth Forshee } 246129cd293fSSeth Forshee 246274facaf7SZhang Rui return value; 246329cd293fSSeth Forshee } 246429cd293fSSeth Forshee 246529cd293fSSeth Forshee static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev, 246629cd293fSSeth Forshee int scancode) 246729cd293fSSeth Forshee { 246829cd293fSSeth Forshee if (scancode == 0x100) 246929cd293fSSeth Forshee return; 247029cd293fSSeth Forshee 2471e0769fe6SDarren Hart /* Act on key press; ignore key release */ 247229cd293fSSeth Forshee if (scancode & 0x80) 247329cd293fSSeth Forshee return; 247429cd293fSSeth Forshee 247529cd293fSSeth Forshee if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true)) 247629cd293fSSeth Forshee pr_info("Unknown key %x\n", scancode); 247729cd293fSSeth Forshee } 247829cd293fSSeth Forshee 247971454d78SAzael Avalos static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) 248071454d78SAzael Avalos { 248171454d78SAzael Avalos u32 hci_result, value; 248271454d78SAzael Avalos int retries = 3; 248371454d78SAzael Avalos int scancode; 248471454d78SAzael Avalos 248571454d78SAzael Avalos if (dev->info_supported) { 248671454d78SAzael Avalos scancode = toshiba_acpi_query_hotkey(dev); 248771454d78SAzael Avalos if (scancode < 0) 248871454d78SAzael Avalos pr_err("Failed to query hotkey event\n"); 248971454d78SAzael Avalos else if (scancode != 0) 249071454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, scancode); 249171454d78SAzael Avalos } else if (dev->system_event_supported) { 249271454d78SAzael Avalos do { 249371454d78SAzael Avalos hci_result = hci_read1(dev, HCI_SYSTEM_EVENT, &value); 249471454d78SAzael Avalos switch (hci_result) { 249571454d78SAzael Avalos case TOS_SUCCESS: 249671454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, (int)value); 249771454d78SAzael Avalos break; 249871454d78SAzael Avalos case TOS_NOT_SUPPORTED: 249971454d78SAzael Avalos /* 250071454d78SAzael Avalos * This is a workaround for an unresolved 250171454d78SAzael Avalos * issue on some machines where system events 250271454d78SAzael Avalos * sporadically become disabled. 250371454d78SAzael Avalos */ 250471454d78SAzael Avalos hci_result = 250571454d78SAzael Avalos hci_write1(dev, HCI_SYSTEM_EVENT, 1); 250671454d78SAzael Avalos pr_notice("Re-enabled hotkeys\n"); 2507e0769fe6SDarren Hart /* Fall through */ 250871454d78SAzael Avalos default: 250971454d78SAzael Avalos retries--; 251071454d78SAzael Avalos break; 251171454d78SAzael Avalos } 251271454d78SAzael Avalos } while (retries && hci_result != TOS_FIFO_EMPTY); 251371454d78SAzael Avalos } 251471454d78SAzael Avalos } 251571454d78SAzael Avalos 2516b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) 25176335e4d5SMatthew Garrett { 2518fe808bfbSTakashi Iwai const struct key_entry *keymap = toshiba_acpi_keymap; 2519a2b3471bSAzael Avalos acpi_handle ec_handle; 2520a2b3471bSAzael Avalos u32 events_type; 2521a2b3471bSAzael Avalos u32 hci_result; 2522a2b3471bSAzael Avalos int error; 2523a2b3471bSAzael Avalos 2524a2b3471bSAzael Avalos error = toshiba_acpi_enable_hotkeys(dev); 2525a2b3471bSAzael Avalos if (error) 2526a2b3471bSAzael Avalos return error; 2527a2b3471bSAzael Avalos 2528a2b3471bSAzael Avalos error = toshiba_hotkey_event_type_get(dev, &events_type); 2529a2b3471bSAzael Avalos if (error) { 2530a2b3471bSAzael Avalos pr_err("Unable to query Hotkey Event Type\n"); 2531a2b3471bSAzael Avalos return error; 2532a2b3471bSAzael Avalos } 2533a2b3471bSAzael Avalos dev->hotkey_event_type = events_type; 2534135740deSSeth Forshee 2535135740deSSeth Forshee dev->hotkey_dev = input_allocate_device(); 2536b222cca6SJoe Perches if (!dev->hotkey_dev) 2537135740deSSeth Forshee return -ENOMEM; 2538135740deSSeth Forshee 2539135740deSSeth Forshee dev->hotkey_dev->name = "Toshiba input device"; 25406e02cc7eSSeth Forshee dev->hotkey_dev->phys = "toshiba_acpi/input0"; 2541135740deSSeth Forshee dev->hotkey_dev->id.bustype = BUS_HOST; 2542135740deSSeth Forshee 2543a2b3471bSAzael Avalos if (events_type == HCI_SYSTEM_TYPE1 || 2544a2b3471bSAzael Avalos !dev->kbd_function_keys_supported) 2545a2b3471bSAzael Avalos keymap = toshiba_acpi_keymap; 2546a2b3471bSAzael Avalos else if (events_type == HCI_SYSTEM_TYPE2 || 2547a2b3471bSAzael Avalos dev->kbd_function_keys_supported) 2548fe808bfbSTakashi Iwai keymap = toshiba_acpi_alt_keymap; 2549a2b3471bSAzael Avalos else 2550a2b3471bSAzael Avalos pr_info("Unknown event type received %x\n", events_type); 2551fe808bfbSTakashi Iwai error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL); 2552135740deSSeth Forshee if (error) 2553135740deSSeth Forshee goto err_free_dev; 2554135740deSSeth Forshee 255529cd293fSSeth Forshee /* 255629cd293fSSeth Forshee * For some machines the SCI responsible for providing hotkey 255729cd293fSSeth Forshee * notification doesn't fire. We can trigger the notification 255829cd293fSSeth Forshee * whenever the Fn key is pressed using the NTFY method, if 255929cd293fSSeth Forshee * supported, so if it's present set up an i8042 key filter 256029cd293fSSeth Forshee * for this purpose. 256129cd293fSSeth Forshee */ 256229cd293fSSeth Forshee ec_handle = ec_get_handle(); 2563e2e19606SZhang Rui if (ec_handle && acpi_has_method(ec_handle, "NTFY")) { 256429cd293fSSeth Forshee INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work); 256529cd293fSSeth Forshee 256629cd293fSSeth Forshee error = i8042_install_filter(toshiba_acpi_i8042_filter); 256729cd293fSSeth Forshee if (error) { 256829cd293fSSeth Forshee pr_err("Error installing key filter\n"); 256929cd293fSSeth Forshee goto err_free_keymap; 257029cd293fSSeth Forshee } 257129cd293fSSeth Forshee 257229cd293fSSeth Forshee dev->ntfy_supported = 1; 257329cd293fSSeth Forshee } 257429cd293fSSeth Forshee 257529cd293fSSeth Forshee /* 257629cd293fSSeth Forshee * Determine hotkey query interface. Prefer using the INFO 257729cd293fSSeth Forshee * method when it is available. 257829cd293fSSeth Forshee */ 2579e2e19606SZhang Rui if (acpi_has_method(dev->acpi_dev->handle, "INFO")) 258029cd293fSSeth Forshee dev->info_supported = 1; 2581e2e19606SZhang Rui else { 2582893f3f62SAzael Avalos hci_result = hci_write1(dev, HCI_SYSTEM_EVENT, 1); 25831864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) 258429cd293fSSeth Forshee dev->system_event_supported = 1; 258529cd293fSSeth Forshee } 258629cd293fSSeth Forshee 258729cd293fSSeth Forshee if (!dev->info_supported && !dev->system_event_supported) { 258829cd293fSSeth Forshee pr_warn("No hotkey query interface found\n"); 258929cd293fSSeth Forshee goto err_remove_filter; 259029cd293fSSeth Forshee } 259129cd293fSSeth Forshee 2592135740deSSeth Forshee error = input_register_device(dev->hotkey_dev); 2593135740deSSeth Forshee if (error) { 2594135740deSSeth Forshee pr_info("Unable to register input device\n"); 259529cd293fSSeth Forshee goto err_remove_filter; 2596135740deSSeth Forshee } 2597135740deSSeth Forshee 2598135740deSSeth Forshee return 0; 2599135740deSSeth Forshee 260029cd293fSSeth Forshee err_remove_filter: 260129cd293fSSeth Forshee if (dev->ntfy_supported) 260229cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 2603135740deSSeth Forshee err_free_keymap: 2604135740deSSeth Forshee sparse_keymap_free(dev->hotkey_dev); 2605135740deSSeth Forshee err_free_dev: 2606135740deSSeth Forshee input_free_device(dev->hotkey_dev); 2607135740deSSeth Forshee dev->hotkey_dev = NULL; 2608135740deSSeth Forshee return error; 2609135740deSSeth Forshee } 2610135740deSSeth Forshee 2611b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) 261262cce752SSeth Forshee { 261362cce752SSeth Forshee struct backlight_properties props; 261462cce752SSeth Forshee int brightness; 261562cce752SSeth Forshee int ret; 2616121b7b0dSAkio Idehara bool enabled; 261762cce752SSeth Forshee 261862cce752SSeth Forshee /* 261962cce752SSeth Forshee * Some machines don't support the backlight methods at all, and 262062cce752SSeth Forshee * others support it read-only. Either of these is pretty useless, 262162cce752SSeth Forshee * so only register the backlight device if the backlight method 262262cce752SSeth Forshee * supports both reads and writes. 262362cce752SSeth Forshee */ 262462cce752SSeth Forshee brightness = __get_lcd_brightness(dev); 262562cce752SSeth Forshee if (brightness < 0) 262662cce752SSeth Forshee return 0; 262762cce752SSeth Forshee ret = set_lcd_brightness(dev, brightness); 262862cce752SSeth Forshee if (ret) { 262962cce752SSeth Forshee pr_debug("Backlight method is read-only, disabling backlight support\n"); 263062cce752SSeth Forshee return 0; 263162cce752SSeth Forshee } 263262cce752SSeth Forshee 2633121b7b0dSAkio Idehara /* Determine whether or not BIOS supports transflective backlight */ 2634121b7b0dSAkio Idehara ret = get_tr_backlight_status(dev, &enabled); 2635121b7b0dSAkio Idehara dev->tr_backlight_supported = !ret; 2636121b7b0dSAkio Idehara 2637*358d6a2cSHans de Goede /* 2638*358d6a2cSHans de Goede * Tell acpi-video-detect code to prefer vendor backlight on all 2639*358d6a2cSHans de Goede * systems with transflective backlight and on dmi matched systems. 2640*358d6a2cSHans de Goede */ 2641*358d6a2cSHans de Goede if (dev->tr_backlight_supported || 2642*358d6a2cSHans de Goede dmi_check_system(toshiba_vendor_backlight_dmi)) 2643*358d6a2cSHans de Goede acpi_video_dmi_promote_vendor(); 2644*358d6a2cSHans de Goede 2645*358d6a2cSHans de Goede if (acpi_video_backlight_support()) 2646*358d6a2cSHans de Goede return 0; 2647*358d6a2cSHans de Goede 2648*358d6a2cSHans de Goede /* acpi-video may have loaded before we called dmi_promote_vendor() */ 2649*358d6a2cSHans de Goede acpi_video_unregister_backlight(); 2650*358d6a2cSHans de Goede 265153039f22SMatthew Garrett memset(&props, 0, sizeof(props)); 265262cce752SSeth Forshee props.type = BACKLIGHT_PLATFORM; 265362cce752SSeth Forshee props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; 265462cce752SSeth Forshee 2655e0769fe6SDarren Hart /* Adding an extra level and having 0 change to transflective mode */ 2656121b7b0dSAkio Idehara if (dev->tr_backlight_supported) 2657121b7b0dSAkio Idehara props.max_brightness++; 2658121b7b0dSAkio Idehara 265962cce752SSeth Forshee dev->backlight_dev = backlight_device_register("toshiba", 266062cce752SSeth Forshee &dev->acpi_dev->dev, 266162cce752SSeth Forshee dev, 266262cce752SSeth Forshee &toshiba_backlight_data, 266362cce752SSeth Forshee &props); 266462cce752SSeth Forshee if (IS_ERR(dev->backlight_dev)) { 266562cce752SSeth Forshee ret = PTR_ERR(dev->backlight_dev); 266662cce752SSeth Forshee pr_err("Could not register toshiba backlight device\n"); 266762cce752SSeth Forshee dev->backlight_dev = NULL; 266862cce752SSeth Forshee return ret; 266962cce752SSeth Forshee } 267062cce752SSeth Forshee 267162cce752SSeth Forshee dev->backlight_dev->props.brightness = brightness; 267262cce752SSeth Forshee return 0; 267362cce752SSeth Forshee } 267462cce752SSeth Forshee 267551fac838SRafael J. Wysocki static int toshiba_acpi_remove(struct acpi_device *acpi_dev) 2676135740deSSeth Forshee { 2677135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 2678135740deSSeth Forshee 267936d03f93SSeth Forshee remove_toshiba_proc_entries(dev); 2680135740deSSeth Forshee 2681360f0f39SAzael Avalos if (dev->sysfs_created) 2682360f0f39SAzael Avalos sysfs_remove_group(&dev->acpi_dev->dev.kobj, 2683360f0f39SAzael Avalos &toshiba_attr_group); 2684360f0f39SAzael Avalos 268529cd293fSSeth Forshee if (dev->ntfy_supported) { 268629cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 268729cd293fSSeth Forshee cancel_work_sync(&dev->hotkey_work); 268829cd293fSSeth Forshee } 268929cd293fSSeth Forshee 2690135740deSSeth Forshee if (dev->hotkey_dev) { 2691135740deSSeth Forshee input_unregister_device(dev->hotkey_dev); 2692135740deSSeth Forshee sparse_keymap_free(dev->hotkey_dev); 2693135740deSSeth Forshee } 2694135740deSSeth Forshee 2695135740deSSeth Forshee if (dev->bt_rfk) { 2696135740deSSeth Forshee rfkill_unregister(dev->bt_rfk); 2697135740deSSeth Forshee rfkill_destroy(dev->bt_rfk); 2698135740deSSeth Forshee } 2699135740deSSeth Forshee 2700135740deSSeth Forshee backlight_device_unregister(dev->backlight_dev); 2701135740deSSeth Forshee 270236d03f93SSeth Forshee if (dev->illumination_supported) 2703135740deSSeth Forshee led_classdev_unregister(&dev->led_dev); 2704135740deSSeth Forshee 2705360f0f39SAzael Avalos if (dev->kbd_led_registered) 2706360f0f39SAzael Avalos led_classdev_unregister(&dev->kbd_led); 2707360f0f39SAzael Avalos 2708def6c4e2SAzael Avalos if (dev->eco_supported) 2709def6c4e2SAzael Avalos led_classdev_unregister(&dev->eco_led); 2710def6c4e2SAzael Avalos 271129cd293fSSeth Forshee if (toshiba_acpi) 271229cd293fSSeth Forshee toshiba_acpi = NULL; 271329cd293fSSeth Forshee 2714135740deSSeth Forshee kfree(dev); 2715135740deSSeth Forshee 2716135740deSSeth Forshee return 0; 2717135740deSSeth Forshee } 2718135740deSSeth Forshee 2719b859f159SGreg Kroah-Hartman static const char *find_hci_method(acpi_handle handle) 2720a540d6b5SSeth Forshee { 2721e2e19606SZhang Rui if (acpi_has_method(handle, "GHCI")) 2722a540d6b5SSeth Forshee return "GHCI"; 2723a540d6b5SSeth Forshee 2724e2e19606SZhang Rui if (acpi_has_method(handle, "SPFC")) 2725a540d6b5SSeth Forshee return "SPFC"; 2726a540d6b5SSeth Forshee 2727a540d6b5SSeth Forshee return NULL; 2728a540d6b5SSeth Forshee } 2729a540d6b5SSeth Forshee 2730b859f159SGreg Kroah-Hartman static int toshiba_acpi_add(struct acpi_device *acpi_dev) 2731135740deSSeth Forshee { 2732135740deSSeth Forshee struct toshiba_acpi_dev *dev; 2733a540d6b5SSeth Forshee const char *hci_method; 2734fb42d1f4SAzael Avalos u32 special_functions; 273536d03f93SSeth Forshee u32 dummy; 2736135740deSSeth Forshee bool bt_present; 2737135740deSSeth Forshee int ret = 0; 2738135740deSSeth Forshee 273929cd293fSSeth Forshee if (toshiba_acpi) 274029cd293fSSeth Forshee return -EBUSY; 274129cd293fSSeth Forshee 2742135740deSSeth Forshee pr_info("Toshiba Laptop ACPI Extras version %s\n", 2743135740deSSeth Forshee TOSHIBA_ACPI_VERSION); 2744135740deSSeth Forshee 2745a540d6b5SSeth Forshee hci_method = find_hci_method(acpi_dev->handle); 2746a540d6b5SSeth Forshee if (!hci_method) { 2747a540d6b5SSeth Forshee pr_err("HCI interface not found\n"); 27486e02cc7eSSeth Forshee return -ENODEV; 2749a540d6b5SSeth Forshee } 27506e02cc7eSSeth Forshee 2751135740deSSeth Forshee dev = kzalloc(sizeof(*dev), GFP_KERNEL); 2752135740deSSeth Forshee if (!dev) 2753135740deSSeth Forshee return -ENOMEM; 2754135740deSSeth Forshee dev->acpi_dev = acpi_dev; 2755a540d6b5SSeth Forshee dev->method_hci = hci_method; 2756135740deSSeth Forshee acpi_dev->driver_data = dev; 2757360f0f39SAzael Avalos dev_set_drvdata(&acpi_dev->dev, dev); 2758135740deSSeth Forshee 2759a2b3471bSAzael Avalos /* Query the BIOS for supported features */ 2760a2b3471bSAzael Avalos 2761a2b3471bSAzael Avalos /* 2762a2b3471bSAzael Avalos * The "Special Functions" are always supported by the laptops 2763a2b3471bSAzael Avalos * with the new keyboard layout, query for its presence to help 2764a2b3471bSAzael Avalos * determine the keymap layout to use. 2765a2b3471bSAzael Avalos */ 2766fb42d1f4SAzael Avalos ret = toshiba_function_keys_get(dev, &special_functions); 2767a2b3471bSAzael Avalos dev->kbd_function_keys_supported = !ret; 2768a2b3471bSAzael Avalos 27696e02cc7eSSeth Forshee if (toshiba_acpi_setup_keyboard(dev)) 2770135740deSSeth Forshee pr_info("Unable to activate hotkeys\n"); 2771135740deSSeth Forshee 2772135740deSSeth Forshee mutex_init(&dev->mutex); 2773135740deSSeth Forshee 277462cce752SSeth Forshee ret = toshiba_acpi_setup_backlight(dev); 277562cce752SSeth Forshee if (ret) 2776135740deSSeth Forshee goto error; 2777135740deSSeth Forshee 2778135740deSSeth Forshee /* Register rfkill switch for Bluetooth */ 27791864bbc2SAzael Avalos if (hci_get_bt_present(dev, &bt_present) == TOS_SUCCESS && bt_present) { 2780135740deSSeth Forshee dev->bt_rfk = rfkill_alloc("Toshiba Bluetooth", 2781135740deSSeth Forshee &acpi_dev->dev, 2782135740deSSeth Forshee RFKILL_TYPE_BLUETOOTH, 2783135740deSSeth Forshee &toshiba_rfk_ops, 2784135740deSSeth Forshee dev); 2785135740deSSeth Forshee if (!dev->bt_rfk) { 2786135740deSSeth Forshee pr_err("unable to allocate rfkill device\n"); 2787135740deSSeth Forshee ret = -ENOMEM; 2788135740deSSeth Forshee goto error; 2789135740deSSeth Forshee } 2790135740deSSeth Forshee 2791135740deSSeth Forshee ret = rfkill_register(dev->bt_rfk); 2792135740deSSeth Forshee if (ret) { 2793135740deSSeth Forshee pr_err("unable to register rfkill device\n"); 2794135740deSSeth Forshee rfkill_destroy(dev->bt_rfk); 2795135740deSSeth Forshee goto error; 2796135740deSSeth Forshee } 2797135740deSSeth Forshee } 2798135740deSSeth Forshee 2799135740deSSeth Forshee if (toshiba_illumination_available(dev)) { 2800135740deSSeth Forshee dev->led_dev.name = "toshiba::illumination"; 2801135740deSSeth Forshee dev->led_dev.max_brightness = 1; 2802135740deSSeth Forshee dev->led_dev.brightness_set = toshiba_illumination_set; 2803135740deSSeth Forshee dev->led_dev.brightness_get = toshiba_illumination_get; 2804135740deSSeth Forshee if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev)) 280536d03f93SSeth Forshee dev->illumination_supported = 1; 2806135740deSSeth Forshee } 2807135740deSSeth Forshee 2808def6c4e2SAzael Avalos if (toshiba_eco_mode_available(dev)) { 2809def6c4e2SAzael Avalos dev->eco_led.name = "toshiba::eco_mode"; 2810def6c4e2SAzael Avalos dev->eco_led.max_brightness = 1; 2811def6c4e2SAzael Avalos dev->eco_led.brightness_set = toshiba_eco_mode_set_status; 2812def6c4e2SAzael Avalos dev->eco_led.brightness_get = toshiba_eco_mode_get_status; 2813def6c4e2SAzael Avalos if (!led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led)) 2814def6c4e2SAzael Avalos dev->eco_supported = 1; 2815def6c4e2SAzael Avalos } 2816def6c4e2SAzael Avalos 281793f8c16dSAzael Avalos dev->kbd_illum_supported = toshiba_kbd_illum_available(dev); 2818360f0f39SAzael Avalos /* 2819360f0f39SAzael Avalos * Only register the LED if KBD illumination is supported 2820360f0f39SAzael Avalos * and the keyboard backlight operation mode is set to FN-Z 2821360f0f39SAzael Avalos */ 2822360f0f39SAzael Avalos if (dev->kbd_illum_supported && dev->kbd_mode == SCI_KBD_MODE_FNZ) { 2823360f0f39SAzael Avalos dev->kbd_led.name = "toshiba::kbd_backlight"; 2824360f0f39SAzael Avalos dev->kbd_led.max_brightness = 1; 2825360f0f39SAzael Avalos dev->kbd_led.brightness_set = toshiba_kbd_backlight_set; 2826360f0f39SAzael Avalos dev->kbd_led.brightness_get = toshiba_kbd_backlight_get; 2827360f0f39SAzael Avalos if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led)) 2828360f0f39SAzael Avalos dev->kbd_led_registered = 1; 2829360f0f39SAzael Avalos } 2830360f0f39SAzael Avalos 28319d8658acSAzael Avalos ret = toshiba_touchpad_get(dev, &dummy); 28329d8658acSAzael Avalos dev->touchpad_supported = !ret; 28339d8658acSAzael Avalos 28345a2813e9SAzael Avalos ret = toshiba_accelerometer_supported(dev); 28355a2813e9SAzael Avalos dev->accelerometer_supported = !ret; 28365a2813e9SAzael Avalos 2837c8c91842SAzael Avalos toshiba_usb_sleep_charge_available(dev); 2838e26ffe51SAzael Avalos 2839bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(dev, &dummy); 2840bb3fe01fSAzael Avalos dev->usb_rapid_charge_supported = !ret; 2841bb3fe01fSAzael Avalos 2842172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(dev, &dummy); 2843172ce0a9SAzael Avalos dev->usb_sleep_music_supported = !ret; 2844172ce0a9SAzael Avalos 284535d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(dev, &dummy); 284635d53ceaSAzael Avalos dev->panel_power_on_supported = !ret; 284735d53ceaSAzael Avalos 284817fe4b3dSAzael Avalos ret = toshiba_usb_three_get(dev, &dummy); 284917fe4b3dSAzael Avalos dev->usb_three_supported = !ret; 285017fe4b3dSAzael Avalos 285136d03f93SSeth Forshee ret = get_video_status(dev, &dummy); 285236d03f93SSeth Forshee dev->video_supported = !ret; 285336d03f93SSeth Forshee 285436d03f93SSeth Forshee ret = get_fan_status(dev, &dummy); 285536d03f93SSeth Forshee dev->fan_supported = !ret; 285636d03f93SSeth Forshee 2857fb42d1f4SAzael Avalos /* 2858fb42d1f4SAzael Avalos * Enable the "Special Functions" mode only if they are 2859fb42d1f4SAzael Avalos * supported and if they are activated. 2860fb42d1f4SAzael Avalos */ 2861fb42d1f4SAzael Avalos if (dev->kbd_function_keys_supported && special_functions) 2862fb42d1f4SAzael Avalos toshiba_acpi_enable_special_functions(dev); 2863fb42d1f4SAzael Avalos 2864360f0f39SAzael Avalos ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, 2865360f0f39SAzael Avalos &toshiba_attr_group); 2866360f0f39SAzael Avalos if (ret) { 2867360f0f39SAzael Avalos dev->sysfs_created = 0; 2868360f0f39SAzael Avalos goto error; 2869360f0f39SAzael Avalos } 2870360f0f39SAzael Avalos dev->sysfs_created = !ret; 2871360f0f39SAzael Avalos 287236d03f93SSeth Forshee create_toshiba_proc_entries(dev); 287336d03f93SSeth Forshee 287429cd293fSSeth Forshee toshiba_acpi = dev; 287529cd293fSSeth Forshee 2876135740deSSeth Forshee return 0; 2877135740deSSeth Forshee 2878135740deSSeth Forshee error: 287951fac838SRafael J. Wysocki toshiba_acpi_remove(acpi_dev); 2880135740deSSeth Forshee return ret; 2881135740deSSeth Forshee } 2882135740deSSeth Forshee 2883135740deSSeth Forshee static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) 2884135740deSSeth Forshee { 2885135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 288680546905SAzael Avalos int ret; 28876335e4d5SMatthew Garrett 288871454d78SAzael Avalos switch (event) { 288971454d78SAzael Avalos case 0x80: /* Hotkeys and some system events */ 289071454d78SAzael Avalos toshiba_acpi_process_hotkeys(dev); 289111948b93SSeth Forshee break; 2892bab09e23SAzael Avalos case 0x81: /* Dock events */ 2893bab09e23SAzael Avalos case 0x82: 2894bab09e23SAzael Avalos case 0x83: 2895bab09e23SAzael Avalos pr_info("Dock event received %x\n", event); 2896bab09e23SAzael Avalos break; 2897bab09e23SAzael Avalos case 0x88: /* Thermal events */ 2898bab09e23SAzael Avalos pr_info("Thermal event received\n"); 2899bab09e23SAzael Avalos break; 2900bab09e23SAzael Avalos case 0x8f: /* LID closed */ 2901bab09e23SAzael Avalos case 0x90: /* LID is closed and Dock has been ejected */ 2902bab09e23SAzael Avalos break; 2903bab09e23SAzael Avalos case 0x8c: /* SATA power events */ 2904bab09e23SAzael Avalos case 0x8b: 2905bab09e23SAzael Avalos pr_info("SATA power event received %x\n", event); 2906bab09e23SAzael Avalos break; 290780546905SAzael Avalos case 0x92: /* Keyboard backlight mode changed */ 290880546905SAzael Avalos /* Update sysfs entries */ 290980546905SAzael Avalos ret = sysfs_update_group(&acpi_dev->dev.kobj, 291080546905SAzael Avalos &toshiba_attr_group); 291180546905SAzael Avalos if (ret) 291280546905SAzael Avalos pr_err("Unable to update sysfs entries\n"); 291380546905SAzael Avalos break; 2914bab09e23SAzael Avalos case 0x85: /* Unknown */ 2915bab09e23SAzael Avalos case 0x8d: /* Unknown */ 291671454d78SAzael Avalos case 0x8e: /* Unknown */ 2917bab09e23SAzael Avalos case 0x94: /* Unknown */ 2918bab09e23SAzael Avalos case 0x95: /* Unknown */ 291911948b93SSeth Forshee default: 292071454d78SAzael Avalos pr_info("Unknown event received %x\n", event); 292111948b93SSeth Forshee break; 29226335e4d5SMatthew Garrett } 2923bab09e23SAzael Avalos 2924bab09e23SAzael Avalos acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class, 2925bab09e23SAzael Avalos dev_name(&acpi_dev->dev), 2926bab09e23SAzael Avalos event, 0); 292729cd293fSSeth Forshee } 29286335e4d5SMatthew Garrett 29293567a4e2SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 293043d2fd3bSRafael J. Wysocki static int toshiba_acpi_suspend(struct device *device) 293129cd293fSSeth Forshee { 293243d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 293329cd293fSSeth Forshee u32 result; 293429cd293fSSeth Forshee 293529cd293fSSeth Forshee if (dev->hotkey_dev) 2936893f3f62SAzael Avalos result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE); 293729cd293fSSeth Forshee 293829cd293fSSeth Forshee return 0; 293929cd293fSSeth Forshee } 294029cd293fSSeth Forshee 294143d2fd3bSRafael J. Wysocki static int toshiba_acpi_resume(struct device *device) 294229cd293fSSeth Forshee { 294343d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 29441f28f290SAzael Avalos int error; 294529cd293fSSeth Forshee 2946e7fdb762SBenjamin Tissoires if (dev->hotkey_dev) { 29471f28f290SAzael Avalos error = toshiba_acpi_enable_hotkeys(dev); 29481f28f290SAzael Avalos if (error) 2949e7fdb762SBenjamin Tissoires pr_info("Unable to re-enable hotkeys\n"); 2950e7fdb762SBenjamin Tissoires } 295129cd293fSSeth Forshee 295229cd293fSSeth Forshee return 0; 295329cd293fSSeth Forshee } 29543567a4e2SRafael J. Wysocki #endif 29556335e4d5SMatthew Garrett 295643d2fd3bSRafael J. Wysocki static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm, 295743d2fd3bSRafael J. Wysocki toshiba_acpi_suspend, toshiba_acpi_resume); 295843d2fd3bSRafael J. Wysocki 2959135740deSSeth Forshee static struct acpi_driver toshiba_acpi_driver = { 2960135740deSSeth Forshee .name = "Toshiba ACPI driver", 2961135740deSSeth Forshee .owner = THIS_MODULE, 2962135740deSSeth Forshee .ids = toshiba_device_ids, 2963135740deSSeth Forshee .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, 2964135740deSSeth Forshee .ops = { 2965135740deSSeth Forshee .add = toshiba_acpi_add, 2966135740deSSeth Forshee .remove = toshiba_acpi_remove, 2967135740deSSeth Forshee .notify = toshiba_acpi_notify, 2968135740deSSeth Forshee }, 296943d2fd3bSRafael J. Wysocki .drv.pm = &toshiba_acpi_pm, 2970135740deSSeth Forshee }; 2971b4f9fe12SLen Brown 2972b4f9fe12SLen Brown static int __init toshiba_acpi_init(void) 2973b4f9fe12SLen Brown { 2974135740deSSeth Forshee int ret; 2975b4f9fe12SLen Brown 2976f11f999eSSeth Forshee /* 2977f11f999eSSeth Forshee * Machines with this WMI guid aren't supported due to bugs in 2978f11f999eSSeth Forshee * their AML. This check relies on wmi initializing before 2979f11f999eSSeth Forshee * toshiba_acpi to guarantee guids have been identified. 2980f11f999eSSeth Forshee */ 2981f11f999eSSeth Forshee if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) 2982f11f999eSSeth Forshee return -ENODEV; 2983f11f999eSSeth Forshee 2984b4f9fe12SLen Brown toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); 2985b4f9fe12SLen Brown if (!toshiba_proc_dir) { 2986135740deSSeth Forshee pr_err("Unable to create proc dir " PROC_TOSHIBA "\n"); 2987b4f9fe12SLen Brown return -ENODEV; 2988b4f9fe12SLen Brown } 2989b4f9fe12SLen Brown 2990135740deSSeth Forshee ret = acpi_bus_register_driver(&toshiba_acpi_driver); 2991b4f9fe12SLen Brown if (ret) { 2992135740deSSeth Forshee pr_err("Failed to register ACPI driver: %d\n", ret); 2993135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 2994135740deSSeth Forshee } 2995135740deSSeth Forshee 2996b4f9fe12SLen Brown return ret; 2997b4f9fe12SLen Brown } 2998b4f9fe12SLen Brown 2999135740deSSeth Forshee static void __exit toshiba_acpi_exit(void) 3000135740deSSeth Forshee { 3001135740deSSeth Forshee acpi_bus_unregister_driver(&toshiba_acpi_driver); 3002135740deSSeth Forshee if (toshiba_proc_dir) 3003135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 3004b4f9fe12SLen Brown } 3005b4f9fe12SLen Brown 3006b4f9fe12SLen Brown module_init(toshiba_acpi_init); 3007b4f9fe12SLen Brown module_exit(toshiba_acpi_exit); 3008