18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * toshiba_acpi.c - Toshiba Laptop ACPI Extras 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2002-2004 John Belmonte 68c2ecf20Sopenharmony_ci * Copyright (C) 2008 Philip Langdale 78c2ecf20Sopenharmony_ci * Copyright (C) 2010 Pierre Ducroquet 88c2ecf20Sopenharmony_ci * Copyright (C) 2014-2016 Azael Avalos 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * The devolpment page for this driver is located at 118c2ecf20Sopenharmony_ci * http://memebeam.org/toys/ToshibaAcpiDriver. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Credits: 148c2ecf20Sopenharmony_ci * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse 158c2ecf20Sopenharmony_ci * engineering the Windows drivers 168c2ecf20Sopenharmony_ci * Yasushi Nagato - changes for linux kernel 2.4 -> 2.5 178c2ecf20Sopenharmony_ci * Rob Miller - TV out and hotkeys help 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define TOSHIBA_ACPI_VERSION "0.24" 238c2ecf20Sopenharmony_ci#define PROC_INTERFACE_VERSION 1 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <linux/compiler.h> 268c2ecf20Sopenharmony_ci#include <linux/kernel.h> 278c2ecf20Sopenharmony_ci#include <linux/module.h> 288c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 298c2ecf20Sopenharmony_ci#include <linux/init.h> 308c2ecf20Sopenharmony_ci#include <linux/types.h> 318c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 328c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 338c2ecf20Sopenharmony_ci#include <linux/backlight.h> 348c2ecf20Sopenharmony_ci#include <linux/input.h> 358c2ecf20Sopenharmony_ci#include <linux/input/sparse-keymap.h> 368c2ecf20Sopenharmony_ci#include <linux/leds.h> 378c2ecf20Sopenharmony_ci#include <linux/slab.h> 388c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 398c2ecf20Sopenharmony_ci#include <linux/i8042.h> 408c2ecf20Sopenharmony_ci#include <linux/acpi.h> 418c2ecf20Sopenharmony_ci#include <linux/dmi.h> 428c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 438c2ecf20Sopenharmony_ci#include <linux/miscdevice.h> 448c2ecf20Sopenharmony_ci#include <linux/rfkill.h> 458c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 468c2ecf20Sopenharmony_ci#include <linux/toshiba.h> 478c2ecf20Sopenharmony_ci#include <acpi/video.h> 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ciMODULE_AUTHOR("John Belmonte"); 508c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); 518c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100" 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* Scan code for Fn key on TOS1900 models */ 568c2ecf20Sopenharmony_ci#define TOS1900_FN_SCAN 0x6e 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* Toshiba ACPI method paths */ 598c2ecf20Sopenharmony_ci#define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX" 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * The Toshiba configuration interface is composed of the HCI and the SCI, 638c2ecf20Sopenharmony_ci * which are defined as follows: 648c2ecf20Sopenharmony_ci * 658c2ecf20Sopenharmony_ci * HCI is Toshiba's "Hardware Control Interface" which is supposed to 668c2ecf20Sopenharmony_ci * be uniform across all their models. Ideally we would just call 678c2ecf20Sopenharmony_ci * dedicated ACPI methods instead of using this primitive interface. 688c2ecf20Sopenharmony_ci * However the ACPI methods seem to be incomplete in some areas (for 698c2ecf20Sopenharmony_ci * example they allow setting, but not reading, the LCD brightness value), 708c2ecf20Sopenharmony_ci * so this is still useful. 718c2ecf20Sopenharmony_ci * 728c2ecf20Sopenharmony_ci * SCI stands for "System Configuration Interface" which aim is to 738c2ecf20Sopenharmony_ci * conceal differences in hardware between different models. 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define TCI_WORDS 6 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* Operations */ 798c2ecf20Sopenharmony_ci#define HCI_SET 0xff00 808c2ecf20Sopenharmony_ci#define HCI_GET 0xfe00 818c2ecf20Sopenharmony_ci#define SCI_OPEN 0xf100 828c2ecf20Sopenharmony_ci#define SCI_CLOSE 0xf200 838c2ecf20Sopenharmony_ci#define SCI_GET 0xf300 848c2ecf20Sopenharmony_ci#define SCI_SET 0xf400 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/* Return codes */ 878c2ecf20Sopenharmony_ci#define TOS_SUCCESS 0x0000 888c2ecf20Sopenharmony_ci#define TOS_SUCCESS2 0x0001 898c2ecf20Sopenharmony_ci#define TOS_OPEN_CLOSE_OK 0x0044 908c2ecf20Sopenharmony_ci#define TOS_FAILURE 0x1000 918c2ecf20Sopenharmony_ci#define TOS_NOT_SUPPORTED 0x8000 928c2ecf20Sopenharmony_ci#define TOS_ALREADY_OPEN 0x8100 938c2ecf20Sopenharmony_ci#define TOS_NOT_OPENED 0x8200 948c2ecf20Sopenharmony_ci#define TOS_INPUT_DATA_ERROR 0x8300 958c2ecf20Sopenharmony_ci#define TOS_WRITE_PROTECTED 0x8400 968c2ecf20Sopenharmony_ci#define TOS_NOT_PRESENT 0x8600 978c2ecf20Sopenharmony_ci#define TOS_FIFO_EMPTY 0x8c00 988c2ecf20Sopenharmony_ci#define TOS_DATA_NOT_AVAILABLE 0x8d20 998c2ecf20Sopenharmony_ci#define TOS_NOT_INITIALIZED 0x8d50 1008c2ecf20Sopenharmony_ci#define TOS_NOT_INSTALLED 0x8e00 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/* Registers */ 1038c2ecf20Sopenharmony_ci#define HCI_FAN 0x0004 1048c2ecf20Sopenharmony_ci#define HCI_TR_BACKLIGHT 0x0005 1058c2ecf20Sopenharmony_ci#define HCI_SYSTEM_EVENT 0x0016 1068c2ecf20Sopenharmony_ci#define HCI_VIDEO_OUT 0x001c 1078c2ecf20Sopenharmony_ci#define HCI_HOTKEY_EVENT 0x001e 1088c2ecf20Sopenharmony_ci#define HCI_LCD_BRIGHTNESS 0x002a 1098c2ecf20Sopenharmony_ci#define HCI_WIRELESS 0x0056 1108c2ecf20Sopenharmony_ci#define HCI_ACCELEROMETER 0x006d 1118c2ecf20Sopenharmony_ci#define HCI_COOLING_METHOD 0x007f 1128c2ecf20Sopenharmony_ci#define HCI_KBD_ILLUMINATION 0x0095 1138c2ecf20Sopenharmony_ci#define HCI_ECO_MODE 0x0097 1148c2ecf20Sopenharmony_ci#define HCI_ACCELEROMETER2 0x00a6 1158c2ecf20Sopenharmony_ci#define HCI_SYSTEM_INFO 0xc000 1168c2ecf20Sopenharmony_ci#define SCI_PANEL_POWER_ON 0x010d 1178c2ecf20Sopenharmony_ci#define SCI_ILLUMINATION 0x014e 1188c2ecf20Sopenharmony_ci#define SCI_USB_SLEEP_CHARGE 0x0150 1198c2ecf20Sopenharmony_ci#define SCI_KBD_ILLUM_STATUS 0x015c 1208c2ecf20Sopenharmony_ci#define SCI_USB_SLEEP_MUSIC 0x015e 1218c2ecf20Sopenharmony_ci#define SCI_USB_THREE 0x0169 1228c2ecf20Sopenharmony_ci#define SCI_TOUCHPAD 0x050e 1238c2ecf20Sopenharmony_ci#define SCI_KBD_FUNCTION_KEYS 0x0522 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci/* Field definitions */ 1268c2ecf20Sopenharmony_ci#define HCI_ACCEL_MASK 0x7fff 1278c2ecf20Sopenharmony_ci#define HCI_ACCEL_DIRECTION_MASK 0x8000 1288c2ecf20Sopenharmony_ci#define HCI_HOTKEY_DISABLE 0x0b 1298c2ecf20Sopenharmony_ci#define HCI_HOTKEY_ENABLE 0x09 1308c2ecf20Sopenharmony_ci#define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10 1318c2ecf20Sopenharmony_ci#define HCI_LCD_BRIGHTNESS_BITS 3 1328c2ecf20Sopenharmony_ci#define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) 1338c2ecf20Sopenharmony_ci#define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS) 1348c2ecf20Sopenharmony_ci#define HCI_MISC_SHIFT 0x10 1358c2ecf20Sopenharmony_ci#define HCI_SYSTEM_TYPE1 0x10 1368c2ecf20Sopenharmony_ci#define HCI_SYSTEM_TYPE2 0x11 1378c2ecf20Sopenharmony_ci#define HCI_VIDEO_OUT_LCD 0x1 1388c2ecf20Sopenharmony_ci#define HCI_VIDEO_OUT_CRT 0x2 1398c2ecf20Sopenharmony_ci#define HCI_VIDEO_OUT_TV 0x4 1408c2ecf20Sopenharmony_ci#define SCI_KBD_MODE_MASK 0x1f 1418c2ecf20Sopenharmony_ci#define SCI_KBD_MODE_FNZ 0x1 1428c2ecf20Sopenharmony_ci#define SCI_KBD_MODE_AUTO 0x2 1438c2ecf20Sopenharmony_ci#define SCI_KBD_MODE_ON 0x8 1448c2ecf20Sopenharmony_ci#define SCI_KBD_MODE_OFF 0x10 1458c2ecf20Sopenharmony_ci#define SCI_KBD_TIME_MAX 0x3c001a 1468c2ecf20Sopenharmony_ci#define HCI_WIRELESS_STATUS 0x1 1478c2ecf20Sopenharmony_ci#define HCI_WIRELESS_WWAN 0x3 1488c2ecf20Sopenharmony_ci#define HCI_WIRELESS_WWAN_STATUS 0x2000 1498c2ecf20Sopenharmony_ci#define HCI_WIRELESS_WWAN_POWER 0x4000 1508c2ecf20Sopenharmony_ci#define SCI_USB_CHARGE_MODE_MASK 0xff 1518c2ecf20Sopenharmony_ci#define SCI_USB_CHARGE_DISABLED 0x00 1528c2ecf20Sopenharmony_ci#define SCI_USB_CHARGE_ALTERNATE 0x09 1538c2ecf20Sopenharmony_ci#define SCI_USB_CHARGE_TYPICAL 0x11 1548c2ecf20Sopenharmony_ci#define SCI_USB_CHARGE_AUTO 0x21 1558c2ecf20Sopenharmony_ci#define SCI_USB_CHARGE_BAT_MASK 0x7 1568c2ecf20Sopenharmony_ci#define SCI_USB_CHARGE_BAT_LVL_OFF 0x1 1578c2ecf20Sopenharmony_ci#define SCI_USB_CHARGE_BAT_LVL_ON 0x4 1588c2ecf20Sopenharmony_ci#define SCI_USB_CHARGE_BAT_LVL 0x0200 1598c2ecf20Sopenharmony_ci#define SCI_USB_CHARGE_RAPID_DSP 0x0300 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistruct toshiba_acpi_dev { 1628c2ecf20Sopenharmony_ci struct acpi_device *acpi_dev; 1638c2ecf20Sopenharmony_ci const char *method_hci; 1648c2ecf20Sopenharmony_ci struct input_dev *hotkey_dev; 1658c2ecf20Sopenharmony_ci struct work_struct hotkey_work; 1668c2ecf20Sopenharmony_ci struct backlight_device *backlight_dev; 1678c2ecf20Sopenharmony_ci struct led_classdev led_dev; 1688c2ecf20Sopenharmony_ci struct led_classdev kbd_led; 1698c2ecf20Sopenharmony_ci struct led_classdev eco_led; 1708c2ecf20Sopenharmony_ci struct miscdevice miscdev; 1718c2ecf20Sopenharmony_ci struct rfkill *wwan_rfk; 1728c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci int force_fan; 1758c2ecf20Sopenharmony_ci int last_key_event; 1768c2ecf20Sopenharmony_ci int key_event_valid; 1778c2ecf20Sopenharmony_ci int kbd_type; 1788c2ecf20Sopenharmony_ci int kbd_mode; 1798c2ecf20Sopenharmony_ci int kbd_time; 1808c2ecf20Sopenharmony_ci int usbsc_bat_level; 1818c2ecf20Sopenharmony_ci int usbsc_mode_base; 1828c2ecf20Sopenharmony_ci int hotkey_event_type; 1838c2ecf20Sopenharmony_ci int max_cooling_method; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci unsigned int illumination_supported:1; 1868c2ecf20Sopenharmony_ci unsigned int video_supported:1; 1878c2ecf20Sopenharmony_ci unsigned int fan_supported:1; 1888c2ecf20Sopenharmony_ci unsigned int system_event_supported:1; 1898c2ecf20Sopenharmony_ci unsigned int ntfy_supported:1; 1908c2ecf20Sopenharmony_ci unsigned int info_supported:1; 1918c2ecf20Sopenharmony_ci unsigned int tr_backlight_supported:1; 1928c2ecf20Sopenharmony_ci unsigned int kbd_illum_supported:1; 1938c2ecf20Sopenharmony_ci unsigned int touchpad_supported:1; 1948c2ecf20Sopenharmony_ci unsigned int eco_supported:1; 1958c2ecf20Sopenharmony_ci unsigned int accelerometer_supported:1; 1968c2ecf20Sopenharmony_ci unsigned int usb_sleep_charge_supported:1; 1978c2ecf20Sopenharmony_ci unsigned int usb_rapid_charge_supported:1; 1988c2ecf20Sopenharmony_ci unsigned int usb_sleep_music_supported:1; 1998c2ecf20Sopenharmony_ci unsigned int kbd_function_keys_supported:1; 2008c2ecf20Sopenharmony_ci unsigned int panel_power_on_supported:1; 2018c2ecf20Sopenharmony_ci unsigned int usb_three_supported:1; 2028c2ecf20Sopenharmony_ci unsigned int wwan_supported:1; 2038c2ecf20Sopenharmony_ci unsigned int cooling_method_supported:1; 2048c2ecf20Sopenharmony_ci unsigned int sysfs_created:1; 2058c2ecf20Sopenharmony_ci unsigned int special_functions; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci bool kbd_event_generated; 2088c2ecf20Sopenharmony_ci bool killswitch; 2098c2ecf20Sopenharmony_ci}; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic struct toshiba_acpi_dev *toshiba_acpi; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic bool disable_hotkeys; 2148c2ecf20Sopenharmony_cimodule_param(disable_hotkeys, bool, 0444); 2158c2ecf20Sopenharmony_ciMODULE_PARM_DESC(disable_hotkeys, "Disables the hotkeys activation"); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic const struct acpi_device_id toshiba_device_ids[] = { 2188c2ecf20Sopenharmony_ci {"TOS6200", 0}, 2198c2ecf20Sopenharmony_ci {"TOS6207", 0}, 2208c2ecf20Sopenharmony_ci {"TOS6208", 0}, 2218c2ecf20Sopenharmony_ci {"TOS1900", 0}, 2228c2ecf20Sopenharmony_ci {"", 0}, 2238c2ecf20Sopenharmony_ci}; 2248c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, toshiba_device_ids); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic const struct key_entry toshiba_acpi_keymap[] = { 2278c2ecf20Sopenharmony_ci { KE_KEY, 0x9e, { KEY_RFKILL } }, 2288c2ecf20Sopenharmony_ci { KE_KEY, 0x101, { KEY_MUTE } }, 2298c2ecf20Sopenharmony_ci { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 2308c2ecf20Sopenharmony_ci { KE_KEY, 0x103, { KEY_ZOOMIN } }, 2318c2ecf20Sopenharmony_ci { KE_KEY, 0x10f, { KEY_TAB } }, 2328c2ecf20Sopenharmony_ci { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 2338c2ecf20Sopenharmony_ci { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 2348c2ecf20Sopenharmony_ci { KE_KEY, 0x13b, { KEY_COFFEE } }, 2358c2ecf20Sopenharmony_ci { KE_KEY, 0x13c, { KEY_BATTERY } }, 2368c2ecf20Sopenharmony_ci { KE_KEY, 0x13d, { KEY_SLEEP } }, 2378c2ecf20Sopenharmony_ci { KE_KEY, 0x13e, { KEY_SUSPEND } }, 2388c2ecf20Sopenharmony_ci { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } }, 2398c2ecf20Sopenharmony_ci { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } }, 2408c2ecf20Sopenharmony_ci { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } }, 2418c2ecf20Sopenharmony_ci { KE_KEY, 0x142, { KEY_WLAN } }, 2428c2ecf20Sopenharmony_ci { KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } }, 2438c2ecf20Sopenharmony_ci { KE_KEY, 0x17f, { KEY_FN } }, 2448c2ecf20Sopenharmony_ci { KE_KEY, 0xb05, { KEY_PROG2 } }, 2458c2ecf20Sopenharmony_ci { KE_KEY, 0xb06, { KEY_WWW } }, 2468c2ecf20Sopenharmony_ci { KE_KEY, 0xb07, { KEY_MAIL } }, 2478c2ecf20Sopenharmony_ci { KE_KEY, 0xb30, { KEY_STOP } }, 2488c2ecf20Sopenharmony_ci { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } }, 2498c2ecf20Sopenharmony_ci { KE_KEY, 0xb32, { KEY_NEXTSONG } }, 2508c2ecf20Sopenharmony_ci { KE_KEY, 0xb33, { KEY_PLAYPAUSE } }, 2518c2ecf20Sopenharmony_ci { KE_KEY, 0xb5a, { KEY_MEDIA } }, 2528c2ecf20Sopenharmony_ci { KE_IGNORE, 0x1430, { KEY_RESERVED } }, /* Wake from sleep */ 2538c2ecf20Sopenharmony_ci { KE_IGNORE, 0x1501, { KEY_RESERVED } }, /* Output changed */ 2548c2ecf20Sopenharmony_ci { KE_IGNORE, 0x1502, { KEY_RESERVED } }, /* HDMI plugged/unplugged */ 2558c2ecf20Sopenharmony_ci { KE_IGNORE, 0x1ABE, { KEY_RESERVED } }, /* Protection level set */ 2568c2ecf20Sopenharmony_ci { KE_IGNORE, 0x1ABF, { KEY_RESERVED } }, /* Protection level off */ 2578c2ecf20Sopenharmony_ci { KE_END, 0 }, 2588c2ecf20Sopenharmony_ci}; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic const struct key_entry toshiba_acpi_alt_keymap[] = { 2618c2ecf20Sopenharmony_ci { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 2628c2ecf20Sopenharmony_ci { KE_KEY, 0x103, { KEY_ZOOMIN } }, 2638c2ecf20Sopenharmony_ci { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, 2648c2ecf20Sopenharmony_ci { KE_KEY, 0x139, { KEY_ZOOMRESET } }, 2658c2ecf20Sopenharmony_ci { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } }, 2668c2ecf20Sopenharmony_ci { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } }, 2678c2ecf20Sopenharmony_ci { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } }, 2688c2ecf20Sopenharmony_ci { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } }, 2698c2ecf20Sopenharmony_ci { KE_KEY, 0x157, { KEY_MUTE } }, 2708c2ecf20Sopenharmony_ci { KE_KEY, 0x158, { KEY_WLAN } }, 2718c2ecf20Sopenharmony_ci { KE_END, 0 }, 2728c2ecf20Sopenharmony_ci}; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci/* 2758c2ecf20Sopenharmony_ci * List of models which have a broken acpi-video backlight interface and thus 2768c2ecf20Sopenharmony_ci * need to use the toshiba (vendor) interface instead. 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_cistatic const struct dmi_system_id toshiba_vendor_backlight_dmi[] = { 2798c2ecf20Sopenharmony_ci {} 2808c2ecf20Sopenharmony_ci}; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci/* 2838c2ecf20Sopenharmony_ci * Utility 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic inline void _set_bit(u32 *word, u32 mask, int value) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci *word = (*word & ~mask) | (mask * value); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci/* 2928c2ecf20Sopenharmony_ci * ACPI interface wrappers 2938c2ecf20Sopenharmony_ci */ 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic int write_acpi_int(const char *methodName, int val) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci acpi_status status; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci status = acpi_execute_simple_method(NULL, (char *)methodName, val); 3008c2ecf20Sopenharmony_ci return (status == AE_OK) ? 0 : -EIO; 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci/* 3048c2ecf20Sopenharmony_ci * Perform a raw configuration call. Here we don't care about input or output 3058c2ecf20Sopenharmony_ci * buffer format. 3068c2ecf20Sopenharmony_ci */ 3078c2ecf20Sopenharmony_cistatic acpi_status tci_raw(struct toshiba_acpi_dev *dev, 3088c2ecf20Sopenharmony_ci const u32 in[TCI_WORDS], u32 out[TCI_WORDS]) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci union acpi_object in_objs[TCI_WORDS], out_objs[TCI_WORDS + 1]; 3118c2ecf20Sopenharmony_ci struct acpi_object_list params; 3128c2ecf20Sopenharmony_ci struct acpi_buffer results; 3138c2ecf20Sopenharmony_ci acpi_status status; 3148c2ecf20Sopenharmony_ci int i; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci params.count = TCI_WORDS; 3178c2ecf20Sopenharmony_ci params.pointer = in_objs; 3188c2ecf20Sopenharmony_ci for (i = 0; i < TCI_WORDS; ++i) { 3198c2ecf20Sopenharmony_ci in_objs[i].type = ACPI_TYPE_INTEGER; 3208c2ecf20Sopenharmony_ci in_objs[i].integer.value = in[i]; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci results.length = sizeof(out_objs); 3248c2ecf20Sopenharmony_ci results.pointer = out_objs; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci status = acpi_evaluate_object(dev->acpi_dev->handle, 3278c2ecf20Sopenharmony_ci (char *)dev->method_hci, ¶ms, 3288c2ecf20Sopenharmony_ci &results); 3298c2ecf20Sopenharmony_ci if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) { 3308c2ecf20Sopenharmony_ci for (i = 0; i < out_objs->package.count; ++i) 3318c2ecf20Sopenharmony_ci out[i] = out_objs->package.elements[i].integer.value; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci return status; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci/* 3388c2ecf20Sopenharmony_ci * Common hci tasks 3398c2ecf20Sopenharmony_ci * 3408c2ecf20Sopenharmony_ci * In addition to the ACPI status, the HCI system returns a result which 3418c2ecf20Sopenharmony_ci * may be useful (such as "not supported"). 3428c2ecf20Sopenharmony_ci */ 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic u32 hci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 }; 3478c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 3488c2ecf20Sopenharmony_ci acpi_status status = tci_raw(dev, in, out); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic u32 hci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 }; 3568c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 3578c2ecf20Sopenharmony_ci acpi_status status = tci_raw(dev, in, out); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 3608c2ecf20Sopenharmony_ci return TOS_FAILURE; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci *out1 = out[2]; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci return out[0]; 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci/* 3688c2ecf20Sopenharmony_ci * Common sci tasks 3698c2ecf20Sopenharmony_ci */ 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic int sci_open(struct toshiba_acpi_dev *dev) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 }; 3748c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 3758c2ecf20Sopenharmony_ci acpi_status status = tci_raw(dev, in, out); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 3788c2ecf20Sopenharmony_ci pr_err("ACPI call to open SCI failed\n"); 3798c2ecf20Sopenharmony_ci return 0; 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (out[0] == TOS_OPEN_CLOSE_OK) { 3838c2ecf20Sopenharmony_ci return 1; 3848c2ecf20Sopenharmony_ci } else if (out[0] == TOS_ALREADY_OPEN) { 3858c2ecf20Sopenharmony_ci pr_info("Toshiba SCI already opened\n"); 3868c2ecf20Sopenharmony_ci return 1; 3878c2ecf20Sopenharmony_ci } else if (out[0] == TOS_NOT_SUPPORTED) { 3888c2ecf20Sopenharmony_ci /* 3898c2ecf20Sopenharmony_ci * Some BIOSes do not have the SCI open/close functions 3908c2ecf20Sopenharmony_ci * implemented and return 0x8000 (Not Supported), failing to 3918c2ecf20Sopenharmony_ci * register some supported features. 3928c2ecf20Sopenharmony_ci * 3938c2ecf20Sopenharmony_ci * Simply return 1 if we hit those affected laptops to make the 3948c2ecf20Sopenharmony_ci * supported features work. 3958c2ecf20Sopenharmony_ci * 3968c2ecf20Sopenharmony_ci * In the case that some laptops really do not support the SCI, 3978c2ecf20Sopenharmony_ci * all the SCI dependent functions check for TOS_NOT_SUPPORTED, 3988c2ecf20Sopenharmony_ci * and thus, not registering support for the queried feature. 3998c2ecf20Sopenharmony_ci */ 4008c2ecf20Sopenharmony_ci return 1; 4018c2ecf20Sopenharmony_ci } else if (out[0] == TOS_NOT_PRESENT) { 4028c2ecf20Sopenharmony_ci pr_info("Toshiba SCI is not present\n"); 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci return 0; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic void sci_close(struct toshiba_acpi_dev *dev) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 }; 4118c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 4128c2ecf20Sopenharmony_ci acpi_status status = tci_raw(dev, in, out); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 4158c2ecf20Sopenharmony_ci pr_err("ACPI call to close SCI failed\n"); 4168c2ecf20Sopenharmony_ci return; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (out[0] == TOS_OPEN_CLOSE_OK) 4208c2ecf20Sopenharmony_ci return; 4218c2ecf20Sopenharmony_ci else if (out[0] == TOS_NOT_OPENED) 4228c2ecf20Sopenharmony_ci pr_info("Toshiba SCI not opened\n"); 4238c2ecf20Sopenharmony_ci else if (out[0] == TOS_NOT_PRESENT) 4248c2ecf20Sopenharmony_ci pr_info("Toshiba SCI is not present\n"); 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 }; 4308c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 4318c2ecf20Sopenharmony_ci acpi_status status = tci_raw(dev, in, out); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 4348c2ecf20Sopenharmony_ci return TOS_FAILURE; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci *out1 = out[2]; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci return out[0]; 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic u32 sci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 }; 4448c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 4458c2ecf20Sopenharmony_ci acpi_status status = tci_raw(dev, in, out); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci/* Illumination support */ 4518c2ecf20Sopenharmony_cistatic void toshiba_illumination_available(struct toshiba_acpi_dev *dev) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 }; 4548c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 4558c2ecf20Sopenharmony_ci acpi_status status; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci dev->illumination_supported = 0; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (!sci_open(dev)) 4608c2ecf20Sopenharmony_ci return; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci status = tci_raw(dev, in, out); 4638c2ecf20Sopenharmony_ci sci_close(dev); 4648c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 4658c2ecf20Sopenharmony_ci pr_err("ACPI call to query Illumination support failed\n"); 4668c2ecf20Sopenharmony_ci return; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (out[0] != TOS_SUCCESS) 4708c2ecf20Sopenharmony_ci return; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci dev->illumination_supported = 1; 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic void toshiba_illumination_set(struct led_classdev *cdev, 4768c2ecf20Sopenharmony_ci enum led_brightness brightness) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = container_of(cdev, 4798c2ecf20Sopenharmony_ci struct toshiba_acpi_dev, led_dev); 4808c2ecf20Sopenharmony_ci u32 result; 4818c2ecf20Sopenharmony_ci u32 state; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci /* First request : initialize communication. */ 4848c2ecf20Sopenharmony_ci if (!sci_open(dev)) 4858c2ecf20Sopenharmony_ci return; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* Switch the illumination on/off */ 4888c2ecf20Sopenharmony_ci state = brightness ? 1 : 0; 4898c2ecf20Sopenharmony_ci result = sci_write(dev, SCI_ILLUMINATION, state); 4908c2ecf20Sopenharmony_ci sci_close(dev); 4918c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 4928c2ecf20Sopenharmony_ci pr_err("ACPI call for illumination failed\n"); 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cistatic enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) 4968c2ecf20Sopenharmony_ci{ 4978c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = container_of(cdev, 4988c2ecf20Sopenharmony_ci struct toshiba_acpi_dev, led_dev); 4998c2ecf20Sopenharmony_ci u32 result; 5008c2ecf20Sopenharmony_ci u32 state; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* First request : initialize communication. */ 5038c2ecf20Sopenharmony_ci if (!sci_open(dev)) 5048c2ecf20Sopenharmony_ci return LED_OFF; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci /* Check the illumination */ 5078c2ecf20Sopenharmony_ci result = sci_read(dev, SCI_ILLUMINATION, &state); 5088c2ecf20Sopenharmony_ci sci_close(dev); 5098c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) { 5108c2ecf20Sopenharmony_ci pr_err("ACPI call for illumination failed\n"); 5118c2ecf20Sopenharmony_ci return LED_OFF; 5128c2ecf20Sopenharmony_ci } else if (result != TOS_SUCCESS) { 5138c2ecf20Sopenharmony_ci return LED_OFF; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci return state ? LED_FULL : LED_OFF; 5178c2ecf20Sopenharmony_ci} 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci/* KBD Illumination */ 5208c2ecf20Sopenharmony_cistatic void toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 }; 5238c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 5248c2ecf20Sopenharmony_ci acpi_status status; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci dev->kbd_illum_supported = 0; 5278c2ecf20Sopenharmony_ci dev->kbd_event_generated = false; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci if (!sci_open(dev)) 5308c2ecf20Sopenharmony_ci return; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci status = tci_raw(dev, in, out); 5338c2ecf20Sopenharmony_ci sci_close(dev); 5348c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 5358c2ecf20Sopenharmony_ci pr_err("ACPI call to query kbd illumination support failed\n"); 5368c2ecf20Sopenharmony_ci return; 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (out[0] != TOS_SUCCESS) 5408c2ecf20Sopenharmony_ci return; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci /* 5438c2ecf20Sopenharmony_ci * Check for keyboard backlight timeout max value, 5448c2ecf20Sopenharmony_ci * previous kbd backlight implementation set this to 5458c2ecf20Sopenharmony_ci * 0x3c0003, and now the new implementation set this 5468c2ecf20Sopenharmony_ci * to 0x3c001a, use this to distinguish between them. 5478c2ecf20Sopenharmony_ci */ 5488c2ecf20Sopenharmony_ci if (out[3] == SCI_KBD_TIME_MAX) 5498c2ecf20Sopenharmony_ci dev->kbd_type = 2; 5508c2ecf20Sopenharmony_ci else 5518c2ecf20Sopenharmony_ci dev->kbd_type = 1; 5528c2ecf20Sopenharmony_ci /* Get the current keyboard backlight mode */ 5538c2ecf20Sopenharmony_ci dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK; 5548c2ecf20Sopenharmony_ci /* Get the current time (1-60 seconds) */ 5558c2ecf20Sopenharmony_ci dev->kbd_time = out[2] >> HCI_MISC_SHIFT; 5568c2ecf20Sopenharmony_ci /* Flag as supported */ 5578c2ecf20Sopenharmony_ci dev->kbd_illum_supported = 1; 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci u32 result; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci if (!sci_open(dev)) 5658c2ecf20Sopenharmony_ci return -EIO; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time); 5688c2ecf20Sopenharmony_ci sci_close(dev); 5698c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 5708c2ecf20Sopenharmony_ci pr_err("ACPI call to set KBD backlight status failed\n"); 5718c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 5728c2ecf20Sopenharmony_ci return -ENODEV; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci return result == TOS_SUCCESS ? 0 : -EIO; 5758c2ecf20Sopenharmony_ci} 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_cistatic int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time) 5788c2ecf20Sopenharmony_ci{ 5798c2ecf20Sopenharmony_ci u32 result; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci if (!sci_open(dev)) 5828c2ecf20Sopenharmony_ci return -EIO; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time); 5858c2ecf20Sopenharmony_ci sci_close(dev); 5868c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 5878c2ecf20Sopenharmony_ci pr_err("ACPI call to get KBD backlight status failed\n"); 5888c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 5898c2ecf20Sopenharmony_ci return -ENODEV; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci return result == TOS_SUCCESS ? 0 : -EIO; 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = container_of(cdev, 5978c2ecf20Sopenharmony_ci struct toshiba_acpi_dev, kbd_led); 5988c2ecf20Sopenharmony_ci u32 result; 5998c2ecf20Sopenharmony_ci u32 state; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci /* Check the keyboard backlight state */ 6028c2ecf20Sopenharmony_ci result = hci_read(dev, HCI_KBD_ILLUMINATION, &state); 6038c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) { 6048c2ecf20Sopenharmony_ci pr_err("ACPI call to get the keyboard backlight failed\n"); 6058c2ecf20Sopenharmony_ci return LED_OFF; 6068c2ecf20Sopenharmony_ci } else if (result != TOS_SUCCESS) { 6078c2ecf20Sopenharmony_ci return LED_OFF; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci return state ? LED_FULL : LED_OFF; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cistatic void toshiba_kbd_backlight_set(struct led_classdev *cdev, 6148c2ecf20Sopenharmony_ci enum led_brightness brightness) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = container_of(cdev, 6178c2ecf20Sopenharmony_ci struct toshiba_acpi_dev, kbd_led); 6188c2ecf20Sopenharmony_ci u32 result; 6198c2ecf20Sopenharmony_ci u32 state; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci /* Set the keyboard backlight state */ 6228c2ecf20Sopenharmony_ci state = brightness ? 1 : 0; 6238c2ecf20Sopenharmony_ci result = hci_write(dev, HCI_KBD_ILLUMINATION, state); 6248c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 6258c2ecf20Sopenharmony_ci pr_err("ACPI call to set KBD Illumination mode failed\n"); 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci/* TouchPad support */ 6298c2ecf20Sopenharmony_cistatic int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci u32 result; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci if (!sci_open(dev)) 6348c2ecf20Sopenharmony_ci return -EIO; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci result = sci_write(dev, SCI_TOUCHPAD, state); 6378c2ecf20Sopenharmony_ci sci_close(dev); 6388c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 6398c2ecf20Sopenharmony_ci pr_err("ACPI call to set the touchpad failed\n"); 6408c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 6418c2ecf20Sopenharmony_ci return -ENODEV; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci return result == TOS_SUCCESS ? 0 : -EIO; 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_cistatic int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state) 6478c2ecf20Sopenharmony_ci{ 6488c2ecf20Sopenharmony_ci u32 result; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci if (!sci_open(dev)) 6518c2ecf20Sopenharmony_ci return -EIO; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci result = sci_read(dev, SCI_TOUCHPAD, state); 6548c2ecf20Sopenharmony_ci sci_close(dev); 6558c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 6568c2ecf20Sopenharmony_ci pr_err("ACPI call to query the touchpad failed\n"); 6578c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 6588c2ecf20Sopenharmony_ci return -ENODEV; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci return result == TOS_SUCCESS ? 0 : -EIO; 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci/* Eco Mode support */ 6648c2ecf20Sopenharmony_cistatic void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 }; 6678c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 6688c2ecf20Sopenharmony_ci acpi_status status; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci dev->eco_supported = 0; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci status = tci_raw(dev, in, out); 6738c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 6748c2ecf20Sopenharmony_ci pr_err("ACPI call to get ECO led failed\n"); 6758c2ecf20Sopenharmony_ci return; 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci if (out[0] == TOS_INPUT_DATA_ERROR) { 6798c2ecf20Sopenharmony_ci /* 6808c2ecf20Sopenharmony_ci * If we receive 0x8300 (Input Data Error), it means that the 6818c2ecf20Sopenharmony_ci * LED device is present, but that we just screwed the input 6828c2ecf20Sopenharmony_ci * parameters. 6838c2ecf20Sopenharmony_ci * 6848c2ecf20Sopenharmony_ci * Let's query the status of the LED to see if we really have a 6858c2ecf20Sopenharmony_ci * success response, indicating the actual presense of the LED, 6868c2ecf20Sopenharmony_ci * bail out otherwise. 6878c2ecf20Sopenharmony_ci */ 6888c2ecf20Sopenharmony_ci in[3] = 1; 6898c2ecf20Sopenharmony_ci status = tci_raw(dev, in, out); 6908c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 6918c2ecf20Sopenharmony_ci pr_err("ACPI call to get ECO led failed\n"); 6928c2ecf20Sopenharmony_ci return; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci if (out[0] != TOS_SUCCESS) 6968c2ecf20Sopenharmony_ci return; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci dev->eco_supported = 1; 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_cistatic enum led_brightness 7038c2ecf20Sopenharmony_citoshiba_eco_mode_get_status(struct led_classdev *cdev) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = container_of(cdev, 7068c2ecf20Sopenharmony_ci struct toshiba_acpi_dev, eco_led); 7078c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 }; 7088c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 7098c2ecf20Sopenharmony_ci acpi_status status; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci status = tci_raw(dev, in, out); 7128c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 7138c2ecf20Sopenharmony_ci pr_err("ACPI call to get ECO led failed\n"); 7148c2ecf20Sopenharmony_ci return LED_OFF; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci if (out[0] != TOS_SUCCESS) 7188c2ecf20Sopenharmony_ci return LED_OFF; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci return out[2] ? LED_FULL : LED_OFF; 7218c2ecf20Sopenharmony_ci} 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_cistatic void toshiba_eco_mode_set_status(struct led_classdev *cdev, 7248c2ecf20Sopenharmony_ci enum led_brightness brightness) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = container_of(cdev, 7278c2ecf20Sopenharmony_ci struct toshiba_acpi_dev, eco_led); 7288c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 }; 7298c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 7308c2ecf20Sopenharmony_ci acpi_status status; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci /* Switch the Eco Mode led on/off */ 7338c2ecf20Sopenharmony_ci in[2] = (brightness) ? 1 : 0; 7348c2ecf20Sopenharmony_ci status = tci_raw(dev, in, out); 7358c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 7368c2ecf20Sopenharmony_ci pr_err("ACPI call to set ECO led failed\n"); 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci/* Accelerometer support */ 7408c2ecf20Sopenharmony_cistatic void toshiba_accelerometer_available(struct toshiba_acpi_dev *dev) 7418c2ecf20Sopenharmony_ci{ 7428c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 }; 7438c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 7448c2ecf20Sopenharmony_ci acpi_status status; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci dev->accelerometer_supported = 0; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci /* 7498c2ecf20Sopenharmony_ci * Check if the accelerometer call exists, 7508c2ecf20Sopenharmony_ci * this call also serves as initialization 7518c2ecf20Sopenharmony_ci */ 7528c2ecf20Sopenharmony_ci status = tci_raw(dev, in, out); 7538c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 7548c2ecf20Sopenharmony_ci pr_err("ACPI call to query the accelerometer failed\n"); 7558c2ecf20Sopenharmony_ci return; 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci if (out[0] != TOS_SUCCESS) 7598c2ecf20Sopenharmony_ci return; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci dev->accelerometer_supported = 1; 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev, 7658c2ecf20Sopenharmony_ci u32 *xy, u32 *z) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 }; 7688c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 7698c2ecf20Sopenharmony_ci acpi_status status; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci /* Check the Accelerometer status */ 7728c2ecf20Sopenharmony_ci status = tci_raw(dev, in, out); 7738c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 7748c2ecf20Sopenharmony_ci pr_err("ACPI call to query the accelerometer failed\n"); 7758c2ecf20Sopenharmony_ci return -EIO; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci if (out[0] == TOS_NOT_SUPPORTED) 7798c2ecf20Sopenharmony_ci return -ENODEV; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if (out[0] != TOS_SUCCESS) 7828c2ecf20Sopenharmony_ci return -EIO; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci *xy = out[2]; 7858c2ecf20Sopenharmony_ci *z = out[4]; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci return 0; 7888c2ecf20Sopenharmony_ci} 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci/* Sleep (Charge and Music) utilities support */ 7918c2ecf20Sopenharmony_cistatic void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev) 7928c2ecf20Sopenharmony_ci{ 7938c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 7948c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 7958c2ecf20Sopenharmony_ci acpi_status status; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci dev->usb_sleep_charge_supported = 0; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci if (!sci_open(dev)) 8008c2ecf20Sopenharmony_ci return; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci status = tci_raw(dev, in, out); 8038c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 8048c2ecf20Sopenharmony_ci pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); 8058c2ecf20Sopenharmony_ci sci_close(dev); 8068c2ecf20Sopenharmony_ci return; 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci if (out[0] != TOS_SUCCESS) { 8108c2ecf20Sopenharmony_ci sci_close(dev); 8118c2ecf20Sopenharmony_ci return; 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci dev->usbsc_mode_base = out[4]; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci in[5] = SCI_USB_CHARGE_BAT_LVL; 8178c2ecf20Sopenharmony_ci status = tci_raw(dev, in, out); 8188c2ecf20Sopenharmony_ci sci_close(dev); 8198c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 8208c2ecf20Sopenharmony_ci pr_err("ACPI call to get USB Sleep and Charge mode failed\n"); 8218c2ecf20Sopenharmony_ci return; 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci if (out[0] != TOS_SUCCESS) 8258c2ecf20Sopenharmony_ci return; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci dev->usbsc_bat_level = out[2]; 8288c2ecf20Sopenharmony_ci /* Flag as supported */ 8298c2ecf20Sopenharmony_ci dev->usb_sleep_charge_supported = 1; 8308c2ecf20Sopenharmony_ci} 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_cistatic int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev, 8338c2ecf20Sopenharmony_ci u32 *mode) 8348c2ecf20Sopenharmony_ci{ 8358c2ecf20Sopenharmony_ci u32 result; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci if (!sci_open(dev)) 8388c2ecf20Sopenharmony_ci return -EIO; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode); 8418c2ecf20Sopenharmony_ci sci_close(dev); 8428c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 8438c2ecf20Sopenharmony_ci pr_err("ACPI call to set USB S&C mode failed\n"); 8448c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 8458c2ecf20Sopenharmony_ci return -ENODEV; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci return result == TOS_SUCCESS ? 0 : -EIO; 8488c2ecf20Sopenharmony_ci} 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_cistatic int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev, 8518c2ecf20Sopenharmony_ci u32 mode) 8528c2ecf20Sopenharmony_ci{ 8538c2ecf20Sopenharmony_ci u32 result; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci if (!sci_open(dev)) 8568c2ecf20Sopenharmony_ci return -EIO; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode); 8598c2ecf20Sopenharmony_ci sci_close(dev); 8608c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 8618c2ecf20Sopenharmony_ci pr_err("ACPI call to set USB S&C mode failed\n"); 8628c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 8638c2ecf20Sopenharmony_ci return -ENODEV; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci return result == TOS_SUCCESS ? 0 : -EIO; 8668c2ecf20Sopenharmony_ci} 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_cistatic int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev, 8698c2ecf20Sopenharmony_ci u32 *mode) 8708c2ecf20Sopenharmony_ci{ 8718c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 8728c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 8738c2ecf20Sopenharmony_ci acpi_status status; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci if (!sci_open(dev)) 8768c2ecf20Sopenharmony_ci return -EIO; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci in[5] = SCI_USB_CHARGE_BAT_LVL; 8798c2ecf20Sopenharmony_ci status = tci_raw(dev, in, out); 8808c2ecf20Sopenharmony_ci sci_close(dev); 8818c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 8828c2ecf20Sopenharmony_ci pr_err("ACPI call to get USB S&C battery level failed\n"); 8838c2ecf20Sopenharmony_ci return -EIO; 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci if (out[0] == TOS_NOT_SUPPORTED) 8878c2ecf20Sopenharmony_ci return -ENODEV; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci if (out[0] != TOS_SUCCESS) 8908c2ecf20Sopenharmony_ci return -EIO; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci *mode = out[2]; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci return 0; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_cistatic int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev, 8998c2ecf20Sopenharmony_ci u32 mode) 9008c2ecf20Sopenharmony_ci{ 9018c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 9028c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 9038c2ecf20Sopenharmony_ci acpi_status status; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci if (!sci_open(dev)) 9068c2ecf20Sopenharmony_ci return -EIO; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci in[2] = mode; 9098c2ecf20Sopenharmony_ci in[5] = SCI_USB_CHARGE_BAT_LVL; 9108c2ecf20Sopenharmony_ci status = tci_raw(dev, in, out); 9118c2ecf20Sopenharmony_ci sci_close(dev); 9128c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 9138c2ecf20Sopenharmony_ci pr_err("ACPI call to set USB S&C battery level failed\n"); 9148c2ecf20Sopenharmony_ci return -EIO; 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci if (out[0] == TOS_NOT_SUPPORTED) 9188c2ecf20Sopenharmony_ci return -ENODEV; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci return out[0] == TOS_SUCCESS ? 0 : -EIO; 9218c2ecf20Sopenharmony_ci} 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_cistatic int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev, 9248c2ecf20Sopenharmony_ci u32 *state) 9258c2ecf20Sopenharmony_ci{ 9268c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 9278c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 9288c2ecf20Sopenharmony_ci acpi_status status; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci if (!sci_open(dev)) 9318c2ecf20Sopenharmony_ci return -EIO; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci in[5] = SCI_USB_CHARGE_RAPID_DSP; 9348c2ecf20Sopenharmony_ci status = tci_raw(dev, in, out); 9358c2ecf20Sopenharmony_ci sci_close(dev); 9368c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 9378c2ecf20Sopenharmony_ci pr_err("ACPI call to get USB Rapid Charge failed\n"); 9388c2ecf20Sopenharmony_ci return -EIO; 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci if (out[0] == TOS_NOT_SUPPORTED) 9428c2ecf20Sopenharmony_ci return -ENODEV; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2) 9458c2ecf20Sopenharmony_ci return -EIO; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci *state = out[2]; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci return 0; 9508c2ecf20Sopenharmony_ci} 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_cistatic int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev, 9538c2ecf20Sopenharmony_ci u32 state) 9548c2ecf20Sopenharmony_ci{ 9558c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 }; 9568c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 9578c2ecf20Sopenharmony_ci acpi_status status; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci if (!sci_open(dev)) 9608c2ecf20Sopenharmony_ci return -EIO; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci in[2] = state; 9638c2ecf20Sopenharmony_ci in[5] = SCI_USB_CHARGE_RAPID_DSP; 9648c2ecf20Sopenharmony_ci status = tci_raw(dev, in, out); 9658c2ecf20Sopenharmony_ci sci_close(dev); 9668c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 9678c2ecf20Sopenharmony_ci pr_err("ACPI call to set USB Rapid Charge failed\n"); 9688c2ecf20Sopenharmony_ci return -EIO; 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci if (out[0] == TOS_NOT_SUPPORTED) 9728c2ecf20Sopenharmony_ci return -ENODEV; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci return (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) ? 0 : -EIO; 9758c2ecf20Sopenharmony_ci} 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_cistatic int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state) 9788c2ecf20Sopenharmony_ci{ 9798c2ecf20Sopenharmony_ci u32 result; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci if (!sci_open(dev)) 9828c2ecf20Sopenharmony_ci return -EIO; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state); 9858c2ecf20Sopenharmony_ci sci_close(dev); 9868c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 9878c2ecf20Sopenharmony_ci pr_err("ACPI call to get Sleep and Music failed\n"); 9888c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 9898c2ecf20Sopenharmony_ci return -ENODEV; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci return result == TOS_SUCCESS ? 0 : -EIO; 9928c2ecf20Sopenharmony_ci} 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_cistatic int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state) 9958c2ecf20Sopenharmony_ci{ 9968c2ecf20Sopenharmony_ci u32 result; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci if (!sci_open(dev)) 9998c2ecf20Sopenharmony_ci return -EIO; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state); 10028c2ecf20Sopenharmony_ci sci_close(dev); 10038c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 10048c2ecf20Sopenharmony_ci pr_err("ACPI call to set Sleep and Music failed\n"); 10058c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 10068c2ecf20Sopenharmony_ci return -ENODEV; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci return result == TOS_SUCCESS ? 0 : -EIO; 10098c2ecf20Sopenharmony_ci} 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci/* Keyboard function keys */ 10128c2ecf20Sopenharmony_cistatic int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode) 10138c2ecf20Sopenharmony_ci{ 10148c2ecf20Sopenharmony_ci u32 result; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci if (!sci_open(dev)) 10178c2ecf20Sopenharmony_ci return -EIO; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci result = sci_read(dev, SCI_KBD_FUNCTION_KEYS, mode); 10208c2ecf20Sopenharmony_ci sci_close(dev); 10218c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 10228c2ecf20Sopenharmony_ci pr_err("ACPI call to get KBD function keys failed\n"); 10238c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 10248c2ecf20Sopenharmony_ci return -ENODEV; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 10278c2ecf20Sopenharmony_ci} 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_cistatic int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode) 10308c2ecf20Sopenharmony_ci{ 10318c2ecf20Sopenharmony_ci u32 result; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci if (!sci_open(dev)) 10348c2ecf20Sopenharmony_ci return -EIO; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci result = sci_write(dev, SCI_KBD_FUNCTION_KEYS, mode); 10378c2ecf20Sopenharmony_ci sci_close(dev); 10388c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 10398c2ecf20Sopenharmony_ci pr_err("ACPI call to set KBD function keys failed\n"); 10408c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 10418c2ecf20Sopenharmony_ci return -ENODEV; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 10448c2ecf20Sopenharmony_ci} 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci/* Panel Power ON */ 10478c2ecf20Sopenharmony_cistatic int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state) 10488c2ecf20Sopenharmony_ci{ 10498c2ecf20Sopenharmony_ci u32 result; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci if (!sci_open(dev)) 10528c2ecf20Sopenharmony_ci return -EIO; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci result = sci_read(dev, SCI_PANEL_POWER_ON, state); 10558c2ecf20Sopenharmony_ci sci_close(dev); 10568c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 10578c2ecf20Sopenharmony_ci pr_err("ACPI call to get Panel Power ON failed\n"); 10588c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 10598c2ecf20Sopenharmony_ci return -ENODEV; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci return result == TOS_SUCCESS ? 0 : -EIO; 10628c2ecf20Sopenharmony_ci} 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_cistatic int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state) 10658c2ecf20Sopenharmony_ci{ 10668c2ecf20Sopenharmony_ci u32 result; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci if (!sci_open(dev)) 10698c2ecf20Sopenharmony_ci return -EIO; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci result = sci_write(dev, SCI_PANEL_POWER_ON, state); 10728c2ecf20Sopenharmony_ci sci_close(dev); 10738c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 10748c2ecf20Sopenharmony_ci pr_err("ACPI call to set Panel Power ON failed\n"); 10758c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 10768c2ecf20Sopenharmony_ci return -ENODEV; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci return result == TOS_SUCCESS ? 0 : -EIO; 10798c2ecf20Sopenharmony_ci} 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci/* USB Three */ 10828c2ecf20Sopenharmony_cistatic int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state) 10838c2ecf20Sopenharmony_ci{ 10848c2ecf20Sopenharmony_ci u32 result; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci if (!sci_open(dev)) 10878c2ecf20Sopenharmony_ci return -EIO; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci result = sci_read(dev, SCI_USB_THREE, state); 10908c2ecf20Sopenharmony_ci sci_close(dev); 10918c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 10928c2ecf20Sopenharmony_ci pr_err("ACPI call to get USB 3 failed\n"); 10938c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 10948c2ecf20Sopenharmony_ci return -ENODEV; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 10978c2ecf20Sopenharmony_ci} 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_cistatic int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state) 11008c2ecf20Sopenharmony_ci{ 11018c2ecf20Sopenharmony_ci u32 result; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci if (!sci_open(dev)) 11048c2ecf20Sopenharmony_ci return -EIO; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci result = sci_write(dev, SCI_USB_THREE, state); 11078c2ecf20Sopenharmony_ci sci_close(dev); 11088c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 11098c2ecf20Sopenharmony_ci pr_err("ACPI call to set USB 3 failed\n"); 11108c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 11118c2ecf20Sopenharmony_ci return -ENODEV; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 11148c2ecf20Sopenharmony_ci} 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci/* Hotkey Event type */ 11178c2ecf20Sopenharmony_cistatic int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev, 11188c2ecf20Sopenharmony_ci u32 *type) 11198c2ecf20Sopenharmony_ci{ 11208c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { HCI_GET, HCI_SYSTEM_INFO, 0x03, 0, 0, 0 }; 11218c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 11228c2ecf20Sopenharmony_ci acpi_status status; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci status = tci_raw(dev, in, out); 11258c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 11268c2ecf20Sopenharmony_ci pr_err("ACPI call to get System type failed\n"); 11278c2ecf20Sopenharmony_ci return -EIO; 11288c2ecf20Sopenharmony_ci } 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci if (out[0] == TOS_NOT_SUPPORTED) 11318c2ecf20Sopenharmony_ci return -ENODEV; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci if (out[0] != TOS_SUCCESS) 11348c2ecf20Sopenharmony_ci return -EIO; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci *type = out[3]; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci return 0; 11398c2ecf20Sopenharmony_ci} 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci/* Wireless status (RFKill, WLAN, BT, WWAN) */ 11428c2ecf20Sopenharmony_cistatic int toshiba_wireless_status(struct toshiba_acpi_dev *dev) 11438c2ecf20Sopenharmony_ci{ 11448c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { HCI_GET, HCI_WIRELESS, 0, 0, 0, 0 }; 11458c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 11468c2ecf20Sopenharmony_ci acpi_status status; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci in[3] = HCI_WIRELESS_STATUS; 11498c2ecf20Sopenharmony_ci status = tci_raw(dev, in, out); 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 11528c2ecf20Sopenharmony_ci pr_err("ACPI call to get Wireless status failed\n"); 11538c2ecf20Sopenharmony_ci return -EIO; 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci if (out[0] == TOS_NOT_SUPPORTED) 11578c2ecf20Sopenharmony_ci return -ENODEV; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci if (out[0] != TOS_SUCCESS) 11608c2ecf20Sopenharmony_ci return -EIO; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci dev->killswitch = !!(out[2] & HCI_WIRELESS_STATUS); 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci return 0; 11658c2ecf20Sopenharmony_ci} 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci/* WWAN */ 11688c2ecf20Sopenharmony_cistatic void toshiba_wwan_available(struct toshiba_acpi_dev *dev) 11698c2ecf20Sopenharmony_ci{ 11708c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { HCI_GET, HCI_WIRELESS, 0, 0, 0, 0 }; 11718c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 11728c2ecf20Sopenharmony_ci acpi_status status; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci dev->wwan_supported = 0; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci /* 11778c2ecf20Sopenharmony_ci * WWAN support can be queried by setting the in[3] value to 11788c2ecf20Sopenharmony_ci * HCI_WIRELESS_WWAN (0x03). 11798c2ecf20Sopenharmony_ci * 11808c2ecf20Sopenharmony_ci * If supported, out[0] contains TOS_SUCCESS and out[2] contains 11818c2ecf20Sopenharmony_ci * HCI_WIRELESS_WWAN_STATUS (0x2000). 11828c2ecf20Sopenharmony_ci * 11838c2ecf20Sopenharmony_ci * If not supported, out[0] contains TOS_INPUT_DATA_ERROR (0x8300) 11848c2ecf20Sopenharmony_ci * or TOS_NOT_SUPPORTED (0x8000). 11858c2ecf20Sopenharmony_ci */ 11868c2ecf20Sopenharmony_ci in[3] = HCI_WIRELESS_WWAN; 11878c2ecf20Sopenharmony_ci status = tci_raw(dev, in, out); 11888c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 11898c2ecf20Sopenharmony_ci pr_err("ACPI call to get WWAN status failed\n"); 11908c2ecf20Sopenharmony_ci return; 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci if (out[0] != TOS_SUCCESS) 11948c2ecf20Sopenharmony_ci return; 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci dev->wwan_supported = (out[2] == HCI_WIRELESS_WWAN_STATUS); 11978c2ecf20Sopenharmony_ci} 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_cistatic int toshiba_wwan_set(struct toshiba_acpi_dev *dev, u32 state) 12008c2ecf20Sopenharmony_ci{ 12018c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { HCI_SET, HCI_WIRELESS, state, 0, 0, 0 }; 12028c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 12038c2ecf20Sopenharmony_ci acpi_status status; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci in[3] = HCI_WIRELESS_WWAN_STATUS; 12068c2ecf20Sopenharmony_ci status = tci_raw(dev, in, out); 12078c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 12088c2ecf20Sopenharmony_ci pr_err("ACPI call to set WWAN status failed\n"); 12098c2ecf20Sopenharmony_ci return -EIO; 12108c2ecf20Sopenharmony_ci } 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci if (out[0] == TOS_NOT_SUPPORTED) 12138c2ecf20Sopenharmony_ci return -ENODEV; 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci if (out[0] != TOS_SUCCESS) 12168c2ecf20Sopenharmony_ci return -EIO; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci /* 12198c2ecf20Sopenharmony_ci * Some devices only need to call HCI_WIRELESS_WWAN_STATUS to 12208c2ecf20Sopenharmony_ci * (de)activate the device, but some others need the 12218c2ecf20Sopenharmony_ci * HCI_WIRELESS_WWAN_POWER call as well. 12228c2ecf20Sopenharmony_ci */ 12238c2ecf20Sopenharmony_ci in[3] = HCI_WIRELESS_WWAN_POWER; 12248c2ecf20Sopenharmony_ci status = tci_raw(dev, in, out); 12258c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 12268c2ecf20Sopenharmony_ci pr_err("ACPI call to set WWAN power failed\n"); 12278c2ecf20Sopenharmony_ci return -EIO; 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci if (out[0] == TOS_NOT_SUPPORTED) 12318c2ecf20Sopenharmony_ci return -ENODEV; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci return out[0] == TOS_SUCCESS ? 0 : -EIO; 12348c2ecf20Sopenharmony_ci} 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci/* Cooling Method */ 12378c2ecf20Sopenharmony_cistatic void toshiba_cooling_method_available(struct toshiba_acpi_dev *dev) 12388c2ecf20Sopenharmony_ci{ 12398c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { HCI_GET, HCI_COOLING_METHOD, 0, 0, 0, 0 }; 12408c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 12418c2ecf20Sopenharmony_ci acpi_status status; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci dev->cooling_method_supported = 0; 12448c2ecf20Sopenharmony_ci dev->max_cooling_method = 0; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci status = tci_raw(dev, in, out); 12478c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 12488c2ecf20Sopenharmony_ci pr_err("ACPI call to get Cooling Method failed\n"); 12498c2ecf20Sopenharmony_ci return; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2) 12538c2ecf20Sopenharmony_ci return; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci dev->cooling_method_supported = 1; 12568c2ecf20Sopenharmony_ci dev->max_cooling_method = out[3]; 12578c2ecf20Sopenharmony_ci} 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_cistatic int toshiba_cooling_method_get(struct toshiba_acpi_dev *dev, u32 *state) 12608c2ecf20Sopenharmony_ci{ 12618c2ecf20Sopenharmony_ci u32 result = hci_read(dev, HCI_COOLING_METHOD, state); 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 12648c2ecf20Sopenharmony_ci pr_err("ACPI call to get Cooling Method failed\n"); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci if (result == TOS_NOT_SUPPORTED) 12678c2ecf20Sopenharmony_ci return -ENODEV; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 12708c2ecf20Sopenharmony_ci} 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_cistatic int toshiba_cooling_method_set(struct toshiba_acpi_dev *dev, u32 state) 12738c2ecf20Sopenharmony_ci{ 12748c2ecf20Sopenharmony_ci u32 result = hci_write(dev, HCI_COOLING_METHOD, state); 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 12778c2ecf20Sopenharmony_ci pr_err("ACPI call to set Cooling Method failed\n"); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci if (result == TOS_NOT_SUPPORTED) 12808c2ecf20Sopenharmony_ci return -ENODEV; 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; 12838c2ecf20Sopenharmony_ci} 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci/* Transflective Backlight */ 12868c2ecf20Sopenharmony_cistatic int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status) 12878c2ecf20Sopenharmony_ci{ 12888c2ecf20Sopenharmony_ci u32 result = hci_read(dev, HCI_TR_BACKLIGHT, status); 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 12918c2ecf20Sopenharmony_ci pr_err("ACPI call to get Transflective Backlight failed\n"); 12928c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 12938c2ecf20Sopenharmony_ci return -ENODEV; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci return result == TOS_SUCCESS ? 0 : -EIO; 12968c2ecf20Sopenharmony_ci} 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_cistatic int set_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 status) 12998c2ecf20Sopenharmony_ci{ 13008c2ecf20Sopenharmony_ci u32 result = hci_write(dev, HCI_TR_BACKLIGHT, !status); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 13038c2ecf20Sopenharmony_ci pr_err("ACPI call to set Transflective Backlight failed\n"); 13048c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 13058c2ecf20Sopenharmony_ci return -ENODEV; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci return result == TOS_SUCCESS ? 0 : -EIO; 13088c2ecf20Sopenharmony_ci} 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_cistatic struct proc_dir_entry *toshiba_proc_dir; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci/* LCD Brightness */ 13138c2ecf20Sopenharmony_cistatic int __get_lcd_brightness(struct toshiba_acpi_dev *dev) 13148c2ecf20Sopenharmony_ci{ 13158c2ecf20Sopenharmony_ci int brightness = 0; 13168c2ecf20Sopenharmony_ci u32 result; 13178c2ecf20Sopenharmony_ci u32 value; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci if (dev->tr_backlight_supported) { 13208c2ecf20Sopenharmony_ci int ret = get_tr_backlight_status(dev, &value); 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci if (ret) 13238c2ecf20Sopenharmony_ci return ret; 13248c2ecf20Sopenharmony_ci if (value) 13258c2ecf20Sopenharmony_ci return 0; 13268c2ecf20Sopenharmony_ci brightness++; 13278c2ecf20Sopenharmony_ci } 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci result = hci_read(dev, HCI_LCD_BRIGHTNESS, &value); 13308c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 13318c2ecf20Sopenharmony_ci pr_err("ACPI call to get LCD Brightness failed\n"); 13328c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 13338c2ecf20Sopenharmony_ci return -ENODEV; 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci return result == TOS_SUCCESS ? 13368c2ecf20Sopenharmony_ci brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT) : 13378c2ecf20Sopenharmony_ci -EIO; 13388c2ecf20Sopenharmony_ci} 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_cistatic int get_lcd_brightness(struct backlight_device *bd) 13418c2ecf20Sopenharmony_ci{ 13428c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = bl_get_data(bd); 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci return __get_lcd_brightness(dev); 13458c2ecf20Sopenharmony_ci} 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_cistatic int lcd_proc_show(struct seq_file *m, void *v) 13488c2ecf20Sopenharmony_ci{ 13498c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = m->private; 13508c2ecf20Sopenharmony_ci int levels; 13518c2ecf20Sopenharmony_ci int value; 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci if (!dev->backlight_dev) 13548c2ecf20Sopenharmony_ci return -ENODEV; 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci levels = dev->backlight_dev->props.max_brightness + 1; 13578c2ecf20Sopenharmony_ci value = get_lcd_brightness(dev->backlight_dev); 13588c2ecf20Sopenharmony_ci if (value < 0) { 13598c2ecf20Sopenharmony_ci pr_err("Error reading LCD brightness\n"); 13608c2ecf20Sopenharmony_ci return value; 13618c2ecf20Sopenharmony_ci } 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci seq_printf(m, "brightness: %d\n", value); 13648c2ecf20Sopenharmony_ci seq_printf(m, "brightness_levels: %d\n", levels); 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci return 0; 13678c2ecf20Sopenharmony_ci} 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_cistatic int lcd_proc_open(struct inode *inode, struct file *file) 13708c2ecf20Sopenharmony_ci{ 13718c2ecf20Sopenharmony_ci return single_open(file, lcd_proc_show, PDE_DATA(inode)); 13728c2ecf20Sopenharmony_ci} 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_cistatic int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) 13758c2ecf20Sopenharmony_ci{ 13768c2ecf20Sopenharmony_ci u32 result; 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci if (dev->tr_backlight_supported) { 13798c2ecf20Sopenharmony_ci int ret = set_tr_backlight_status(dev, !value); 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci if (ret) 13828c2ecf20Sopenharmony_ci return ret; 13838c2ecf20Sopenharmony_ci if (value) 13848c2ecf20Sopenharmony_ci value--; 13858c2ecf20Sopenharmony_ci } 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci value = value << HCI_LCD_BRIGHTNESS_SHIFT; 13888c2ecf20Sopenharmony_ci result = hci_write(dev, HCI_LCD_BRIGHTNESS, value); 13898c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 13908c2ecf20Sopenharmony_ci pr_err("ACPI call to set LCD Brightness failed\n"); 13918c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 13928c2ecf20Sopenharmony_ci return -ENODEV; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci return result == TOS_SUCCESS ? 0 : -EIO; 13958c2ecf20Sopenharmony_ci} 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_cistatic int set_lcd_status(struct backlight_device *bd) 13988c2ecf20Sopenharmony_ci{ 13998c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = bl_get_data(bd); 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci return set_lcd_brightness(dev, bd->props.brightness); 14028c2ecf20Sopenharmony_ci} 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_cistatic ssize_t lcd_proc_write(struct file *file, const char __user *buf, 14058c2ecf20Sopenharmony_ci size_t count, loff_t *pos) 14068c2ecf20Sopenharmony_ci{ 14078c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 14088c2ecf20Sopenharmony_ci char cmd[42]; 14098c2ecf20Sopenharmony_ci size_t len; 14108c2ecf20Sopenharmony_ci int levels; 14118c2ecf20Sopenharmony_ci int value; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci len = min(count, sizeof(cmd) - 1); 14148c2ecf20Sopenharmony_ci if (copy_from_user(cmd, buf, len)) 14158c2ecf20Sopenharmony_ci return -EFAULT; 14168c2ecf20Sopenharmony_ci cmd[len] = '\0'; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci levels = dev->backlight_dev->props.max_brightness + 1; 14198c2ecf20Sopenharmony_ci if (sscanf(cmd, " brightness : %i", &value) != 1 && 14208c2ecf20Sopenharmony_ci value < 0 && value > levels) 14218c2ecf20Sopenharmony_ci return -EINVAL; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci if (set_lcd_brightness(dev, value)) 14248c2ecf20Sopenharmony_ci return -EIO; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci return count; 14278c2ecf20Sopenharmony_ci} 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_cistatic const struct proc_ops lcd_proc_ops = { 14308c2ecf20Sopenharmony_ci .proc_open = lcd_proc_open, 14318c2ecf20Sopenharmony_ci .proc_read = seq_read, 14328c2ecf20Sopenharmony_ci .proc_lseek = seq_lseek, 14338c2ecf20Sopenharmony_ci .proc_release = single_release, 14348c2ecf20Sopenharmony_ci .proc_write = lcd_proc_write, 14358c2ecf20Sopenharmony_ci}; 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci/* Video-Out */ 14388c2ecf20Sopenharmony_cistatic int get_video_status(struct toshiba_acpi_dev *dev, u32 *status) 14398c2ecf20Sopenharmony_ci{ 14408c2ecf20Sopenharmony_ci u32 result = hci_read(dev, HCI_VIDEO_OUT, status); 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 14438c2ecf20Sopenharmony_ci pr_err("ACPI call to get Video-Out failed\n"); 14448c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 14458c2ecf20Sopenharmony_ci return -ENODEV; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci return result == TOS_SUCCESS ? 0 : -EIO; 14488c2ecf20Sopenharmony_ci} 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_cistatic int video_proc_show(struct seq_file *m, void *v) 14518c2ecf20Sopenharmony_ci{ 14528c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = m->private; 14538c2ecf20Sopenharmony_ci int is_lcd, is_crt, is_tv; 14548c2ecf20Sopenharmony_ci u32 value; 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci if (get_video_status(dev, &value)) 14578c2ecf20Sopenharmony_ci return -EIO; 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0; 14608c2ecf20Sopenharmony_ci is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0; 14618c2ecf20Sopenharmony_ci is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci seq_printf(m, "lcd_out: %d\n", is_lcd); 14648c2ecf20Sopenharmony_ci seq_printf(m, "crt_out: %d\n", is_crt); 14658c2ecf20Sopenharmony_ci seq_printf(m, "tv_out: %d\n", is_tv); 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci return 0; 14688c2ecf20Sopenharmony_ci} 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_cistatic int video_proc_open(struct inode *inode, struct file *file) 14718c2ecf20Sopenharmony_ci{ 14728c2ecf20Sopenharmony_ci return single_open(file, video_proc_show, PDE_DATA(inode)); 14738c2ecf20Sopenharmony_ci} 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_cistatic ssize_t video_proc_write(struct file *file, const char __user *buf, 14768c2ecf20Sopenharmony_ci size_t count, loff_t *pos) 14778c2ecf20Sopenharmony_ci{ 14788c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 14798c2ecf20Sopenharmony_ci char *buffer; 14808c2ecf20Sopenharmony_ci char *cmd; 14818c2ecf20Sopenharmony_ci int lcd_out = -1, crt_out = -1, tv_out = -1; 14828c2ecf20Sopenharmony_ci int remain = count; 14838c2ecf20Sopenharmony_ci int value; 14848c2ecf20Sopenharmony_ci int ret; 14858c2ecf20Sopenharmony_ci u32 video_out; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci cmd = memdup_user_nul(buf, count); 14888c2ecf20Sopenharmony_ci if (IS_ERR(cmd)) 14898c2ecf20Sopenharmony_ci return PTR_ERR(cmd); 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci buffer = cmd; 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci /* 14948c2ecf20Sopenharmony_ci * Scan expression. Multiple expressions may be delimited with ; 14958c2ecf20Sopenharmony_ci * NOTE: To keep scanning simple, invalid fields are ignored. 14968c2ecf20Sopenharmony_ci */ 14978c2ecf20Sopenharmony_ci while (remain) { 14988c2ecf20Sopenharmony_ci if (sscanf(buffer, " lcd_out : %i", &value) == 1) 14998c2ecf20Sopenharmony_ci lcd_out = value & 1; 15008c2ecf20Sopenharmony_ci else if (sscanf(buffer, " crt_out : %i", &value) == 1) 15018c2ecf20Sopenharmony_ci crt_out = value & 1; 15028c2ecf20Sopenharmony_ci else if (sscanf(buffer, " tv_out : %i", &value) == 1) 15038c2ecf20Sopenharmony_ci tv_out = value & 1; 15048c2ecf20Sopenharmony_ci /* Advance to one character past the next ; */ 15058c2ecf20Sopenharmony_ci do { 15068c2ecf20Sopenharmony_ci ++buffer; 15078c2ecf20Sopenharmony_ci --remain; 15088c2ecf20Sopenharmony_ci } while (remain && *(buffer - 1) != ';'); 15098c2ecf20Sopenharmony_ci } 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci kfree(cmd); 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci ret = get_video_status(dev, &video_out); 15148c2ecf20Sopenharmony_ci if (!ret) { 15158c2ecf20Sopenharmony_ci unsigned int new_video_out = video_out; 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci if (lcd_out != -1) 15188c2ecf20Sopenharmony_ci _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out); 15198c2ecf20Sopenharmony_ci if (crt_out != -1) 15208c2ecf20Sopenharmony_ci _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out); 15218c2ecf20Sopenharmony_ci if (tv_out != -1) 15228c2ecf20Sopenharmony_ci _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out); 15238c2ecf20Sopenharmony_ci /* 15248c2ecf20Sopenharmony_ci * To avoid unnecessary video disruption, only write the new 15258c2ecf20Sopenharmony_ci * video setting if something changed. 15268c2ecf20Sopenharmony_ci */ 15278c2ecf20Sopenharmony_ci if (new_video_out != video_out) 15288c2ecf20Sopenharmony_ci ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out); 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci return ret ? -EIO : count; 15328c2ecf20Sopenharmony_ci} 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_cistatic const struct proc_ops video_proc_ops = { 15358c2ecf20Sopenharmony_ci .proc_open = video_proc_open, 15368c2ecf20Sopenharmony_ci .proc_read = seq_read, 15378c2ecf20Sopenharmony_ci .proc_lseek = seq_lseek, 15388c2ecf20Sopenharmony_ci .proc_release = single_release, 15398c2ecf20Sopenharmony_ci .proc_write = video_proc_write, 15408c2ecf20Sopenharmony_ci}; 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci/* Fan status */ 15438c2ecf20Sopenharmony_cistatic int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status) 15448c2ecf20Sopenharmony_ci{ 15458c2ecf20Sopenharmony_ci u32 result = hci_read(dev, HCI_FAN, status); 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 15488c2ecf20Sopenharmony_ci pr_err("ACPI call to get Fan status failed\n"); 15498c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 15508c2ecf20Sopenharmony_ci return -ENODEV; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci return result == TOS_SUCCESS ? 0 : -EIO; 15538c2ecf20Sopenharmony_ci} 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_cistatic int set_fan_status(struct toshiba_acpi_dev *dev, u32 status) 15568c2ecf20Sopenharmony_ci{ 15578c2ecf20Sopenharmony_ci u32 result = hci_write(dev, HCI_FAN, status); 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 15608c2ecf20Sopenharmony_ci pr_err("ACPI call to set Fan status failed\n"); 15618c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 15628c2ecf20Sopenharmony_ci return -ENODEV; 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci return result == TOS_SUCCESS ? 0 : -EIO; 15658c2ecf20Sopenharmony_ci} 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_cistatic int fan_proc_show(struct seq_file *m, void *v) 15688c2ecf20Sopenharmony_ci{ 15698c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = m->private; 15708c2ecf20Sopenharmony_ci u32 value; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci if (get_fan_status(dev, &value)) 15738c2ecf20Sopenharmony_ci return -EIO; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci seq_printf(m, "running: %d\n", (value > 0)); 15768c2ecf20Sopenharmony_ci seq_printf(m, "force_on: %d\n", dev->force_fan); 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci return 0; 15798c2ecf20Sopenharmony_ci} 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_cistatic int fan_proc_open(struct inode *inode, struct file *file) 15828c2ecf20Sopenharmony_ci{ 15838c2ecf20Sopenharmony_ci return single_open(file, fan_proc_show, PDE_DATA(inode)); 15848c2ecf20Sopenharmony_ci} 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_cistatic ssize_t fan_proc_write(struct file *file, const char __user *buf, 15878c2ecf20Sopenharmony_ci size_t count, loff_t *pos) 15888c2ecf20Sopenharmony_ci{ 15898c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 15908c2ecf20Sopenharmony_ci char cmd[42]; 15918c2ecf20Sopenharmony_ci size_t len; 15928c2ecf20Sopenharmony_ci int value; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci len = min(count, sizeof(cmd) - 1); 15958c2ecf20Sopenharmony_ci if (copy_from_user(cmd, buf, len)) 15968c2ecf20Sopenharmony_ci return -EFAULT; 15978c2ecf20Sopenharmony_ci cmd[len] = '\0'; 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci if (sscanf(cmd, " force_on : %i", &value) != 1 && 16008c2ecf20Sopenharmony_ci value != 0 && value != 1) 16018c2ecf20Sopenharmony_ci return -EINVAL; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci if (set_fan_status(dev, value)) 16048c2ecf20Sopenharmony_ci return -EIO; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci dev->force_fan = value; 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci return count; 16098c2ecf20Sopenharmony_ci} 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_cistatic const struct proc_ops fan_proc_ops = { 16128c2ecf20Sopenharmony_ci .proc_open = fan_proc_open, 16138c2ecf20Sopenharmony_ci .proc_read = seq_read, 16148c2ecf20Sopenharmony_ci .proc_lseek = seq_lseek, 16158c2ecf20Sopenharmony_ci .proc_release = single_release, 16168c2ecf20Sopenharmony_ci .proc_write = fan_proc_write, 16178c2ecf20Sopenharmony_ci}; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_cistatic int keys_proc_show(struct seq_file *m, void *v) 16208c2ecf20Sopenharmony_ci{ 16218c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = m->private; 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid); 16248c2ecf20Sopenharmony_ci seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event); 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci return 0; 16278c2ecf20Sopenharmony_ci} 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_cistatic int keys_proc_open(struct inode *inode, struct file *file) 16308c2ecf20Sopenharmony_ci{ 16318c2ecf20Sopenharmony_ci return single_open(file, keys_proc_show, PDE_DATA(inode)); 16328c2ecf20Sopenharmony_ci} 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_cistatic ssize_t keys_proc_write(struct file *file, const char __user *buf, 16358c2ecf20Sopenharmony_ci size_t count, loff_t *pos) 16368c2ecf20Sopenharmony_ci{ 16378c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file)); 16388c2ecf20Sopenharmony_ci char cmd[42]; 16398c2ecf20Sopenharmony_ci size_t len; 16408c2ecf20Sopenharmony_ci int value; 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci len = min(count, sizeof(cmd) - 1); 16438c2ecf20Sopenharmony_ci if (copy_from_user(cmd, buf, len)) 16448c2ecf20Sopenharmony_ci return -EFAULT; 16458c2ecf20Sopenharmony_ci cmd[len] = '\0'; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) 16488c2ecf20Sopenharmony_ci dev->key_event_valid = 0; 16498c2ecf20Sopenharmony_ci else 16508c2ecf20Sopenharmony_ci return -EINVAL; 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci return count; 16538c2ecf20Sopenharmony_ci} 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_cistatic const struct proc_ops keys_proc_ops = { 16568c2ecf20Sopenharmony_ci .proc_open = keys_proc_open, 16578c2ecf20Sopenharmony_ci .proc_read = seq_read, 16588c2ecf20Sopenharmony_ci .proc_lseek = seq_lseek, 16598c2ecf20Sopenharmony_ci .proc_release = single_release, 16608c2ecf20Sopenharmony_ci .proc_write = keys_proc_write, 16618c2ecf20Sopenharmony_ci}; 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_cistatic int __maybe_unused version_proc_show(struct seq_file *m, void *v) 16648c2ecf20Sopenharmony_ci{ 16658c2ecf20Sopenharmony_ci seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION); 16668c2ecf20Sopenharmony_ci seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION); 16678c2ecf20Sopenharmony_ci return 0; 16688c2ecf20Sopenharmony_ci} 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci/* 16718c2ecf20Sopenharmony_ci * Proc and module init 16728c2ecf20Sopenharmony_ci */ 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci#define PROC_TOSHIBA "toshiba" 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_cistatic void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 16778c2ecf20Sopenharmony_ci{ 16788c2ecf20Sopenharmony_ci if (dev->backlight_dev) 16798c2ecf20Sopenharmony_ci proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, 16808c2ecf20Sopenharmony_ci &lcd_proc_ops, dev); 16818c2ecf20Sopenharmony_ci if (dev->video_supported) 16828c2ecf20Sopenharmony_ci proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, 16838c2ecf20Sopenharmony_ci &video_proc_ops, dev); 16848c2ecf20Sopenharmony_ci if (dev->fan_supported) 16858c2ecf20Sopenharmony_ci proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, 16868c2ecf20Sopenharmony_ci &fan_proc_ops, dev); 16878c2ecf20Sopenharmony_ci if (dev->hotkey_dev) 16888c2ecf20Sopenharmony_ci proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, 16898c2ecf20Sopenharmony_ci &keys_proc_ops, dev); 16908c2ecf20Sopenharmony_ci proc_create_single_data("version", S_IRUGO, toshiba_proc_dir, 16918c2ecf20Sopenharmony_ci version_proc_show, dev); 16928c2ecf20Sopenharmony_ci} 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_cistatic void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev) 16958c2ecf20Sopenharmony_ci{ 16968c2ecf20Sopenharmony_ci if (dev->backlight_dev) 16978c2ecf20Sopenharmony_ci remove_proc_entry("lcd", toshiba_proc_dir); 16988c2ecf20Sopenharmony_ci if (dev->video_supported) 16998c2ecf20Sopenharmony_ci remove_proc_entry("video", toshiba_proc_dir); 17008c2ecf20Sopenharmony_ci if (dev->fan_supported) 17018c2ecf20Sopenharmony_ci remove_proc_entry("fan", toshiba_proc_dir); 17028c2ecf20Sopenharmony_ci if (dev->hotkey_dev) 17038c2ecf20Sopenharmony_ci remove_proc_entry("keys", toshiba_proc_dir); 17048c2ecf20Sopenharmony_ci remove_proc_entry("version", toshiba_proc_dir); 17058c2ecf20Sopenharmony_ci} 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_cistatic const struct backlight_ops toshiba_backlight_data = { 17088c2ecf20Sopenharmony_ci .options = BL_CORE_SUSPENDRESUME, 17098c2ecf20Sopenharmony_ci .get_brightness = get_lcd_brightness, 17108c2ecf20Sopenharmony_ci .update_status = set_lcd_status, 17118c2ecf20Sopenharmony_ci}; 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci/* Keyboard backlight work */ 17148c2ecf20Sopenharmony_cistatic void toshiba_acpi_kbd_bl_work(struct work_struct *work); 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_cistatic DECLARE_WORK(kbd_bl_work, toshiba_acpi_kbd_bl_work); 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci/* 17198c2ecf20Sopenharmony_ci * Sysfs files 17208c2ecf20Sopenharmony_ci */ 17218c2ecf20Sopenharmony_cistatic ssize_t version_show(struct device *dev, 17228c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 17238c2ecf20Sopenharmony_ci{ 17248c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", TOSHIBA_ACPI_VERSION); 17258c2ecf20Sopenharmony_ci} 17268c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(version); 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_cistatic ssize_t fan_store(struct device *dev, 17298c2ecf20Sopenharmony_ci struct device_attribute *attr, 17308c2ecf20Sopenharmony_ci const char *buf, size_t count) 17318c2ecf20Sopenharmony_ci{ 17328c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 17338c2ecf20Sopenharmony_ci int state; 17348c2ecf20Sopenharmony_ci int ret; 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci ret = kstrtoint(buf, 0, &state); 17378c2ecf20Sopenharmony_ci if (ret) 17388c2ecf20Sopenharmony_ci return ret; 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci if (state != 0 && state != 1) 17418c2ecf20Sopenharmony_ci return -EINVAL; 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci ret = set_fan_status(toshiba, state); 17448c2ecf20Sopenharmony_ci if (ret) 17458c2ecf20Sopenharmony_ci return ret; 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci return count; 17488c2ecf20Sopenharmony_ci} 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_cistatic ssize_t fan_show(struct device *dev, 17518c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 17528c2ecf20Sopenharmony_ci{ 17538c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 17548c2ecf20Sopenharmony_ci u32 value; 17558c2ecf20Sopenharmony_ci int ret; 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci ret = get_fan_status(toshiba, &value); 17588c2ecf20Sopenharmony_ci if (ret) 17598c2ecf20Sopenharmony_ci return ret; 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", value); 17628c2ecf20Sopenharmony_ci} 17638c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(fan); 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_cistatic ssize_t kbd_backlight_mode_store(struct device *dev, 17668c2ecf20Sopenharmony_ci struct device_attribute *attr, 17678c2ecf20Sopenharmony_ci const char *buf, size_t count) 17688c2ecf20Sopenharmony_ci{ 17698c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 17708c2ecf20Sopenharmony_ci int mode; 17718c2ecf20Sopenharmony_ci int ret; 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci ret = kstrtoint(buf, 0, &mode); 17758c2ecf20Sopenharmony_ci if (ret) 17768c2ecf20Sopenharmony_ci return ret; 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci /* Check for supported modes depending on keyboard backlight type */ 17798c2ecf20Sopenharmony_ci if (toshiba->kbd_type == 1) { 17808c2ecf20Sopenharmony_ci /* Type 1 supports SCI_KBD_MODE_FNZ and SCI_KBD_MODE_AUTO */ 17818c2ecf20Sopenharmony_ci if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO) 17828c2ecf20Sopenharmony_ci return -EINVAL; 17838c2ecf20Sopenharmony_ci } else if (toshiba->kbd_type == 2) { 17848c2ecf20Sopenharmony_ci /* Type 2 doesn't support SCI_KBD_MODE_FNZ */ 17858c2ecf20Sopenharmony_ci if (mode != SCI_KBD_MODE_AUTO && mode != SCI_KBD_MODE_ON && 17868c2ecf20Sopenharmony_ci mode != SCI_KBD_MODE_OFF) 17878c2ecf20Sopenharmony_ci return -EINVAL; 17888c2ecf20Sopenharmony_ci } 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci /* 17918c2ecf20Sopenharmony_ci * Set the Keyboard Backlight Mode where: 17928c2ecf20Sopenharmony_ci * Auto - KBD backlight turns off automatically in given time 17938c2ecf20Sopenharmony_ci * FN-Z - KBD backlight "toggles" when hotkey pressed 17948c2ecf20Sopenharmony_ci * ON - KBD backlight is always on 17958c2ecf20Sopenharmony_ci * OFF - KBD backlight is always off 17968c2ecf20Sopenharmony_ci */ 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci /* Only make a change if the actual mode has changed */ 17998c2ecf20Sopenharmony_ci if (toshiba->kbd_mode != mode) { 18008c2ecf20Sopenharmony_ci /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 18018c2ecf20Sopenharmony_ci int time = toshiba->kbd_time << HCI_MISC_SHIFT; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci /* OR the "base time" to the actual method format */ 18048c2ecf20Sopenharmony_ci if (toshiba->kbd_type == 1) { 18058c2ecf20Sopenharmony_ci /* Type 1 requires the current mode */ 18068c2ecf20Sopenharmony_ci time |= toshiba->kbd_mode; 18078c2ecf20Sopenharmony_ci } else if (toshiba->kbd_type == 2) { 18088c2ecf20Sopenharmony_ci /* Type 2 requires the desired mode */ 18098c2ecf20Sopenharmony_ci time |= mode; 18108c2ecf20Sopenharmony_ci } 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci ret = toshiba_kbd_illum_status_set(toshiba, time); 18138c2ecf20Sopenharmony_ci if (ret) 18148c2ecf20Sopenharmony_ci return ret; 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci toshiba->kbd_mode = mode; 18178c2ecf20Sopenharmony_ci toshiba_acpi->kbd_mode = mode; 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci /* 18208c2ecf20Sopenharmony_ci * Some laptop models with the second generation backlit 18218c2ecf20Sopenharmony_ci * keyboard (type 2) do not generate the keyboard backlight 18228c2ecf20Sopenharmony_ci * changed event (0x92), and thus, the driver will never update 18238c2ecf20Sopenharmony_ci * the sysfs entries. 18248c2ecf20Sopenharmony_ci * 18258c2ecf20Sopenharmony_ci * The event is generated right when changing the keyboard 18268c2ecf20Sopenharmony_ci * backlight mode and the *notify function will set the 18278c2ecf20Sopenharmony_ci * kbd_event_generated to true. 18288c2ecf20Sopenharmony_ci * 18298c2ecf20Sopenharmony_ci * In case the event is not generated, schedule the keyboard 18308c2ecf20Sopenharmony_ci * backlight work to update the sysfs entries and emulate the 18318c2ecf20Sopenharmony_ci * event via genetlink. 18328c2ecf20Sopenharmony_ci */ 18338c2ecf20Sopenharmony_ci if (toshiba->kbd_type == 2 && 18348c2ecf20Sopenharmony_ci !toshiba->kbd_event_generated) 18358c2ecf20Sopenharmony_ci schedule_work(&kbd_bl_work); 18368c2ecf20Sopenharmony_ci } 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci return count; 18398c2ecf20Sopenharmony_ci} 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_cistatic ssize_t kbd_backlight_mode_show(struct device *dev, 18428c2ecf20Sopenharmony_ci struct device_attribute *attr, 18438c2ecf20Sopenharmony_ci char *buf) 18448c2ecf20Sopenharmony_ci{ 18458c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 18468c2ecf20Sopenharmony_ci u32 time; 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 18498c2ecf20Sopenharmony_ci return -EIO; 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK); 18528c2ecf20Sopenharmony_ci} 18538c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(kbd_backlight_mode); 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_cistatic ssize_t kbd_type_show(struct device *dev, 18568c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 18578c2ecf20Sopenharmony_ci{ 18588c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", toshiba->kbd_type); 18618c2ecf20Sopenharmony_ci} 18628c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(kbd_type); 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_cistatic ssize_t available_kbd_modes_show(struct device *dev, 18658c2ecf20Sopenharmony_ci struct device_attribute *attr, 18668c2ecf20Sopenharmony_ci char *buf) 18678c2ecf20Sopenharmony_ci{ 18688c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci if (toshiba->kbd_type == 1) 18718c2ecf20Sopenharmony_ci return sprintf(buf, "0x%x 0x%x\n", 18728c2ecf20Sopenharmony_ci SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO); 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci return sprintf(buf, "0x%x 0x%x 0x%x\n", 18758c2ecf20Sopenharmony_ci SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF); 18768c2ecf20Sopenharmony_ci} 18778c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(available_kbd_modes); 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_cistatic ssize_t kbd_backlight_timeout_store(struct device *dev, 18808c2ecf20Sopenharmony_ci struct device_attribute *attr, 18818c2ecf20Sopenharmony_ci const char *buf, size_t count) 18828c2ecf20Sopenharmony_ci{ 18838c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 18848c2ecf20Sopenharmony_ci int time; 18858c2ecf20Sopenharmony_ci int ret; 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci ret = kstrtoint(buf, 0, &time); 18888c2ecf20Sopenharmony_ci if (ret) 18898c2ecf20Sopenharmony_ci return ret; 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci /* Check for supported values depending on kbd_type */ 18928c2ecf20Sopenharmony_ci if (toshiba->kbd_type == 1) { 18938c2ecf20Sopenharmony_ci if (time < 0 || time > 60) 18948c2ecf20Sopenharmony_ci return -EINVAL; 18958c2ecf20Sopenharmony_ci } else if (toshiba->kbd_type == 2) { 18968c2ecf20Sopenharmony_ci if (time < 1 || time > 60) 18978c2ecf20Sopenharmony_ci return -EINVAL; 18988c2ecf20Sopenharmony_ci } 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci /* Set the Keyboard Backlight Timeout */ 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci /* Only make a change if the actual timeout has changed */ 19038c2ecf20Sopenharmony_ci if (toshiba->kbd_time != time) { 19048c2ecf20Sopenharmony_ci /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ 19058c2ecf20Sopenharmony_ci time = time << HCI_MISC_SHIFT; 19068c2ecf20Sopenharmony_ci /* OR the "base time" to the actual method format */ 19078c2ecf20Sopenharmony_ci if (toshiba->kbd_type == 1) 19088c2ecf20Sopenharmony_ci time |= SCI_KBD_MODE_FNZ; 19098c2ecf20Sopenharmony_ci else if (toshiba->kbd_type == 2) 19108c2ecf20Sopenharmony_ci time |= SCI_KBD_MODE_AUTO; 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci ret = toshiba_kbd_illum_status_set(toshiba, time); 19138c2ecf20Sopenharmony_ci if (ret) 19148c2ecf20Sopenharmony_ci return ret; 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ci toshiba->kbd_time = time >> HCI_MISC_SHIFT; 19178c2ecf20Sopenharmony_ci } 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci return count; 19208c2ecf20Sopenharmony_ci} 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_cistatic ssize_t kbd_backlight_timeout_show(struct device *dev, 19238c2ecf20Sopenharmony_ci struct device_attribute *attr, 19248c2ecf20Sopenharmony_ci char *buf) 19258c2ecf20Sopenharmony_ci{ 19268c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 19278c2ecf20Sopenharmony_ci u32 time; 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci if (toshiba_kbd_illum_status_get(toshiba, &time) < 0) 19308c2ecf20Sopenharmony_ci return -EIO; 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT); 19338c2ecf20Sopenharmony_ci} 19348c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(kbd_backlight_timeout); 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_cistatic ssize_t touchpad_store(struct device *dev, 19378c2ecf20Sopenharmony_ci struct device_attribute *attr, 19388c2ecf20Sopenharmony_ci const char *buf, size_t count) 19398c2ecf20Sopenharmony_ci{ 19408c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 19418c2ecf20Sopenharmony_ci int state; 19428c2ecf20Sopenharmony_ci int ret; 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci /* Set the TouchPad on/off, 0 - Disable | 1 - Enable */ 19458c2ecf20Sopenharmony_ci ret = kstrtoint(buf, 0, &state); 19468c2ecf20Sopenharmony_ci if (ret) 19478c2ecf20Sopenharmony_ci return ret; 19488c2ecf20Sopenharmony_ci if (state != 0 && state != 1) 19498c2ecf20Sopenharmony_ci return -EINVAL; 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci ret = toshiba_touchpad_set(toshiba, state); 19528c2ecf20Sopenharmony_ci if (ret) 19538c2ecf20Sopenharmony_ci return ret; 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci return count; 19568c2ecf20Sopenharmony_ci} 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_cistatic ssize_t touchpad_show(struct device *dev, 19598c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 19608c2ecf20Sopenharmony_ci{ 19618c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 19628c2ecf20Sopenharmony_ci u32 state; 19638c2ecf20Sopenharmony_ci int ret; 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci ret = toshiba_touchpad_get(toshiba, &state); 19668c2ecf20Sopenharmony_ci if (ret < 0) 19678c2ecf20Sopenharmony_ci return ret; 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci return sprintf(buf, "%i\n", state); 19708c2ecf20Sopenharmony_ci} 19718c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(touchpad); 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_cistatic ssize_t usb_sleep_charge_show(struct device *dev, 19748c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 19758c2ecf20Sopenharmony_ci{ 19768c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 19778c2ecf20Sopenharmony_ci u32 mode; 19788c2ecf20Sopenharmony_ci int ret; 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci ret = toshiba_usb_sleep_charge_get(toshiba, &mode); 19818c2ecf20Sopenharmony_ci if (ret < 0) 19828c2ecf20Sopenharmony_ci return ret; 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci return sprintf(buf, "%x\n", mode & SCI_USB_CHARGE_MODE_MASK); 19858c2ecf20Sopenharmony_ci} 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_cistatic ssize_t usb_sleep_charge_store(struct device *dev, 19888c2ecf20Sopenharmony_ci struct device_attribute *attr, 19898c2ecf20Sopenharmony_ci const char *buf, size_t count) 19908c2ecf20Sopenharmony_ci{ 19918c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 19928c2ecf20Sopenharmony_ci int state; 19938c2ecf20Sopenharmony_ci u32 mode; 19948c2ecf20Sopenharmony_ci int ret; 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci ret = kstrtoint(buf, 0, &state); 19978c2ecf20Sopenharmony_ci if (ret) 19988c2ecf20Sopenharmony_ci return ret; 19998c2ecf20Sopenharmony_ci /* 20008c2ecf20Sopenharmony_ci * Check for supported values, where: 20018c2ecf20Sopenharmony_ci * 0 - Disabled 20028c2ecf20Sopenharmony_ci * 1 - Alternate (Non USB conformant devices that require more power) 20038c2ecf20Sopenharmony_ci * 2 - Auto (USB conformant devices) 20048c2ecf20Sopenharmony_ci * 3 - Typical 20058c2ecf20Sopenharmony_ci */ 20068c2ecf20Sopenharmony_ci if (state != 0 && state != 1 && state != 2 && state != 3) 20078c2ecf20Sopenharmony_ci return -EINVAL; 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci /* Set the USB charging mode to internal value */ 20108c2ecf20Sopenharmony_ci mode = toshiba->usbsc_mode_base; 20118c2ecf20Sopenharmony_ci if (state == 0) 20128c2ecf20Sopenharmony_ci mode |= SCI_USB_CHARGE_DISABLED; 20138c2ecf20Sopenharmony_ci else if (state == 1) 20148c2ecf20Sopenharmony_ci mode |= SCI_USB_CHARGE_ALTERNATE; 20158c2ecf20Sopenharmony_ci else if (state == 2) 20168c2ecf20Sopenharmony_ci mode |= SCI_USB_CHARGE_AUTO; 20178c2ecf20Sopenharmony_ci else if (state == 3) 20188c2ecf20Sopenharmony_ci mode |= SCI_USB_CHARGE_TYPICAL; 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci ret = toshiba_usb_sleep_charge_set(toshiba, mode); 20218c2ecf20Sopenharmony_ci if (ret) 20228c2ecf20Sopenharmony_ci return ret; 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci return count; 20258c2ecf20Sopenharmony_ci} 20268c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(usb_sleep_charge); 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_cistatic ssize_t sleep_functions_on_battery_show(struct device *dev, 20298c2ecf20Sopenharmony_ci struct device_attribute *attr, 20308c2ecf20Sopenharmony_ci char *buf) 20318c2ecf20Sopenharmony_ci{ 20328c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 20338c2ecf20Sopenharmony_ci int bat_lvl, status; 20348c2ecf20Sopenharmony_ci u32 state; 20358c2ecf20Sopenharmony_ci int ret; 20368c2ecf20Sopenharmony_ci int tmp; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci ret = toshiba_sleep_functions_status_get(toshiba, &state); 20398c2ecf20Sopenharmony_ci if (ret < 0) 20408c2ecf20Sopenharmony_ci return ret; 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci /* Determine the status: 0x4 - Enabled | 0x1 - Disabled */ 20438c2ecf20Sopenharmony_ci tmp = state & SCI_USB_CHARGE_BAT_MASK; 20448c2ecf20Sopenharmony_ci status = (tmp == 0x4) ? 1 : 0; 20458c2ecf20Sopenharmony_ci /* Determine the battery level set */ 20468c2ecf20Sopenharmony_ci bat_lvl = state >> HCI_MISC_SHIFT; 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci return sprintf(buf, "%d %d\n", status, bat_lvl); 20498c2ecf20Sopenharmony_ci} 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_cistatic ssize_t sleep_functions_on_battery_store(struct device *dev, 20528c2ecf20Sopenharmony_ci struct device_attribute *attr, 20538c2ecf20Sopenharmony_ci const char *buf, size_t count) 20548c2ecf20Sopenharmony_ci{ 20558c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 20568c2ecf20Sopenharmony_ci u32 status; 20578c2ecf20Sopenharmony_ci int value; 20588c2ecf20Sopenharmony_ci int ret; 20598c2ecf20Sopenharmony_ci int tmp; 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci ret = kstrtoint(buf, 0, &value); 20628c2ecf20Sopenharmony_ci if (ret) 20638c2ecf20Sopenharmony_ci return ret; 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci /* 20668c2ecf20Sopenharmony_ci * Set the status of the function: 20678c2ecf20Sopenharmony_ci * 0 - Disabled 20688c2ecf20Sopenharmony_ci * 1-100 - Enabled 20698c2ecf20Sopenharmony_ci */ 20708c2ecf20Sopenharmony_ci if (value < 0 || value > 100) 20718c2ecf20Sopenharmony_ci return -EINVAL; 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci if (value == 0) { 20748c2ecf20Sopenharmony_ci tmp = toshiba->usbsc_bat_level << HCI_MISC_SHIFT; 20758c2ecf20Sopenharmony_ci status = tmp | SCI_USB_CHARGE_BAT_LVL_OFF; 20768c2ecf20Sopenharmony_ci } else { 20778c2ecf20Sopenharmony_ci tmp = value << HCI_MISC_SHIFT; 20788c2ecf20Sopenharmony_ci status = tmp | SCI_USB_CHARGE_BAT_LVL_ON; 20798c2ecf20Sopenharmony_ci } 20808c2ecf20Sopenharmony_ci ret = toshiba_sleep_functions_status_set(toshiba, status); 20818c2ecf20Sopenharmony_ci if (ret < 0) 20828c2ecf20Sopenharmony_ci return ret; 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci toshiba->usbsc_bat_level = status >> HCI_MISC_SHIFT; 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci return count; 20878c2ecf20Sopenharmony_ci} 20888c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(sleep_functions_on_battery); 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_cistatic ssize_t usb_rapid_charge_show(struct device *dev, 20918c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 20928c2ecf20Sopenharmony_ci{ 20938c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 20948c2ecf20Sopenharmony_ci u32 state; 20958c2ecf20Sopenharmony_ci int ret; 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci ret = toshiba_usb_rapid_charge_get(toshiba, &state); 20988c2ecf20Sopenharmony_ci if (ret < 0) 20998c2ecf20Sopenharmony_ci return ret; 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", state); 21028c2ecf20Sopenharmony_ci} 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_cistatic ssize_t usb_rapid_charge_store(struct device *dev, 21058c2ecf20Sopenharmony_ci struct device_attribute *attr, 21068c2ecf20Sopenharmony_ci const char *buf, size_t count) 21078c2ecf20Sopenharmony_ci{ 21088c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 21098c2ecf20Sopenharmony_ci int state; 21108c2ecf20Sopenharmony_ci int ret; 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci ret = kstrtoint(buf, 0, &state); 21138c2ecf20Sopenharmony_ci if (ret) 21148c2ecf20Sopenharmony_ci return ret; 21158c2ecf20Sopenharmony_ci if (state != 0 && state != 1) 21168c2ecf20Sopenharmony_ci return -EINVAL; 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci ret = toshiba_usb_rapid_charge_set(toshiba, state); 21198c2ecf20Sopenharmony_ci if (ret) 21208c2ecf20Sopenharmony_ci return ret; 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci return count; 21238c2ecf20Sopenharmony_ci} 21248c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(usb_rapid_charge); 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_cistatic ssize_t usb_sleep_music_show(struct device *dev, 21278c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 21288c2ecf20Sopenharmony_ci{ 21298c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 21308c2ecf20Sopenharmony_ci u32 state; 21318c2ecf20Sopenharmony_ci int ret; 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci ret = toshiba_usb_sleep_music_get(toshiba, &state); 21348c2ecf20Sopenharmony_ci if (ret < 0) 21358c2ecf20Sopenharmony_ci return ret; 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", state); 21388c2ecf20Sopenharmony_ci} 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_cistatic ssize_t usb_sleep_music_store(struct device *dev, 21418c2ecf20Sopenharmony_ci struct device_attribute *attr, 21428c2ecf20Sopenharmony_ci const char *buf, size_t count) 21438c2ecf20Sopenharmony_ci{ 21448c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 21458c2ecf20Sopenharmony_ci int state; 21468c2ecf20Sopenharmony_ci int ret; 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci ret = kstrtoint(buf, 0, &state); 21498c2ecf20Sopenharmony_ci if (ret) 21508c2ecf20Sopenharmony_ci return ret; 21518c2ecf20Sopenharmony_ci if (state != 0 && state != 1) 21528c2ecf20Sopenharmony_ci return -EINVAL; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci ret = toshiba_usb_sleep_music_set(toshiba, state); 21558c2ecf20Sopenharmony_ci if (ret) 21568c2ecf20Sopenharmony_ci return ret; 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci return count; 21598c2ecf20Sopenharmony_ci} 21608c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(usb_sleep_music); 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_cistatic ssize_t kbd_function_keys_show(struct device *dev, 21638c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 21648c2ecf20Sopenharmony_ci{ 21658c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 21668c2ecf20Sopenharmony_ci int mode; 21678c2ecf20Sopenharmony_ci int ret; 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci ret = toshiba_function_keys_get(toshiba, &mode); 21708c2ecf20Sopenharmony_ci if (ret < 0) 21718c2ecf20Sopenharmony_ci return ret; 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", mode); 21748c2ecf20Sopenharmony_ci} 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_cistatic ssize_t kbd_function_keys_store(struct device *dev, 21778c2ecf20Sopenharmony_ci struct device_attribute *attr, 21788c2ecf20Sopenharmony_ci const char *buf, size_t count) 21798c2ecf20Sopenharmony_ci{ 21808c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 21818c2ecf20Sopenharmony_ci int mode; 21828c2ecf20Sopenharmony_ci int ret; 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci ret = kstrtoint(buf, 0, &mode); 21858c2ecf20Sopenharmony_ci if (ret) 21868c2ecf20Sopenharmony_ci return ret; 21878c2ecf20Sopenharmony_ci /* 21888c2ecf20Sopenharmony_ci * Check for the function keys mode where: 21898c2ecf20Sopenharmony_ci * 0 - Normal operation (F{1-12} as usual and hotkeys via FN-F{1-12}) 21908c2ecf20Sopenharmony_ci * 1 - Special functions (Opposite of the above setting) 21918c2ecf20Sopenharmony_ci */ 21928c2ecf20Sopenharmony_ci if (mode != 0 && mode != 1) 21938c2ecf20Sopenharmony_ci return -EINVAL; 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci ret = toshiba_function_keys_set(toshiba, mode); 21968c2ecf20Sopenharmony_ci if (ret) 21978c2ecf20Sopenharmony_ci return ret; 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_ci pr_info("Reboot for changes to KBD Function Keys to take effect"); 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci return count; 22028c2ecf20Sopenharmony_ci} 22038c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(kbd_function_keys); 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_cistatic ssize_t panel_power_on_show(struct device *dev, 22068c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 22078c2ecf20Sopenharmony_ci{ 22088c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 22098c2ecf20Sopenharmony_ci u32 state; 22108c2ecf20Sopenharmony_ci int ret; 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci ret = toshiba_panel_power_on_get(toshiba, &state); 22138c2ecf20Sopenharmony_ci if (ret < 0) 22148c2ecf20Sopenharmony_ci return ret; 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", state); 22178c2ecf20Sopenharmony_ci} 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_cistatic ssize_t panel_power_on_store(struct device *dev, 22208c2ecf20Sopenharmony_ci struct device_attribute *attr, 22218c2ecf20Sopenharmony_ci const char *buf, size_t count) 22228c2ecf20Sopenharmony_ci{ 22238c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 22248c2ecf20Sopenharmony_ci int state; 22258c2ecf20Sopenharmony_ci int ret; 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci ret = kstrtoint(buf, 0, &state); 22288c2ecf20Sopenharmony_ci if (ret) 22298c2ecf20Sopenharmony_ci return ret; 22308c2ecf20Sopenharmony_ci if (state != 0 && state != 1) 22318c2ecf20Sopenharmony_ci return -EINVAL; 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_ci ret = toshiba_panel_power_on_set(toshiba, state); 22348c2ecf20Sopenharmony_ci if (ret) 22358c2ecf20Sopenharmony_ci return ret; 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci pr_info("Reboot for changes to Panel Power ON to take effect"); 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci return count; 22408c2ecf20Sopenharmony_ci} 22418c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(panel_power_on); 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_cistatic ssize_t usb_three_show(struct device *dev, 22448c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 22458c2ecf20Sopenharmony_ci{ 22468c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 22478c2ecf20Sopenharmony_ci u32 state; 22488c2ecf20Sopenharmony_ci int ret; 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ci ret = toshiba_usb_three_get(toshiba, &state); 22518c2ecf20Sopenharmony_ci if (ret < 0) 22528c2ecf20Sopenharmony_ci return ret; 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", state); 22558c2ecf20Sopenharmony_ci} 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_cistatic ssize_t usb_three_store(struct device *dev, 22588c2ecf20Sopenharmony_ci struct device_attribute *attr, 22598c2ecf20Sopenharmony_ci const char *buf, size_t count) 22608c2ecf20Sopenharmony_ci{ 22618c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 22628c2ecf20Sopenharmony_ci int state; 22638c2ecf20Sopenharmony_ci int ret; 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_ci ret = kstrtoint(buf, 0, &state); 22668c2ecf20Sopenharmony_ci if (ret) 22678c2ecf20Sopenharmony_ci return ret; 22688c2ecf20Sopenharmony_ci /* 22698c2ecf20Sopenharmony_ci * Check for USB 3 mode where: 22708c2ecf20Sopenharmony_ci * 0 - Disabled (Acts like a USB 2 port, saving power) 22718c2ecf20Sopenharmony_ci * 1 - Enabled 22728c2ecf20Sopenharmony_ci */ 22738c2ecf20Sopenharmony_ci if (state != 0 && state != 1) 22748c2ecf20Sopenharmony_ci return -EINVAL; 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci ret = toshiba_usb_three_set(toshiba, state); 22778c2ecf20Sopenharmony_ci if (ret) 22788c2ecf20Sopenharmony_ci return ret; 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_ci pr_info("Reboot for changes to USB 3 to take effect"); 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci return count; 22838c2ecf20Sopenharmony_ci} 22848c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(usb_three); 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_cistatic ssize_t cooling_method_show(struct device *dev, 22878c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 22888c2ecf20Sopenharmony_ci{ 22898c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 22908c2ecf20Sopenharmony_ci int state; 22918c2ecf20Sopenharmony_ci int ret; 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_ci ret = toshiba_cooling_method_get(toshiba, &state); 22948c2ecf20Sopenharmony_ci if (ret < 0) 22958c2ecf20Sopenharmony_ci return ret; 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci return sprintf(buf, "%d %d\n", state, toshiba->max_cooling_method); 22988c2ecf20Sopenharmony_ci} 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_cistatic ssize_t cooling_method_store(struct device *dev, 23018c2ecf20Sopenharmony_ci struct device_attribute *attr, 23028c2ecf20Sopenharmony_ci const char *buf, size_t count) 23038c2ecf20Sopenharmony_ci{ 23048c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); 23058c2ecf20Sopenharmony_ci int state; 23068c2ecf20Sopenharmony_ci int ret; 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_ci ret = kstrtoint(buf, 0, &state); 23098c2ecf20Sopenharmony_ci if (ret) 23108c2ecf20Sopenharmony_ci return ret; 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci /* 23138c2ecf20Sopenharmony_ci * Check for supported values 23148c2ecf20Sopenharmony_ci * Depending on the laptop model, some only support these two: 23158c2ecf20Sopenharmony_ci * 0 - Maximum Performance 23168c2ecf20Sopenharmony_ci * 1 - Battery Optimized 23178c2ecf20Sopenharmony_ci * 23188c2ecf20Sopenharmony_ci * While some others support all three methods: 23198c2ecf20Sopenharmony_ci * 0 - Maximum Performance 23208c2ecf20Sopenharmony_ci * 1 - Performance 23218c2ecf20Sopenharmony_ci * 2 - Battery Optimized 23228c2ecf20Sopenharmony_ci */ 23238c2ecf20Sopenharmony_ci if (state < 0 || state > toshiba->max_cooling_method) 23248c2ecf20Sopenharmony_ci return -EINVAL; 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci ret = toshiba_cooling_method_set(toshiba, state); 23278c2ecf20Sopenharmony_ci if (ret) 23288c2ecf20Sopenharmony_ci return ret; 23298c2ecf20Sopenharmony_ci 23308c2ecf20Sopenharmony_ci return count; 23318c2ecf20Sopenharmony_ci} 23328c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(cooling_method); 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_cistatic struct attribute *toshiba_attributes[] = { 23358c2ecf20Sopenharmony_ci &dev_attr_version.attr, 23368c2ecf20Sopenharmony_ci &dev_attr_fan.attr, 23378c2ecf20Sopenharmony_ci &dev_attr_kbd_backlight_mode.attr, 23388c2ecf20Sopenharmony_ci &dev_attr_kbd_type.attr, 23398c2ecf20Sopenharmony_ci &dev_attr_available_kbd_modes.attr, 23408c2ecf20Sopenharmony_ci &dev_attr_kbd_backlight_timeout.attr, 23418c2ecf20Sopenharmony_ci &dev_attr_touchpad.attr, 23428c2ecf20Sopenharmony_ci &dev_attr_usb_sleep_charge.attr, 23438c2ecf20Sopenharmony_ci &dev_attr_sleep_functions_on_battery.attr, 23448c2ecf20Sopenharmony_ci &dev_attr_usb_rapid_charge.attr, 23458c2ecf20Sopenharmony_ci &dev_attr_usb_sleep_music.attr, 23468c2ecf20Sopenharmony_ci &dev_attr_kbd_function_keys.attr, 23478c2ecf20Sopenharmony_ci &dev_attr_panel_power_on.attr, 23488c2ecf20Sopenharmony_ci &dev_attr_usb_three.attr, 23498c2ecf20Sopenharmony_ci &dev_attr_cooling_method.attr, 23508c2ecf20Sopenharmony_ci NULL, 23518c2ecf20Sopenharmony_ci}; 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_cistatic umode_t toshiba_sysfs_is_visible(struct kobject *kobj, 23548c2ecf20Sopenharmony_ci struct attribute *attr, int idx) 23558c2ecf20Sopenharmony_ci{ 23568c2ecf20Sopenharmony_ci struct device *dev = container_of(kobj, struct device, kobj); 23578c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *drv = dev_get_drvdata(dev); 23588c2ecf20Sopenharmony_ci bool exists = true; 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci if (attr == &dev_attr_fan.attr) 23618c2ecf20Sopenharmony_ci exists = (drv->fan_supported) ? true : false; 23628c2ecf20Sopenharmony_ci else if (attr == &dev_attr_kbd_backlight_mode.attr) 23638c2ecf20Sopenharmony_ci exists = (drv->kbd_illum_supported) ? true : false; 23648c2ecf20Sopenharmony_ci else if (attr == &dev_attr_kbd_backlight_timeout.attr) 23658c2ecf20Sopenharmony_ci exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false; 23668c2ecf20Sopenharmony_ci else if (attr == &dev_attr_touchpad.attr) 23678c2ecf20Sopenharmony_ci exists = (drv->touchpad_supported) ? true : false; 23688c2ecf20Sopenharmony_ci else if (attr == &dev_attr_usb_sleep_charge.attr) 23698c2ecf20Sopenharmony_ci exists = (drv->usb_sleep_charge_supported) ? true : false; 23708c2ecf20Sopenharmony_ci else if (attr == &dev_attr_sleep_functions_on_battery.attr) 23718c2ecf20Sopenharmony_ci exists = (drv->usb_sleep_charge_supported) ? true : false; 23728c2ecf20Sopenharmony_ci else if (attr == &dev_attr_usb_rapid_charge.attr) 23738c2ecf20Sopenharmony_ci exists = (drv->usb_rapid_charge_supported) ? true : false; 23748c2ecf20Sopenharmony_ci else if (attr == &dev_attr_usb_sleep_music.attr) 23758c2ecf20Sopenharmony_ci exists = (drv->usb_sleep_music_supported) ? true : false; 23768c2ecf20Sopenharmony_ci else if (attr == &dev_attr_kbd_function_keys.attr) 23778c2ecf20Sopenharmony_ci exists = (drv->kbd_function_keys_supported) ? true : false; 23788c2ecf20Sopenharmony_ci else if (attr == &dev_attr_panel_power_on.attr) 23798c2ecf20Sopenharmony_ci exists = (drv->panel_power_on_supported) ? true : false; 23808c2ecf20Sopenharmony_ci else if (attr == &dev_attr_usb_three.attr) 23818c2ecf20Sopenharmony_ci exists = (drv->usb_three_supported) ? true : false; 23828c2ecf20Sopenharmony_ci else if (attr == &dev_attr_cooling_method.attr) 23838c2ecf20Sopenharmony_ci exists = (drv->cooling_method_supported) ? true : false; 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_ci return exists ? attr->mode : 0; 23868c2ecf20Sopenharmony_ci} 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_cistatic const struct attribute_group toshiba_attr_group = { 23898c2ecf20Sopenharmony_ci .is_visible = toshiba_sysfs_is_visible, 23908c2ecf20Sopenharmony_ci .attrs = toshiba_attributes, 23918c2ecf20Sopenharmony_ci}; 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_cistatic void toshiba_acpi_kbd_bl_work(struct work_struct *work) 23948c2ecf20Sopenharmony_ci{ 23958c2ecf20Sopenharmony_ci /* Update the sysfs entries */ 23968c2ecf20Sopenharmony_ci if (sysfs_update_group(&toshiba_acpi->acpi_dev->dev.kobj, 23978c2ecf20Sopenharmony_ci &toshiba_attr_group)) 23988c2ecf20Sopenharmony_ci pr_err("Unable to update sysfs entries\n"); 23998c2ecf20Sopenharmony_ci 24008c2ecf20Sopenharmony_ci /* Notify LED subsystem about keyboard backlight change */ 24018c2ecf20Sopenharmony_ci if (toshiba_acpi->kbd_type == 2 && 24028c2ecf20Sopenharmony_ci toshiba_acpi->kbd_mode != SCI_KBD_MODE_AUTO) 24038c2ecf20Sopenharmony_ci led_classdev_notify_brightness_hw_changed(&toshiba_acpi->kbd_led, 24048c2ecf20Sopenharmony_ci (toshiba_acpi->kbd_mode == SCI_KBD_MODE_ON) ? 24058c2ecf20Sopenharmony_ci LED_FULL : LED_OFF); 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci /* Emulate the keyboard backlight event */ 24088c2ecf20Sopenharmony_ci acpi_bus_generate_netlink_event(toshiba_acpi->acpi_dev->pnp.device_class, 24098c2ecf20Sopenharmony_ci dev_name(&toshiba_acpi->acpi_dev->dev), 24108c2ecf20Sopenharmony_ci 0x92, 0); 24118c2ecf20Sopenharmony_ci} 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci/* 24148c2ecf20Sopenharmony_ci * IIO device 24158c2ecf20Sopenharmony_ci */ 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_cienum toshiba_iio_accel_chan { 24188c2ecf20Sopenharmony_ci AXIS_X, 24198c2ecf20Sopenharmony_ci AXIS_Y, 24208c2ecf20Sopenharmony_ci AXIS_Z 24218c2ecf20Sopenharmony_ci}; 24228c2ecf20Sopenharmony_ci 24238c2ecf20Sopenharmony_cistatic int toshiba_iio_accel_get_axis(enum toshiba_iio_accel_chan chan) 24248c2ecf20Sopenharmony_ci{ 24258c2ecf20Sopenharmony_ci u32 xyval, zval; 24268c2ecf20Sopenharmony_ci int ret; 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci ret = toshiba_accelerometer_get(toshiba_acpi, &xyval, &zval); 24298c2ecf20Sopenharmony_ci if (ret < 0) 24308c2ecf20Sopenharmony_ci return ret; 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci switch (chan) { 24338c2ecf20Sopenharmony_ci case AXIS_X: 24348c2ecf20Sopenharmony_ci return xyval & HCI_ACCEL_DIRECTION_MASK ? 24358c2ecf20Sopenharmony_ci -(xyval & HCI_ACCEL_MASK) : xyval & HCI_ACCEL_MASK; 24368c2ecf20Sopenharmony_ci case AXIS_Y: 24378c2ecf20Sopenharmony_ci return (xyval >> HCI_MISC_SHIFT) & HCI_ACCEL_DIRECTION_MASK ? 24388c2ecf20Sopenharmony_ci -((xyval >> HCI_MISC_SHIFT) & HCI_ACCEL_MASK) : 24398c2ecf20Sopenharmony_ci (xyval >> HCI_MISC_SHIFT) & HCI_ACCEL_MASK; 24408c2ecf20Sopenharmony_ci case AXIS_Z: 24418c2ecf20Sopenharmony_ci return zval & HCI_ACCEL_DIRECTION_MASK ? 24428c2ecf20Sopenharmony_ci -(zval & HCI_ACCEL_MASK) : zval & HCI_ACCEL_MASK; 24438c2ecf20Sopenharmony_ci } 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ci return ret; 24468c2ecf20Sopenharmony_ci} 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_cistatic int toshiba_iio_accel_read_raw(struct iio_dev *indio_dev, 24498c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 24508c2ecf20Sopenharmony_ci int *val, int *val2, long mask) 24518c2ecf20Sopenharmony_ci{ 24528c2ecf20Sopenharmony_ci int ret; 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci switch (mask) { 24558c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 24568c2ecf20Sopenharmony_ci ret = toshiba_iio_accel_get_axis(chan->channel); 24578c2ecf20Sopenharmony_ci if (ret == -EIO || ret == -ENODEV) 24588c2ecf20Sopenharmony_ci return ret; 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci *val = ret; 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci return IIO_VAL_INT; 24638c2ecf20Sopenharmony_ci } 24648c2ecf20Sopenharmony_ci 24658c2ecf20Sopenharmony_ci return -EINVAL; 24668c2ecf20Sopenharmony_ci} 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_ci#define TOSHIBA_IIO_ACCEL_CHANNEL(axis, chan) { \ 24698c2ecf20Sopenharmony_ci .type = IIO_ACCEL, \ 24708c2ecf20Sopenharmony_ci .modified = 1, \ 24718c2ecf20Sopenharmony_ci .channel = chan, \ 24728c2ecf20Sopenharmony_ci .channel2 = IIO_MOD_##axis, \ 24738c2ecf20Sopenharmony_ci .output = 1, \ 24748c2ecf20Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 24758c2ecf20Sopenharmony_ci} 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_cistatic const struct iio_chan_spec toshiba_iio_accel_channels[] = { 24788c2ecf20Sopenharmony_ci TOSHIBA_IIO_ACCEL_CHANNEL(X, AXIS_X), 24798c2ecf20Sopenharmony_ci TOSHIBA_IIO_ACCEL_CHANNEL(Y, AXIS_Y), 24808c2ecf20Sopenharmony_ci TOSHIBA_IIO_ACCEL_CHANNEL(Z, AXIS_Z), 24818c2ecf20Sopenharmony_ci}; 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_cistatic const struct iio_info toshiba_iio_accel_info = { 24848c2ecf20Sopenharmony_ci .read_raw = &toshiba_iio_accel_read_raw, 24858c2ecf20Sopenharmony_ci}; 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ci/* 24888c2ecf20Sopenharmony_ci * Misc device 24898c2ecf20Sopenharmony_ci */ 24908c2ecf20Sopenharmony_cistatic int toshiba_acpi_smm_bridge(SMMRegisters *regs) 24918c2ecf20Sopenharmony_ci{ 24928c2ecf20Sopenharmony_ci u32 in[TCI_WORDS] = { regs->eax, regs->ebx, regs->ecx, 24938c2ecf20Sopenharmony_ci regs->edx, regs->esi, regs->edi }; 24948c2ecf20Sopenharmony_ci u32 out[TCI_WORDS]; 24958c2ecf20Sopenharmony_ci acpi_status status; 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ci status = tci_raw(toshiba_acpi, in, out); 24988c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 24998c2ecf20Sopenharmony_ci pr_err("ACPI call to query SMM registers failed\n"); 25008c2ecf20Sopenharmony_ci return -EIO; 25018c2ecf20Sopenharmony_ci } 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci /* Fillout the SMM struct with the TCI call results */ 25048c2ecf20Sopenharmony_ci regs->eax = out[0]; 25058c2ecf20Sopenharmony_ci regs->ebx = out[1]; 25068c2ecf20Sopenharmony_ci regs->ecx = out[2]; 25078c2ecf20Sopenharmony_ci regs->edx = out[3]; 25088c2ecf20Sopenharmony_ci regs->esi = out[4]; 25098c2ecf20Sopenharmony_ci regs->edi = out[5]; 25108c2ecf20Sopenharmony_ci 25118c2ecf20Sopenharmony_ci return 0; 25128c2ecf20Sopenharmony_ci} 25138c2ecf20Sopenharmony_ci 25148c2ecf20Sopenharmony_cistatic long toshiba_acpi_ioctl(struct file *fp, unsigned int cmd, 25158c2ecf20Sopenharmony_ci unsigned long arg) 25168c2ecf20Sopenharmony_ci{ 25178c2ecf20Sopenharmony_ci SMMRegisters __user *argp = (SMMRegisters __user *)arg; 25188c2ecf20Sopenharmony_ci SMMRegisters regs; 25198c2ecf20Sopenharmony_ci int ret; 25208c2ecf20Sopenharmony_ci 25218c2ecf20Sopenharmony_ci if (!argp) 25228c2ecf20Sopenharmony_ci return -EINVAL; 25238c2ecf20Sopenharmony_ci 25248c2ecf20Sopenharmony_ci switch (cmd) { 25258c2ecf20Sopenharmony_ci case TOSH_SMM: 25268c2ecf20Sopenharmony_ci if (copy_from_user(®s, argp, sizeof(SMMRegisters))) 25278c2ecf20Sopenharmony_ci return -EFAULT; 25288c2ecf20Sopenharmony_ci ret = toshiba_acpi_smm_bridge(®s); 25298c2ecf20Sopenharmony_ci if (ret) 25308c2ecf20Sopenharmony_ci return ret; 25318c2ecf20Sopenharmony_ci if (copy_to_user(argp, ®s, sizeof(SMMRegisters))) 25328c2ecf20Sopenharmony_ci return -EFAULT; 25338c2ecf20Sopenharmony_ci break; 25348c2ecf20Sopenharmony_ci case TOSHIBA_ACPI_SCI: 25358c2ecf20Sopenharmony_ci if (copy_from_user(®s, argp, sizeof(SMMRegisters))) 25368c2ecf20Sopenharmony_ci return -EFAULT; 25378c2ecf20Sopenharmony_ci /* Ensure we are being called with a SCI_{GET, SET} register */ 25388c2ecf20Sopenharmony_ci if (regs.eax != SCI_GET && regs.eax != SCI_SET) 25398c2ecf20Sopenharmony_ci return -EINVAL; 25408c2ecf20Sopenharmony_ci if (!sci_open(toshiba_acpi)) 25418c2ecf20Sopenharmony_ci return -EIO; 25428c2ecf20Sopenharmony_ci ret = toshiba_acpi_smm_bridge(®s); 25438c2ecf20Sopenharmony_ci sci_close(toshiba_acpi); 25448c2ecf20Sopenharmony_ci if (ret) 25458c2ecf20Sopenharmony_ci return ret; 25468c2ecf20Sopenharmony_ci if (copy_to_user(argp, ®s, sizeof(SMMRegisters))) 25478c2ecf20Sopenharmony_ci return -EFAULT; 25488c2ecf20Sopenharmony_ci break; 25498c2ecf20Sopenharmony_ci default: 25508c2ecf20Sopenharmony_ci return -EINVAL; 25518c2ecf20Sopenharmony_ci } 25528c2ecf20Sopenharmony_ci 25538c2ecf20Sopenharmony_ci return 0; 25548c2ecf20Sopenharmony_ci} 25558c2ecf20Sopenharmony_ci 25568c2ecf20Sopenharmony_cistatic const struct file_operations toshiba_acpi_fops = { 25578c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 25588c2ecf20Sopenharmony_ci .unlocked_ioctl = toshiba_acpi_ioctl, 25598c2ecf20Sopenharmony_ci .llseek = noop_llseek, 25608c2ecf20Sopenharmony_ci}; 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_ci/* 25638c2ecf20Sopenharmony_ci * WWAN RFKill handlers 25648c2ecf20Sopenharmony_ci */ 25658c2ecf20Sopenharmony_cistatic int toshiba_acpi_wwan_set_block(void *data, bool blocked) 25668c2ecf20Sopenharmony_ci{ 25678c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = data; 25688c2ecf20Sopenharmony_ci int ret; 25698c2ecf20Sopenharmony_ci 25708c2ecf20Sopenharmony_ci ret = toshiba_wireless_status(dev); 25718c2ecf20Sopenharmony_ci if (ret) 25728c2ecf20Sopenharmony_ci return ret; 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci if (!dev->killswitch) 25758c2ecf20Sopenharmony_ci return 0; 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_ci return toshiba_wwan_set(dev, !blocked); 25788c2ecf20Sopenharmony_ci} 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_cistatic void toshiba_acpi_wwan_poll(struct rfkill *rfkill, void *data) 25818c2ecf20Sopenharmony_ci{ 25828c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = data; 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci if (toshiba_wireless_status(dev)) 25858c2ecf20Sopenharmony_ci return; 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch); 25888c2ecf20Sopenharmony_ci} 25898c2ecf20Sopenharmony_ci 25908c2ecf20Sopenharmony_cistatic const struct rfkill_ops wwan_rfk_ops = { 25918c2ecf20Sopenharmony_ci .set_block = toshiba_acpi_wwan_set_block, 25928c2ecf20Sopenharmony_ci .poll = toshiba_acpi_wwan_poll, 25938c2ecf20Sopenharmony_ci}; 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_cistatic int toshiba_acpi_setup_wwan_rfkill(struct toshiba_acpi_dev *dev) 25968c2ecf20Sopenharmony_ci{ 25978c2ecf20Sopenharmony_ci int ret = toshiba_wireless_status(dev); 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci if (ret) 26008c2ecf20Sopenharmony_ci return ret; 26018c2ecf20Sopenharmony_ci 26028c2ecf20Sopenharmony_ci dev->wwan_rfk = rfkill_alloc("Toshiba WWAN", 26038c2ecf20Sopenharmony_ci &dev->acpi_dev->dev, 26048c2ecf20Sopenharmony_ci RFKILL_TYPE_WWAN, 26058c2ecf20Sopenharmony_ci &wwan_rfk_ops, 26068c2ecf20Sopenharmony_ci dev); 26078c2ecf20Sopenharmony_ci if (!dev->wwan_rfk) { 26088c2ecf20Sopenharmony_ci pr_err("Unable to allocate WWAN rfkill device\n"); 26098c2ecf20Sopenharmony_ci return -ENOMEM; 26108c2ecf20Sopenharmony_ci } 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ci rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch); 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci ret = rfkill_register(dev->wwan_rfk); 26158c2ecf20Sopenharmony_ci if (ret) { 26168c2ecf20Sopenharmony_ci pr_err("Unable to register WWAN rfkill device\n"); 26178c2ecf20Sopenharmony_ci rfkill_destroy(dev->wwan_rfk); 26188c2ecf20Sopenharmony_ci } 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_ci return ret; 26218c2ecf20Sopenharmony_ci} 26228c2ecf20Sopenharmony_ci 26238c2ecf20Sopenharmony_ci/* 26248c2ecf20Sopenharmony_ci * Hotkeys 26258c2ecf20Sopenharmony_ci */ 26268c2ecf20Sopenharmony_cistatic int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev) 26278c2ecf20Sopenharmony_ci{ 26288c2ecf20Sopenharmony_ci acpi_status status; 26298c2ecf20Sopenharmony_ci u32 result; 26308c2ecf20Sopenharmony_ci 26318c2ecf20Sopenharmony_ci status = acpi_evaluate_object(dev->acpi_dev->handle, 26328c2ecf20Sopenharmony_ci "ENAB", NULL, NULL); 26338c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 26348c2ecf20Sopenharmony_ci return -ENODEV; 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_ci /* 26378c2ecf20Sopenharmony_ci * Enable the "Special Functions" mode only if they are 26388c2ecf20Sopenharmony_ci * supported and if they are activated. 26398c2ecf20Sopenharmony_ci */ 26408c2ecf20Sopenharmony_ci if (dev->kbd_function_keys_supported && dev->special_functions) 26418c2ecf20Sopenharmony_ci result = hci_write(dev, HCI_HOTKEY_EVENT, 26428c2ecf20Sopenharmony_ci HCI_HOTKEY_SPECIAL_FUNCTIONS); 26438c2ecf20Sopenharmony_ci else 26448c2ecf20Sopenharmony_ci result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE); 26458c2ecf20Sopenharmony_ci 26468c2ecf20Sopenharmony_ci if (result == TOS_FAILURE) 26478c2ecf20Sopenharmony_ci return -EIO; 26488c2ecf20Sopenharmony_ci else if (result == TOS_NOT_SUPPORTED) 26498c2ecf20Sopenharmony_ci return -ENODEV; 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_ci return 0; 26528c2ecf20Sopenharmony_ci} 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_cistatic bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, 26558c2ecf20Sopenharmony_ci struct serio *port) 26568c2ecf20Sopenharmony_ci{ 26578c2ecf20Sopenharmony_ci if (str & I8042_STR_AUXDATA) 26588c2ecf20Sopenharmony_ci return false; 26598c2ecf20Sopenharmony_ci 26608c2ecf20Sopenharmony_ci if (unlikely(data == 0xe0)) 26618c2ecf20Sopenharmony_ci return false; 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_ci if ((data & 0x7f) == TOS1900_FN_SCAN) { 26648c2ecf20Sopenharmony_ci schedule_work(&toshiba_acpi->hotkey_work); 26658c2ecf20Sopenharmony_ci return true; 26668c2ecf20Sopenharmony_ci } 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci return false; 26698c2ecf20Sopenharmony_ci} 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_cistatic void toshiba_acpi_hotkey_work(struct work_struct *work) 26728c2ecf20Sopenharmony_ci{ 26738c2ecf20Sopenharmony_ci acpi_handle ec_handle = ec_get_handle(); 26748c2ecf20Sopenharmony_ci acpi_status status; 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_ci if (!ec_handle) 26778c2ecf20Sopenharmony_ci return; 26788c2ecf20Sopenharmony_ci 26798c2ecf20Sopenharmony_ci status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL); 26808c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 26818c2ecf20Sopenharmony_ci pr_err("ACPI NTFY method execution failed\n"); 26828c2ecf20Sopenharmony_ci} 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_ci/* 26858c2ecf20Sopenharmony_ci * Returns hotkey scancode, or < 0 on failure. 26868c2ecf20Sopenharmony_ci */ 26878c2ecf20Sopenharmony_cistatic int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev) 26888c2ecf20Sopenharmony_ci{ 26898c2ecf20Sopenharmony_ci unsigned long long value; 26908c2ecf20Sopenharmony_ci acpi_status status; 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_ci status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO", 26938c2ecf20Sopenharmony_ci NULL, &value); 26948c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 26958c2ecf20Sopenharmony_ci pr_err("ACPI INFO method execution failed\n"); 26968c2ecf20Sopenharmony_ci return -EIO; 26978c2ecf20Sopenharmony_ci } 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_ci return value; 27008c2ecf20Sopenharmony_ci} 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_cistatic void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev, 27038c2ecf20Sopenharmony_ci int scancode) 27048c2ecf20Sopenharmony_ci{ 27058c2ecf20Sopenharmony_ci if (scancode == 0x100) 27068c2ecf20Sopenharmony_ci return; 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci /* Act on key press; ignore key release */ 27098c2ecf20Sopenharmony_ci if (scancode & 0x80) 27108c2ecf20Sopenharmony_ci return; 27118c2ecf20Sopenharmony_ci 27128c2ecf20Sopenharmony_ci if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true)) 27138c2ecf20Sopenharmony_ci pr_info("Unknown key %x\n", scancode); 27148c2ecf20Sopenharmony_ci} 27158c2ecf20Sopenharmony_ci 27168c2ecf20Sopenharmony_cistatic void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) 27178c2ecf20Sopenharmony_ci{ 27188c2ecf20Sopenharmony_ci if (dev->info_supported) { 27198c2ecf20Sopenharmony_ci int scancode = toshiba_acpi_query_hotkey(dev); 27208c2ecf20Sopenharmony_ci 27218c2ecf20Sopenharmony_ci if (scancode < 0) { 27228c2ecf20Sopenharmony_ci pr_err("Failed to query hotkey event\n"); 27238c2ecf20Sopenharmony_ci } else if (scancode != 0) { 27248c2ecf20Sopenharmony_ci toshiba_acpi_report_hotkey(dev, scancode); 27258c2ecf20Sopenharmony_ci dev->key_event_valid = 1; 27268c2ecf20Sopenharmony_ci dev->last_key_event = scancode; 27278c2ecf20Sopenharmony_ci } 27288c2ecf20Sopenharmony_ci } else if (dev->system_event_supported) { 27298c2ecf20Sopenharmony_ci u32 result; 27308c2ecf20Sopenharmony_ci u32 value; 27318c2ecf20Sopenharmony_ci int retries = 3; 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ci do { 27348c2ecf20Sopenharmony_ci result = hci_read(dev, HCI_SYSTEM_EVENT, &value); 27358c2ecf20Sopenharmony_ci switch (result) { 27368c2ecf20Sopenharmony_ci case TOS_SUCCESS: 27378c2ecf20Sopenharmony_ci toshiba_acpi_report_hotkey(dev, (int)value); 27388c2ecf20Sopenharmony_ci dev->key_event_valid = 1; 27398c2ecf20Sopenharmony_ci dev->last_key_event = value; 27408c2ecf20Sopenharmony_ci break; 27418c2ecf20Sopenharmony_ci case TOS_NOT_SUPPORTED: 27428c2ecf20Sopenharmony_ci /* 27438c2ecf20Sopenharmony_ci * This is a workaround for an unresolved 27448c2ecf20Sopenharmony_ci * issue on some machines where system events 27458c2ecf20Sopenharmony_ci * sporadically become disabled. 27468c2ecf20Sopenharmony_ci */ 27478c2ecf20Sopenharmony_ci result = hci_write(dev, HCI_SYSTEM_EVENT, 1); 27488c2ecf20Sopenharmony_ci if (result == TOS_SUCCESS) 27498c2ecf20Sopenharmony_ci pr_notice("Re-enabled hotkeys\n"); 27508c2ecf20Sopenharmony_ci fallthrough; 27518c2ecf20Sopenharmony_ci default: 27528c2ecf20Sopenharmony_ci retries--; 27538c2ecf20Sopenharmony_ci break; 27548c2ecf20Sopenharmony_ci } 27558c2ecf20Sopenharmony_ci } while (retries && result != TOS_FIFO_EMPTY); 27568c2ecf20Sopenharmony_ci } 27578c2ecf20Sopenharmony_ci} 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_cistatic int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) 27608c2ecf20Sopenharmony_ci{ 27618c2ecf20Sopenharmony_ci const struct key_entry *keymap = toshiba_acpi_keymap; 27628c2ecf20Sopenharmony_ci acpi_handle ec_handle; 27638c2ecf20Sopenharmony_ci int error; 27648c2ecf20Sopenharmony_ci 27658c2ecf20Sopenharmony_ci if (disable_hotkeys) { 27668c2ecf20Sopenharmony_ci pr_info("Hotkeys disabled by module parameter\n"); 27678c2ecf20Sopenharmony_ci return 0; 27688c2ecf20Sopenharmony_ci } 27698c2ecf20Sopenharmony_ci 27708c2ecf20Sopenharmony_ci if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) { 27718c2ecf20Sopenharmony_ci pr_info("WMI event detected, hotkeys will not be monitored\n"); 27728c2ecf20Sopenharmony_ci return 0; 27738c2ecf20Sopenharmony_ci } 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci error = toshiba_acpi_enable_hotkeys(dev); 27768c2ecf20Sopenharmony_ci if (error) 27778c2ecf20Sopenharmony_ci return error; 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ci if (toshiba_hotkey_event_type_get(dev, &dev->hotkey_event_type)) 27808c2ecf20Sopenharmony_ci pr_notice("Unable to query Hotkey Event Type\n"); 27818c2ecf20Sopenharmony_ci 27828c2ecf20Sopenharmony_ci dev->hotkey_dev = input_allocate_device(); 27838c2ecf20Sopenharmony_ci if (!dev->hotkey_dev) 27848c2ecf20Sopenharmony_ci return -ENOMEM; 27858c2ecf20Sopenharmony_ci 27868c2ecf20Sopenharmony_ci dev->hotkey_dev->name = "Toshiba input device"; 27878c2ecf20Sopenharmony_ci dev->hotkey_dev->phys = "toshiba_acpi/input0"; 27888c2ecf20Sopenharmony_ci dev->hotkey_dev->id.bustype = BUS_HOST; 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_ci if (dev->hotkey_event_type == HCI_SYSTEM_TYPE1 || 27918c2ecf20Sopenharmony_ci !dev->kbd_function_keys_supported) 27928c2ecf20Sopenharmony_ci keymap = toshiba_acpi_keymap; 27938c2ecf20Sopenharmony_ci else if (dev->hotkey_event_type == HCI_SYSTEM_TYPE2 || 27948c2ecf20Sopenharmony_ci dev->kbd_function_keys_supported) 27958c2ecf20Sopenharmony_ci keymap = toshiba_acpi_alt_keymap; 27968c2ecf20Sopenharmony_ci else 27978c2ecf20Sopenharmony_ci pr_info("Unknown event type received %x\n", 27988c2ecf20Sopenharmony_ci dev->hotkey_event_type); 27998c2ecf20Sopenharmony_ci error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL); 28008c2ecf20Sopenharmony_ci if (error) 28018c2ecf20Sopenharmony_ci goto err_free_dev; 28028c2ecf20Sopenharmony_ci 28038c2ecf20Sopenharmony_ci /* 28048c2ecf20Sopenharmony_ci * For some machines the SCI responsible for providing hotkey 28058c2ecf20Sopenharmony_ci * notification doesn't fire. We can trigger the notification 28068c2ecf20Sopenharmony_ci * whenever the Fn key is pressed using the NTFY method, if 28078c2ecf20Sopenharmony_ci * supported, so if it's present set up an i8042 key filter 28088c2ecf20Sopenharmony_ci * for this purpose. 28098c2ecf20Sopenharmony_ci */ 28108c2ecf20Sopenharmony_ci ec_handle = ec_get_handle(); 28118c2ecf20Sopenharmony_ci if (ec_handle && acpi_has_method(ec_handle, "NTFY")) { 28128c2ecf20Sopenharmony_ci INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work); 28138c2ecf20Sopenharmony_ci 28148c2ecf20Sopenharmony_ci error = i8042_install_filter(toshiba_acpi_i8042_filter); 28158c2ecf20Sopenharmony_ci if (error) { 28168c2ecf20Sopenharmony_ci pr_err("Error installing key filter\n"); 28178c2ecf20Sopenharmony_ci goto err_free_dev; 28188c2ecf20Sopenharmony_ci } 28198c2ecf20Sopenharmony_ci 28208c2ecf20Sopenharmony_ci dev->ntfy_supported = 1; 28218c2ecf20Sopenharmony_ci } 28228c2ecf20Sopenharmony_ci 28238c2ecf20Sopenharmony_ci /* 28248c2ecf20Sopenharmony_ci * Determine hotkey query interface. Prefer using the INFO 28258c2ecf20Sopenharmony_ci * method when it is available. 28268c2ecf20Sopenharmony_ci */ 28278c2ecf20Sopenharmony_ci if (acpi_has_method(dev->acpi_dev->handle, "INFO")) 28288c2ecf20Sopenharmony_ci dev->info_supported = 1; 28298c2ecf20Sopenharmony_ci else if (hci_write(dev, HCI_SYSTEM_EVENT, 1) == TOS_SUCCESS) 28308c2ecf20Sopenharmony_ci dev->system_event_supported = 1; 28318c2ecf20Sopenharmony_ci 28328c2ecf20Sopenharmony_ci if (!dev->info_supported && !dev->system_event_supported) { 28338c2ecf20Sopenharmony_ci pr_warn("No hotkey query interface found\n"); 28348c2ecf20Sopenharmony_ci error = -EINVAL; 28358c2ecf20Sopenharmony_ci goto err_remove_filter; 28368c2ecf20Sopenharmony_ci } 28378c2ecf20Sopenharmony_ci 28388c2ecf20Sopenharmony_ci error = input_register_device(dev->hotkey_dev); 28398c2ecf20Sopenharmony_ci if (error) { 28408c2ecf20Sopenharmony_ci pr_info("Unable to register input device\n"); 28418c2ecf20Sopenharmony_ci goto err_remove_filter; 28428c2ecf20Sopenharmony_ci } 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_ci return 0; 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_ci err_remove_filter: 28478c2ecf20Sopenharmony_ci if (dev->ntfy_supported) 28488c2ecf20Sopenharmony_ci i8042_remove_filter(toshiba_acpi_i8042_filter); 28498c2ecf20Sopenharmony_ci err_free_dev: 28508c2ecf20Sopenharmony_ci input_free_device(dev->hotkey_dev); 28518c2ecf20Sopenharmony_ci dev->hotkey_dev = NULL; 28528c2ecf20Sopenharmony_ci return error; 28538c2ecf20Sopenharmony_ci} 28548c2ecf20Sopenharmony_ci 28558c2ecf20Sopenharmony_cistatic int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) 28568c2ecf20Sopenharmony_ci{ 28578c2ecf20Sopenharmony_ci struct backlight_properties props; 28588c2ecf20Sopenharmony_ci int brightness; 28598c2ecf20Sopenharmony_ci int ret; 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_ci /* 28628c2ecf20Sopenharmony_ci * Some machines don't support the backlight methods at all, and 28638c2ecf20Sopenharmony_ci * others support it read-only. Either of these is pretty useless, 28648c2ecf20Sopenharmony_ci * so only register the backlight device if the backlight method 28658c2ecf20Sopenharmony_ci * supports both reads and writes. 28668c2ecf20Sopenharmony_ci */ 28678c2ecf20Sopenharmony_ci brightness = __get_lcd_brightness(dev); 28688c2ecf20Sopenharmony_ci if (brightness < 0) 28698c2ecf20Sopenharmony_ci return 0; 28708c2ecf20Sopenharmony_ci /* 28718c2ecf20Sopenharmony_ci * If transflective backlight is supported and the brightness is zero 28728c2ecf20Sopenharmony_ci * (lowest brightness level), the set_lcd_brightness function will 28738c2ecf20Sopenharmony_ci * activate the transflective backlight, making the LCD appear to be 28748c2ecf20Sopenharmony_ci * turned off, simply increment the brightness level to avoid that. 28758c2ecf20Sopenharmony_ci */ 28768c2ecf20Sopenharmony_ci if (dev->tr_backlight_supported && brightness == 0) 28778c2ecf20Sopenharmony_ci brightness++; 28788c2ecf20Sopenharmony_ci ret = set_lcd_brightness(dev, brightness); 28798c2ecf20Sopenharmony_ci if (ret) { 28808c2ecf20Sopenharmony_ci pr_debug("Backlight method is read-only, disabling backlight support\n"); 28818c2ecf20Sopenharmony_ci return 0; 28828c2ecf20Sopenharmony_ci } 28838c2ecf20Sopenharmony_ci 28848c2ecf20Sopenharmony_ci /* 28858c2ecf20Sopenharmony_ci * Tell acpi-video-detect code to prefer vendor backlight on all 28868c2ecf20Sopenharmony_ci * systems with transflective backlight and on dmi matched systems. 28878c2ecf20Sopenharmony_ci */ 28888c2ecf20Sopenharmony_ci if (dev->tr_backlight_supported || 28898c2ecf20Sopenharmony_ci dmi_check_system(toshiba_vendor_backlight_dmi)) 28908c2ecf20Sopenharmony_ci acpi_video_set_dmi_backlight_type(acpi_backlight_vendor); 28918c2ecf20Sopenharmony_ci 28928c2ecf20Sopenharmony_ci if (acpi_video_get_backlight_type() != acpi_backlight_vendor) 28938c2ecf20Sopenharmony_ci return 0; 28948c2ecf20Sopenharmony_ci 28958c2ecf20Sopenharmony_ci memset(&props, 0, sizeof(props)); 28968c2ecf20Sopenharmony_ci props.type = BACKLIGHT_PLATFORM; 28978c2ecf20Sopenharmony_ci props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; 28988c2ecf20Sopenharmony_ci 28998c2ecf20Sopenharmony_ci /* Adding an extra level and having 0 change to transflective mode */ 29008c2ecf20Sopenharmony_ci if (dev->tr_backlight_supported) 29018c2ecf20Sopenharmony_ci props.max_brightness++; 29028c2ecf20Sopenharmony_ci 29038c2ecf20Sopenharmony_ci dev->backlight_dev = backlight_device_register("toshiba", 29048c2ecf20Sopenharmony_ci &dev->acpi_dev->dev, 29058c2ecf20Sopenharmony_ci dev, 29068c2ecf20Sopenharmony_ci &toshiba_backlight_data, 29078c2ecf20Sopenharmony_ci &props); 29088c2ecf20Sopenharmony_ci if (IS_ERR(dev->backlight_dev)) { 29098c2ecf20Sopenharmony_ci ret = PTR_ERR(dev->backlight_dev); 29108c2ecf20Sopenharmony_ci pr_err("Could not register toshiba backlight device\n"); 29118c2ecf20Sopenharmony_ci dev->backlight_dev = NULL; 29128c2ecf20Sopenharmony_ci return ret; 29138c2ecf20Sopenharmony_ci } 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_ci dev->backlight_dev->props.brightness = brightness; 29168c2ecf20Sopenharmony_ci return 0; 29178c2ecf20Sopenharmony_ci} 29188c2ecf20Sopenharmony_ci 29198c2ecf20Sopenharmony_cistatic void print_supported_features(struct toshiba_acpi_dev *dev) 29208c2ecf20Sopenharmony_ci{ 29218c2ecf20Sopenharmony_ci pr_info("Supported laptop features:"); 29228c2ecf20Sopenharmony_ci 29238c2ecf20Sopenharmony_ci if (dev->hotkey_dev) 29248c2ecf20Sopenharmony_ci pr_cont(" hotkeys"); 29258c2ecf20Sopenharmony_ci if (dev->backlight_dev) 29268c2ecf20Sopenharmony_ci pr_cont(" backlight"); 29278c2ecf20Sopenharmony_ci if (dev->video_supported) 29288c2ecf20Sopenharmony_ci pr_cont(" video-out"); 29298c2ecf20Sopenharmony_ci if (dev->fan_supported) 29308c2ecf20Sopenharmony_ci pr_cont(" fan"); 29318c2ecf20Sopenharmony_ci if (dev->tr_backlight_supported) 29328c2ecf20Sopenharmony_ci pr_cont(" transflective-backlight"); 29338c2ecf20Sopenharmony_ci if (dev->illumination_supported) 29348c2ecf20Sopenharmony_ci pr_cont(" illumination"); 29358c2ecf20Sopenharmony_ci if (dev->kbd_illum_supported) 29368c2ecf20Sopenharmony_ci pr_cont(" keyboard-backlight"); 29378c2ecf20Sopenharmony_ci if (dev->touchpad_supported) 29388c2ecf20Sopenharmony_ci pr_cont(" touchpad"); 29398c2ecf20Sopenharmony_ci if (dev->eco_supported) 29408c2ecf20Sopenharmony_ci pr_cont(" eco-led"); 29418c2ecf20Sopenharmony_ci if (dev->accelerometer_supported) 29428c2ecf20Sopenharmony_ci pr_cont(" accelerometer-axes"); 29438c2ecf20Sopenharmony_ci if (dev->usb_sleep_charge_supported) 29448c2ecf20Sopenharmony_ci pr_cont(" usb-sleep-charge"); 29458c2ecf20Sopenharmony_ci if (dev->usb_rapid_charge_supported) 29468c2ecf20Sopenharmony_ci pr_cont(" usb-rapid-charge"); 29478c2ecf20Sopenharmony_ci if (dev->usb_sleep_music_supported) 29488c2ecf20Sopenharmony_ci pr_cont(" usb-sleep-music"); 29498c2ecf20Sopenharmony_ci if (dev->kbd_function_keys_supported) 29508c2ecf20Sopenharmony_ci pr_cont(" special-function-keys"); 29518c2ecf20Sopenharmony_ci if (dev->panel_power_on_supported) 29528c2ecf20Sopenharmony_ci pr_cont(" panel-power-on"); 29538c2ecf20Sopenharmony_ci if (dev->usb_three_supported) 29548c2ecf20Sopenharmony_ci pr_cont(" usb3"); 29558c2ecf20Sopenharmony_ci if (dev->wwan_supported) 29568c2ecf20Sopenharmony_ci pr_cont(" wwan"); 29578c2ecf20Sopenharmony_ci if (dev->cooling_method_supported) 29588c2ecf20Sopenharmony_ci pr_cont(" cooling-method"); 29598c2ecf20Sopenharmony_ci 29608c2ecf20Sopenharmony_ci pr_cont("\n"); 29618c2ecf20Sopenharmony_ci} 29628c2ecf20Sopenharmony_ci 29638c2ecf20Sopenharmony_cistatic int toshiba_acpi_remove(struct acpi_device *acpi_dev) 29648c2ecf20Sopenharmony_ci{ 29658c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 29668c2ecf20Sopenharmony_ci 29678c2ecf20Sopenharmony_ci misc_deregister(&dev->miscdev); 29688c2ecf20Sopenharmony_ci 29698c2ecf20Sopenharmony_ci remove_toshiba_proc_entries(dev); 29708c2ecf20Sopenharmony_ci 29718c2ecf20Sopenharmony_ci if (dev->accelerometer_supported && dev->indio_dev) { 29728c2ecf20Sopenharmony_ci iio_device_unregister(dev->indio_dev); 29738c2ecf20Sopenharmony_ci iio_device_free(dev->indio_dev); 29748c2ecf20Sopenharmony_ci } 29758c2ecf20Sopenharmony_ci 29768c2ecf20Sopenharmony_ci if (dev->sysfs_created) 29778c2ecf20Sopenharmony_ci sysfs_remove_group(&dev->acpi_dev->dev.kobj, 29788c2ecf20Sopenharmony_ci &toshiba_attr_group); 29798c2ecf20Sopenharmony_ci 29808c2ecf20Sopenharmony_ci if (dev->ntfy_supported) { 29818c2ecf20Sopenharmony_ci i8042_remove_filter(toshiba_acpi_i8042_filter); 29828c2ecf20Sopenharmony_ci cancel_work_sync(&dev->hotkey_work); 29838c2ecf20Sopenharmony_ci } 29848c2ecf20Sopenharmony_ci 29858c2ecf20Sopenharmony_ci if (dev->hotkey_dev) 29868c2ecf20Sopenharmony_ci input_unregister_device(dev->hotkey_dev); 29878c2ecf20Sopenharmony_ci 29888c2ecf20Sopenharmony_ci backlight_device_unregister(dev->backlight_dev); 29898c2ecf20Sopenharmony_ci 29908c2ecf20Sopenharmony_ci led_classdev_unregister(&dev->led_dev); 29918c2ecf20Sopenharmony_ci led_classdev_unregister(&dev->kbd_led); 29928c2ecf20Sopenharmony_ci led_classdev_unregister(&dev->eco_led); 29938c2ecf20Sopenharmony_ci 29948c2ecf20Sopenharmony_ci if (dev->wwan_rfk) { 29958c2ecf20Sopenharmony_ci rfkill_unregister(dev->wwan_rfk); 29968c2ecf20Sopenharmony_ci rfkill_destroy(dev->wwan_rfk); 29978c2ecf20Sopenharmony_ci } 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_ci if (toshiba_acpi) 30008c2ecf20Sopenharmony_ci toshiba_acpi = NULL; 30018c2ecf20Sopenharmony_ci 30028c2ecf20Sopenharmony_ci kfree(dev); 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ci return 0; 30058c2ecf20Sopenharmony_ci} 30068c2ecf20Sopenharmony_ci 30078c2ecf20Sopenharmony_cistatic const char *find_hci_method(acpi_handle handle) 30088c2ecf20Sopenharmony_ci{ 30098c2ecf20Sopenharmony_ci if (acpi_has_method(handle, "GHCI")) 30108c2ecf20Sopenharmony_ci return "GHCI"; 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_ci if (acpi_has_method(handle, "SPFC")) 30138c2ecf20Sopenharmony_ci return "SPFC"; 30148c2ecf20Sopenharmony_ci 30158c2ecf20Sopenharmony_ci return NULL; 30168c2ecf20Sopenharmony_ci} 30178c2ecf20Sopenharmony_ci 30188c2ecf20Sopenharmony_cistatic int toshiba_acpi_add(struct acpi_device *acpi_dev) 30198c2ecf20Sopenharmony_ci{ 30208c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev; 30218c2ecf20Sopenharmony_ci const char *hci_method; 30228c2ecf20Sopenharmony_ci u32 dummy; 30238c2ecf20Sopenharmony_ci int ret = 0; 30248c2ecf20Sopenharmony_ci 30258c2ecf20Sopenharmony_ci if (toshiba_acpi) 30268c2ecf20Sopenharmony_ci return -EBUSY; 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci pr_info("Toshiba Laptop ACPI Extras version %s\n", 30298c2ecf20Sopenharmony_ci TOSHIBA_ACPI_VERSION); 30308c2ecf20Sopenharmony_ci 30318c2ecf20Sopenharmony_ci hci_method = find_hci_method(acpi_dev->handle); 30328c2ecf20Sopenharmony_ci if (!hci_method) { 30338c2ecf20Sopenharmony_ci pr_err("HCI interface not found\n"); 30348c2ecf20Sopenharmony_ci return -ENODEV; 30358c2ecf20Sopenharmony_ci } 30368c2ecf20Sopenharmony_ci 30378c2ecf20Sopenharmony_ci dev = kzalloc(sizeof(*dev), GFP_KERNEL); 30388c2ecf20Sopenharmony_ci if (!dev) 30398c2ecf20Sopenharmony_ci return -ENOMEM; 30408c2ecf20Sopenharmony_ci dev->acpi_dev = acpi_dev; 30418c2ecf20Sopenharmony_ci dev->method_hci = hci_method; 30428c2ecf20Sopenharmony_ci dev->miscdev.minor = MISC_DYNAMIC_MINOR; 30438c2ecf20Sopenharmony_ci dev->miscdev.name = "toshiba_acpi"; 30448c2ecf20Sopenharmony_ci dev->miscdev.fops = &toshiba_acpi_fops; 30458c2ecf20Sopenharmony_ci 30468c2ecf20Sopenharmony_ci ret = misc_register(&dev->miscdev); 30478c2ecf20Sopenharmony_ci if (ret) { 30488c2ecf20Sopenharmony_ci pr_err("Failed to register miscdevice\n"); 30498c2ecf20Sopenharmony_ci kfree(dev); 30508c2ecf20Sopenharmony_ci return ret; 30518c2ecf20Sopenharmony_ci } 30528c2ecf20Sopenharmony_ci 30538c2ecf20Sopenharmony_ci acpi_dev->driver_data = dev; 30548c2ecf20Sopenharmony_ci dev_set_drvdata(&acpi_dev->dev, dev); 30558c2ecf20Sopenharmony_ci 30568c2ecf20Sopenharmony_ci /* Query the BIOS for supported features */ 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci /* 30598c2ecf20Sopenharmony_ci * The "Special Functions" are always supported by the laptops 30608c2ecf20Sopenharmony_ci * with the new keyboard layout, query for its presence to help 30618c2ecf20Sopenharmony_ci * determine the keymap layout to use. 30628c2ecf20Sopenharmony_ci */ 30638c2ecf20Sopenharmony_ci ret = toshiba_function_keys_get(dev, &dev->special_functions); 30648c2ecf20Sopenharmony_ci dev->kbd_function_keys_supported = !ret; 30658c2ecf20Sopenharmony_ci 30668c2ecf20Sopenharmony_ci dev->hotkey_event_type = 0; 30678c2ecf20Sopenharmony_ci if (toshiba_acpi_setup_keyboard(dev)) 30688c2ecf20Sopenharmony_ci pr_info("Unable to activate hotkeys\n"); 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci /* Determine whether or not BIOS supports transflective backlight */ 30718c2ecf20Sopenharmony_ci ret = get_tr_backlight_status(dev, &dummy); 30728c2ecf20Sopenharmony_ci dev->tr_backlight_supported = !ret; 30738c2ecf20Sopenharmony_ci 30748c2ecf20Sopenharmony_ci ret = toshiba_acpi_setup_backlight(dev); 30758c2ecf20Sopenharmony_ci if (ret) 30768c2ecf20Sopenharmony_ci goto error; 30778c2ecf20Sopenharmony_ci 30788c2ecf20Sopenharmony_ci toshiba_illumination_available(dev); 30798c2ecf20Sopenharmony_ci if (dev->illumination_supported) { 30808c2ecf20Sopenharmony_ci dev->led_dev.name = "toshiba::illumination"; 30818c2ecf20Sopenharmony_ci dev->led_dev.max_brightness = 1; 30828c2ecf20Sopenharmony_ci dev->led_dev.brightness_set = toshiba_illumination_set; 30838c2ecf20Sopenharmony_ci dev->led_dev.brightness_get = toshiba_illumination_get; 30848c2ecf20Sopenharmony_ci led_classdev_register(&acpi_dev->dev, &dev->led_dev); 30858c2ecf20Sopenharmony_ci } 30868c2ecf20Sopenharmony_ci 30878c2ecf20Sopenharmony_ci toshiba_eco_mode_available(dev); 30888c2ecf20Sopenharmony_ci if (dev->eco_supported) { 30898c2ecf20Sopenharmony_ci dev->eco_led.name = "toshiba::eco_mode"; 30908c2ecf20Sopenharmony_ci dev->eco_led.max_brightness = 1; 30918c2ecf20Sopenharmony_ci dev->eco_led.brightness_set = toshiba_eco_mode_set_status; 30928c2ecf20Sopenharmony_ci dev->eco_led.brightness_get = toshiba_eco_mode_get_status; 30938c2ecf20Sopenharmony_ci led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led); 30948c2ecf20Sopenharmony_ci } 30958c2ecf20Sopenharmony_ci 30968c2ecf20Sopenharmony_ci toshiba_kbd_illum_available(dev); 30978c2ecf20Sopenharmony_ci /* 30988c2ecf20Sopenharmony_ci * Only register the LED if KBD illumination is supported 30998c2ecf20Sopenharmony_ci * and the keyboard backlight operation mode is set to FN-Z 31008c2ecf20Sopenharmony_ci * or we detect a second gen keyboard backlight 31018c2ecf20Sopenharmony_ci */ 31028c2ecf20Sopenharmony_ci if (dev->kbd_illum_supported && 31038c2ecf20Sopenharmony_ci (dev->kbd_mode == SCI_KBD_MODE_FNZ || dev->kbd_type == 2)) { 31048c2ecf20Sopenharmony_ci dev->kbd_led.name = "toshiba::kbd_backlight"; 31058c2ecf20Sopenharmony_ci dev->kbd_led.flags = LED_BRIGHT_HW_CHANGED; 31068c2ecf20Sopenharmony_ci dev->kbd_led.max_brightness = 1; 31078c2ecf20Sopenharmony_ci dev->kbd_led.brightness_set = toshiba_kbd_backlight_set; 31088c2ecf20Sopenharmony_ci dev->kbd_led.brightness_get = toshiba_kbd_backlight_get; 31098c2ecf20Sopenharmony_ci led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led); 31108c2ecf20Sopenharmony_ci } 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_ci ret = toshiba_touchpad_get(dev, &dummy); 31138c2ecf20Sopenharmony_ci dev->touchpad_supported = !ret; 31148c2ecf20Sopenharmony_ci 31158c2ecf20Sopenharmony_ci toshiba_accelerometer_available(dev); 31168c2ecf20Sopenharmony_ci if (dev->accelerometer_supported) { 31178c2ecf20Sopenharmony_ci dev->indio_dev = iio_device_alloc(&acpi_dev->dev, sizeof(*dev)); 31188c2ecf20Sopenharmony_ci if (!dev->indio_dev) { 31198c2ecf20Sopenharmony_ci pr_err("Unable to allocate iio device\n"); 31208c2ecf20Sopenharmony_ci goto iio_error; 31218c2ecf20Sopenharmony_ci } 31228c2ecf20Sopenharmony_ci 31238c2ecf20Sopenharmony_ci pr_info("Registering Toshiba accelerometer iio device\n"); 31248c2ecf20Sopenharmony_ci 31258c2ecf20Sopenharmony_ci dev->indio_dev->info = &toshiba_iio_accel_info; 31268c2ecf20Sopenharmony_ci dev->indio_dev->name = "Toshiba accelerometer"; 31278c2ecf20Sopenharmony_ci dev->indio_dev->modes = INDIO_DIRECT_MODE; 31288c2ecf20Sopenharmony_ci dev->indio_dev->channels = toshiba_iio_accel_channels; 31298c2ecf20Sopenharmony_ci dev->indio_dev->num_channels = 31308c2ecf20Sopenharmony_ci ARRAY_SIZE(toshiba_iio_accel_channels); 31318c2ecf20Sopenharmony_ci 31328c2ecf20Sopenharmony_ci ret = iio_device_register(dev->indio_dev); 31338c2ecf20Sopenharmony_ci if (ret < 0) { 31348c2ecf20Sopenharmony_ci pr_err("Unable to register iio device\n"); 31358c2ecf20Sopenharmony_ci iio_device_free(dev->indio_dev); 31368c2ecf20Sopenharmony_ci } 31378c2ecf20Sopenharmony_ci } 31388c2ecf20Sopenharmony_ciiio_error: 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_ci toshiba_usb_sleep_charge_available(dev); 31418c2ecf20Sopenharmony_ci 31428c2ecf20Sopenharmony_ci ret = toshiba_usb_rapid_charge_get(dev, &dummy); 31438c2ecf20Sopenharmony_ci dev->usb_rapid_charge_supported = !ret; 31448c2ecf20Sopenharmony_ci 31458c2ecf20Sopenharmony_ci ret = toshiba_usb_sleep_music_get(dev, &dummy); 31468c2ecf20Sopenharmony_ci dev->usb_sleep_music_supported = !ret; 31478c2ecf20Sopenharmony_ci 31488c2ecf20Sopenharmony_ci ret = toshiba_panel_power_on_get(dev, &dummy); 31498c2ecf20Sopenharmony_ci dev->panel_power_on_supported = !ret; 31508c2ecf20Sopenharmony_ci 31518c2ecf20Sopenharmony_ci ret = toshiba_usb_three_get(dev, &dummy); 31528c2ecf20Sopenharmony_ci dev->usb_three_supported = !ret; 31538c2ecf20Sopenharmony_ci 31548c2ecf20Sopenharmony_ci ret = get_video_status(dev, &dummy); 31558c2ecf20Sopenharmony_ci dev->video_supported = !ret; 31568c2ecf20Sopenharmony_ci 31578c2ecf20Sopenharmony_ci ret = get_fan_status(dev, &dummy); 31588c2ecf20Sopenharmony_ci dev->fan_supported = !ret; 31598c2ecf20Sopenharmony_ci 31608c2ecf20Sopenharmony_ci toshiba_wwan_available(dev); 31618c2ecf20Sopenharmony_ci if (dev->wwan_supported) 31628c2ecf20Sopenharmony_ci toshiba_acpi_setup_wwan_rfkill(dev); 31638c2ecf20Sopenharmony_ci 31648c2ecf20Sopenharmony_ci toshiba_cooling_method_available(dev); 31658c2ecf20Sopenharmony_ci 31668c2ecf20Sopenharmony_ci print_supported_features(dev); 31678c2ecf20Sopenharmony_ci 31688c2ecf20Sopenharmony_ci ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, 31698c2ecf20Sopenharmony_ci &toshiba_attr_group); 31708c2ecf20Sopenharmony_ci if (ret) { 31718c2ecf20Sopenharmony_ci dev->sysfs_created = 0; 31728c2ecf20Sopenharmony_ci goto error; 31738c2ecf20Sopenharmony_ci } 31748c2ecf20Sopenharmony_ci dev->sysfs_created = !ret; 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ci create_toshiba_proc_entries(dev); 31778c2ecf20Sopenharmony_ci 31788c2ecf20Sopenharmony_ci toshiba_acpi = dev; 31798c2ecf20Sopenharmony_ci 31808c2ecf20Sopenharmony_ci return 0; 31818c2ecf20Sopenharmony_ci 31828c2ecf20Sopenharmony_cierror: 31838c2ecf20Sopenharmony_ci toshiba_acpi_remove(acpi_dev); 31848c2ecf20Sopenharmony_ci return ret; 31858c2ecf20Sopenharmony_ci} 31868c2ecf20Sopenharmony_ci 31878c2ecf20Sopenharmony_cistatic void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) 31888c2ecf20Sopenharmony_ci{ 31898c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 31908c2ecf20Sopenharmony_ci 31918c2ecf20Sopenharmony_ci switch (event) { 31928c2ecf20Sopenharmony_ci case 0x80: /* Hotkeys and some system events */ 31938c2ecf20Sopenharmony_ci /* 31948c2ecf20Sopenharmony_ci * Machines with this WMI GUID aren't supported due to bugs in 31958c2ecf20Sopenharmony_ci * their AML. 31968c2ecf20Sopenharmony_ci * 31978c2ecf20Sopenharmony_ci * Return silently to avoid triggering a netlink event. 31988c2ecf20Sopenharmony_ci */ 31998c2ecf20Sopenharmony_ci if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) 32008c2ecf20Sopenharmony_ci return; 32018c2ecf20Sopenharmony_ci toshiba_acpi_process_hotkeys(dev); 32028c2ecf20Sopenharmony_ci break; 32038c2ecf20Sopenharmony_ci case 0x81: /* Dock events */ 32048c2ecf20Sopenharmony_ci case 0x82: 32058c2ecf20Sopenharmony_ci case 0x83: 32068c2ecf20Sopenharmony_ci pr_info("Dock event received %x\n", event); 32078c2ecf20Sopenharmony_ci break; 32088c2ecf20Sopenharmony_ci case 0x88: /* Thermal events */ 32098c2ecf20Sopenharmony_ci pr_info("Thermal event received\n"); 32108c2ecf20Sopenharmony_ci break; 32118c2ecf20Sopenharmony_ci case 0x8f: /* LID closed */ 32128c2ecf20Sopenharmony_ci case 0x90: /* LID is closed and Dock has been ejected */ 32138c2ecf20Sopenharmony_ci break; 32148c2ecf20Sopenharmony_ci case 0x8c: /* SATA power events */ 32158c2ecf20Sopenharmony_ci case 0x8b: 32168c2ecf20Sopenharmony_ci pr_info("SATA power event received %x\n", event); 32178c2ecf20Sopenharmony_ci break; 32188c2ecf20Sopenharmony_ci case 0x92: /* Keyboard backlight mode changed */ 32198c2ecf20Sopenharmony_ci dev->kbd_event_generated = true; 32208c2ecf20Sopenharmony_ci /* Update sysfs entries */ 32218c2ecf20Sopenharmony_ci if (sysfs_update_group(&acpi_dev->dev.kobj, 32228c2ecf20Sopenharmony_ci &toshiba_attr_group)) 32238c2ecf20Sopenharmony_ci pr_err("Unable to update sysfs entries\n"); 32248c2ecf20Sopenharmony_ci /* Notify LED subsystem about keyboard backlight change */ 32258c2ecf20Sopenharmony_ci if (dev->kbd_type == 2 && dev->kbd_mode != SCI_KBD_MODE_AUTO) 32268c2ecf20Sopenharmony_ci led_classdev_notify_brightness_hw_changed(&dev->kbd_led, 32278c2ecf20Sopenharmony_ci (dev->kbd_mode == SCI_KBD_MODE_ON) ? 32288c2ecf20Sopenharmony_ci LED_FULL : LED_OFF); 32298c2ecf20Sopenharmony_ci break; 32308c2ecf20Sopenharmony_ci case 0x85: /* Unknown */ 32318c2ecf20Sopenharmony_ci case 0x8d: /* Unknown */ 32328c2ecf20Sopenharmony_ci case 0x8e: /* Unknown */ 32338c2ecf20Sopenharmony_ci case 0x94: /* Unknown */ 32348c2ecf20Sopenharmony_ci case 0x95: /* Unknown */ 32358c2ecf20Sopenharmony_ci default: 32368c2ecf20Sopenharmony_ci pr_info("Unknown event received %x\n", event); 32378c2ecf20Sopenharmony_ci break; 32388c2ecf20Sopenharmony_ci } 32398c2ecf20Sopenharmony_ci 32408c2ecf20Sopenharmony_ci acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class, 32418c2ecf20Sopenharmony_ci dev_name(&acpi_dev->dev), 32428c2ecf20Sopenharmony_ci event, (event == 0x80) ? 32438c2ecf20Sopenharmony_ci dev->last_key_event : 0); 32448c2ecf20Sopenharmony_ci} 32458c2ecf20Sopenharmony_ci 32468c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 32478c2ecf20Sopenharmony_cistatic int toshiba_acpi_suspend(struct device *device) 32488c2ecf20Sopenharmony_ci{ 32498c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_ci if (dev->hotkey_dev) { 32528c2ecf20Sopenharmony_ci u32 result; 32538c2ecf20Sopenharmony_ci 32548c2ecf20Sopenharmony_ci result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE); 32558c2ecf20Sopenharmony_ci if (result != TOS_SUCCESS) 32568c2ecf20Sopenharmony_ci pr_info("Unable to disable hotkeys\n"); 32578c2ecf20Sopenharmony_ci } 32588c2ecf20Sopenharmony_ci 32598c2ecf20Sopenharmony_ci return 0; 32608c2ecf20Sopenharmony_ci} 32618c2ecf20Sopenharmony_ci 32628c2ecf20Sopenharmony_cistatic int toshiba_acpi_resume(struct device *device) 32638c2ecf20Sopenharmony_ci{ 32648c2ecf20Sopenharmony_ci struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); 32658c2ecf20Sopenharmony_ci 32668c2ecf20Sopenharmony_ci if (dev->hotkey_dev) { 32678c2ecf20Sopenharmony_ci if (toshiba_acpi_enable_hotkeys(dev)) 32688c2ecf20Sopenharmony_ci pr_info("Unable to re-enable hotkeys\n"); 32698c2ecf20Sopenharmony_ci } 32708c2ecf20Sopenharmony_ci 32718c2ecf20Sopenharmony_ci if (dev->wwan_rfk) { 32728c2ecf20Sopenharmony_ci if (!toshiba_wireless_status(dev)) 32738c2ecf20Sopenharmony_ci rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch); 32748c2ecf20Sopenharmony_ci } 32758c2ecf20Sopenharmony_ci 32768c2ecf20Sopenharmony_ci return 0; 32778c2ecf20Sopenharmony_ci} 32788c2ecf20Sopenharmony_ci#endif 32798c2ecf20Sopenharmony_ci 32808c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(toshiba_acpi_pm, 32818c2ecf20Sopenharmony_ci toshiba_acpi_suspend, toshiba_acpi_resume); 32828c2ecf20Sopenharmony_ci 32838c2ecf20Sopenharmony_cistatic struct acpi_driver toshiba_acpi_driver = { 32848c2ecf20Sopenharmony_ci .name = "Toshiba ACPI driver", 32858c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 32868c2ecf20Sopenharmony_ci .ids = toshiba_device_ids, 32878c2ecf20Sopenharmony_ci .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, 32888c2ecf20Sopenharmony_ci .ops = { 32898c2ecf20Sopenharmony_ci .add = toshiba_acpi_add, 32908c2ecf20Sopenharmony_ci .remove = toshiba_acpi_remove, 32918c2ecf20Sopenharmony_ci .notify = toshiba_acpi_notify, 32928c2ecf20Sopenharmony_ci }, 32938c2ecf20Sopenharmony_ci .drv.pm = &toshiba_acpi_pm, 32948c2ecf20Sopenharmony_ci}; 32958c2ecf20Sopenharmony_ci 32968c2ecf20Sopenharmony_cistatic int __init toshiba_acpi_init(void) 32978c2ecf20Sopenharmony_ci{ 32988c2ecf20Sopenharmony_ci int ret; 32998c2ecf20Sopenharmony_ci 33008c2ecf20Sopenharmony_ci toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); 33018c2ecf20Sopenharmony_ci if (!toshiba_proc_dir) { 33028c2ecf20Sopenharmony_ci pr_err("Unable to create proc dir " PROC_TOSHIBA "\n"); 33038c2ecf20Sopenharmony_ci return -ENODEV; 33048c2ecf20Sopenharmony_ci } 33058c2ecf20Sopenharmony_ci 33068c2ecf20Sopenharmony_ci ret = acpi_bus_register_driver(&toshiba_acpi_driver); 33078c2ecf20Sopenharmony_ci if (ret) { 33088c2ecf20Sopenharmony_ci pr_err("Failed to register ACPI driver: %d\n", ret); 33098c2ecf20Sopenharmony_ci remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 33108c2ecf20Sopenharmony_ci } 33118c2ecf20Sopenharmony_ci 33128c2ecf20Sopenharmony_ci return ret; 33138c2ecf20Sopenharmony_ci} 33148c2ecf20Sopenharmony_ci 33158c2ecf20Sopenharmony_cistatic void __exit toshiba_acpi_exit(void) 33168c2ecf20Sopenharmony_ci{ 33178c2ecf20Sopenharmony_ci acpi_bus_unregister_driver(&toshiba_acpi_driver); 33188c2ecf20Sopenharmony_ci if (toshiba_proc_dir) 33198c2ecf20Sopenharmony_ci remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 33208c2ecf20Sopenharmony_ci} 33218c2ecf20Sopenharmony_ci 33228c2ecf20Sopenharmony_cimodule_init(toshiba_acpi_init); 33238c2ecf20Sopenharmony_cimodule_exit(toshiba_acpi_exit); 3324