1b4f9fe12SLen Brown /* 2b4f9fe12SLen Brown * toshiba_acpi.c - Toshiba Laptop ACPI Extras 3b4f9fe12SLen Brown * 4b4f9fe12SLen Brown * 5b4f9fe12SLen Brown * Copyright (C) 2002-2004 John Belmonte 6b4f9fe12SLen Brown * Copyright (C) 2008 Philip Langdale 76c3f6e6cSPierre Ducroquet * Copyright (C) 2010 Pierre Ducroquet 8548c4306SAzael Avalos * Copyright (C) 2014 Azael Avalos 9b4f9fe12SLen Brown * 10b4f9fe12SLen Brown * This program is free software; you can redistribute it and/or modify 11b4f9fe12SLen Brown * it under the terms of the GNU General Public License as published by 12b4f9fe12SLen Brown * the Free Software Foundation; either version 2 of the License, or 13b4f9fe12SLen Brown * (at your option) any later version. 14b4f9fe12SLen Brown * 15b4f9fe12SLen Brown * This program is distributed in the hope that it will be useful, 16b4f9fe12SLen Brown * but WITHOUT ANY WARRANTY; without even the implied warranty of 17b4f9fe12SLen Brown * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18b4f9fe12SLen Brown * GNU General Public License for more details. 19b4f9fe12SLen Brown * 20b4f9fe12SLen Brown * You should have received a copy of the GNU General Public License 21b4f9fe12SLen Brown * along with this program; if not, write to the Free Software 22b4f9fe12SLen Brown * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23b4f9fe12SLen Brown * 24b4f9fe12SLen Brown * 25b4f9fe12SLen Brown * The devolpment page for this driver is located at 26b4f9fe12SLen Brown * http://memebeam.org/toys/ToshibaAcpiDriver. 27b4f9fe12SLen Brown * 28b4f9fe12SLen Brown * Credits: 29b4f9fe12SLen Brown * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse 30b4f9fe12SLen Brown * engineering the Windows drivers 31b4f9fe12SLen Brown * Yasushi Nagato - changes for linux kernel 2.4 -> 2.5 32b4f9fe12SLen Brown * Rob Miller - TV out and hotkeys help 33b4f9fe12SLen Brown * 34b4f9fe12SLen Brown * 35b4f9fe12SLen Brown * TODO 36b4f9fe12SLen Brown * 37b4f9fe12SLen Brown */ 38b4f9fe12SLen Brown 397e33460dSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 407e33460dSJoe Perches 41548c4306SAzael Avalos #define TOSHIBA_ACPI_VERSION "0.20" 42b4f9fe12SLen Brown #define PROC_INTERFACE_VERSION 1 43b4f9fe12SLen Brown 44b4f9fe12SLen Brown #include <linux/kernel.h> 45b4f9fe12SLen Brown #include <linux/module.h> 46b4f9fe12SLen Brown #include <linux/init.h> 47b4f9fe12SLen Brown #include <linux/types.h> 48b4f9fe12SLen Brown #include <linux/proc_fs.h> 49936c8bcdSAlexey Dobriyan #include <linux/seq_file.h> 50b4f9fe12SLen Brown #include <linux/backlight.h> 51b4f9fe12SLen Brown #include <linux/rfkill.h> 526335e4d5SMatthew Garrett #include <linux/input.h> 53384a7cd9SDmitry Torokhov #include <linux/input/sparse-keymap.h> 546c3f6e6cSPierre Ducroquet #include <linux/leds.h> 555a0e3ad6STejun Heo #include <linux/slab.h> 5629cd293fSSeth Forshee #include <linux/workqueue.h> 5729cd293fSSeth Forshee #include <linux/i8042.h> 588b48463fSLv Zheng #include <linux/acpi.h> 59fe808bfbSTakashi Iwai #include <linux/dmi.h> 60b4f9fe12SLen Brown #include <asm/uaccess.h> 61b4f9fe12SLen Brown 62b4f9fe12SLen Brown MODULE_AUTHOR("John Belmonte"); 63b4f9fe12SLen Brown MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); 64b4f9fe12SLen Brown MODULE_LICENSE("GPL"); 65b4f9fe12SLen Brown 66f11f999eSSeth Forshee #define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100" 67f11f999eSSeth Forshee 6829cd293fSSeth Forshee /* Scan code for Fn key on TOS1900 models */ 6929cd293fSSeth Forshee #define TOS1900_FN_SCAN 0x6e 7029cd293fSSeth Forshee 71b4f9fe12SLen Brown /* Toshiba ACPI method paths */ 72b4f9fe12SLen Brown #define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX" 73b4f9fe12SLen Brown 74258c5903SAzael Avalos /* The Toshiba configuration interface is composed of the HCI and the SCI, 75258c5903SAzael Avalos * which are defined as follows: 76b4f9fe12SLen Brown * 77b4f9fe12SLen Brown * HCI is Toshiba's "Hardware Control Interface" which is supposed to 78b4f9fe12SLen Brown * be uniform across all their models. Ideally we would just call 79b4f9fe12SLen Brown * dedicated ACPI methods instead of using this primitive interface. 80b4f9fe12SLen Brown * However the ACPI methods seem to be incomplete in some areas (for 81b4f9fe12SLen Brown * example they allow setting, but not reading, the LCD brightness value), 82b4f9fe12SLen Brown * so this is still useful. 8384a6273fSAzael Avalos * 8484a6273fSAzael Avalos * SCI stands for "System Configuration Interface" which aim is to 8584a6273fSAzael Avalos * conceal differences in hardware between different models. 86b4f9fe12SLen Brown */ 87b4f9fe12SLen Brown 88258c5903SAzael Avalos #define TCI_WORDS 6 89b4f9fe12SLen Brown 90b4f9fe12SLen Brown /* operations */ 91b4f9fe12SLen Brown #define HCI_SET 0xff00 92b4f9fe12SLen Brown #define HCI_GET 0xfe00 9384a6273fSAzael Avalos #define SCI_OPEN 0xf100 9484a6273fSAzael Avalos #define SCI_CLOSE 0xf200 9584a6273fSAzael Avalos #define SCI_GET 0xf300 9684a6273fSAzael Avalos #define SCI_SET 0xf400 97b4f9fe12SLen Brown 98b4f9fe12SLen Brown /* return codes */ 991864bbc2SAzael Avalos #define TOS_SUCCESS 0x0000 1001864bbc2SAzael Avalos #define TOS_OPEN_CLOSE_OK 0x0044 1011864bbc2SAzael Avalos #define TOS_FAILURE 0x1000 1021864bbc2SAzael Avalos #define TOS_NOT_SUPPORTED 0x8000 1031864bbc2SAzael Avalos #define TOS_ALREADY_OPEN 0x8100 1041864bbc2SAzael Avalos #define TOS_NOT_OPENED 0x8200 1051864bbc2SAzael Avalos #define TOS_INPUT_DATA_ERROR 0x8300 1061864bbc2SAzael Avalos #define TOS_WRITE_PROTECTED 0x8400 1071864bbc2SAzael Avalos #define TOS_NOT_PRESENT 0x8600 1081864bbc2SAzael Avalos #define TOS_FIFO_EMPTY 0x8c00 1091864bbc2SAzael Avalos #define TOS_DATA_NOT_AVAILABLE 0x8d20 1101864bbc2SAzael Avalos #define TOS_NOT_INITIALIZED 0x8d50 11198fc4ec6SAzael Avalos #define TOS_NOT_INSTALLED 0x8e00 112b4f9fe12SLen Brown 113b4f9fe12SLen Brown /* registers */ 114b4f9fe12SLen Brown #define HCI_FAN 0x0004 115121b7b0dSAkio Idehara #define HCI_TR_BACKLIGHT 0x0005 116b4f9fe12SLen Brown #define HCI_SYSTEM_EVENT 0x0016 117b4f9fe12SLen Brown #define HCI_VIDEO_OUT 0x001c 118b4f9fe12SLen Brown #define HCI_HOTKEY_EVENT 0x001e 119b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS 0x002a 120b4f9fe12SLen Brown #define HCI_WIRELESS 0x0056 1215a2813e9SAzael Avalos #define HCI_ACCELEROMETER 0x006d 122360f0f39SAzael Avalos #define HCI_KBD_ILLUMINATION 0x0095 123def6c4e2SAzael Avalos #define HCI_ECO_MODE 0x0097 1245a2813e9SAzael Avalos #define HCI_ACCELEROMETER2 0x00a6 125fdb79081SAzael Avalos #define SCI_ILLUMINATION 0x014e 126e26ffe51SAzael Avalos #define SCI_USB_SLEEP_CHARGE 0x0150 127360f0f39SAzael Avalos #define SCI_KBD_ILLUM_STATUS 0x015c 128172ce0a9SAzael Avalos #define SCI_USB_SLEEP_MUSIC 0x015e 1299d8658acSAzael Avalos #define SCI_TOUCHPAD 0x050e 130*bae84195SAzael Avalos #define SCI_KBD_FUNCTION_KEYS 0x0522 131b4f9fe12SLen Brown 132b4f9fe12SLen Brown /* field definitions */ 1335a2813e9SAzael Avalos #define HCI_ACCEL_MASK 0x7fff 13429cd293fSSeth Forshee #define HCI_HOTKEY_DISABLE 0x0b 13529cd293fSSeth Forshee #define HCI_HOTKEY_ENABLE 0x09 136b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_BITS 3 137b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) 138b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS) 139360f0f39SAzael Avalos #define HCI_MISC_SHIFT 0x10 140b4f9fe12SLen Brown #define HCI_VIDEO_OUT_LCD 0x1 141b4f9fe12SLen Brown #define HCI_VIDEO_OUT_CRT 0x2 142b4f9fe12SLen Brown #define HCI_VIDEO_OUT_TV 0x4 143b4f9fe12SLen Brown #define HCI_WIRELESS_KILL_SWITCH 0x01 144b4f9fe12SLen Brown #define HCI_WIRELESS_BT_PRESENT 0x0f 145b4f9fe12SLen Brown #define HCI_WIRELESS_BT_ATTACH 0x40 146b4f9fe12SLen Brown #define HCI_WIRELESS_BT_POWER 0x80 14793f8c16dSAzael Avalos #define SCI_KBD_MODE_MASK 0x1f 148360f0f39SAzael Avalos #define SCI_KBD_MODE_FNZ 0x1 149360f0f39SAzael Avalos #define SCI_KBD_MODE_AUTO 0x2 15093f8c16dSAzael Avalos #define SCI_KBD_MODE_ON 0x8 15193f8c16dSAzael Avalos #define SCI_KBD_MODE_OFF 0x10 15293f8c16dSAzael Avalos #define SCI_KBD_TIME_MAX 0x3c001a 153e26ffe51SAzael Avalos #define SCI_USB_CHARGE_MODE_MASK 0xff 154e26ffe51SAzael Avalos #define SCI_USB_CHARGE_DISABLED 0x30000 155e26ffe51SAzael Avalos #define SCI_USB_CHARGE_ALTERNATE 0x30009 156e26ffe51SAzael Avalos #define SCI_USB_CHARGE_AUTO 0x30021 157182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_MASK 0x7 158182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_OFF 0x1 159182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_ON 0x4 160182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL 0x0200 161bb3fe01fSAzael Avalos #define SCI_USB_CHARGE_RAPID_DSP 0x0300 162b4f9fe12SLen Brown 163135740deSSeth Forshee struct toshiba_acpi_dev { 164135740deSSeth Forshee struct acpi_device *acpi_dev; 165135740deSSeth Forshee const char *method_hci; 166135740deSSeth Forshee struct rfkill *bt_rfk; 167135740deSSeth Forshee struct input_dev *hotkey_dev; 16829cd293fSSeth Forshee struct work_struct hotkey_work; 169135740deSSeth Forshee struct backlight_device *backlight_dev; 170135740deSSeth Forshee struct led_classdev led_dev; 171360f0f39SAzael Avalos struct led_classdev kbd_led; 172def6c4e2SAzael Avalos struct led_classdev eco_led; 17336d03f93SSeth Forshee 174135740deSSeth Forshee int force_fan; 175135740deSSeth Forshee int last_key_event; 176135740deSSeth Forshee int key_event_valid; 17793f8c16dSAzael Avalos int kbd_type; 178360f0f39SAzael Avalos int kbd_mode; 179360f0f39SAzael Avalos int kbd_time; 180182bcaa5SAzael Avalos int usbsc_bat_level; 181135740deSSeth Forshee 182592b746cSDan Carpenter unsigned int illumination_supported:1; 183592b746cSDan Carpenter unsigned int video_supported:1; 184592b746cSDan Carpenter unsigned int fan_supported:1; 185592b746cSDan Carpenter unsigned int system_event_supported:1; 18629cd293fSSeth Forshee unsigned int ntfy_supported:1; 18729cd293fSSeth Forshee unsigned int info_supported:1; 188121b7b0dSAkio Idehara unsigned int tr_backlight_supported:1; 189360f0f39SAzael Avalos unsigned int kbd_illum_supported:1; 190360f0f39SAzael Avalos unsigned int kbd_led_registered:1; 1919d8658acSAzael Avalos unsigned int touchpad_supported:1; 192def6c4e2SAzael Avalos unsigned int eco_supported:1; 1935a2813e9SAzael Avalos unsigned int accelerometer_supported:1; 194e26ffe51SAzael Avalos unsigned int usb_sleep_charge_supported:1; 195bb3fe01fSAzael Avalos unsigned int usb_rapid_charge_supported:1; 196172ce0a9SAzael Avalos unsigned int usb_sleep_music_supported:1; 197*bae84195SAzael Avalos unsigned int kbd_function_keys_supported:1; 198360f0f39SAzael Avalos unsigned int sysfs_created:1; 19936d03f93SSeth Forshee 200135740deSSeth Forshee struct mutex mutex; 201135740deSSeth Forshee }; 202135740deSSeth Forshee 20329cd293fSSeth Forshee static struct toshiba_acpi_dev *toshiba_acpi; 20429cd293fSSeth Forshee 205b4f9fe12SLen Brown static const struct acpi_device_id toshiba_device_ids[] = { 206b4f9fe12SLen Brown {"TOS6200", 0}, 20763a9e016SOndrej Zary {"TOS6207", 0}, 208b4f9fe12SLen Brown {"TOS6208", 0}, 209b4f9fe12SLen Brown {"TOS1900", 0}, 210b4f9fe12SLen Brown {"", 0}, 211b4f9fe12SLen Brown }; 212b4f9fe12SLen Brown MODULE_DEVICE_TABLE(acpi, toshiba_device_ids); 213b4f9fe12SLen Brown 214b859f159SGreg Kroah-Hartman static const struct key_entry toshiba_acpi_keymap[] = { 215fec278a1SUnai Uribarri { KE_KEY, 0x9e, { KEY_RFKILL } }, 216384a7cd9SDmitry Torokhov { KE_KEY, 0x101, { KEY_MUTE } }, 217384a7cd9SDmitry Torokhov { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 218384a7cd9SDmitry Torokhov { KE_KEY, 0x103, { KEY_ZOOMIN } }, 219408a5d13SAzael Avalos { KE_KEY, 0x10f, { KEY_TAB } }, 220af502837SAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 221af502837SAzael Avalos { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 222384a7cd9SDmitry Torokhov { KE_KEY, 0x13b, { KEY_COFFEE } }, 223384a7cd9SDmitry Torokhov { KE_KEY, 0x13c, { KEY_BATTERY } }, 224384a7cd9SDmitry Torokhov { KE_KEY, 0x13d, { KEY_SLEEP } }, 225384a7cd9SDmitry Torokhov { KE_KEY, 0x13e, { KEY_SUSPEND } }, 226384a7cd9SDmitry Torokhov { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } }, 227384a7cd9SDmitry Torokhov { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } }, 228384a7cd9SDmitry Torokhov { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } }, 229384a7cd9SDmitry Torokhov { KE_KEY, 0x142, { KEY_WLAN } }, 230af502837SAzael Avalos { KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } }, 231a49010f5SJon Dowland { KE_KEY, 0x17f, { KEY_FN } }, 232384a7cd9SDmitry Torokhov { KE_KEY, 0xb05, { KEY_PROG2 } }, 233384a7cd9SDmitry Torokhov { KE_KEY, 0xb06, { KEY_WWW } }, 234384a7cd9SDmitry Torokhov { KE_KEY, 0xb07, { KEY_MAIL } }, 235384a7cd9SDmitry Torokhov { KE_KEY, 0xb30, { KEY_STOP } }, 236384a7cd9SDmitry Torokhov { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } }, 237384a7cd9SDmitry Torokhov { KE_KEY, 0xb32, { KEY_NEXTSONG } }, 238384a7cd9SDmitry Torokhov { KE_KEY, 0xb33, { KEY_PLAYPAUSE } }, 239384a7cd9SDmitry Torokhov { KE_KEY, 0xb5a, { KEY_MEDIA } }, 240408a5d13SAzael Avalos { KE_IGNORE, 0x1430, { KEY_RESERVED } }, /* Wake from sleep */ 241408a5d13SAzael Avalos { KE_IGNORE, 0x1501, { KEY_RESERVED } }, /* Output changed */ 242408a5d13SAzael Avalos { KE_IGNORE, 0x1502, { KEY_RESERVED } }, /* HDMI plugged/unplugged */ 243408a5d13SAzael Avalos { KE_IGNORE, 0x1ABE, { KEY_RESERVED } }, /* Protection level set */ 244408a5d13SAzael Avalos { KE_IGNORE, 0x1ABF, { KEY_RESERVED } }, /* Protection level off */ 245384a7cd9SDmitry Torokhov { KE_END, 0 }, 2466335e4d5SMatthew Garrett }; 2476335e4d5SMatthew Garrett 248fe808bfbSTakashi Iwai /* alternative keymap */ 249fe808bfbSTakashi Iwai static const struct dmi_system_id toshiba_alt_keymap_dmi[] = { 250fe808bfbSTakashi Iwai { 251fe808bfbSTakashi Iwai .matches = { 252fe808bfbSTakashi Iwai DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 253fe808bfbSTakashi Iwai DMI_MATCH(DMI_PRODUCT_NAME, "Satellite M840"), 254fe808bfbSTakashi Iwai }, 255fe808bfbSTakashi Iwai }, 256e6efad7fSAzael Avalos { 257e6efad7fSAzael Avalos .matches = { 258e6efad7fSAzael Avalos DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 259e6efad7fSAzael Avalos DMI_MATCH(DMI_PRODUCT_NAME, "Qosmio X75-A"), 260e6efad7fSAzael Avalos }, 261e6efad7fSAzael Avalos }, 262b1bde689SAaron Lu { 263b1bde689SAaron Lu .matches = { 264b1bde689SAaron Lu DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), 265b1bde689SAaron Lu DMI_MATCH(DMI_PRODUCT_NAME, "TECRA A50-A"), 266b1bde689SAaron Lu }, 267b1bde689SAaron Lu }, 268fe808bfbSTakashi Iwai {} 269fe808bfbSTakashi Iwai }; 270fe808bfbSTakashi Iwai 271fe808bfbSTakashi Iwai static const struct key_entry toshiba_acpi_alt_keymap[] = { 272fe808bfbSTakashi Iwai { KE_KEY, 0x157, { KEY_MUTE } }, 273fe808bfbSTakashi Iwai { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 274fe808bfbSTakashi Iwai { KE_KEY, 0x103, { KEY_ZOOMIN } }, 275e6efad7fSAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 276fe808bfbSTakashi Iwai { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 277fe808bfbSTakashi Iwai { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } }, 278fe808bfbSTakashi Iwai { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } }, 279fe808bfbSTakashi Iwai { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } }, 280fe808bfbSTakashi Iwai { KE_KEY, 0x158, { KEY_WLAN } }, 281fe808bfbSTakashi Iwai { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } }, 282fe808bfbSTakashi Iwai { KE_END, 0 }, 283fe808bfbSTakashi Iwai }; 284fe808bfbSTakashi Iwai 285b4f9fe12SLen Brown /* utility 286b4f9fe12SLen Brown */ 287b4f9fe12SLen Brown 288b4f9fe12SLen Brown static __inline__ void _set_bit(u32 * word, u32 mask, int value) 289b4f9fe12SLen Brown { 290b4f9fe12SLen Brown *word = (*word & ~mask) | (mask * value); 291b4f9fe12SLen Brown } 292b4f9fe12SLen Brown 293b4f9fe12SLen Brown /* acpi interface wrappers 294b4f9fe12SLen Brown */ 295b4f9fe12SLen Brown 296b4f9fe12SLen Brown static int write_acpi_int(const char *methodName, int val) 297b4f9fe12SLen Brown { 298b4f9fe12SLen Brown acpi_status status; 299b4f9fe12SLen Brown 300619400daSZhang Rui status = acpi_execute_simple_method(NULL, (char *)methodName, val); 30132bcd5cbSSeth Forshee return (status == AE_OK) ? 0 : -EIO; 302b4f9fe12SLen Brown } 303b4f9fe12SLen Brown 304258c5903SAzael Avalos /* Perform a raw configuration call. Here we don't care about input or output 305258c5903SAzael Avalos * buffer format. 306b4f9fe12SLen Brown */ 307258c5903SAzael Avalos static acpi_status tci_raw(struct toshiba_acpi_dev *dev, 308258c5903SAzael Avalos const u32 in[TCI_WORDS], u32 out[TCI_WORDS]) 309b4f9fe12SLen Brown { 310b4f9fe12SLen Brown struct acpi_object_list params; 311258c5903SAzael Avalos union acpi_object in_objs[TCI_WORDS]; 312b4f9fe12SLen Brown struct acpi_buffer results; 313258c5903SAzael Avalos union acpi_object out_objs[TCI_WORDS + 1]; 314b4f9fe12SLen Brown acpi_status status; 315b4f9fe12SLen Brown int i; 316b4f9fe12SLen Brown 317258c5903SAzael Avalos params.count = TCI_WORDS; 318b4f9fe12SLen Brown params.pointer = in_objs; 319258c5903SAzael Avalos for (i = 0; i < TCI_WORDS; ++i) { 320b4f9fe12SLen Brown in_objs[i].type = ACPI_TYPE_INTEGER; 321b4f9fe12SLen Brown in_objs[i].integer.value = in[i]; 322b4f9fe12SLen Brown } 323b4f9fe12SLen Brown 324b4f9fe12SLen Brown results.length = sizeof(out_objs); 325b4f9fe12SLen Brown results.pointer = out_objs; 326b4f9fe12SLen Brown 3276e02cc7eSSeth Forshee status = acpi_evaluate_object(dev->acpi_dev->handle, 3286e02cc7eSSeth Forshee (char *)dev->method_hci, ¶ms, 329b4f9fe12SLen Brown &results); 330258c5903SAzael Avalos if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) { 331b4f9fe12SLen Brown for (i = 0; i < out_objs->package.count; ++i) { 332b4f9fe12SLen Brown out[i] = out_objs->package.elements[i].integer.value; 333b4f9fe12SLen Brown } 334b4f9fe12SLen Brown } 335b4f9fe12SLen Brown 336b4f9fe12SLen Brown return status; 337b4f9fe12SLen Brown } 338b4f9fe12SLen Brown 339b4f9fe12SLen Brown /* common hci tasks (get or set one or two value) 340b4f9fe12SLen Brown * 341b4f9fe12SLen Brown * In addition to the ACPI status, the HCI system returns a result which 342b4f9fe12SLen Brown * may be useful (such as "not supported"). 343b4f9fe12SLen Brown */ 344b4f9fe12SLen Brown 345893f3f62SAzael Avalos static u32 hci_write1(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 346b4f9fe12SLen Brown { 347258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 }; 348258c5903SAzael Avalos u32 out[TCI_WORDS]; 349258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 350893f3f62SAzael Avalos 351893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 352b4f9fe12SLen Brown } 353b4f9fe12SLen Brown 354893f3f62SAzael Avalos static u32 hci_read1(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 355b4f9fe12SLen Brown { 356258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 }; 357258c5903SAzael Avalos u32 out[TCI_WORDS]; 358258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 359893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 360893f3f62SAzael Avalos return TOS_FAILURE; 361893f3f62SAzael Avalos 362b4f9fe12SLen Brown *out1 = out[2]; 363893f3f62SAzael Avalos 364893f3f62SAzael Avalos return out[0]; 365b4f9fe12SLen Brown } 366b4f9fe12SLen Brown 367893f3f62SAzael Avalos static u32 hci_write2(struct toshiba_acpi_dev *dev, u32 reg, u32 in1, u32 in2) 368b4f9fe12SLen Brown { 369258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, reg, in1, in2, 0, 0 }; 370258c5903SAzael Avalos u32 out[TCI_WORDS]; 371258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 372893f3f62SAzael Avalos 373893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 374b4f9fe12SLen Brown } 375b4f9fe12SLen Brown 376893f3f62SAzael Avalos static u32 hci_read2(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1, u32 *out2) 377b4f9fe12SLen Brown { 378258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 }; 379258c5903SAzael Avalos u32 out[TCI_WORDS]; 380258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 381893f3f62SAzael Avalos if (ACPI_FAILURE(status)) 382893f3f62SAzael Avalos return TOS_FAILURE; 383893f3f62SAzael Avalos 384b4f9fe12SLen Brown *out1 = out[2]; 385b4f9fe12SLen Brown *out2 = out[3]; 386893f3f62SAzael Avalos 387893f3f62SAzael Avalos return out[0]; 388b4f9fe12SLen Brown } 389b4f9fe12SLen Brown 39084a6273fSAzael Avalos /* common sci tasks 39184a6273fSAzael Avalos */ 39284a6273fSAzael Avalos 39384a6273fSAzael Avalos static int sci_open(struct toshiba_acpi_dev *dev) 39484a6273fSAzael Avalos { 395258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 }; 396258c5903SAzael Avalos u32 out[TCI_WORDS]; 39784a6273fSAzael Avalos acpi_status status; 39884a6273fSAzael Avalos 399258c5903SAzael Avalos status = tci_raw(dev, in, out); 4001864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 40184a6273fSAzael Avalos pr_err("ACPI call to open SCI failed\n"); 40284a6273fSAzael Avalos return 0; 40384a6273fSAzael Avalos } 40484a6273fSAzael Avalos 4051864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) { 40684a6273fSAzael Avalos return 1; 4071864bbc2SAzael Avalos } else if (out[0] == TOS_ALREADY_OPEN) { 40884a6273fSAzael Avalos pr_info("Toshiba SCI already opened\n"); 40984a6273fSAzael Avalos return 1; 410fa465739SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 411fa465739SAzael Avalos /* Some BIOSes do not have the SCI open/close functions 412fa465739SAzael Avalos * implemented and return 0x8000 (Not Supported), failing to 413fa465739SAzael Avalos * register some supported features. 414fa465739SAzael Avalos * 415fa465739SAzael Avalos * Simply return 1 if we hit those affected laptops to make the 416fa465739SAzael Avalos * supported features work. 417fa465739SAzael Avalos * 418fa465739SAzael Avalos * In the case that some laptops really do not support the SCI, 419fa465739SAzael Avalos * all the SCI dependent functions check for TOS_NOT_SUPPORTED, 420fa465739SAzael Avalos * and thus, not registering support for the queried feature. 421fa465739SAzael Avalos */ 422fa465739SAzael Avalos return 1; 4231864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_PRESENT) { 42484a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 42584a6273fSAzael Avalos } 42684a6273fSAzael Avalos 42784a6273fSAzael Avalos return 0; 42884a6273fSAzael Avalos } 42984a6273fSAzael Avalos 43084a6273fSAzael Avalos static void sci_close(struct toshiba_acpi_dev *dev) 43184a6273fSAzael Avalos { 432258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 }; 433258c5903SAzael Avalos u32 out[TCI_WORDS]; 43484a6273fSAzael Avalos acpi_status status; 43584a6273fSAzael Avalos 436258c5903SAzael Avalos status = tci_raw(dev, in, out); 4371864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 43884a6273fSAzael Avalos pr_err("ACPI call to close SCI failed\n"); 43984a6273fSAzael Avalos return; 44084a6273fSAzael Avalos } 44184a6273fSAzael Avalos 4421864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) 44384a6273fSAzael Avalos return; 4441864bbc2SAzael Avalos else if (out[0] == TOS_NOT_OPENED) 44584a6273fSAzael Avalos pr_info("Toshiba SCI not opened\n"); 4461864bbc2SAzael Avalos else if (out[0] == TOS_NOT_PRESENT) 44784a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n"); 44884a6273fSAzael Avalos } 44984a6273fSAzael Avalos 450893f3f62SAzael Avalos static u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 45184a6273fSAzael Avalos { 452258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 }; 453258c5903SAzael Avalos u32 out[TCI_WORDS]; 454258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out); 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 56393f8c16dSAzael Avalos /* Check for keyboard backlight timeout max value, 56493f8c16dSAzael Avalos * previous kbd backlight implementation set this to 56593f8c16dSAzael Avalos * 0x3c0003, and now the new implementation set this 56693f8c16dSAzael Avalos * to 0x3c001a, use this to distinguish between them 56793f8c16dSAzael Avalos */ 56893f8c16dSAzael Avalos if (out[3] == SCI_KBD_TIME_MAX) 56993f8c16dSAzael Avalos dev->kbd_type = 2; 57093f8c16dSAzael Avalos else 57193f8c16dSAzael Avalos dev->kbd_type = 1; 57293f8c16dSAzael Avalos /* Get the current keyboard backlight mode */ 57393f8c16dSAzael Avalos dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK; 57493f8c16dSAzael Avalos /* Get the current time (1-60 seconds) */ 57593f8c16dSAzael Avalos dev->kbd_time = out[2] >> HCI_MISC_SHIFT; 57693f8c16dSAzael Avalos 57793f8c16dSAzael Avalos return 1; 57893f8c16dSAzael Avalos } 57993f8c16dSAzael Avalos 580360f0f39SAzael Avalos static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time) 581360f0f39SAzael Avalos { 582360f0f39SAzael Avalos u32 result; 583360f0f39SAzael Avalos 584360f0f39SAzael Avalos if (!sci_open(dev)) 585360f0f39SAzael Avalos return -EIO; 586360f0f39SAzael Avalos 587893f3f62SAzael Avalos result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time); 588360f0f39SAzael Avalos sci_close(dev); 589893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 590360f0f39SAzael Avalos pr_err("ACPI call to set KBD backlight status failed\n"); 591360f0f39SAzael Avalos return -EIO; 5921864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 593360f0f39SAzael Avalos pr_info("Keyboard backlight status not supported\n"); 594360f0f39SAzael Avalos return -ENODEV; 595360f0f39SAzael Avalos } 596360f0f39SAzael Avalos 597360f0f39SAzael Avalos return 0; 598360f0f39SAzael Avalos } 599360f0f39SAzael Avalos 600360f0f39SAzael Avalos static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time) 601360f0f39SAzael Avalos { 602360f0f39SAzael Avalos u32 result; 603360f0f39SAzael Avalos 604360f0f39SAzael Avalos if (!sci_open(dev)) 605360f0f39SAzael Avalos return -EIO; 606360f0f39SAzael Avalos 607893f3f62SAzael Avalos result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time); 608360f0f39SAzael Avalos sci_close(dev); 609893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 610360f0f39SAzael Avalos pr_err("ACPI call to get KBD backlight status failed\n"); 611360f0f39SAzael Avalos return -EIO; 6121864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 613360f0f39SAzael Avalos pr_info("Keyboard backlight status not supported\n"); 614360f0f39SAzael Avalos return -ENODEV; 615360f0f39SAzael Avalos } 616360f0f39SAzael Avalos 617360f0f39SAzael Avalos return 0; 618360f0f39SAzael Avalos } 619360f0f39SAzael Avalos 620360f0f39SAzael Avalos static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev) 621360f0f39SAzael Avalos { 622360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 623360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 624360f0f39SAzael Avalos u32 state, result; 625360f0f39SAzael Avalos 626360f0f39SAzael Avalos /* Check the keyboard backlight state */ 627893f3f62SAzael Avalos result = hci_read1(dev, HCI_KBD_ILLUMINATION, &state); 628893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 629360f0f39SAzael Avalos pr_err("ACPI call to get the keyboard backlight failed\n"); 630360f0f39SAzael Avalos return LED_OFF; 6311864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 632360f0f39SAzael Avalos pr_info("Keyboard backlight not supported\n"); 633360f0f39SAzael Avalos return LED_OFF; 634360f0f39SAzael Avalos } 635360f0f39SAzael Avalos 636360f0f39SAzael Avalos return state ? LED_FULL : LED_OFF; 637360f0f39SAzael Avalos } 638360f0f39SAzael Avalos 639360f0f39SAzael Avalos static void toshiba_kbd_backlight_set(struct led_classdev *cdev, 640360f0f39SAzael Avalos enum led_brightness brightness) 641360f0f39SAzael Avalos { 642360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 643360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led); 644360f0f39SAzael Avalos u32 state, result; 645360f0f39SAzael Avalos 646360f0f39SAzael Avalos /* Set the keyboard backlight state */ 647360f0f39SAzael Avalos state = brightness ? 1 : 0; 648893f3f62SAzael Avalos result = hci_write1(dev, HCI_KBD_ILLUMINATION, state); 649893f3f62SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 650360f0f39SAzael Avalos pr_err("ACPI call to set KBD Illumination mode failed\n"); 651360f0f39SAzael Avalos return; 6521864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 653360f0f39SAzael Avalos pr_info("Keyboard backlight not supported\n"); 654360f0f39SAzael Avalos return; 655360f0f39SAzael Avalos } 656360f0f39SAzael Avalos } 657360f0f39SAzael Avalos 6589d8658acSAzael Avalos /* TouchPad support */ 6599d8658acSAzael Avalos static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state) 6609d8658acSAzael Avalos { 6619d8658acSAzael Avalos u32 result; 6629d8658acSAzael Avalos 6639d8658acSAzael Avalos if (!sci_open(dev)) 6649d8658acSAzael Avalos return -EIO; 6659d8658acSAzael Avalos 666893f3f62SAzael Avalos result = sci_write(dev, SCI_TOUCHPAD, state); 6679d8658acSAzael Avalos sci_close(dev); 668893f3f62SAzael Avalos if (result == TOS_FAILURE) { 6699d8658acSAzael Avalos pr_err("ACPI call to set the touchpad failed\n"); 6709d8658acSAzael Avalos return -EIO; 6711864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 6729d8658acSAzael Avalos return -ENODEV; 6739d8658acSAzael Avalos } 6749d8658acSAzael Avalos 6759d8658acSAzael Avalos return 0; 6769d8658acSAzael Avalos } 6779d8658acSAzael Avalos 6789d8658acSAzael Avalos static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) 6799d8658acSAzael Avalos { 6809d8658acSAzael Avalos u32 result; 6819d8658acSAzael Avalos 6829d8658acSAzael Avalos if (!sci_open(dev)) 6839d8658acSAzael Avalos return -EIO; 6849d8658acSAzael Avalos 685893f3f62SAzael Avalos result = sci_read(dev, SCI_TOUCHPAD, state); 6869d8658acSAzael Avalos sci_close(dev); 687893f3f62SAzael Avalos if (result == TOS_FAILURE) { 6889d8658acSAzael Avalos pr_err("ACPI call to query the touchpad failed\n"); 6899d8658acSAzael Avalos return -EIO; 6901864bbc2SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 6919d8658acSAzael Avalos return -ENODEV; 6929d8658acSAzael Avalos } 6939d8658acSAzael Avalos 6949d8658acSAzael Avalos return 0; 6959d8658acSAzael Avalos } 6969d8658acSAzael Avalos 697def6c4e2SAzael Avalos /* Eco Mode support */ 698def6c4e2SAzael Avalos static int toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) 699def6c4e2SAzael Avalos { 700def6c4e2SAzael Avalos acpi_status status; 70198fc4ec6SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 }; 702258c5903SAzael Avalos u32 out[TCI_WORDS]; 703def6c4e2SAzael Avalos 704258c5903SAzael Avalos status = tci_raw(dev, in, out); 70598fc4ec6SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 70698fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 70798fc4ec6SAzael Avalos } else if (out[0] == TOS_NOT_INSTALLED) { 70898fc4ec6SAzael Avalos pr_info("ECO led not installed"); 70998fc4ec6SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 71098fc4ec6SAzael Avalos /* If we receive 0x8300 (Input Data Error), it means that the 71198fc4ec6SAzael Avalos * LED device is present, but that we just screwed the input 71298fc4ec6SAzael Avalos * parameters. 71398fc4ec6SAzael Avalos * 71498fc4ec6SAzael Avalos * Let's query the status of the LED to see if we really have a 71598fc4ec6SAzael Avalos * success response, indicating the actual presense of the LED, 71698fc4ec6SAzael Avalos * bail out otherwise. 71798fc4ec6SAzael Avalos */ 71898fc4ec6SAzael Avalos in[3] = 1; 71998fc4ec6SAzael Avalos status = tci_raw(dev, in, out); 72098fc4ec6SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) 72198fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 72298fc4ec6SAzael Avalos else if (out[0] == TOS_SUCCESS) 72398fc4ec6SAzael Avalos return 1; 724def6c4e2SAzael Avalos } 725def6c4e2SAzael Avalos 72698fc4ec6SAzael Avalos return 0; 727def6c4e2SAzael Avalos } 728def6c4e2SAzael Avalos 729def6c4e2SAzael Avalos static enum led_brightness toshiba_eco_mode_get_status(struct led_classdev *cdev) 730def6c4e2SAzael Avalos { 731def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 732def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 733258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 }; 734258c5903SAzael Avalos u32 out[TCI_WORDS]; 735def6c4e2SAzael Avalos acpi_status status; 736def6c4e2SAzael Avalos 737258c5903SAzael Avalos status = tci_raw(dev, in, out); 7381864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 739def6c4e2SAzael Avalos pr_err("ACPI call to get ECO led failed\n"); 740def6c4e2SAzael Avalos return LED_OFF; 741def6c4e2SAzael Avalos } 742def6c4e2SAzael Avalos 743def6c4e2SAzael Avalos return out[2] ? LED_FULL : LED_OFF; 744def6c4e2SAzael Avalos } 745def6c4e2SAzael Avalos 746def6c4e2SAzael Avalos static void toshiba_eco_mode_set_status(struct led_classdev *cdev, 747def6c4e2SAzael Avalos enum led_brightness brightness) 748def6c4e2SAzael Avalos { 749def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev, 750def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led); 751258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 }; 752258c5903SAzael Avalos u32 out[TCI_WORDS]; 753def6c4e2SAzael Avalos acpi_status status; 754def6c4e2SAzael Avalos 755def6c4e2SAzael Avalos /* Switch the Eco Mode led on/off */ 756def6c4e2SAzael Avalos in[2] = (brightness) ? 1 : 0; 757258c5903SAzael Avalos status = tci_raw(dev, in, out); 7581864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 759def6c4e2SAzael Avalos pr_err("ACPI call to set ECO led failed\n"); 760def6c4e2SAzael Avalos return; 761def6c4e2SAzael Avalos } 762def6c4e2SAzael Avalos } 763def6c4e2SAzael Avalos 7645a2813e9SAzael Avalos /* Accelerometer support */ 7655a2813e9SAzael Avalos static int toshiba_accelerometer_supported(struct toshiba_acpi_dev *dev) 7665a2813e9SAzael Avalos { 767258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 }; 768258c5903SAzael Avalos u32 out[TCI_WORDS]; 7695a2813e9SAzael Avalos acpi_status status; 7705a2813e9SAzael Avalos 7715a2813e9SAzael Avalos /* Check if the accelerometer call exists, 7725a2813e9SAzael Avalos * this call also serves as initialization 7735a2813e9SAzael Avalos */ 774258c5903SAzael Avalos status = tci_raw(dev, in, out); 7751864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 7765a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 7775a2813e9SAzael Avalos return -EIO; 7781864bbc2SAzael Avalos } else if (out[0] == TOS_DATA_NOT_AVAILABLE || 7791864bbc2SAzael Avalos out[0] == TOS_NOT_INITIALIZED) { 7805a2813e9SAzael Avalos pr_err("Accelerometer not initialized\n"); 7815a2813e9SAzael Avalos return -EIO; 7821864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 7835a2813e9SAzael Avalos pr_info("Accelerometer not supported\n"); 7845a2813e9SAzael Avalos return -ENODEV; 7855a2813e9SAzael Avalos } 7865a2813e9SAzael Avalos 7875a2813e9SAzael Avalos return 0; 7885a2813e9SAzael Avalos } 7895a2813e9SAzael Avalos 7905a2813e9SAzael Avalos static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, 7915a2813e9SAzael Avalos u32 *xy, u32 *z) 7925a2813e9SAzael Avalos { 793258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 }; 794258c5903SAzael Avalos u32 out[TCI_WORDS]; 7955a2813e9SAzael Avalos acpi_status status; 7965a2813e9SAzael Avalos 7975a2813e9SAzael Avalos /* Check the Accelerometer status */ 798258c5903SAzael Avalos status = tci_raw(dev, in, out); 7991864bbc2SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) { 8005a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n"); 8015a2813e9SAzael Avalos return -EIO; 8025a2813e9SAzael Avalos } 8035a2813e9SAzael Avalos 8045a2813e9SAzael Avalos *xy = out[2]; 8055a2813e9SAzael Avalos *z = out[4]; 8065a2813e9SAzael Avalos 8075a2813e9SAzael Avalos return 0; 8085a2813e9SAzael Avalos } 8095a2813e9SAzael Avalos 810e26ffe51SAzael Avalos /* Sleep (Charge and Music) utilities support */ 811e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, 812e26ffe51SAzael Avalos u32 *mode) 813e26ffe51SAzael Avalos { 814e26ffe51SAzael Avalos u32 result; 815e26ffe51SAzael Avalos 816e26ffe51SAzael Avalos if (!sci_open(dev)) 817e26ffe51SAzael Avalos return -EIO; 818e26ffe51SAzael Avalos 819e26ffe51SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode); 820e26ffe51SAzael Avalos sci_close(dev); 821e26ffe51SAzael Avalos if (result == TOS_FAILURE) { 822e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 823e26ffe51SAzael Avalos return -EIO; 824e26ffe51SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 825e26ffe51SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 826e26ffe51SAzael Avalos return -ENODEV; 827e26ffe51SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 828e26ffe51SAzael Avalos return -EIO; 829e26ffe51SAzael Avalos } 830e26ffe51SAzael Avalos 831e26ffe51SAzael Avalos return 0; 832e26ffe51SAzael Avalos } 833e26ffe51SAzael Avalos 834e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev, 835e26ffe51SAzael Avalos u32 mode) 836e26ffe51SAzael Avalos { 837e26ffe51SAzael Avalos u32 result; 838e26ffe51SAzael Avalos 839e26ffe51SAzael Avalos if (!sci_open(dev)) 840e26ffe51SAzael Avalos return -EIO; 841e26ffe51SAzael Avalos 842e26ffe51SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode); 843e26ffe51SAzael Avalos sci_close(dev); 844e26ffe51SAzael Avalos if (result == TOS_FAILURE) { 845e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 846e26ffe51SAzael Avalos return -EIO; 847e26ffe51SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 848e26ffe51SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 849e26ffe51SAzael Avalos return -ENODEV; 850e26ffe51SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 851e26ffe51SAzael Avalos return -EIO; 852e26ffe51SAzael Avalos } 853e26ffe51SAzael Avalos 854e26ffe51SAzael Avalos return 0; 855e26ffe51SAzael Avalos } 856e26ffe51SAzael Avalos 857182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev, 858182bcaa5SAzael Avalos u32 *mode) 859182bcaa5SAzael Avalos { 860182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 861182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 862182bcaa5SAzael Avalos acpi_status status; 863182bcaa5SAzael Avalos 864182bcaa5SAzael Avalos if (!sci_open(dev)) 865182bcaa5SAzael Avalos return -EIO; 866182bcaa5SAzael Avalos 867182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 868182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 869182bcaa5SAzael Avalos sci_close(dev); 870182bcaa5SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 871182bcaa5SAzael Avalos pr_err("ACPI call to get USB S&C battery level failed\n"); 872182bcaa5SAzael Avalos return -EIO; 873182bcaa5SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 874182bcaa5SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 875182bcaa5SAzael Avalos return -ENODEV; 876182bcaa5SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 877182bcaa5SAzael Avalos return -EIO; 878182bcaa5SAzael Avalos } 879182bcaa5SAzael Avalos 880182bcaa5SAzael Avalos *mode = out[2]; 881182bcaa5SAzael Avalos 882182bcaa5SAzael Avalos return 0; 883182bcaa5SAzael Avalos } 884182bcaa5SAzael Avalos 885182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, 886182bcaa5SAzael Avalos u32 mode) 887182bcaa5SAzael Avalos { 888182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 889182bcaa5SAzael Avalos u32 out[TCI_WORDS]; 890182bcaa5SAzael Avalos acpi_status status; 891182bcaa5SAzael Avalos 892182bcaa5SAzael Avalos if (!sci_open(dev)) 893182bcaa5SAzael Avalos return -EIO; 894182bcaa5SAzael Avalos 895182bcaa5SAzael Avalos in[2] = mode; 896182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL; 897182bcaa5SAzael Avalos status = tci_raw(dev, in, out); 898182bcaa5SAzael Avalos sci_close(dev); 899182bcaa5SAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 900182bcaa5SAzael Avalos pr_err("ACPI call to set USB S&C battery level failed\n"); 901182bcaa5SAzael Avalos return -EIO; 902182bcaa5SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 903182bcaa5SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 904182bcaa5SAzael Avalos return -ENODEV; 905182bcaa5SAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 906182bcaa5SAzael Avalos return -EIO; 907182bcaa5SAzael Avalos } 908182bcaa5SAzael Avalos 909182bcaa5SAzael Avalos return 0; 910182bcaa5SAzael Avalos } 911182bcaa5SAzael Avalos 912bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, 913bb3fe01fSAzael Avalos u32 *state) 914bb3fe01fSAzael Avalos { 915bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 916bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 917bb3fe01fSAzael Avalos acpi_status status; 918bb3fe01fSAzael Avalos 919bb3fe01fSAzael Avalos if (!sci_open(dev)) 920bb3fe01fSAzael Avalos return -EIO; 921bb3fe01fSAzael Avalos 922bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 923bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 924bb3fe01fSAzael Avalos sci_close(dev); 925bb3fe01fSAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 926bb3fe01fSAzael Avalos pr_err("ACPI call to get USB S&C battery level failed\n"); 927bb3fe01fSAzael Avalos return -EIO; 928bb3fe01fSAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED || 929bb3fe01fSAzael Avalos out[0] == TOS_INPUT_DATA_ERROR) { 930bb3fe01fSAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 931bb3fe01fSAzael Avalos return -ENODEV; 932bb3fe01fSAzael Avalos } 933bb3fe01fSAzael Avalos 934bb3fe01fSAzael Avalos *state = out[2]; 935bb3fe01fSAzael Avalos 936bb3fe01fSAzael Avalos return 0; 937bb3fe01fSAzael Avalos } 938bb3fe01fSAzael Avalos 939bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, 940bb3fe01fSAzael Avalos u32 state) 941bb3fe01fSAzael Avalos { 942bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 943bb3fe01fSAzael Avalos u32 out[TCI_WORDS]; 944bb3fe01fSAzael Avalos acpi_status status; 945bb3fe01fSAzael Avalos 946bb3fe01fSAzael Avalos if (!sci_open(dev)) 947bb3fe01fSAzael Avalos return -EIO; 948bb3fe01fSAzael Avalos 949bb3fe01fSAzael Avalos in[2] = state; 950bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP; 951bb3fe01fSAzael Avalos status = tci_raw(dev, in, out); 952bb3fe01fSAzael Avalos sci_close(dev); 953bb3fe01fSAzael Avalos if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) { 954bb3fe01fSAzael Avalos pr_err("ACPI call to set USB S&C battery level failed\n"); 955bb3fe01fSAzael Avalos return -EIO; 956bb3fe01fSAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) { 957bb3fe01fSAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 958bb3fe01fSAzael Avalos return -ENODEV; 959bb3fe01fSAzael Avalos } else if (out[0] == TOS_INPUT_DATA_ERROR) { 960bb3fe01fSAzael Avalos return -EIO; 961bb3fe01fSAzael Avalos } 962bb3fe01fSAzael Avalos 963bb3fe01fSAzael Avalos return 0; 964bb3fe01fSAzael Avalos } 965bb3fe01fSAzael Avalos 966172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state) 967172ce0a9SAzael Avalos { 968172ce0a9SAzael Avalos u32 result; 969172ce0a9SAzael Avalos 970172ce0a9SAzael Avalos if (!sci_open(dev)) 971172ce0a9SAzael Avalos return -EIO; 972172ce0a9SAzael Avalos 973172ce0a9SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state); 974172ce0a9SAzael Avalos sci_close(dev); 975172ce0a9SAzael Avalos if (result == TOS_FAILURE) { 976172ce0a9SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 977172ce0a9SAzael Avalos return -EIO; 978172ce0a9SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 979172ce0a9SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 980172ce0a9SAzael Avalos return -ENODEV; 981172ce0a9SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 982172ce0a9SAzael Avalos return -EIO; 983172ce0a9SAzael Avalos } 984172ce0a9SAzael Avalos 985172ce0a9SAzael Avalos return 0; 986172ce0a9SAzael Avalos } 987172ce0a9SAzael Avalos 988172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state) 989172ce0a9SAzael Avalos { 990172ce0a9SAzael Avalos u32 result; 991172ce0a9SAzael Avalos 992172ce0a9SAzael Avalos if (!sci_open(dev)) 993172ce0a9SAzael Avalos return -EIO; 994172ce0a9SAzael Avalos 995172ce0a9SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state); 996172ce0a9SAzael Avalos sci_close(dev); 997172ce0a9SAzael Avalos if (result == TOS_FAILURE) { 998172ce0a9SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n"); 999172ce0a9SAzael Avalos return -EIO; 1000172ce0a9SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1001172ce0a9SAzael Avalos pr_info("USB Sleep and Charge not supported\n"); 1002172ce0a9SAzael Avalos return -ENODEV; 1003172ce0a9SAzael Avalos } else if (result == TOS_INPUT_DATA_ERROR) { 1004172ce0a9SAzael Avalos return -EIO; 1005172ce0a9SAzael Avalos } 1006172ce0a9SAzael Avalos 1007172ce0a9SAzael Avalos return 0; 1008172ce0a9SAzael Avalos } 1009172ce0a9SAzael Avalos 1010*bae84195SAzael Avalos /* Keyboard function keys */ 1011*bae84195SAzael Avalos static int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode) 1012*bae84195SAzael Avalos { 1013*bae84195SAzael Avalos u32 result; 1014*bae84195SAzael Avalos 1015*bae84195SAzael Avalos if (!sci_open(dev)) 1016*bae84195SAzael Avalos return -EIO; 1017*bae84195SAzael Avalos 1018*bae84195SAzael Avalos result = sci_read(dev, SCI_KBD_FUNCTION_KEYS, mode); 1019*bae84195SAzael Avalos sci_close(dev); 1020*bae84195SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 1021*bae84195SAzael Avalos pr_err("ACPI call to get KBD function keys failed\n"); 1022*bae84195SAzael Avalos return -EIO; 1023*bae84195SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1024*bae84195SAzael Avalos pr_info("KBD function keys not supported\n"); 1025*bae84195SAzael Avalos return -ENODEV; 1026*bae84195SAzael Avalos } 1027*bae84195SAzael Avalos 1028*bae84195SAzael Avalos return 0; 1029*bae84195SAzael Avalos } 1030*bae84195SAzael Avalos 1031*bae84195SAzael Avalos static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode) 1032*bae84195SAzael Avalos { 1033*bae84195SAzael Avalos u32 result; 1034*bae84195SAzael Avalos 1035*bae84195SAzael Avalos if (!sci_open(dev)) 1036*bae84195SAzael Avalos return -EIO; 1037*bae84195SAzael Avalos 1038*bae84195SAzael Avalos result = sci_write(dev, SCI_KBD_FUNCTION_KEYS, mode); 1039*bae84195SAzael Avalos sci_close(dev); 1040*bae84195SAzael Avalos if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) { 1041*bae84195SAzael Avalos pr_err("ACPI call to set KBD function keys failed\n"); 1042*bae84195SAzael Avalos return -EIO; 1043*bae84195SAzael Avalos } else if (result == TOS_NOT_SUPPORTED) { 1044*bae84195SAzael Avalos pr_info("KBD function keys not supported\n"); 1045*bae84195SAzael Avalos return -ENODEV; 1046*bae84195SAzael Avalos } 1047*bae84195SAzael Avalos 1048*bae84195SAzael Avalos return 0; 1049*bae84195SAzael Avalos } 1050*bae84195SAzael Avalos 1051b4f9fe12SLen Brown /* Bluetooth rfkill handlers */ 1052b4f9fe12SLen Brown 1053135740deSSeth Forshee static u32 hci_get_bt_present(struct toshiba_acpi_dev *dev, bool *present) 1054b4f9fe12SLen Brown { 1055b4f9fe12SLen Brown u32 hci_result; 1056b4f9fe12SLen Brown u32 value, value2; 1057b4f9fe12SLen Brown 1058b4f9fe12SLen Brown value = 0; 1059b4f9fe12SLen Brown value2 = 0; 1060893f3f62SAzael Avalos hci_result = hci_read2(dev, HCI_WIRELESS, &value, &value2); 10611864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) 1062b4f9fe12SLen Brown *present = (value & HCI_WIRELESS_BT_PRESENT) ? true : false; 1063b4f9fe12SLen Brown 1064b4f9fe12SLen Brown return hci_result; 1065b4f9fe12SLen Brown } 1066b4f9fe12SLen Brown 1067135740deSSeth Forshee static u32 hci_get_radio_state(struct toshiba_acpi_dev *dev, bool *radio_state) 1068b4f9fe12SLen Brown { 1069b4f9fe12SLen Brown u32 hci_result; 1070b4f9fe12SLen Brown u32 value, value2; 1071b4f9fe12SLen Brown 1072b4f9fe12SLen Brown value = 0; 1073b4f9fe12SLen Brown value2 = 0x0001; 1074893f3f62SAzael Avalos hci_result = hci_read2(dev, HCI_WIRELESS, &value, &value2); 1075b4f9fe12SLen Brown 1076b4f9fe12SLen Brown *radio_state = value & HCI_WIRELESS_KILL_SWITCH; 1077b4f9fe12SLen Brown return hci_result; 1078b4f9fe12SLen Brown } 1079b4f9fe12SLen Brown 108019d337dfSJohannes Berg static int bt_rfkill_set_block(void *data, bool blocked) 1081b4f9fe12SLen Brown { 108219d337dfSJohannes Berg struct toshiba_acpi_dev *dev = data; 1083b4f9fe12SLen Brown u32 result1, result2; 1084b4f9fe12SLen Brown u32 value; 108519d337dfSJohannes Berg int err; 1086b4f9fe12SLen Brown bool radio_state; 1087b4f9fe12SLen Brown 108819d337dfSJohannes Berg value = (blocked == false); 1089b4f9fe12SLen Brown 1090b4f9fe12SLen Brown mutex_lock(&dev->mutex); 10911864bbc2SAzael Avalos if (hci_get_radio_state(dev, &radio_state) != TOS_SUCCESS) { 109232bcd5cbSSeth Forshee err = -EIO; 109319d337dfSJohannes Berg goto out; 1094b4f9fe12SLen Brown } 1095b4f9fe12SLen Brown 109619d337dfSJohannes Berg if (!radio_state) { 109719d337dfSJohannes Berg err = 0; 109819d337dfSJohannes Berg goto out; 109919d337dfSJohannes Berg } 110019d337dfSJohannes Berg 1101893f3f62SAzael Avalos result1 = hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER); 1102893f3f62SAzael Avalos result2 = hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH); 110319d337dfSJohannes Berg 11041864bbc2SAzael Avalos if (result1 != TOS_SUCCESS || result2 != TOS_SUCCESS) 110532bcd5cbSSeth Forshee err = -EIO; 110619d337dfSJohannes Berg else 110719d337dfSJohannes Berg err = 0; 110819d337dfSJohannes Berg out: 110919d337dfSJohannes Berg mutex_unlock(&dev->mutex); 111019d337dfSJohannes Berg return err; 111119d337dfSJohannes Berg } 111219d337dfSJohannes Berg 111319d337dfSJohannes Berg static void bt_rfkill_poll(struct rfkill *rfkill, void *data) 1114b4f9fe12SLen Brown { 1115b4f9fe12SLen Brown bool new_rfk_state; 1116b4f9fe12SLen Brown bool value; 1117b4f9fe12SLen Brown u32 hci_result; 111819d337dfSJohannes Berg struct toshiba_acpi_dev *dev = data; 111919d337dfSJohannes Berg 112019d337dfSJohannes Berg mutex_lock(&dev->mutex); 1121b4f9fe12SLen Brown 1122135740deSSeth Forshee hci_result = hci_get_radio_state(dev, &value); 11231864bbc2SAzael Avalos if (hci_result != TOS_SUCCESS) { 112419d337dfSJohannes Berg /* Can't do anything useful */ 112519d337dfSJohannes Berg mutex_unlock(&dev->mutex); 112682e7784fSJiri Slaby return; 112719d337dfSJohannes Berg } 1128b4f9fe12SLen Brown 1129b4f9fe12SLen Brown new_rfk_state = value; 1130b4f9fe12SLen Brown 1131b4f9fe12SLen Brown mutex_unlock(&dev->mutex); 1132b4f9fe12SLen Brown 113319d337dfSJohannes Berg if (rfkill_set_hw_state(rfkill, !new_rfk_state)) 113419d337dfSJohannes Berg bt_rfkill_set_block(data, true); 1135b4f9fe12SLen Brown } 113619d337dfSJohannes Berg 113719d337dfSJohannes Berg static const struct rfkill_ops toshiba_rfk_ops = { 113819d337dfSJohannes Berg .set_block = bt_rfkill_set_block, 113919d337dfSJohannes Berg .poll = bt_rfkill_poll, 114019d337dfSJohannes Berg }; 1141b4f9fe12SLen Brown 1142121b7b0dSAkio Idehara static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled) 1143121b7b0dSAkio Idehara { 1144121b7b0dSAkio Idehara u32 hci_result; 1145121b7b0dSAkio Idehara u32 status; 1146121b7b0dSAkio Idehara 1147893f3f62SAzael Avalos hci_result = hci_read1(dev, HCI_TR_BACKLIGHT, &status); 1148121b7b0dSAkio Idehara *enabled = !status; 11491864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 1150121b7b0dSAkio Idehara } 1151121b7b0dSAkio Idehara 1152121b7b0dSAkio Idehara static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable) 1153121b7b0dSAkio Idehara { 1154121b7b0dSAkio Idehara u32 hci_result; 1155121b7b0dSAkio Idehara u32 value = !enable; 1156121b7b0dSAkio Idehara 1157893f3f62SAzael Avalos hci_result = hci_write1(dev, HCI_TR_BACKLIGHT, value); 11581864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 1159121b7b0dSAkio Idehara } 1160121b7b0dSAkio Idehara 1161b4f9fe12SLen Brown static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; 1162b4f9fe12SLen Brown 116362cce752SSeth Forshee static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) 1164b4f9fe12SLen Brown { 1165b4f9fe12SLen Brown u32 hci_result; 1166b4f9fe12SLen Brown u32 value; 1167121b7b0dSAkio Idehara int brightness = 0; 1168121b7b0dSAkio Idehara 1169121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1170121b7b0dSAkio Idehara bool enabled; 1171121b7b0dSAkio Idehara int ret = get_tr_backlight_status(dev, &enabled); 1172121b7b0dSAkio Idehara if (ret) 1173121b7b0dSAkio Idehara return ret; 1174121b7b0dSAkio Idehara if (enabled) 1175121b7b0dSAkio Idehara return 0; 1176121b7b0dSAkio Idehara brightness++; 1177121b7b0dSAkio Idehara } 1178b4f9fe12SLen Brown 1179893f3f62SAzael Avalos hci_result = hci_read1(dev, HCI_LCD_BRIGHTNESS, &value); 11801864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) 1181121b7b0dSAkio Idehara return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT); 118232bcd5cbSSeth Forshee 118332bcd5cbSSeth Forshee return -EIO; 1184b4f9fe12SLen Brown } 1185b4f9fe12SLen Brown 118662cce752SSeth Forshee static int get_lcd_brightness(struct backlight_device *bd) 118762cce752SSeth Forshee { 118862cce752SSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 118962cce752SSeth Forshee return __get_lcd_brightness(dev); 119062cce752SSeth Forshee } 119162cce752SSeth Forshee 1192936c8bcdSAlexey Dobriyan static int lcd_proc_show(struct seq_file *m, void *v) 1193b4f9fe12SLen Brown { 1194135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1195135740deSSeth Forshee int value; 1196121b7b0dSAkio Idehara int levels; 1197b4f9fe12SLen Brown 1198135740deSSeth Forshee if (!dev->backlight_dev) 1199135740deSSeth Forshee return -ENODEV; 1200135740deSSeth Forshee 1201121b7b0dSAkio Idehara levels = dev->backlight_dev->props.max_brightness + 1; 120262cce752SSeth Forshee value = get_lcd_brightness(dev->backlight_dev); 1203b4f9fe12SLen Brown if (value >= 0) { 1204936c8bcdSAlexey Dobriyan seq_printf(m, "brightness: %d\n", value); 1205121b7b0dSAkio Idehara seq_printf(m, "brightness_levels: %d\n", levels); 120632bcd5cbSSeth Forshee return 0; 1207b4f9fe12SLen Brown } 1208b4f9fe12SLen Brown 120932bcd5cbSSeth Forshee pr_err("Error reading LCD brightness\n"); 121032bcd5cbSSeth Forshee return -EIO; 1211936c8bcdSAlexey Dobriyan } 1212936c8bcdSAlexey Dobriyan 1213936c8bcdSAlexey Dobriyan static int lcd_proc_open(struct inode *inode, struct file *file) 1214936c8bcdSAlexey Dobriyan { 1215d9dda78bSAl Viro return single_open(file, lcd_proc_show, PDE_DATA(inode)); 1216b4f9fe12SLen Brown } 1217b4f9fe12SLen Brown 121862cce752SSeth Forshee static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) 1219b4f9fe12SLen Brown { 1220a39f46dfSAzael Avalos u32 hci_result; 1221b4f9fe12SLen Brown 1222121b7b0dSAkio Idehara if (dev->tr_backlight_supported) { 1223121b7b0dSAkio Idehara bool enable = !value; 1224121b7b0dSAkio Idehara int ret = set_tr_backlight_status(dev, enable); 1225121b7b0dSAkio Idehara if (ret) 1226121b7b0dSAkio Idehara return ret; 1227121b7b0dSAkio Idehara if (value) 1228121b7b0dSAkio Idehara value--; 1229121b7b0dSAkio Idehara } 1230121b7b0dSAkio Idehara 1231a39f46dfSAzael Avalos value = value << HCI_LCD_BRIGHTNESS_SHIFT; 1232a39f46dfSAzael Avalos hci_result = hci_write1(dev, HCI_LCD_BRIGHTNESS, value); 1233a39f46dfSAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 1234b4f9fe12SLen Brown } 1235b4f9fe12SLen Brown 1236b4f9fe12SLen Brown static int set_lcd_status(struct backlight_device *bd) 1237b4f9fe12SLen Brown { 1238135740deSSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd); 123962cce752SSeth Forshee return set_lcd_brightness(dev, bd->props.brightness); 1240b4f9fe12SLen Brown } 1241b4f9fe12SLen Brown 1242936c8bcdSAlexey Dobriyan static ssize_t lcd_proc_write(struct file *file, const char __user *buf, 1243936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1244b4f9fe12SLen Brown { 1245d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1246936c8bcdSAlexey Dobriyan char cmd[42]; 1247936c8bcdSAlexey Dobriyan size_t len; 1248b4f9fe12SLen Brown int value; 1249b4f9fe12SLen Brown int ret; 1250121b7b0dSAkio Idehara int levels = dev->backlight_dev->props.max_brightness + 1; 1251b4f9fe12SLen Brown 1252936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1253936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1254936c8bcdSAlexey Dobriyan return -EFAULT; 1255936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1256936c8bcdSAlexey Dobriyan 1257936c8bcdSAlexey Dobriyan if (sscanf(cmd, " brightness : %i", &value) == 1 && 1258121b7b0dSAkio Idehara value >= 0 && value < levels) { 125962cce752SSeth Forshee ret = set_lcd_brightness(dev, value); 1260b4f9fe12SLen Brown if (ret == 0) 1261b4f9fe12SLen Brown ret = count; 1262b4f9fe12SLen Brown } else { 1263b4f9fe12SLen Brown ret = -EINVAL; 1264b4f9fe12SLen Brown } 1265b4f9fe12SLen Brown return ret; 1266b4f9fe12SLen Brown } 1267b4f9fe12SLen Brown 1268936c8bcdSAlexey Dobriyan static const struct file_operations lcd_proc_fops = { 1269936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1270936c8bcdSAlexey Dobriyan .open = lcd_proc_open, 1271936c8bcdSAlexey Dobriyan .read = seq_read, 1272936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1273936c8bcdSAlexey Dobriyan .release = single_release, 1274936c8bcdSAlexey Dobriyan .write = lcd_proc_write, 1275936c8bcdSAlexey Dobriyan }; 1276936c8bcdSAlexey Dobriyan 127736d03f93SSeth Forshee static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status) 127836d03f93SSeth Forshee { 127936d03f93SSeth Forshee u32 hci_result; 128036d03f93SSeth Forshee 1281893f3f62SAzael Avalos hci_result = hci_read1(dev, HCI_VIDEO_OUT, status); 12821864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 128336d03f93SSeth Forshee } 128436d03f93SSeth Forshee 1285936c8bcdSAlexey Dobriyan static int video_proc_show(struct seq_file *m, void *v) 1286b4f9fe12SLen Brown { 1287135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1288b4f9fe12SLen Brown u32 value; 128936d03f93SSeth Forshee int ret; 1290b4f9fe12SLen Brown 129136d03f93SSeth Forshee ret = get_video_status(dev, &value); 129236d03f93SSeth Forshee if (!ret) { 1293b4f9fe12SLen Brown int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; 1294b4f9fe12SLen Brown int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; 1295b4f9fe12SLen Brown int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; 1296936c8bcdSAlexey Dobriyan seq_printf(m, "lcd_out: %d\n", is_lcd); 1297936c8bcdSAlexey Dobriyan seq_printf(m, "crt_out: %d\n", is_crt); 1298936c8bcdSAlexey Dobriyan seq_printf(m, "tv_out: %d\n", is_tv); 1299b4f9fe12SLen Brown } 1300b4f9fe12SLen Brown 130136d03f93SSeth Forshee return ret; 1302b4f9fe12SLen Brown } 1303b4f9fe12SLen Brown 1304936c8bcdSAlexey Dobriyan static int video_proc_open(struct inode *inode, struct file *file) 1305b4f9fe12SLen Brown { 1306d9dda78bSAl Viro return single_open(file, video_proc_show, PDE_DATA(inode)); 1307936c8bcdSAlexey Dobriyan } 1308936c8bcdSAlexey Dobriyan 1309936c8bcdSAlexey Dobriyan static ssize_t video_proc_write(struct file *file, const char __user *buf, 1310936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1311936c8bcdSAlexey Dobriyan { 1312d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1313936c8bcdSAlexey Dobriyan char *cmd, *buffer; 131436d03f93SSeth Forshee int ret; 1315b4f9fe12SLen Brown int value; 1316b4f9fe12SLen Brown int remain = count; 1317b4f9fe12SLen Brown int lcd_out = -1; 1318b4f9fe12SLen Brown int crt_out = -1; 1319b4f9fe12SLen Brown int tv_out = -1; 1320b4f9fe12SLen Brown u32 video_out; 1321b4f9fe12SLen Brown 1322936c8bcdSAlexey Dobriyan cmd = kmalloc(count + 1, GFP_KERNEL); 1323936c8bcdSAlexey Dobriyan if (!cmd) 1324936c8bcdSAlexey Dobriyan return -ENOMEM; 1325936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, count)) { 1326936c8bcdSAlexey Dobriyan kfree(cmd); 1327936c8bcdSAlexey Dobriyan return -EFAULT; 1328936c8bcdSAlexey Dobriyan } 1329936c8bcdSAlexey Dobriyan cmd[count] = '\0'; 1330936c8bcdSAlexey Dobriyan 1331936c8bcdSAlexey Dobriyan buffer = cmd; 1332936c8bcdSAlexey Dobriyan 1333b4f9fe12SLen Brown /* scan expression. Multiple expressions may be delimited with ; 1334b4f9fe12SLen Brown * 1335b4f9fe12SLen Brown * NOTE: to keep scanning simple, invalid fields are ignored 1336b4f9fe12SLen Brown */ 1337b4f9fe12SLen Brown while (remain) { 1338b4f9fe12SLen Brown if (sscanf(buffer, " lcd_out : %i", &value) == 1) 1339b4f9fe12SLen Brown lcd_out = value & 1; 1340b4f9fe12SLen Brown else if (sscanf(buffer, " crt_out : %i", &value) == 1) 1341b4f9fe12SLen Brown crt_out = value & 1; 1342b4f9fe12SLen Brown else if (sscanf(buffer, " tv_out : %i", &value) == 1) 1343b4f9fe12SLen Brown tv_out = value & 1; 1344b4f9fe12SLen Brown /* advance to one character past the next ; */ 1345b4f9fe12SLen Brown do { 1346b4f9fe12SLen Brown ++buffer; 1347b4f9fe12SLen Brown --remain; 1348b4f9fe12SLen Brown } 1349b4f9fe12SLen Brown while (remain && *(buffer - 1) != ';'); 1350b4f9fe12SLen Brown } 1351b4f9fe12SLen Brown 1352936c8bcdSAlexey Dobriyan kfree(cmd); 1353936c8bcdSAlexey Dobriyan 135436d03f93SSeth Forshee ret = get_video_status(dev, &video_out); 135536d03f93SSeth Forshee if (!ret) { 1356b4f9fe12SLen Brown unsigned int new_video_out = video_out; 1357b4f9fe12SLen Brown if (lcd_out != -1) 1358b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out); 1359b4f9fe12SLen Brown if (crt_out != -1) 1360b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out); 1361b4f9fe12SLen Brown if (tv_out != -1) 1362b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out); 1363b4f9fe12SLen Brown /* To avoid unnecessary video disruption, only write the new 1364b4f9fe12SLen Brown * video setting if something changed. */ 1365b4f9fe12SLen Brown if (new_video_out != video_out) 136632bcd5cbSSeth Forshee ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out); 1367b4f9fe12SLen Brown } 1368b4f9fe12SLen Brown 136932bcd5cbSSeth Forshee return ret ? ret : count; 1370b4f9fe12SLen Brown } 1371b4f9fe12SLen Brown 1372936c8bcdSAlexey Dobriyan static const struct file_operations video_proc_fops = { 1373936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1374936c8bcdSAlexey Dobriyan .open = video_proc_open, 1375936c8bcdSAlexey Dobriyan .read = seq_read, 1376936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1377936c8bcdSAlexey Dobriyan .release = single_release, 1378936c8bcdSAlexey Dobriyan .write = video_proc_write, 1379936c8bcdSAlexey Dobriyan }; 1380936c8bcdSAlexey Dobriyan 138136d03f93SSeth Forshee static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status) 138236d03f93SSeth Forshee { 138336d03f93SSeth Forshee u32 hci_result; 138436d03f93SSeth Forshee 1385893f3f62SAzael Avalos hci_result = hci_read1(dev, HCI_FAN, status); 13861864bbc2SAzael Avalos return hci_result == TOS_SUCCESS ? 0 : -EIO; 138736d03f93SSeth Forshee } 138836d03f93SSeth Forshee 1389936c8bcdSAlexey Dobriyan static int fan_proc_show(struct seq_file *m, void *v) 1390b4f9fe12SLen Brown { 1391135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 139236d03f93SSeth Forshee int ret; 1393b4f9fe12SLen Brown u32 value; 1394b4f9fe12SLen Brown 139536d03f93SSeth Forshee ret = get_fan_status(dev, &value); 139636d03f93SSeth Forshee if (!ret) { 1397936c8bcdSAlexey Dobriyan seq_printf(m, "running: %d\n", (value > 0)); 1398135740deSSeth Forshee seq_printf(m, "force_on: %d\n", dev->force_fan); 1399b4f9fe12SLen Brown } 1400b4f9fe12SLen Brown 140136d03f93SSeth Forshee return ret; 1402b4f9fe12SLen Brown } 1403b4f9fe12SLen Brown 1404936c8bcdSAlexey Dobriyan static int fan_proc_open(struct inode *inode, struct file *file) 1405b4f9fe12SLen Brown { 1406d9dda78bSAl Viro return single_open(file, fan_proc_show, PDE_DATA(inode)); 1407936c8bcdSAlexey Dobriyan } 1408936c8bcdSAlexey Dobriyan 1409936c8bcdSAlexey Dobriyan static ssize_t fan_proc_write(struct file *file, const char __user *buf, 1410936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1411936c8bcdSAlexey Dobriyan { 1412d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1413936c8bcdSAlexey Dobriyan char cmd[42]; 1414936c8bcdSAlexey Dobriyan size_t len; 1415b4f9fe12SLen Brown int value; 1416b4f9fe12SLen Brown u32 hci_result; 1417b4f9fe12SLen Brown 1418936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1419936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1420936c8bcdSAlexey Dobriyan return -EFAULT; 1421936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1422936c8bcdSAlexey Dobriyan 1423936c8bcdSAlexey Dobriyan if (sscanf(cmd, " force_on : %i", &value) == 1 && 1424b4f9fe12SLen Brown value >= 0 && value <= 1) { 1425893f3f62SAzael Avalos hci_result = hci_write1(dev, HCI_FAN, value); 14261864bbc2SAzael Avalos if (hci_result != TOS_SUCCESS) 142732bcd5cbSSeth Forshee return -EIO; 1428b4f9fe12SLen Brown else 1429135740deSSeth Forshee dev->force_fan = value; 1430b4f9fe12SLen Brown } else { 1431b4f9fe12SLen Brown return -EINVAL; 1432b4f9fe12SLen Brown } 1433b4f9fe12SLen Brown 1434b4f9fe12SLen Brown return count; 1435b4f9fe12SLen Brown } 1436b4f9fe12SLen Brown 1437936c8bcdSAlexey Dobriyan static const struct file_operations fan_proc_fops = { 1438936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1439936c8bcdSAlexey Dobriyan .open = fan_proc_open, 1440936c8bcdSAlexey Dobriyan .read = seq_read, 1441936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1442936c8bcdSAlexey Dobriyan .release = single_release, 1443936c8bcdSAlexey Dobriyan .write = fan_proc_write, 1444936c8bcdSAlexey Dobriyan }; 1445936c8bcdSAlexey Dobriyan 1446936c8bcdSAlexey Dobriyan static int keys_proc_show(struct seq_file *m, void *v) 1447b4f9fe12SLen Brown { 1448135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private; 1449b4f9fe12SLen Brown u32 hci_result; 1450b4f9fe12SLen Brown u32 value; 1451b4f9fe12SLen Brown 145211948b93SSeth Forshee if (!dev->key_event_valid && dev->system_event_supported) { 1453893f3f62SAzael Avalos hci_result = hci_read1(dev, HCI_SYSTEM_EVENT, &value); 14541864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) { 1455135740deSSeth Forshee dev->key_event_valid = 1; 1456135740deSSeth Forshee dev->last_key_event = value; 14571864bbc2SAzael Avalos } else if (hci_result == TOS_FIFO_EMPTY) { 1458b4f9fe12SLen Brown /* better luck next time */ 14591864bbc2SAzael Avalos } else if (hci_result == TOS_NOT_SUPPORTED) { 1460b4f9fe12SLen Brown /* This is a workaround for an unresolved issue on 1461b4f9fe12SLen Brown * some machines where system events sporadically 1462b4f9fe12SLen Brown * become disabled. */ 1463893f3f62SAzael Avalos hci_result = hci_write1(dev, HCI_SYSTEM_EVENT, 1); 14647e33460dSJoe Perches pr_notice("Re-enabled hotkeys\n"); 1465b4f9fe12SLen Brown } else { 14667e33460dSJoe Perches pr_err("Error reading hotkey status\n"); 146732bcd5cbSSeth Forshee return -EIO; 1468b4f9fe12SLen Brown } 1469b4f9fe12SLen Brown } 1470b4f9fe12SLen Brown 1471135740deSSeth Forshee seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid); 1472135740deSSeth Forshee seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event); 1473936c8bcdSAlexey Dobriyan return 0; 1474b4f9fe12SLen Brown } 1475b4f9fe12SLen Brown 1476936c8bcdSAlexey Dobriyan static int keys_proc_open(struct inode *inode, struct file *file) 1477b4f9fe12SLen Brown { 1478d9dda78bSAl Viro return single_open(file, keys_proc_show, PDE_DATA(inode)); 1479936c8bcdSAlexey Dobriyan } 1480936c8bcdSAlexey Dobriyan 1481936c8bcdSAlexey Dobriyan static ssize_t keys_proc_write(struct file *file, const char __user *buf, 1482936c8bcdSAlexey Dobriyan size_t count, loff_t *pos) 1483936c8bcdSAlexey Dobriyan { 1484d9dda78bSAl Viro struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 1485936c8bcdSAlexey Dobriyan char cmd[42]; 1486936c8bcdSAlexey Dobriyan size_t len; 1487b4f9fe12SLen Brown int value; 1488b4f9fe12SLen Brown 1489936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1); 1490936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len)) 1491936c8bcdSAlexey Dobriyan return -EFAULT; 1492936c8bcdSAlexey Dobriyan cmd[len] = '\0'; 1493936c8bcdSAlexey Dobriyan 1494936c8bcdSAlexey Dobriyan if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) { 1495135740deSSeth Forshee dev->key_event_valid = 0; 1496b4f9fe12SLen Brown } else { 1497b4f9fe12SLen Brown return -EINVAL; 1498b4f9fe12SLen Brown } 1499b4f9fe12SLen Brown 1500b4f9fe12SLen Brown return count; 1501b4f9fe12SLen Brown } 1502b4f9fe12SLen Brown 1503936c8bcdSAlexey Dobriyan static const struct file_operations keys_proc_fops = { 1504936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1505936c8bcdSAlexey Dobriyan .open = keys_proc_open, 1506936c8bcdSAlexey Dobriyan .read = seq_read, 1507936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1508936c8bcdSAlexey Dobriyan .release = single_release, 1509936c8bcdSAlexey Dobriyan .write = keys_proc_write, 1510936c8bcdSAlexey Dobriyan }; 1511936c8bcdSAlexey Dobriyan 1512936c8bcdSAlexey Dobriyan static int version_proc_show(struct seq_file *m, void *v) 1513b4f9fe12SLen Brown { 1514936c8bcdSAlexey Dobriyan seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION); 1515936c8bcdSAlexey Dobriyan seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION); 1516936c8bcdSAlexey Dobriyan return 0; 1517b4f9fe12SLen Brown } 1518b4f9fe12SLen Brown 1519936c8bcdSAlexey Dobriyan static int version_proc_open(struct inode *inode, struct file *file) 1520936c8bcdSAlexey Dobriyan { 1521d9dda78bSAl Viro return single_open(file, version_proc_show, PDE_DATA(inode)); 1522936c8bcdSAlexey Dobriyan } 1523936c8bcdSAlexey Dobriyan 1524936c8bcdSAlexey Dobriyan static const struct file_operations version_proc_fops = { 1525936c8bcdSAlexey Dobriyan .owner = THIS_MODULE, 1526936c8bcdSAlexey Dobriyan .open = version_proc_open, 1527936c8bcdSAlexey Dobriyan .read = seq_read, 1528936c8bcdSAlexey Dobriyan .llseek = seq_lseek, 1529936c8bcdSAlexey Dobriyan .release = single_release, 1530936c8bcdSAlexey Dobriyan }; 1531936c8bcdSAlexey Dobriyan 1532b4f9fe12SLen Brown /* proc and module init 1533b4f9fe12SLen Brown */ 1534b4f9fe12SLen Brown 1535b4f9fe12SLen Brown #define PROC_TOSHIBA "toshiba" 1536b4f9fe12SLen Brown 1537b859f159SGreg Kroah-Hartman static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1538b4f9fe12SLen Brown { 153936d03f93SSeth Forshee if (dev->backlight_dev) 1540135740deSSeth Forshee proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1541135740deSSeth Forshee &lcd_proc_fops, dev); 154236d03f93SSeth Forshee if (dev->video_supported) 1543135740deSSeth Forshee proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1544135740deSSeth Forshee &video_proc_fops, dev); 154536d03f93SSeth Forshee if (dev->fan_supported) 1546135740deSSeth Forshee proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1547135740deSSeth Forshee &fan_proc_fops, dev); 154836d03f93SSeth Forshee if (dev->hotkey_dev) 1549135740deSSeth Forshee proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, 1550135740deSSeth Forshee &keys_proc_fops, dev); 1551135740deSSeth Forshee proc_create_data("version", S_IRUGO, toshiba_proc_dir, 1552135740deSSeth Forshee &version_proc_fops, dev); 1553b4f9fe12SLen Brown } 1554b4f9fe12SLen Brown 155536d03f93SSeth Forshee static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 1556b4f9fe12SLen Brown { 155736d03f93SSeth Forshee if (dev->backlight_dev) 1558936c8bcdSAlexey Dobriyan remove_proc_entry("lcd", toshiba_proc_dir); 155936d03f93SSeth Forshee if (dev->video_supported) 1560936c8bcdSAlexey Dobriyan remove_proc_entry("video", toshiba_proc_dir); 156136d03f93SSeth Forshee if (dev->fan_supported) 1562936c8bcdSAlexey Dobriyan remove_proc_entry("fan", toshiba_proc_dir); 156336d03f93SSeth Forshee if (dev->hotkey_dev) 1564936c8bcdSAlexey Dobriyan remove_proc_entry("keys", toshiba_proc_dir); 1565936c8bcdSAlexey Dobriyan remove_proc_entry("version", toshiba_proc_dir); 1566b4f9fe12SLen Brown } 1567b4f9fe12SLen Brown 1568acc2472eSLionel Debroux static const struct backlight_ops toshiba_backlight_data = { 1569121b7b0dSAkio Idehara .options = BL_CORE_SUSPENDRESUME, 157062cce752SSeth Forshee .get_brightness = get_lcd_brightness, 1571b4f9fe12SLen Brown .update_status = set_lcd_status, 1572b4f9fe12SLen Brown }; 1573b4f9fe12SLen Brown 1574360f0f39SAzael Avalos /* 1575360f0f39SAzael Avalos * Sysfs files 1576360f0f39SAzael Avalos */ 1577c6c68ff8SAzael Avalos static ssize_t toshiba_version_show(struct device *dev, 1578c6c68ff8SAzael Avalos struct device_attribute *attr, char *buf); 157994477d4cSAzael Avalos static ssize_t toshiba_fan_store(struct device *dev, 158094477d4cSAzael Avalos struct device_attribute *attr, 158194477d4cSAzael Avalos const char *buf, size_t count); 158294477d4cSAzael Avalos static ssize_t toshiba_fan_show(struct device *dev, 158394477d4cSAzael Avalos struct device_attribute *attr, char *buf); 158493f8c16dSAzael Avalos static ssize_t toshiba_kbd_bl_mode_store(struct device *dev, 158593f8c16dSAzael Avalos struct device_attribute *attr, 158693f8c16dSAzael Avalos const char *buf, size_t count); 158793f8c16dSAzael Avalos static ssize_t toshiba_kbd_bl_mode_show(struct device *dev, 158893f8c16dSAzael Avalos struct device_attribute *attr, 158993f8c16dSAzael Avalos char *buf); 159093f8c16dSAzael Avalos static ssize_t toshiba_kbd_type_show(struct device *dev, 159193f8c16dSAzael Avalos struct device_attribute *attr, 159293f8c16dSAzael Avalos char *buf); 159393f8c16dSAzael Avalos static ssize_t toshiba_available_kbd_modes_show(struct device *dev, 159493f8c16dSAzael Avalos struct device_attribute *attr, 159593f8c16dSAzael Avalos char *buf); 159693f8c16dSAzael Avalos static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev, 159793f8c16dSAzael Avalos struct device_attribute *attr, 159893f8c16dSAzael Avalos const char *buf, size_t count); 159993f8c16dSAzael Avalos static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev, 160093f8c16dSAzael Avalos struct device_attribute *attr, 160193f8c16dSAzael Avalos char *buf); 160293f8c16dSAzael Avalos static ssize_t toshiba_touchpad_store(struct device *dev, 160393f8c16dSAzael Avalos struct device_attribute *attr, 160493f8c16dSAzael Avalos const char *buf, size_t count); 160593f8c16dSAzael Avalos static ssize_t toshiba_touchpad_show(struct device *dev, 160693f8c16dSAzael Avalos struct device_attribute *attr, 160793f8c16dSAzael Avalos char *buf); 160893f8c16dSAzael Avalos static ssize_t toshiba_position_show(struct device *dev, 160993f8c16dSAzael Avalos struct device_attribute *attr, 161093f8c16dSAzael Avalos char *buf); 1611e26ffe51SAzael Avalos static ssize_t toshiba_usb_sleep_charge_show(struct device *dev, 1612e26ffe51SAzael Avalos struct device_attribute *attr, 1613e26ffe51SAzael Avalos char *buf); 1614e26ffe51SAzael Avalos static ssize_t toshiba_usb_sleep_charge_store(struct device *dev, 1615e26ffe51SAzael Avalos struct device_attribute *attr, 1616e26ffe51SAzael Avalos const char *buf, size_t count); 1617182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_show(struct device *dev, 1618182bcaa5SAzael Avalos struct device_attribute *attr, 1619182bcaa5SAzael Avalos char *buf); 1620182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_store(struct device *dev, 1621182bcaa5SAzael Avalos struct device_attribute *attr, 1622182bcaa5SAzael Avalos const char *buf, size_t count); 1623bb3fe01fSAzael Avalos static ssize_t toshiba_usb_rapid_charge_show(struct device *dev, 1624bb3fe01fSAzael Avalos struct device_attribute *attr, 1625bb3fe01fSAzael Avalos char *buf); 1626bb3fe01fSAzael Avalos static ssize_t toshiba_usb_rapid_charge_store(struct device *dev, 1627bb3fe01fSAzael Avalos struct device_attribute *attr, 1628bb3fe01fSAzael Avalos const char *buf, size_t count); 1629172ce0a9SAzael Avalos static ssize_t toshiba_usb_sleep_music_show(struct device *dev, 1630172ce0a9SAzael Avalos struct device_attribute *attr, 1631172ce0a9SAzael Avalos char *buf); 1632172ce0a9SAzael Avalos static ssize_t toshiba_usb_sleep_music_store(struct device *dev, 1633172ce0a9SAzael Avalos struct device_attribute *attr, 1634172ce0a9SAzael Avalos const char *buf, size_t count); 1635*bae84195SAzael Avalos static ssize_t toshiba_kbd_function_keys_show(struct device *dev, 1636*bae84195SAzael Avalos struct device_attribute *attr, 1637*bae84195SAzael Avalos char *buf); 1638*bae84195SAzael Avalos static ssize_t toshiba_kbd_function_keys_store(struct device *dev, 1639*bae84195SAzael Avalos struct device_attribute *attr, 1640*bae84195SAzael Avalos const char *buf, size_t count); 164193f8c16dSAzael Avalos 1642c6c68ff8SAzael Avalos static DEVICE_ATTR(version, S_IRUGO, toshiba_version_show, NULL); 164394477d4cSAzael Avalos static DEVICE_ATTR(fan, S_IRUGO | S_IWUSR, 164494477d4cSAzael Avalos toshiba_fan_show, toshiba_fan_store); 164593f8c16dSAzael Avalos static DEVICE_ATTR(kbd_backlight_mode, S_IRUGO | S_IWUSR, 164693f8c16dSAzael Avalos toshiba_kbd_bl_mode_show, toshiba_kbd_bl_mode_store); 164793f8c16dSAzael Avalos static DEVICE_ATTR(kbd_type, S_IRUGO, toshiba_kbd_type_show, NULL); 164893f8c16dSAzael Avalos static DEVICE_ATTR(available_kbd_modes, S_IRUGO, 164993f8c16dSAzael Avalos toshiba_available_kbd_modes_show, NULL); 165093f8c16dSAzael Avalos static DEVICE_ATTR(kbd_backlight_timeout, S_IRUGO | S_IWUSR, 165193f8c16dSAzael Avalos toshiba_kbd_bl_timeout_show, toshiba_kbd_bl_timeout_store); 165293f8c16dSAzael Avalos static DEVICE_ATTR(touchpad, S_IRUGO | S_IWUSR, 165393f8c16dSAzael Avalos toshiba_touchpad_show, toshiba_touchpad_store); 165493f8c16dSAzael Avalos static DEVICE_ATTR(position, S_IRUGO, toshiba_position_show, NULL); 1655e26ffe51SAzael Avalos static DEVICE_ATTR(usb_sleep_charge, S_IRUGO | S_IWUSR, 1656e26ffe51SAzael Avalos toshiba_usb_sleep_charge_show, 1657e26ffe51SAzael Avalos toshiba_usb_sleep_charge_store); 1658182bcaa5SAzael Avalos static DEVICE_ATTR(sleep_functions_on_battery, S_IRUGO | S_IWUSR, 1659182bcaa5SAzael Avalos sleep_functions_on_battery_show, 1660182bcaa5SAzael Avalos sleep_functions_on_battery_store); 1661bb3fe01fSAzael Avalos static DEVICE_ATTR(usb_rapid_charge, S_IRUGO | S_IWUSR, 1662bb3fe01fSAzael Avalos toshiba_usb_rapid_charge_show, 1663bb3fe01fSAzael Avalos toshiba_usb_rapid_charge_store); 1664172ce0a9SAzael Avalos static DEVICE_ATTR(usb_sleep_music, S_IRUGO | S_IWUSR, 1665172ce0a9SAzael Avalos toshiba_usb_sleep_music_show, 1666172ce0a9SAzael Avalos toshiba_usb_sleep_music_store); 1667*bae84195SAzael Avalos static DEVICE_ATTR(kbd_function_keys, S_IRUGO | S_IWUSR, 1668*bae84195SAzael Avalos toshiba_kbd_function_keys_show, 1669*bae84195SAzael Avalos toshiba_kbd_function_keys_store); 167093f8c16dSAzael Avalos 167193f8c16dSAzael Avalos static struct attribute *toshiba_attributes[] = { 1672c6c68ff8SAzael Avalos &dev_attr_version.attr, 167394477d4cSAzael Avalos &dev_attr_fan.attr, 167493f8c16dSAzael Avalos &dev_attr_kbd_backlight_mode.attr, 167593f8c16dSAzael Avalos &dev_attr_kbd_type.attr, 167693f8c16dSAzael Avalos &dev_attr_available_kbd_modes.attr, 167793f8c16dSAzael Avalos &dev_attr_kbd_backlight_timeout.attr, 167893f8c16dSAzael Avalos &dev_attr_touchpad.attr, 167993f8c16dSAzael Avalos &dev_attr_position.attr, 1680e26ffe51SAzael Avalos &dev_attr_usb_sleep_charge.attr, 1681182bcaa5SAzael Avalos &dev_attr_sleep_functions_on_battery.attr, 1682bb3fe01fSAzael Avalos &dev_attr_usb_rapid_charge.attr, 1683172ce0a9SAzael Avalos &dev_attr_usb_sleep_music.attr, 1684*bae84195SAzael Avalos &dev_attr_kbd_function_keys.attr, 168593f8c16dSAzael Avalos NULL, 168693f8c16dSAzael Avalos }; 168793f8c16dSAzael Avalos 168893f8c16dSAzael Avalos static umode_t toshiba_sysfs_is_visible(struct kobject *, 168993f8c16dSAzael Avalos struct attribute *, int); 169093f8c16dSAzael Avalos 169193f8c16dSAzael Avalos static struct attribute_group toshiba_attr_group = { 169293f8c16dSAzael Avalos .is_visible = toshiba_sysfs_is_visible, 169393f8c16dSAzael Avalos .attrs = toshiba_attributes, 169493f8c16dSAzael Avalos }; 1695360f0f39SAzael Avalos 1696c6c68ff8SAzael Avalos static ssize_t toshiba_version_show(struct device *dev, 1697c6c68ff8SAzael Avalos struct device_attribute *attr, char *buf) 1698c6c68ff8SAzael Avalos { 1699c6c68ff8SAzael Avalos return sprintf(buf, "%s\n", TOSHIBA_ACPI_VERSION); 1700c6c68ff8SAzael Avalos } 1701c6c68ff8SAzael Avalos 170294477d4cSAzael Avalos static ssize_t toshiba_fan_store(struct device *dev, 170394477d4cSAzael Avalos struct device_attribute *attr, 170494477d4cSAzael Avalos const char *buf, size_t count) 170594477d4cSAzael Avalos { 170694477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 170794477d4cSAzael Avalos u32 result; 170894477d4cSAzael Avalos int state; 170994477d4cSAzael Avalos int ret; 171094477d4cSAzael Avalos 171194477d4cSAzael Avalos ret = kstrtoint(buf, 0, &state); 171294477d4cSAzael Avalos if (ret) 171394477d4cSAzael Avalos return ret; 171494477d4cSAzael Avalos 171594477d4cSAzael Avalos if (state != 0 && state != 1) 171694477d4cSAzael Avalos return -EINVAL; 171794477d4cSAzael Avalos 171894477d4cSAzael Avalos result = hci_write1(toshiba, HCI_FAN, state); 171994477d4cSAzael Avalos if (result == TOS_FAILURE) 172094477d4cSAzael Avalos return -EIO; 172194477d4cSAzael Avalos else if (result == TOS_NOT_SUPPORTED) 172294477d4cSAzael Avalos return -ENODEV; 172394477d4cSAzael Avalos 172494477d4cSAzael Avalos return count; 172594477d4cSAzael Avalos } 172694477d4cSAzael Avalos 172794477d4cSAzael Avalos static ssize_t toshiba_fan_show(struct device *dev, 172894477d4cSAzael Avalos struct device_attribute *attr, char *buf) 172994477d4cSAzael Avalos { 173094477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 173194477d4cSAzael Avalos u32 value; 173294477d4cSAzael Avalos int ret; 173394477d4cSAzael Avalos 173494477d4cSAzael Avalos ret = get_fan_status(toshiba, &value); 173594477d4cSAzael Avalos if (ret) 173694477d4cSAzael Avalos return ret; 173794477d4cSAzael Avalos 173894477d4cSAzael Avalos return sprintf(buf, "%d\n", value); 173994477d4cSAzael Avalos } 174094477d4cSAzael Avalos 1741360f0f39SAzael Avalos static ssize_t toshiba_kbd_bl_mode_store(struct device *dev, 1742360f0f39SAzael Avalos struct device_attribute *attr, 1743360f0f39SAzael Avalos const char *buf, size_t count) 1744360f0f39SAzael Avalos { 1745360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1746aeaac098SDan Carpenter int mode; 1747aeaac098SDan Carpenter int time; 1748aeaac098SDan Carpenter int ret; 1749360f0f39SAzael Avalos 1750aeaac098SDan Carpenter 1751aeaac098SDan Carpenter ret = kstrtoint(buf, 0, &mode); 1752aeaac098SDan Carpenter if (ret) 1753aeaac098SDan Carpenter return ret; 175493f8c16dSAzael Avalos 175593f8c16dSAzael Avalos /* Check for supported modes depending on keyboard backlight type */ 175693f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 175793f8c16dSAzael Avalos /* Type 1 supports SCI_KBD_MODE_FNZ and SCI_KBD_MODE_AUTO */ 1758aeaac098SDan Carpenter if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO) 1759360f0f39SAzael Avalos return -EINVAL; 176093f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 176193f8c16dSAzael Avalos /* Type 2 doesn't support SCI_KBD_MODE_FNZ */ 176293f8c16dSAzael Avalos if (mode != SCI_KBD_MODE_AUTO && mode != SCI_KBD_MODE_ON && 176393f8c16dSAzael Avalos mode != SCI_KBD_MODE_OFF) 176493f8c16dSAzael Avalos return -EINVAL; 176593f8c16dSAzael Avalos } 1766360f0f39SAzael Avalos 1767360f0f39SAzael Avalos /* Set the Keyboard Backlight Mode where: 1768360f0f39SAzael Avalos * Auto - KBD backlight turns off automatically in given time 1769360f0f39SAzael Avalos * FN-Z - KBD backlight "toggles" when hotkey pressed 177093f8c16dSAzael Avalos * ON - KBD backlight is always on 177193f8c16dSAzael Avalos * OFF - KBD backlight is always off 1772360f0f39SAzael Avalos */ 177393f8c16dSAzael Avalos 177493f8c16dSAzael Avalos /* Only make a change if the actual mode has changed */ 1775aeaac098SDan Carpenter if (toshiba->kbd_mode != mode) { 177693f8c16dSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 1777360f0f39SAzael Avalos time = toshiba->kbd_time << HCI_MISC_SHIFT; 177893f8c16dSAzael Avalos 177993f8c16dSAzael Avalos /* OR the "base time" to the actual method format */ 178093f8c16dSAzael Avalos if (toshiba->kbd_type == 1) { 178193f8c16dSAzael Avalos /* Type 1 requires the current mode */ 178293f8c16dSAzael Avalos time |= toshiba->kbd_mode; 178393f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) { 178493f8c16dSAzael Avalos /* Type 2 requires the desired mode */ 178593f8c16dSAzael Avalos time |= mode; 178693f8c16dSAzael Avalos } 178793f8c16dSAzael Avalos 1788aeaac098SDan Carpenter ret = toshiba_kbd_illum_status_set(toshiba, time); 1789aeaac098SDan Carpenter if (ret) 1790aeaac098SDan Carpenter return ret; 179193f8c16dSAzael Avalos 1792360f0f39SAzael Avalos toshiba->kbd_mode = mode; 1793360f0f39SAzael Avalos } 1794360f0f39SAzael Avalos 1795360f0f39SAzael Avalos return count; 1796360f0f39SAzael Avalos } 1797360f0f39SAzael Avalos 1798360f0f39SAzael Avalos static ssize_t toshiba_kbd_bl_mode_show(struct device *dev, 1799360f0f39SAzael Avalos struct device_attribute *attr, 1800360f0f39SAzael Avalos char *buf) 1801360f0f39SAzael Avalos { 1802360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1803360f0f39SAzael Avalos u32 time; 1804360f0f39SAzael Avalos 1805360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1806360f0f39SAzael Avalos return -EIO; 1807360f0f39SAzael Avalos 180893f8c16dSAzael Avalos return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK); 180993f8c16dSAzael Avalos } 181093f8c16dSAzael Avalos 181193f8c16dSAzael Avalos static ssize_t toshiba_kbd_type_show(struct device *dev, 181293f8c16dSAzael Avalos struct device_attribute *attr, 181393f8c16dSAzael Avalos char *buf) 181493f8c16dSAzael Avalos { 181593f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 181693f8c16dSAzael Avalos 181793f8c16dSAzael Avalos return sprintf(buf, "%d\n", toshiba->kbd_type); 181893f8c16dSAzael Avalos } 181993f8c16dSAzael Avalos 182093f8c16dSAzael Avalos static ssize_t toshiba_available_kbd_modes_show(struct device *dev, 182193f8c16dSAzael Avalos struct device_attribute *attr, 182293f8c16dSAzael Avalos char *buf) 182393f8c16dSAzael Avalos { 182493f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 182593f8c16dSAzael Avalos 182693f8c16dSAzael Avalos if (toshiba->kbd_type == 1) 182793f8c16dSAzael Avalos return sprintf(buf, "%x %x\n", 182893f8c16dSAzael Avalos SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO); 182993f8c16dSAzael Avalos 183093f8c16dSAzael Avalos return sprintf(buf, "%x %x %x\n", 183193f8c16dSAzael Avalos SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF); 1832360f0f39SAzael Avalos } 1833360f0f39SAzael Avalos 1834360f0f39SAzael Avalos static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev, 1835360f0f39SAzael Avalos struct device_attribute *attr, 1836360f0f39SAzael Avalos const char *buf, size_t count) 1837360f0f39SAzael Avalos { 1838360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1839eabde0faSAzael Avalos int time; 1840eabde0faSAzael Avalos int ret; 1841360f0f39SAzael Avalos 1842eabde0faSAzael Avalos ret = kstrtoint(buf, 0, &time); 1843eabde0faSAzael Avalos if (ret) 1844eabde0faSAzael Avalos return ret; 1845eabde0faSAzael Avalos 1846eabde0faSAzael Avalos /* Check for supported values depending on kbd_type */ 1847eabde0faSAzael Avalos if (toshiba->kbd_type == 1) { 1848eabde0faSAzael Avalos if (time < 0 || time > 60) 1849360f0f39SAzael Avalos return -EINVAL; 1850eabde0faSAzael Avalos } else if (toshiba->kbd_type == 2) { 1851eabde0faSAzael Avalos if (time < 1 || time > 60) 1852eabde0faSAzael Avalos return -EINVAL; 1853eabde0faSAzael Avalos } 1854360f0f39SAzael Avalos 1855eabde0faSAzael Avalos /* Set the Keyboard Backlight Timeout */ 1856eabde0faSAzael Avalos 1857eabde0faSAzael Avalos /* Only make a change if the actual timeout has changed */ 1858eabde0faSAzael Avalos if (toshiba->kbd_time != time) { 1859eabde0faSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 1860360f0f39SAzael Avalos time = time << HCI_MISC_SHIFT; 1861eabde0faSAzael Avalos /* OR the "base time" to the actual method format */ 1862eabde0faSAzael Avalos if (toshiba->kbd_type == 1) 1863eabde0faSAzael Avalos time |= SCI_KBD_MODE_FNZ; 1864eabde0faSAzael Avalos else if (toshiba->kbd_type == 2) 1865eabde0faSAzael Avalos time |= SCI_KBD_MODE_AUTO; 1866eabde0faSAzael Avalos 1867eabde0faSAzael Avalos ret = toshiba_kbd_illum_status_set(toshiba, time); 1868eabde0faSAzael Avalos if (ret) 1869eabde0faSAzael Avalos return ret; 1870eabde0faSAzael Avalos 1871360f0f39SAzael Avalos toshiba->kbd_time = time >> HCI_MISC_SHIFT; 1872360f0f39SAzael Avalos } 1873360f0f39SAzael Avalos 1874360f0f39SAzael Avalos return count; 1875360f0f39SAzael Avalos } 1876360f0f39SAzael Avalos 1877360f0f39SAzael Avalos static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev, 1878360f0f39SAzael Avalos struct device_attribute *attr, 1879360f0f39SAzael Avalos char *buf) 1880360f0f39SAzael Avalos { 1881360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1882360f0f39SAzael Avalos u32 time; 1883360f0f39SAzael Avalos 1884360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 1885360f0f39SAzael Avalos return -EIO; 1886360f0f39SAzael Avalos 1887360f0f39SAzael Avalos return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT); 1888360f0f39SAzael Avalos } 1889360f0f39SAzael Avalos 18909d8658acSAzael Avalos static ssize_t toshiba_touchpad_store(struct device *dev, 18919d8658acSAzael Avalos struct device_attribute *attr, 18929d8658acSAzael Avalos const char *buf, size_t count) 18939d8658acSAzael Avalos { 18949d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 18959d8658acSAzael Avalos int state; 1896c8a41669SAzael Avalos int ret; 18979d8658acSAzael Avalos 18989d8658acSAzael Avalos /* Set the TouchPad on/off, 0 - Disable | 1 - Enable */ 1899c8a41669SAzael Avalos ret = kstrtoint(buf, 0, &state); 1900c8a41669SAzael Avalos if (ret) 1901c8a41669SAzael Avalos return ret; 1902c8a41669SAzael Avalos if (state != 0 && state != 1) 1903c8a41669SAzael Avalos return -EINVAL; 1904c8a41669SAzael Avalos 1905c8a41669SAzael Avalos ret = toshiba_touchpad_set(toshiba, state); 1906c8a41669SAzael Avalos if (ret) 1907c8a41669SAzael Avalos return ret; 19089d8658acSAzael Avalos 19099d8658acSAzael Avalos return count; 19109d8658acSAzael Avalos } 19119d8658acSAzael Avalos 19129d8658acSAzael Avalos static ssize_t toshiba_touchpad_show(struct device *dev, 19139d8658acSAzael Avalos struct device_attribute *attr, char *buf) 19149d8658acSAzael Avalos { 19159d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 19169d8658acSAzael Avalos u32 state; 19179d8658acSAzael Avalos int ret; 19189d8658acSAzael Avalos 19199d8658acSAzael Avalos ret = toshiba_touchpad_get(toshiba, &state); 19209d8658acSAzael Avalos if (ret < 0) 19219d8658acSAzael Avalos return ret; 19229d8658acSAzael Avalos 19239d8658acSAzael Avalos return sprintf(buf, "%i\n", state); 19249d8658acSAzael Avalos } 19259d8658acSAzael Avalos 19265a2813e9SAzael Avalos static ssize_t toshiba_position_show(struct device *dev, 19275a2813e9SAzael Avalos struct device_attribute *attr, char *buf) 19285a2813e9SAzael Avalos { 19295a2813e9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 19305a2813e9SAzael Avalos u32 xyval, zval, tmp; 19315a2813e9SAzael Avalos u16 x, y, z; 19325a2813e9SAzael Avalos int ret; 19335a2813e9SAzael Avalos 19345a2813e9SAzael Avalos xyval = zval = 0; 19355a2813e9SAzael Avalos ret = toshiba_accelerometer_get(toshiba, &xyval, &zval); 19365a2813e9SAzael Avalos if (ret < 0) 19375a2813e9SAzael Avalos return ret; 19385a2813e9SAzael Avalos 19395a2813e9SAzael Avalos x = xyval & HCI_ACCEL_MASK; 19405a2813e9SAzael Avalos tmp = xyval >> HCI_MISC_SHIFT; 19415a2813e9SAzael Avalos y = tmp & HCI_ACCEL_MASK; 19425a2813e9SAzael Avalos z = zval & HCI_ACCEL_MASK; 19435a2813e9SAzael Avalos 19445a2813e9SAzael Avalos return sprintf(buf, "%d %d %d\n", x, y, z); 19455a2813e9SAzael Avalos } 19465a2813e9SAzael Avalos 1947e26ffe51SAzael Avalos static ssize_t toshiba_usb_sleep_charge_show(struct device *dev, 1948e26ffe51SAzael Avalos struct device_attribute *attr, 1949e26ffe51SAzael Avalos char *buf) 1950e26ffe51SAzael Avalos { 1951e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1952e26ffe51SAzael Avalos u32 mode; 1953e26ffe51SAzael Avalos int ret; 1954e26ffe51SAzael Avalos 1955e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_get(toshiba, &mode); 1956e26ffe51SAzael Avalos if (ret < 0) 1957e26ffe51SAzael Avalos return ret; 1958e26ffe51SAzael Avalos 1959e26ffe51SAzael Avalos return sprintf(buf, "%x\n", mode & SCI_USB_CHARGE_MODE_MASK); 1960e26ffe51SAzael Avalos } 1961e26ffe51SAzael Avalos 1962e26ffe51SAzael Avalos static ssize_t toshiba_usb_sleep_charge_store(struct device *dev, 1963e26ffe51SAzael Avalos struct device_attribute *attr, 1964e26ffe51SAzael Avalos const char *buf, size_t count) 1965e26ffe51SAzael Avalos { 1966e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 1967e26ffe51SAzael Avalos u32 mode; 1968e26ffe51SAzael Avalos int state; 1969e26ffe51SAzael Avalos int ret; 1970e26ffe51SAzael Avalos 1971e26ffe51SAzael Avalos ret = kstrtoint(buf, 0, &state); 1972e26ffe51SAzael Avalos if (ret) 1973e26ffe51SAzael Avalos return ret; 1974e26ffe51SAzael Avalos /* Check for supported values, where: 1975e26ffe51SAzael Avalos * 0 - Disabled 1976e26ffe51SAzael Avalos * 1 - Alternate (Non USB conformant devices that require more power) 1977e26ffe51SAzael Avalos * 2 - Auto (USB conformant devices) 1978e26ffe51SAzael Avalos */ 1979e26ffe51SAzael Avalos if (state != 0 && state != 1 && state != 2) 1980e26ffe51SAzael Avalos return -EINVAL; 1981e26ffe51SAzael Avalos 1982e26ffe51SAzael Avalos /* Set the USB charging mode to internal value */ 1983e26ffe51SAzael Avalos if (state == 0) 1984e26ffe51SAzael Avalos mode = SCI_USB_CHARGE_DISABLED; 1985e26ffe51SAzael Avalos else if (state == 1) 1986e26ffe51SAzael Avalos mode = SCI_USB_CHARGE_ALTERNATE; 1987e26ffe51SAzael Avalos else if (state == 2) 1988e26ffe51SAzael Avalos mode = SCI_USB_CHARGE_AUTO; 1989e26ffe51SAzael Avalos 1990e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_set(toshiba, mode); 1991e26ffe51SAzael Avalos if (ret) 1992e26ffe51SAzael Avalos return ret; 1993e26ffe51SAzael Avalos 1994e26ffe51SAzael Avalos return count; 1995e26ffe51SAzael Avalos } 1996e26ffe51SAzael Avalos 1997182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_show(struct device *dev, 1998182bcaa5SAzael Avalos struct device_attribute *attr, 1999182bcaa5SAzael Avalos char *buf) 2000182bcaa5SAzael Avalos { 2001182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2002182bcaa5SAzael Avalos u32 state; 2003182bcaa5SAzael Avalos int bat_lvl; 2004182bcaa5SAzael Avalos int status; 2005182bcaa5SAzael Avalos int ret; 2006182bcaa5SAzael Avalos int tmp; 2007182bcaa5SAzael Avalos 2008182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_get(toshiba, &state); 2009182bcaa5SAzael Avalos if (ret < 0) 2010182bcaa5SAzael Avalos return ret; 2011182bcaa5SAzael Avalos 2012182bcaa5SAzael Avalos /* Determine the status: 0x4 - Enabled | 0x1 - Disabled */ 2013182bcaa5SAzael Avalos tmp = state & SCI_USB_CHARGE_BAT_MASK; 2014182bcaa5SAzael Avalos status = (tmp == 0x4) ? 1 : 0; 2015182bcaa5SAzael Avalos /* Determine the battery level set */ 2016182bcaa5SAzael Avalos bat_lvl = state >> HCI_MISC_SHIFT; 2017182bcaa5SAzael Avalos 2018182bcaa5SAzael Avalos return sprintf(buf, "%d %d\n", status, bat_lvl); 2019182bcaa5SAzael Avalos } 2020182bcaa5SAzael Avalos 2021182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_store(struct device *dev, 2022182bcaa5SAzael Avalos struct device_attribute *attr, 2023182bcaa5SAzael Avalos const char *buf, size_t count) 2024182bcaa5SAzael Avalos { 2025182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2026182bcaa5SAzael Avalos u32 status; 2027182bcaa5SAzael Avalos int value; 2028182bcaa5SAzael Avalos int ret; 2029182bcaa5SAzael Avalos int tmp; 2030182bcaa5SAzael Avalos 2031182bcaa5SAzael Avalos ret = kstrtoint(buf, 0, &value); 2032182bcaa5SAzael Avalos if (ret) 2033182bcaa5SAzael Avalos return ret; 2034182bcaa5SAzael Avalos 2035182bcaa5SAzael Avalos /* Set the status of the function: 2036182bcaa5SAzael Avalos * 0 - Disabled 2037182bcaa5SAzael Avalos * 1-100 - Enabled 2038182bcaa5SAzael Avalos */ 2039182bcaa5SAzael Avalos if (value < 0 || value > 100) 2040182bcaa5SAzael Avalos return -EINVAL; 2041182bcaa5SAzael Avalos 2042182bcaa5SAzael Avalos if (value == 0) { 2043182bcaa5SAzael Avalos tmp = toshiba->usbsc_bat_level << HCI_MISC_SHIFT; 2044182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_OFF; 2045182bcaa5SAzael Avalos } else { 2046182bcaa5SAzael Avalos tmp = value << HCI_MISC_SHIFT; 2047182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_ON; 2048182bcaa5SAzael Avalos } 2049182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_set(toshiba, status); 2050182bcaa5SAzael Avalos if (ret < 0) 2051182bcaa5SAzael Avalos return ret; 2052182bcaa5SAzael Avalos 2053182bcaa5SAzael Avalos toshiba->usbsc_bat_level = status >> HCI_MISC_SHIFT; 2054182bcaa5SAzael Avalos 2055182bcaa5SAzael Avalos return count; 2056182bcaa5SAzael Avalos } 2057182bcaa5SAzael Avalos 2058bb3fe01fSAzael Avalos static ssize_t toshiba_usb_rapid_charge_show(struct device *dev, 2059bb3fe01fSAzael Avalos struct device_attribute *attr, 2060bb3fe01fSAzael Avalos char *buf) 2061bb3fe01fSAzael Avalos { 2062bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2063bb3fe01fSAzael Avalos u32 state; 2064bb3fe01fSAzael Avalos int ret; 2065bb3fe01fSAzael Avalos 2066bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(toshiba, &state); 2067bb3fe01fSAzael Avalos if (ret < 0) 2068bb3fe01fSAzael Avalos return ret; 2069bb3fe01fSAzael Avalos 2070bb3fe01fSAzael Avalos return sprintf(buf, "%d\n", state); 2071bb3fe01fSAzael Avalos } 2072bb3fe01fSAzael Avalos 2073bb3fe01fSAzael Avalos static ssize_t toshiba_usb_rapid_charge_store(struct device *dev, 2074bb3fe01fSAzael Avalos struct device_attribute *attr, 2075bb3fe01fSAzael Avalos const char *buf, size_t count) 2076bb3fe01fSAzael Avalos { 2077bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2078bb3fe01fSAzael Avalos int state; 2079bb3fe01fSAzael Avalos int ret; 2080bb3fe01fSAzael Avalos 2081bb3fe01fSAzael Avalos ret = kstrtoint(buf, 0, &state); 2082bb3fe01fSAzael Avalos if (ret) 2083bb3fe01fSAzael Avalos return ret; 2084bb3fe01fSAzael Avalos if (state != 0 && state != 1) 2085bb3fe01fSAzael Avalos return -EINVAL; 2086bb3fe01fSAzael Avalos 2087bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_set(toshiba, state); 2088bb3fe01fSAzael Avalos if (ret) 2089bb3fe01fSAzael Avalos return ret; 2090bb3fe01fSAzael Avalos 2091bb3fe01fSAzael Avalos return count; 2092bb3fe01fSAzael Avalos } 2093bb3fe01fSAzael Avalos 2094172ce0a9SAzael Avalos static ssize_t toshiba_usb_sleep_music_show(struct device *dev, 2095172ce0a9SAzael Avalos struct device_attribute *attr, 2096172ce0a9SAzael Avalos char *buf) 2097172ce0a9SAzael Avalos { 2098172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2099172ce0a9SAzael Avalos u32 state; 2100172ce0a9SAzael Avalos int ret; 2101172ce0a9SAzael Avalos 2102172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(toshiba, &state); 2103172ce0a9SAzael Avalos if (ret < 0) 2104172ce0a9SAzael Avalos return ret; 2105172ce0a9SAzael Avalos 2106172ce0a9SAzael Avalos return sprintf(buf, "%d\n", state); 2107172ce0a9SAzael Avalos } 2108172ce0a9SAzael Avalos 2109172ce0a9SAzael Avalos static ssize_t toshiba_usb_sleep_music_store(struct device *dev, 2110172ce0a9SAzael Avalos struct device_attribute *attr, 2111172ce0a9SAzael Avalos const char *buf, size_t count) 2112172ce0a9SAzael Avalos { 2113172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2114172ce0a9SAzael Avalos int state; 2115172ce0a9SAzael Avalos int ret; 2116172ce0a9SAzael Avalos 2117172ce0a9SAzael Avalos ret = kstrtoint(buf, 0, &state); 2118172ce0a9SAzael Avalos if (ret) 2119172ce0a9SAzael Avalos return ret; 2120172ce0a9SAzael Avalos if (state != 0 && state != 1) 2121172ce0a9SAzael Avalos return -EINVAL; 2122172ce0a9SAzael Avalos 2123172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_set(toshiba, state); 2124172ce0a9SAzael Avalos if (ret) 2125172ce0a9SAzael Avalos return ret; 2126172ce0a9SAzael Avalos 2127172ce0a9SAzael Avalos return count; 2128172ce0a9SAzael Avalos } 2129172ce0a9SAzael Avalos 2130*bae84195SAzael Avalos static ssize_t toshiba_kbd_function_keys_show(struct device *dev, 2131*bae84195SAzael Avalos struct device_attribute *attr, 2132*bae84195SAzael Avalos char *buf) 2133*bae84195SAzael Avalos { 2134*bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2135*bae84195SAzael Avalos int mode; 2136*bae84195SAzael Avalos int ret; 2137*bae84195SAzael Avalos 2138*bae84195SAzael Avalos ret = toshiba_function_keys_get(toshiba, &mode); 2139*bae84195SAzael Avalos if (ret < 0) 2140*bae84195SAzael Avalos return ret; 2141*bae84195SAzael Avalos 2142*bae84195SAzael Avalos return sprintf(buf, "%d\n", mode); 2143*bae84195SAzael Avalos } 2144*bae84195SAzael Avalos 2145*bae84195SAzael Avalos static ssize_t toshiba_kbd_function_keys_store(struct device *dev, 2146*bae84195SAzael Avalos struct device_attribute *attr, 2147*bae84195SAzael Avalos const char *buf, size_t count) 2148*bae84195SAzael Avalos { 2149*bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 2150*bae84195SAzael Avalos int mode; 2151*bae84195SAzael Avalos int ret; 2152*bae84195SAzael Avalos 2153*bae84195SAzael Avalos ret = kstrtoint(buf, 0, &mode); 2154*bae84195SAzael Avalos if (ret) 2155*bae84195SAzael Avalos return ret; 2156*bae84195SAzael Avalos /* Check for the function keys mode where: 2157*bae84195SAzael Avalos * 0 - Normal operation (F{1-12} as usual and hotkeys via FN-F{1-12}) 2158*bae84195SAzael Avalos * 1 - Special functions (Opposite of the above setting) 2159*bae84195SAzael Avalos */ 2160*bae84195SAzael Avalos if (mode != 0 && mode != 1) 2161*bae84195SAzael Avalos return -EINVAL; 2162*bae84195SAzael Avalos 2163*bae84195SAzael Avalos ret = toshiba_function_keys_set(toshiba, mode); 2164*bae84195SAzael Avalos if (ret) 2165*bae84195SAzael Avalos return ret; 2166*bae84195SAzael Avalos 2167*bae84195SAzael Avalos pr_info("Reboot for changes to KBD Function Keys to take effect"); 2168*bae84195SAzael Avalos 2169*bae84195SAzael Avalos return count; 2170*bae84195SAzael Avalos } 2171*bae84195SAzael Avalos 2172360f0f39SAzael Avalos static umode_t toshiba_sysfs_is_visible(struct kobject *kobj, 2173360f0f39SAzael Avalos struct attribute *attr, int idx) 2174360f0f39SAzael Avalos { 2175360f0f39SAzael Avalos struct device *dev = container_of(kobj, struct device, kobj); 2176360f0f39SAzael Avalos struct toshiba_acpi_dev *drv = dev_get_drvdata(dev); 2177360f0f39SAzael Avalos bool exists = true; 2178360f0f39SAzael Avalos 217994477d4cSAzael Avalos if (attr == &dev_attr_fan.attr) 218094477d4cSAzael Avalos exists = (drv->fan_supported) ? true : false; 218194477d4cSAzael Avalos else if (attr == &dev_attr_kbd_backlight_mode.attr) 2182360f0f39SAzael Avalos exists = (drv->kbd_illum_supported) ? true : false; 2183360f0f39SAzael Avalos else if (attr == &dev_attr_kbd_backlight_timeout.attr) 2184360f0f39SAzael Avalos exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false; 21859d8658acSAzael Avalos else if (attr == &dev_attr_touchpad.attr) 21869d8658acSAzael Avalos exists = (drv->touchpad_supported) ? true : false; 21875a2813e9SAzael Avalos else if (attr == &dev_attr_position.attr) 21885a2813e9SAzael Avalos exists = (drv->accelerometer_supported) ? true : false; 2189e26ffe51SAzael Avalos else if (attr == &dev_attr_usb_sleep_charge.attr) 2190e26ffe51SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2191182bcaa5SAzael Avalos else if (attr == &dev_attr_sleep_functions_on_battery.attr) 2192182bcaa5SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false; 2193bb3fe01fSAzael Avalos else if (attr == &dev_attr_usb_rapid_charge.attr) 2194bb3fe01fSAzael Avalos exists = (drv->usb_rapid_charge_supported) ? true : false; 2195172ce0a9SAzael Avalos else if (attr == &dev_attr_usb_sleep_music.attr) 2196172ce0a9SAzael Avalos exists = (drv->usb_sleep_music_supported) ? true : false; 2197*bae84195SAzael Avalos else if (attr == &dev_attr_kbd_function_keys.attr) 2198*bae84195SAzael Avalos exists = (drv->kbd_function_keys_supported) ? true : false; 2199360f0f39SAzael Avalos 2200360f0f39SAzael Avalos return exists ? attr->mode : 0; 2201360f0f39SAzael Avalos } 2202360f0f39SAzael Avalos 22031f28f290SAzael Avalos /* 22041f28f290SAzael Avalos * Hotkeys 22051f28f290SAzael Avalos */ 22061f28f290SAzael Avalos static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev) 22071f28f290SAzael Avalos { 22081f28f290SAzael Avalos acpi_status status; 22091f28f290SAzael Avalos u32 result; 22101f28f290SAzael Avalos 22111f28f290SAzael Avalos status = acpi_evaluate_object(dev->acpi_dev->handle, 22121f28f290SAzael Avalos "ENAB", NULL, NULL); 22131f28f290SAzael Avalos if (ACPI_FAILURE(status)) 22141f28f290SAzael Avalos return -ENODEV; 22151f28f290SAzael Avalos 22161f28f290SAzael Avalos result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE); 22171f28f290SAzael Avalos if (result == TOS_FAILURE) 22181f28f290SAzael Avalos return -EIO; 22191f28f290SAzael Avalos else if (result == TOS_NOT_SUPPORTED) 22201f28f290SAzael Avalos return -ENODEV; 22211f28f290SAzael Avalos 22221f28f290SAzael Avalos return 0; 22231f28f290SAzael Avalos } 22241f28f290SAzael Avalos 222529cd293fSSeth Forshee static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, 222629cd293fSSeth Forshee struct serio *port) 222729cd293fSSeth Forshee { 222898280374SGiedrius Statkevičius if (str & I8042_STR_AUXDATA) 222929cd293fSSeth Forshee return false; 223029cd293fSSeth Forshee 223129cd293fSSeth Forshee if (unlikely(data == 0xe0)) 223229cd293fSSeth Forshee return false; 223329cd293fSSeth Forshee 223429cd293fSSeth Forshee if ((data & 0x7f) == TOS1900_FN_SCAN) { 223529cd293fSSeth Forshee schedule_work(&toshiba_acpi->hotkey_work); 223629cd293fSSeth Forshee return true; 223729cd293fSSeth Forshee } 223829cd293fSSeth Forshee 223929cd293fSSeth Forshee return false; 224029cd293fSSeth Forshee } 224129cd293fSSeth Forshee 224229cd293fSSeth Forshee static void toshiba_acpi_hotkey_work(struct work_struct *work) 224329cd293fSSeth Forshee { 224429cd293fSSeth Forshee acpi_handle ec_handle = ec_get_handle(); 224529cd293fSSeth Forshee acpi_status status; 224629cd293fSSeth Forshee 224729cd293fSSeth Forshee if (!ec_handle) 224829cd293fSSeth Forshee return; 224929cd293fSSeth Forshee 225029cd293fSSeth Forshee status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL); 225129cd293fSSeth Forshee if (ACPI_FAILURE(status)) 225229cd293fSSeth Forshee pr_err("ACPI NTFY method execution failed\n"); 225329cd293fSSeth Forshee } 225429cd293fSSeth Forshee 225529cd293fSSeth Forshee /* 225629cd293fSSeth Forshee * Returns hotkey scancode, or < 0 on failure. 225729cd293fSSeth Forshee */ 225829cd293fSSeth Forshee static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev) 225929cd293fSSeth Forshee { 226074facaf7SZhang Rui unsigned long long value; 226129cd293fSSeth Forshee acpi_status status; 226229cd293fSSeth Forshee 226374facaf7SZhang Rui status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO", 226474facaf7SZhang Rui NULL, &value); 226574facaf7SZhang Rui if (ACPI_FAILURE(status)) { 226629cd293fSSeth Forshee pr_err("ACPI INFO method execution failed\n"); 226729cd293fSSeth Forshee return -EIO; 226829cd293fSSeth Forshee } 226929cd293fSSeth Forshee 227074facaf7SZhang Rui return value; 227129cd293fSSeth Forshee } 227229cd293fSSeth Forshee 227329cd293fSSeth Forshee static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev, 227429cd293fSSeth Forshee int scancode) 227529cd293fSSeth Forshee { 227629cd293fSSeth Forshee if (scancode == 0x100) 227729cd293fSSeth Forshee return; 227829cd293fSSeth Forshee 227929cd293fSSeth Forshee /* act on key press; ignore key release */ 228029cd293fSSeth Forshee if (scancode & 0x80) 228129cd293fSSeth Forshee return; 228229cd293fSSeth Forshee 228329cd293fSSeth Forshee if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true)) 228429cd293fSSeth Forshee pr_info("Unknown key %x\n", scancode); 228529cd293fSSeth Forshee } 228629cd293fSSeth Forshee 228771454d78SAzael Avalos static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) 228871454d78SAzael Avalos { 228971454d78SAzael Avalos u32 hci_result, value; 229071454d78SAzael Avalos int retries = 3; 229171454d78SAzael Avalos int scancode; 229271454d78SAzael Avalos 229371454d78SAzael Avalos if (dev->info_supported) { 229471454d78SAzael Avalos scancode = toshiba_acpi_query_hotkey(dev); 229571454d78SAzael Avalos if (scancode < 0) 229671454d78SAzael Avalos pr_err("Failed to query hotkey event\n"); 229771454d78SAzael Avalos else if (scancode != 0) 229871454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, scancode); 229971454d78SAzael Avalos } else if (dev->system_event_supported) { 230071454d78SAzael Avalos do { 230171454d78SAzael Avalos hci_result = hci_read1(dev, HCI_SYSTEM_EVENT, &value); 230271454d78SAzael Avalos switch (hci_result) { 230371454d78SAzael Avalos case TOS_SUCCESS: 230471454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, (int)value); 230571454d78SAzael Avalos break; 230671454d78SAzael Avalos case TOS_NOT_SUPPORTED: 230771454d78SAzael Avalos /* 230871454d78SAzael Avalos * This is a workaround for an unresolved 230971454d78SAzael Avalos * issue on some machines where system events 231071454d78SAzael Avalos * sporadically become disabled. 231171454d78SAzael Avalos */ 231271454d78SAzael Avalos hci_result = 231371454d78SAzael Avalos hci_write1(dev, HCI_SYSTEM_EVENT, 1); 231471454d78SAzael Avalos pr_notice("Re-enabled hotkeys\n"); 231571454d78SAzael Avalos /* fall through */ 231671454d78SAzael Avalos default: 231771454d78SAzael Avalos retries--; 231871454d78SAzael Avalos break; 231971454d78SAzael Avalos } 232071454d78SAzael Avalos } while (retries && hci_result != TOS_FIFO_EMPTY); 232171454d78SAzael Avalos } 232271454d78SAzael Avalos } 232371454d78SAzael Avalos 2324b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) 23256335e4d5SMatthew Garrett { 2326e2e19606SZhang Rui acpi_handle ec_handle; 2327135740deSSeth Forshee int error; 232829cd293fSSeth Forshee u32 hci_result; 2329fe808bfbSTakashi Iwai const struct key_entry *keymap = toshiba_acpi_keymap; 2330135740deSSeth Forshee 2331135740deSSeth Forshee dev->hotkey_dev = input_allocate_device(); 2332b222cca6SJoe Perches if (!dev->hotkey_dev) 2333135740deSSeth Forshee return -ENOMEM; 2334135740deSSeth Forshee 2335135740deSSeth Forshee dev->hotkey_dev->name = "Toshiba input device"; 23366e02cc7eSSeth Forshee dev->hotkey_dev->phys = "toshiba_acpi/input0"; 2337135740deSSeth Forshee dev->hotkey_dev->id.bustype = BUS_HOST; 2338135740deSSeth Forshee 2339fe808bfbSTakashi Iwai if (dmi_check_system(toshiba_alt_keymap_dmi)) 2340fe808bfbSTakashi Iwai keymap = toshiba_acpi_alt_keymap; 2341fe808bfbSTakashi Iwai error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL); 2342135740deSSeth Forshee if (error) 2343135740deSSeth Forshee goto err_free_dev; 2344135740deSSeth Forshee 234529cd293fSSeth Forshee /* 234629cd293fSSeth Forshee * For some machines the SCI responsible for providing hotkey 234729cd293fSSeth Forshee * notification doesn't fire. We can trigger the notification 234829cd293fSSeth Forshee * whenever the Fn key is pressed using the NTFY method, if 234929cd293fSSeth Forshee * supported, so if it's present set up an i8042 key filter 235029cd293fSSeth Forshee * for this purpose. 235129cd293fSSeth Forshee */ 235229cd293fSSeth Forshee ec_handle = ec_get_handle(); 2353e2e19606SZhang Rui if (ec_handle && acpi_has_method(ec_handle, "NTFY")) { 235429cd293fSSeth Forshee INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work); 235529cd293fSSeth Forshee 235629cd293fSSeth Forshee error = i8042_install_filter(toshiba_acpi_i8042_filter); 235729cd293fSSeth Forshee if (error) { 235829cd293fSSeth Forshee pr_err("Error installing key filter\n"); 235929cd293fSSeth Forshee goto err_free_keymap; 236029cd293fSSeth Forshee } 236129cd293fSSeth Forshee 236229cd293fSSeth Forshee dev->ntfy_supported = 1; 236329cd293fSSeth Forshee } 236429cd293fSSeth Forshee 236529cd293fSSeth Forshee /* 236629cd293fSSeth Forshee * Determine hotkey query interface. Prefer using the INFO 236729cd293fSSeth Forshee * method when it is available. 236829cd293fSSeth Forshee */ 2369e2e19606SZhang Rui if (acpi_has_method(dev->acpi_dev->handle, "INFO")) 237029cd293fSSeth Forshee dev->info_supported = 1; 2371e2e19606SZhang Rui else { 2372893f3f62SAzael Avalos hci_result = hci_write1(dev, HCI_SYSTEM_EVENT, 1); 23731864bbc2SAzael Avalos if (hci_result == TOS_SUCCESS) 237429cd293fSSeth Forshee dev->system_event_supported = 1; 237529cd293fSSeth Forshee } 237629cd293fSSeth Forshee 237729cd293fSSeth Forshee if (!dev->info_supported && !dev->system_event_supported) { 237829cd293fSSeth Forshee pr_warn("No hotkey query interface found\n"); 237929cd293fSSeth Forshee goto err_remove_filter; 238029cd293fSSeth Forshee } 238129cd293fSSeth Forshee 23821f28f290SAzael Avalos error = toshiba_acpi_enable_hotkeys(dev); 23831f28f290SAzael Avalos if (error) { 2384135740deSSeth Forshee pr_info("Unable to enable hotkeys\n"); 238529cd293fSSeth Forshee goto err_remove_filter; 2386135740deSSeth Forshee } 2387135740deSSeth Forshee 2388135740deSSeth Forshee error = input_register_device(dev->hotkey_dev); 2389135740deSSeth Forshee if (error) { 2390135740deSSeth Forshee pr_info("Unable to register input device\n"); 239129cd293fSSeth Forshee goto err_remove_filter; 2392135740deSSeth Forshee } 2393135740deSSeth Forshee 2394135740deSSeth Forshee return 0; 2395135740deSSeth Forshee 239629cd293fSSeth Forshee err_remove_filter: 239729cd293fSSeth Forshee if (dev->ntfy_supported) 239829cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 2399135740deSSeth Forshee err_free_keymap: 2400135740deSSeth Forshee sparse_keymap_free(dev->hotkey_dev); 2401135740deSSeth Forshee err_free_dev: 2402135740deSSeth Forshee input_free_device(dev->hotkey_dev); 2403135740deSSeth Forshee dev->hotkey_dev = NULL; 2404135740deSSeth Forshee return error; 2405135740deSSeth Forshee } 2406135740deSSeth Forshee 2407b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) 240862cce752SSeth Forshee { 240962cce752SSeth Forshee struct backlight_properties props; 241062cce752SSeth Forshee int brightness; 241162cce752SSeth Forshee int ret; 2412121b7b0dSAkio Idehara bool enabled; 241362cce752SSeth Forshee 241462cce752SSeth Forshee /* 241562cce752SSeth Forshee * Some machines don't support the backlight methods at all, and 241662cce752SSeth Forshee * others support it read-only. Either of these is pretty useless, 241762cce752SSeth Forshee * so only register the backlight device if the backlight method 241862cce752SSeth Forshee * supports both reads and writes. 241962cce752SSeth Forshee */ 242062cce752SSeth Forshee brightness = __get_lcd_brightness(dev); 242162cce752SSeth Forshee if (brightness < 0) 242262cce752SSeth Forshee return 0; 242362cce752SSeth Forshee ret = set_lcd_brightness(dev, brightness); 242462cce752SSeth Forshee if (ret) { 242562cce752SSeth Forshee pr_debug("Backlight method is read-only, disabling backlight support\n"); 242662cce752SSeth Forshee return 0; 242762cce752SSeth Forshee } 242862cce752SSeth Forshee 2429121b7b0dSAkio Idehara /* Determine whether or not BIOS supports transflective backlight */ 2430121b7b0dSAkio Idehara ret = get_tr_backlight_status(dev, &enabled); 2431121b7b0dSAkio Idehara dev->tr_backlight_supported = !ret; 2432121b7b0dSAkio Idehara 243353039f22SMatthew Garrett memset(&props, 0, sizeof(props)); 243462cce752SSeth Forshee props.type = BACKLIGHT_PLATFORM; 243562cce752SSeth Forshee props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; 243662cce752SSeth Forshee 2437121b7b0dSAkio Idehara /* adding an extra level and having 0 change to transflective mode */ 2438121b7b0dSAkio Idehara if (dev->tr_backlight_supported) 2439121b7b0dSAkio Idehara props.max_brightness++; 2440121b7b0dSAkio Idehara 244162cce752SSeth Forshee dev->backlight_dev = backlight_device_register("toshiba", 244262cce752SSeth Forshee &dev->acpi_dev->dev, 244362cce752SSeth Forshee dev, 244462cce752SSeth Forshee &toshiba_backlight_data, 244562cce752SSeth Forshee &props); 244662cce752SSeth Forshee if (IS_ERR(dev->backlight_dev)) { 244762cce752SSeth Forshee ret = PTR_ERR(dev->backlight_dev); 244862cce752SSeth Forshee pr_err("Could not register toshiba backlight device\n"); 244962cce752SSeth Forshee dev->backlight_dev = NULL; 245062cce752SSeth Forshee return ret; 245162cce752SSeth Forshee } 245262cce752SSeth Forshee 245362cce752SSeth Forshee dev->backlight_dev->props.brightness = brightness; 245462cce752SSeth Forshee return 0; 245562cce752SSeth Forshee } 245662cce752SSeth Forshee 245751fac838SRafael J. Wysocki static int toshiba_acpi_remove(struct acpi_device *acpi_dev) 2458135740deSSeth Forshee { 2459135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 2460135740deSSeth Forshee 246136d03f93SSeth Forshee remove_toshiba_proc_entries(dev); 2462135740deSSeth Forshee 2463360f0f39SAzael Avalos if (dev->sysfs_created) 2464360f0f39SAzael Avalos sysfs_remove_group(&dev->acpi_dev->dev.kobj, 2465360f0f39SAzael Avalos &toshiba_attr_group); 2466360f0f39SAzael Avalos 246729cd293fSSeth Forshee if (dev->ntfy_supported) { 246829cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter); 246929cd293fSSeth Forshee cancel_work_sync(&dev->hotkey_work); 247029cd293fSSeth Forshee } 247129cd293fSSeth Forshee 2472135740deSSeth Forshee if (dev->hotkey_dev) { 2473135740deSSeth Forshee input_unregister_device(dev->hotkey_dev); 2474135740deSSeth Forshee sparse_keymap_free(dev->hotkey_dev); 2475135740deSSeth Forshee } 2476135740deSSeth Forshee 2477135740deSSeth Forshee if (dev->bt_rfk) { 2478135740deSSeth Forshee rfkill_unregister(dev->bt_rfk); 2479135740deSSeth Forshee rfkill_destroy(dev->bt_rfk); 2480135740deSSeth Forshee } 2481135740deSSeth Forshee 2482135740deSSeth Forshee backlight_device_unregister(dev->backlight_dev); 2483135740deSSeth Forshee 248436d03f93SSeth Forshee if (dev->illumination_supported) 2485135740deSSeth Forshee led_classdev_unregister(&dev->led_dev); 2486135740deSSeth Forshee 2487360f0f39SAzael Avalos if (dev->kbd_led_registered) 2488360f0f39SAzael Avalos led_classdev_unregister(&dev->kbd_led); 2489360f0f39SAzael Avalos 2490def6c4e2SAzael Avalos if (dev->eco_supported) 2491def6c4e2SAzael Avalos led_classdev_unregister(&dev->eco_led); 2492def6c4e2SAzael Avalos 249329cd293fSSeth Forshee if (toshiba_acpi) 249429cd293fSSeth Forshee toshiba_acpi = NULL; 249529cd293fSSeth Forshee 2496135740deSSeth Forshee kfree(dev); 2497135740deSSeth Forshee 2498135740deSSeth Forshee return 0; 2499135740deSSeth Forshee } 2500135740deSSeth Forshee 2501b859f159SGreg Kroah-Hartman static const char *find_hci_method(acpi_handle handle) 2502a540d6b5SSeth Forshee { 2503e2e19606SZhang Rui if (acpi_has_method(handle, "GHCI")) 2504a540d6b5SSeth Forshee return "GHCI"; 2505a540d6b5SSeth Forshee 2506e2e19606SZhang Rui if (acpi_has_method(handle, "SPFC")) 2507a540d6b5SSeth Forshee return "SPFC"; 2508a540d6b5SSeth Forshee 2509a540d6b5SSeth Forshee return NULL; 2510a540d6b5SSeth Forshee } 2511a540d6b5SSeth Forshee 2512b859f159SGreg Kroah-Hartman static int toshiba_acpi_add(struct acpi_device *acpi_dev) 2513135740deSSeth Forshee { 2514135740deSSeth Forshee struct toshiba_acpi_dev *dev; 2515a540d6b5SSeth Forshee const char *hci_method; 251636d03f93SSeth Forshee u32 dummy; 2517135740deSSeth Forshee bool bt_present; 2518135740deSSeth Forshee int ret = 0; 2519135740deSSeth Forshee 252029cd293fSSeth Forshee if (toshiba_acpi) 252129cd293fSSeth Forshee return -EBUSY; 252229cd293fSSeth Forshee 2523135740deSSeth Forshee pr_info("Toshiba Laptop ACPI Extras version %s\n", 2524135740deSSeth Forshee TOSHIBA_ACPI_VERSION); 2525135740deSSeth Forshee 2526a540d6b5SSeth Forshee hci_method = find_hci_method(acpi_dev->handle); 2527a540d6b5SSeth Forshee if (!hci_method) { 2528a540d6b5SSeth Forshee pr_err("HCI interface not found\n"); 25296e02cc7eSSeth Forshee return -ENODEV; 2530a540d6b5SSeth Forshee } 25316e02cc7eSSeth Forshee 2532135740deSSeth Forshee dev = kzalloc(sizeof(*dev), GFP_KERNEL); 2533135740deSSeth Forshee if (!dev) 2534135740deSSeth Forshee return -ENOMEM; 2535135740deSSeth Forshee dev->acpi_dev = acpi_dev; 2536a540d6b5SSeth Forshee dev->method_hci = hci_method; 2537135740deSSeth Forshee acpi_dev->driver_data = dev; 2538360f0f39SAzael Avalos dev_set_drvdata(&acpi_dev->dev, dev); 2539135740deSSeth Forshee 25406e02cc7eSSeth Forshee if (toshiba_acpi_setup_keyboard(dev)) 2541135740deSSeth Forshee pr_info("Unable to activate hotkeys\n"); 2542135740deSSeth Forshee 2543135740deSSeth Forshee mutex_init(&dev->mutex); 2544135740deSSeth Forshee 254562cce752SSeth Forshee ret = toshiba_acpi_setup_backlight(dev); 254662cce752SSeth Forshee if (ret) 2547135740deSSeth Forshee goto error; 2548135740deSSeth Forshee 2549135740deSSeth Forshee /* Register rfkill switch for Bluetooth */ 25501864bbc2SAzael Avalos if (hci_get_bt_present(dev, &bt_present) == TOS_SUCCESS && bt_present) { 2551135740deSSeth Forshee dev->bt_rfk = rfkill_alloc("Toshiba Bluetooth", 2552135740deSSeth Forshee &acpi_dev->dev, 2553135740deSSeth Forshee RFKILL_TYPE_BLUETOOTH, 2554135740deSSeth Forshee &toshiba_rfk_ops, 2555135740deSSeth Forshee dev); 2556135740deSSeth Forshee if (!dev->bt_rfk) { 2557135740deSSeth Forshee pr_err("unable to allocate rfkill device\n"); 2558135740deSSeth Forshee ret = -ENOMEM; 2559135740deSSeth Forshee goto error; 2560135740deSSeth Forshee } 2561135740deSSeth Forshee 2562135740deSSeth Forshee ret = rfkill_register(dev->bt_rfk); 2563135740deSSeth Forshee if (ret) { 2564135740deSSeth Forshee pr_err("unable to register rfkill device\n"); 2565135740deSSeth Forshee rfkill_destroy(dev->bt_rfk); 2566135740deSSeth Forshee goto error; 2567135740deSSeth Forshee } 2568135740deSSeth Forshee } 2569135740deSSeth Forshee 2570135740deSSeth Forshee if (toshiba_illumination_available(dev)) { 2571135740deSSeth Forshee dev->led_dev.name = "toshiba::illumination"; 2572135740deSSeth Forshee dev->led_dev.max_brightness = 1; 2573135740deSSeth Forshee dev->led_dev.brightness_set = toshiba_illumination_set; 2574135740deSSeth Forshee dev->led_dev.brightness_get = toshiba_illumination_get; 2575135740deSSeth Forshee if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev)) 257636d03f93SSeth Forshee dev->illumination_supported = 1; 2577135740deSSeth Forshee } 2578135740deSSeth Forshee 2579def6c4e2SAzael Avalos if (toshiba_eco_mode_available(dev)) { 2580def6c4e2SAzael Avalos dev->eco_led.name = "toshiba::eco_mode"; 2581def6c4e2SAzael Avalos dev->eco_led.max_brightness = 1; 2582def6c4e2SAzael Avalos dev->eco_led.brightness_set = toshiba_eco_mode_set_status; 2583def6c4e2SAzael Avalos dev->eco_led.brightness_get = toshiba_eco_mode_get_status; 2584def6c4e2SAzael Avalos if (!led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led)) 2585def6c4e2SAzael Avalos dev->eco_supported = 1; 2586def6c4e2SAzael Avalos } 2587def6c4e2SAzael Avalos 258893f8c16dSAzael Avalos dev->kbd_illum_supported = toshiba_kbd_illum_available(dev); 2589360f0f39SAzael Avalos /* 2590360f0f39SAzael Avalos * Only register the LED if KBD illumination is supported 2591360f0f39SAzael Avalos * and the keyboard backlight operation mode is set to FN-Z 2592360f0f39SAzael Avalos */ 2593360f0f39SAzael Avalos if (dev->kbd_illum_supported && dev->kbd_mode == SCI_KBD_MODE_FNZ) { 2594360f0f39SAzael Avalos dev->kbd_led.name = "toshiba::kbd_backlight"; 2595360f0f39SAzael Avalos dev->kbd_led.max_brightness = 1; 2596360f0f39SAzael Avalos dev->kbd_led.brightness_set = toshiba_kbd_backlight_set; 2597360f0f39SAzael Avalos dev->kbd_led.brightness_get = toshiba_kbd_backlight_get; 2598360f0f39SAzael Avalos if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led)) 2599360f0f39SAzael Avalos dev->kbd_led_registered = 1; 2600360f0f39SAzael Avalos } 2601360f0f39SAzael Avalos 26029d8658acSAzael Avalos ret = toshiba_touchpad_get(dev, &dummy); 26039d8658acSAzael Avalos dev->touchpad_supported = !ret; 26049d8658acSAzael Avalos 26055a2813e9SAzael Avalos ret = toshiba_accelerometer_supported(dev); 26065a2813e9SAzael Avalos dev->accelerometer_supported = !ret; 26075a2813e9SAzael Avalos 2608e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_get(dev, &dummy); 2609e26ffe51SAzael Avalos dev->usb_sleep_charge_supported = !ret; 2610e26ffe51SAzael Avalos 2611bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(dev, &dummy); 2612bb3fe01fSAzael Avalos dev->usb_rapid_charge_supported = !ret; 2613bb3fe01fSAzael Avalos 2614172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(dev, &dummy); 2615172ce0a9SAzael Avalos dev->usb_sleep_music_supported = !ret; 2616172ce0a9SAzael Avalos 2617*bae84195SAzael Avalos ret = toshiba_function_keys_get(dev, &dummy); 2618*bae84195SAzael Avalos dev->kbd_function_keys_supported = !ret; 2619*bae84195SAzael Avalos 262036d03f93SSeth Forshee /* Determine whether or not BIOS supports fan and video interfaces */ 262136d03f93SSeth Forshee 262236d03f93SSeth Forshee ret = get_video_status(dev, &dummy); 262336d03f93SSeth Forshee dev->video_supported = !ret; 262436d03f93SSeth Forshee 262536d03f93SSeth Forshee ret = get_fan_status(dev, &dummy); 262636d03f93SSeth Forshee dev->fan_supported = !ret; 262736d03f93SSeth Forshee 2628360f0f39SAzael Avalos ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, 2629360f0f39SAzael Avalos &toshiba_attr_group); 2630360f0f39SAzael Avalos if (ret) { 2631360f0f39SAzael Avalos dev->sysfs_created = 0; 2632360f0f39SAzael Avalos goto error; 2633360f0f39SAzael Avalos } 2634360f0f39SAzael Avalos dev->sysfs_created = !ret; 2635360f0f39SAzael Avalos 263636d03f93SSeth Forshee create_toshiba_proc_entries(dev); 263736d03f93SSeth Forshee 263829cd293fSSeth Forshee toshiba_acpi = dev; 263929cd293fSSeth Forshee 2640135740deSSeth Forshee return 0; 2641135740deSSeth Forshee 2642135740deSSeth Forshee error: 264351fac838SRafael J. Wysocki toshiba_acpi_remove(acpi_dev); 2644135740deSSeth Forshee return ret; 2645135740deSSeth Forshee } 2646135740deSSeth Forshee 2647135740deSSeth Forshee static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) 2648135740deSSeth Forshee { 2649135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 265080546905SAzael Avalos int ret; 26516335e4d5SMatthew Garrett 265271454d78SAzael Avalos switch (event) { 265371454d78SAzael Avalos case 0x80: /* Hotkeys and some system events */ 265471454d78SAzael Avalos toshiba_acpi_process_hotkeys(dev); 265511948b93SSeth Forshee break; 265680546905SAzael Avalos case 0x92: /* Keyboard backlight mode changed */ 265780546905SAzael Avalos /* Update sysfs entries */ 265880546905SAzael Avalos ret = sysfs_update_group(&acpi_dev->dev.kobj, 265980546905SAzael Avalos &toshiba_attr_group); 266080546905SAzael Avalos if (ret) 266180546905SAzael Avalos pr_err("Unable to update sysfs entries\n"); 266280546905SAzael Avalos break; 266371454d78SAzael Avalos case 0x81: /* Unknown */ 266471454d78SAzael Avalos case 0x82: /* Unknown */ 266571454d78SAzael Avalos case 0x83: /* Unknown */ 266671454d78SAzael Avalos case 0x8c: /* Unknown */ 266771454d78SAzael Avalos case 0x8e: /* Unknown */ 266871454d78SAzael Avalos case 0x8f: /* Unknown */ 266971454d78SAzael Avalos case 0x90: /* Unknown */ 267011948b93SSeth Forshee default: 267171454d78SAzael Avalos pr_info("Unknown event received %x\n", event); 267211948b93SSeth Forshee break; 26736335e4d5SMatthew Garrett } 267429cd293fSSeth Forshee } 26756335e4d5SMatthew Garrett 26763567a4e2SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP 267743d2fd3bSRafael J. Wysocki static int toshiba_acpi_suspend(struct device *device) 267829cd293fSSeth Forshee { 267943d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 268029cd293fSSeth Forshee u32 result; 268129cd293fSSeth Forshee 268229cd293fSSeth Forshee if (dev->hotkey_dev) 2683893f3f62SAzael Avalos result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE); 268429cd293fSSeth Forshee 268529cd293fSSeth Forshee return 0; 268629cd293fSSeth Forshee } 268729cd293fSSeth Forshee 268843d2fd3bSRafael J. Wysocki static int toshiba_acpi_resume(struct device *device) 268929cd293fSSeth Forshee { 269043d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 26911f28f290SAzael Avalos int error; 269229cd293fSSeth Forshee 2693e7fdb762SBenjamin Tissoires if (dev->hotkey_dev) { 26941f28f290SAzael Avalos error = toshiba_acpi_enable_hotkeys(dev); 26951f28f290SAzael Avalos if (error) 2696e7fdb762SBenjamin Tissoires pr_info("Unable to re-enable hotkeys\n"); 2697e7fdb762SBenjamin Tissoires } 269829cd293fSSeth Forshee 269929cd293fSSeth Forshee return 0; 270029cd293fSSeth Forshee } 27013567a4e2SRafael J. Wysocki #endif 27026335e4d5SMatthew Garrett 270343d2fd3bSRafael J. Wysocki static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm, 270443d2fd3bSRafael J. Wysocki toshiba_acpi_suspend, toshiba_acpi_resume); 270543d2fd3bSRafael J. Wysocki 2706135740deSSeth Forshee static struct acpi_driver toshiba_acpi_driver = { 2707135740deSSeth Forshee .name = "Toshiba ACPI driver", 2708135740deSSeth Forshee .owner = THIS_MODULE, 2709135740deSSeth Forshee .ids = toshiba_device_ids, 2710135740deSSeth Forshee .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, 2711135740deSSeth Forshee .ops = { 2712135740deSSeth Forshee .add = toshiba_acpi_add, 2713135740deSSeth Forshee .remove = toshiba_acpi_remove, 2714135740deSSeth Forshee .notify = toshiba_acpi_notify, 2715135740deSSeth Forshee }, 271643d2fd3bSRafael J. Wysocki .drv.pm = &toshiba_acpi_pm, 2717135740deSSeth Forshee }; 2718b4f9fe12SLen Brown 2719b4f9fe12SLen Brown static int __init toshiba_acpi_init(void) 2720b4f9fe12SLen Brown { 2721135740deSSeth Forshee int ret; 2722b4f9fe12SLen Brown 2723f11f999eSSeth Forshee /* 2724f11f999eSSeth Forshee * Machines with this WMI guid aren't supported due to bugs in 2725f11f999eSSeth Forshee * their AML. This check relies on wmi initializing before 2726f11f999eSSeth Forshee * toshiba_acpi to guarantee guids have been identified. 2727f11f999eSSeth Forshee */ 2728f11f999eSSeth Forshee if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) 2729f11f999eSSeth Forshee return -ENODEV; 2730f11f999eSSeth Forshee 2731b4f9fe12SLen Brown toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); 2732b4f9fe12SLen Brown if (!toshiba_proc_dir) { 2733135740deSSeth Forshee pr_err("Unable to create proc dir " PROC_TOSHIBA "\n"); 2734b4f9fe12SLen Brown return -ENODEV; 2735b4f9fe12SLen Brown } 2736b4f9fe12SLen Brown 2737135740deSSeth Forshee ret = acpi_bus_register_driver(&toshiba_acpi_driver); 2738b4f9fe12SLen Brown if (ret) { 2739135740deSSeth Forshee pr_err("Failed to register ACPI driver: %d\n", ret); 2740135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 2741135740deSSeth Forshee } 2742135740deSSeth Forshee 2743b4f9fe12SLen Brown return ret; 2744b4f9fe12SLen Brown } 2745b4f9fe12SLen Brown 2746135740deSSeth Forshee static void __exit toshiba_acpi_exit(void) 2747135740deSSeth Forshee { 2748135740deSSeth Forshee acpi_bus_unregister_driver(&toshiba_acpi_driver); 2749135740deSSeth Forshee if (toshiba_proc_dir) 2750135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 2751b4f9fe12SLen Brown } 2752b4f9fe12SLen Brown 2753b4f9fe12SLen Brown module_init(toshiba_acpi_init); 2754b4f9fe12SLen Brown module_exit(toshiba_acpi_exit); 2755