19ab65affSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2b4f9fe12SLen Brown /*
3b4f9fe12SLen Brown * toshiba_acpi.c - Toshiba Laptop ACPI Extras
4b4f9fe12SLen Brown *
5b4f9fe12SLen Brown * Copyright (C) 2002-2004 John Belmonte
6b4f9fe12SLen Brown * Copyright (C) 2008 Philip Langdale
76c3f6e6cSPierre Ducroquet * Copyright (C) 2010 Pierre Ducroquet
895d16d81SAzael Avalos * Copyright (C) 2014-2016 Azael Avalos
9b4f9fe12SLen Brown *
10b4f9fe12SLen Brown * The devolpment page for this driver is located at
11b4f9fe12SLen Brown * http://memebeam.org/toys/ToshibaAcpiDriver.
12b4f9fe12SLen Brown *
13b4f9fe12SLen Brown * Credits:
14b4f9fe12SLen Brown * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse
15b4f9fe12SLen Brown * engineering the Windows drivers
16b4f9fe12SLen Brown * Yasushi Nagato - changes for linux kernel 2.4 -> 2.5
17b4f9fe12SLen Brown * Rob Miller - TV out and hotkeys help
18b4f9fe12SLen Brown */
19b4f9fe12SLen Brown
207e33460dSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
217e33460dSJoe Perches
2295d16d81SAzael Avalos #define TOSHIBA_ACPI_VERSION "0.24"
23b4f9fe12SLen Brown #define PROC_INTERFACE_VERSION 1
24b4f9fe12SLen Brown
25c2e2a618SRandy Dunlap #include <linux/compiler.h>
263cb1f40dSHans de Goede #include <linux/dmi.h>
27b4f9fe12SLen Brown #include <linux/kernel.h>
28b4f9fe12SLen Brown #include <linux/module.h>
297faa6a37SAzael Avalos #include <linux/moduleparam.h>
30b4f9fe12SLen Brown #include <linux/init.h>
31b4f9fe12SLen Brown #include <linux/types.h>
32b4f9fe12SLen Brown #include <linux/proc_fs.h>
33936c8bcdSAlexey Dobriyan #include <linux/seq_file.h>
34b4f9fe12SLen Brown #include <linux/backlight.h>
356335e4d5SMatthew Garrett #include <linux/input.h>
36384a7cd9SDmitry Torokhov #include <linux/input/sparse-keymap.h>
376c3f6e6cSPierre Ducroquet #include <linux/leds.h>
385a0e3ad6STejun Heo #include <linux/slab.h>
3929cd293fSSeth Forshee #include <linux/workqueue.h>
4029cd293fSSeth Forshee #include <linux/i8042.h>
418b48463fSLv Zheng #include <linux/acpi.h>
42b5163992SAzael Avalos #include <linux/uaccess.h>
43fc5462f8SAzael Avalos #include <linux/miscdevice.h>
442fdde834SAzael Avalos #include <linux/rfkill.h>
45c727ba4cSArvid Norlander #include <linux/hwmon.h>
4698010f1eSAzael Avalos #include <linux/iio/iio.h>
47fc5462f8SAzael Avalos #include <linux/toshiba.h>
488ef5db9eSArvid Norlander #include <acpi/battery.h>
49358d6a2cSHans de Goede #include <acpi/video.h>
50b4f9fe12SLen Brown
51b4f9fe12SLen Brown MODULE_AUTHOR("John Belmonte");
52b4f9fe12SLen Brown MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
53b4f9fe12SLen Brown MODULE_LICENSE("GPL");
54b4f9fe12SLen Brown
5558900325SYang Yingliang static int turn_on_panel_on_resume = -1;
563cb1f40dSHans de Goede module_param(turn_on_panel_on_resume, int, 0644);
573cb1f40dSHans de Goede MODULE_PARM_DESC(turn_on_panel_on_resume,
583cb1f40dSHans de Goede "Call HCI_PANEL_POWER_ON on resume (-1 = auto, 0 = no, 1 = yes");
593cb1f40dSHans de Goede
6023f1d8b4SArvid Norlander static int hci_hotkey_quickstart = -1;
6123f1d8b4SArvid Norlander module_param(hci_hotkey_quickstart, int, 0644);
6223f1d8b4SArvid Norlander MODULE_PARM_DESC(hci_hotkey_quickstart,
6323f1d8b4SArvid Norlander "Call HCI_HOTKEY_EVENT with value 0x5 for quickstart button support (-1 = auto, 0 = no, 1 = yes");
6423f1d8b4SArvid Norlander
65f11f999eSSeth Forshee #define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100"
66f11f999eSSeth Forshee
6729cd293fSSeth Forshee /* Scan code for Fn key on TOS1900 models */
6829cd293fSSeth Forshee #define TOS1900_FN_SCAN 0x6e
6929cd293fSSeth Forshee
70b4f9fe12SLen Brown /* Toshiba ACPI method paths */
71b4f9fe12SLen Brown #define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX"
72b4f9fe12SLen Brown
73e0769fe6SDarren Hart /*
74e0769fe6SDarren Hart * The Toshiba configuration interface is composed of the HCI and the SCI,
75258c5903SAzael Avalos * which are defined as follows:
76b4f9fe12SLen Brown *
77b4f9fe12SLen Brown * HCI is Toshiba's "Hardware Control Interface" which is supposed to
78b4f9fe12SLen Brown * be uniform across all their models. Ideally we would just call
79b4f9fe12SLen Brown * dedicated ACPI methods instead of using this primitive interface.
80b4f9fe12SLen Brown * However the ACPI methods seem to be incomplete in some areas (for
81b4f9fe12SLen Brown * example they allow setting, but not reading, the LCD brightness value),
82b4f9fe12SLen Brown * so this is still useful.
8384a6273fSAzael Avalos *
8484a6273fSAzael Avalos * SCI stands for "System Configuration Interface" which aim is to
8584a6273fSAzael Avalos * conceal differences in hardware between different models.
86b4f9fe12SLen Brown */
87b4f9fe12SLen Brown
88258c5903SAzael Avalos #define TCI_WORDS 6
89b4f9fe12SLen Brown
903f75bbe9SAzael Avalos /* Operations */
91b4f9fe12SLen Brown #define HCI_SET 0xff00
92b4f9fe12SLen Brown #define HCI_GET 0xfe00
9384a6273fSAzael Avalos #define SCI_OPEN 0xf100
9484a6273fSAzael Avalos #define SCI_CLOSE 0xf200
9584a6273fSAzael Avalos #define SCI_GET 0xf300
9684a6273fSAzael Avalos #define SCI_SET 0xf400
97b4f9fe12SLen Brown
983f75bbe9SAzael Avalos /* Return codes */
991864bbc2SAzael Avalos #define TOS_SUCCESS 0x0000
100e1a949c1SAzael Avalos #define TOS_SUCCESS2 0x0001
1011864bbc2SAzael Avalos #define TOS_OPEN_CLOSE_OK 0x0044
1021864bbc2SAzael Avalos #define TOS_FAILURE 0x1000
1031864bbc2SAzael Avalos #define TOS_NOT_SUPPORTED 0x8000
1041864bbc2SAzael Avalos #define TOS_ALREADY_OPEN 0x8100
1051864bbc2SAzael Avalos #define TOS_NOT_OPENED 0x8200
1061864bbc2SAzael Avalos #define TOS_INPUT_DATA_ERROR 0x8300
1071864bbc2SAzael Avalos #define TOS_WRITE_PROTECTED 0x8400
1081864bbc2SAzael Avalos #define TOS_NOT_PRESENT 0x8600
1091864bbc2SAzael Avalos #define TOS_FIFO_EMPTY 0x8c00
1101864bbc2SAzael Avalos #define TOS_DATA_NOT_AVAILABLE 0x8d20
1111864bbc2SAzael Avalos #define TOS_NOT_INITIALIZED 0x8d50
11298fc4ec6SAzael Avalos #define TOS_NOT_INSTALLED 0x8e00
113b4f9fe12SLen Brown
1143f75bbe9SAzael Avalos /* Registers */
1153cb1f40dSHans de Goede #define HCI_PANEL_POWER_ON 0x0002
116b4f9fe12SLen Brown #define HCI_FAN 0x0004
117121b7b0dSAkio Idehara #define HCI_TR_BACKLIGHT 0x0005
118b4f9fe12SLen Brown #define HCI_SYSTEM_EVENT 0x0016
119b4f9fe12SLen Brown #define HCI_VIDEO_OUT 0x001c
120b4f9fe12SLen Brown #define HCI_HOTKEY_EVENT 0x001e
121b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS 0x002a
122dd193dcdSArvid Norlander #define HCI_FAN_RPM 0x0045
1236873f46aSAzael Avalos #define HCI_WIRELESS 0x0056
1245a2813e9SAzael Avalos #define HCI_ACCELEROMETER 0x006d
125763ff32fSAzael Avalos #define HCI_COOLING_METHOD 0x007f
126360f0f39SAzael Avalos #define HCI_KBD_ILLUMINATION 0x0095
127def6c4e2SAzael Avalos #define HCI_ECO_MODE 0x0097
1285a2813e9SAzael Avalos #define HCI_ACCELEROMETER2 0x00a6
12989655fbbSArvid Norlander #define HCI_BATTERY_CHARGE_MODE 0x00ba
13056e6b353SAzael Avalos #define HCI_SYSTEM_INFO 0xc000
13135d53ceaSAzael Avalos #define SCI_PANEL_POWER_ON 0x010d
132fdb79081SAzael Avalos #define SCI_ILLUMINATION 0x014e
133e26ffe51SAzael Avalos #define SCI_USB_SLEEP_CHARGE 0x0150
134360f0f39SAzael Avalos #define SCI_KBD_ILLUM_STATUS 0x015c
135172ce0a9SAzael Avalos #define SCI_USB_SLEEP_MUSIC 0x015e
13617fe4b3dSAzael Avalos #define SCI_USB_THREE 0x0169
1379d8658acSAzael Avalos #define SCI_TOUCHPAD 0x050e
138bae84195SAzael Avalos #define SCI_KBD_FUNCTION_KEYS 0x0522
139b4f9fe12SLen Brown
1403f75bbe9SAzael Avalos /* Field definitions */
1415a2813e9SAzael Avalos #define HCI_ACCEL_MASK 0x7fff
14298010f1eSAzael Avalos #define HCI_ACCEL_DIRECTION_MASK 0x8000
14329cd293fSSeth Forshee #define HCI_HOTKEY_DISABLE 0x0b
14423f1d8b4SArvid Norlander #define HCI_HOTKEY_ENABLE_QUICKSTART 0x05
145a30b8f81SAzael Avalos #define HCI_HOTKEY_ENABLE 0x09
146fb42d1f4SAzael Avalos #define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10
147b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_BITS 3
148b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS)
149b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS)
150360f0f39SAzael Avalos #define HCI_MISC_SHIFT 0x10
15156e6b353SAzael Avalos #define HCI_SYSTEM_TYPE1 0x10
15256e6b353SAzael Avalos #define HCI_SYSTEM_TYPE2 0x11
153b4f9fe12SLen Brown #define HCI_VIDEO_OUT_LCD 0x1
154b4f9fe12SLen Brown #define HCI_VIDEO_OUT_CRT 0x2
155b4f9fe12SLen Brown #define HCI_VIDEO_OUT_TV 0x4
15693f8c16dSAzael Avalos #define SCI_KBD_MODE_MASK 0x1f
157360f0f39SAzael Avalos #define SCI_KBD_MODE_FNZ 0x1
158360f0f39SAzael Avalos #define SCI_KBD_MODE_AUTO 0x2
15993f8c16dSAzael Avalos #define SCI_KBD_MODE_ON 0x8
16093f8c16dSAzael Avalos #define SCI_KBD_MODE_OFF 0x10
16193f8c16dSAzael Avalos #define SCI_KBD_TIME_MAX 0x3c001a
1626873f46aSAzael Avalos #define HCI_WIRELESS_STATUS 0x1
1636873f46aSAzael Avalos #define HCI_WIRELESS_WWAN 0x3
1646873f46aSAzael Avalos #define HCI_WIRELESS_WWAN_STATUS 0x2000
1656873f46aSAzael Avalos #define HCI_WIRELESS_WWAN_POWER 0x4000
166e26ffe51SAzael Avalos #define SCI_USB_CHARGE_MODE_MASK 0xff
167c8c91842SAzael Avalos #define SCI_USB_CHARGE_DISABLED 0x00
168c8c91842SAzael Avalos #define SCI_USB_CHARGE_ALTERNATE 0x09
169c8c91842SAzael Avalos #define SCI_USB_CHARGE_TYPICAL 0x11
170c8c91842SAzael Avalos #define SCI_USB_CHARGE_AUTO 0x21
171182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_MASK 0x7
172182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_OFF 0x1
173182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_ON 0x4
174182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL 0x0200
175bb3fe01fSAzael Avalos #define SCI_USB_CHARGE_RAPID_DSP 0x0300
176b4f9fe12SLen Brown
177135740deSSeth Forshee struct toshiba_acpi_dev {
178135740deSSeth Forshee struct acpi_device *acpi_dev;
179135740deSSeth Forshee const char *method_hci;
180135740deSSeth Forshee struct input_dev *hotkey_dev;
18129cd293fSSeth Forshee struct work_struct hotkey_work;
182135740deSSeth Forshee struct backlight_device *backlight_dev;
183135740deSSeth Forshee struct led_classdev led_dev;
184360f0f39SAzael Avalos struct led_classdev kbd_led;
185def6c4e2SAzael Avalos struct led_classdev eco_led;
186fc5462f8SAzael Avalos struct miscdevice miscdev;
1872fdde834SAzael Avalos struct rfkill *wwan_rfk;
18898010f1eSAzael Avalos struct iio_dev *indio_dev;
189c727ba4cSArvid Norlander #if IS_ENABLED(CONFIG_HWMON)
190c727ba4cSArvid Norlander struct device *hwmon_device;
191c727ba4cSArvid Norlander #endif
19236d03f93SSeth Forshee
193135740deSSeth Forshee int force_fan;
194135740deSSeth Forshee int last_key_event;
195135740deSSeth Forshee int key_event_valid;
19693f8c16dSAzael Avalos int kbd_type;
197360f0f39SAzael Avalos int kbd_mode;
198360f0f39SAzael Avalos int kbd_time;
199182bcaa5SAzael Avalos int usbsc_bat_level;
200c8c91842SAzael Avalos int usbsc_mode_base;
201a2b3471bSAzael Avalos int hotkey_event_type;
202763ff32fSAzael Avalos int max_cooling_method;
203135740deSSeth Forshee
204592b746cSDan Carpenter unsigned int illumination_supported:1;
205592b746cSDan Carpenter unsigned int video_supported:1;
206592b746cSDan Carpenter unsigned int fan_supported:1;
207dd193dcdSArvid Norlander unsigned int fan_rpm_supported:1;
208592b746cSDan Carpenter unsigned int system_event_supported:1;
20929cd293fSSeth Forshee unsigned int ntfy_supported:1;
21029cd293fSSeth Forshee unsigned int info_supported:1;
211121b7b0dSAkio Idehara unsigned int tr_backlight_supported:1;
212360f0f39SAzael Avalos unsigned int kbd_illum_supported:1;
2139d8658acSAzael Avalos unsigned int touchpad_supported:1;
214def6c4e2SAzael Avalos unsigned int eco_supported:1;
2155a2813e9SAzael Avalos unsigned int accelerometer_supported:1;
216e26ffe51SAzael Avalos unsigned int usb_sleep_charge_supported:1;
217bb3fe01fSAzael Avalos unsigned int usb_rapid_charge_supported:1;
218172ce0a9SAzael Avalos unsigned int usb_sleep_music_supported:1;
219bae84195SAzael Avalos unsigned int kbd_function_keys_supported:1;
22035d53ceaSAzael Avalos unsigned int panel_power_on_supported:1;
22117fe4b3dSAzael Avalos unsigned int usb_three_supported:1;
2226873f46aSAzael Avalos unsigned int wwan_supported:1;
223763ff32fSAzael Avalos unsigned int cooling_method_supported:1;
22489655fbbSArvid Norlander unsigned int battery_charge_mode_supported:1;
225360f0f39SAzael Avalos unsigned int sysfs_created:1;
226b116fd00SAzael Avalos unsigned int special_functions;
227ea215a3fSAzael Avalos
22865e3cf9cSAzael Avalos bool kbd_event_generated;
2296873f46aSAzael Avalos bool killswitch;
230135740deSSeth Forshee };
231135740deSSeth Forshee
23229cd293fSSeth Forshee static struct toshiba_acpi_dev *toshiba_acpi;
23329cd293fSSeth Forshee
2347faa6a37SAzael Avalos static bool disable_hotkeys;
2357faa6a37SAzael Avalos module_param(disable_hotkeys, bool, 0444);
2367faa6a37SAzael Avalos MODULE_PARM_DESC(disable_hotkeys, "Disables the hotkeys activation");
2377faa6a37SAzael Avalos
238b4f9fe12SLen Brown static const struct acpi_device_id toshiba_device_ids[] = {
239b4f9fe12SLen Brown {"TOS6200", 0},
24063a9e016SOndrej Zary {"TOS6207", 0},
241b4f9fe12SLen Brown {"TOS6208", 0},
242b4f9fe12SLen Brown {"TOS1900", 0},
243b4f9fe12SLen Brown {"", 0},
244b4f9fe12SLen Brown };
245b4f9fe12SLen Brown MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
246b4f9fe12SLen Brown
247b859f159SGreg Kroah-Hartman static const struct key_entry toshiba_acpi_keymap[] = {
248fec278a1SUnai Uribarri { KE_KEY, 0x9e, { KEY_RFKILL } },
249384a7cd9SDmitry Torokhov { KE_KEY, 0x101, { KEY_MUTE } },
250384a7cd9SDmitry Torokhov { KE_KEY, 0x102, { KEY_ZOOMOUT } },
251384a7cd9SDmitry Torokhov { KE_KEY, 0x103, { KEY_ZOOMIN } },
252408a5d13SAzael Avalos { KE_KEY, 0x10f, { KEY_TAB } },
253af502837SAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
254af502837SAzael Avalos { KE_KEY, 0x139, { KEY_ZOOMRESET } },
255384a7cd9SDmitry Torokhov { KE_KEY, 0x13b, { KEY_COFFEE } },
256384a7cd9SDmitry Torokhov { KE_KEY, 0x13c, { KEY_BATTERY } },
257384a7cd9SDmitry Torokhov { KE_KEY, 0x13d, { KEY_SLEEP } },
258384a7cd9SDmitry Torokhov { KE_KEY, 0x13e, { KEY_SUSPEND } },
259384a7cd9SDmitry Torokhov { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } },
260384a7cd9SDmitry Torokhov { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } },
261384a7cd9SDmitry Torokhov { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } },
262384a7cd9SDmitry Torokhov { KE_KEY, 0x142, { KEY_WLAN } },
263af502837SAzael Avalos { KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } },
264a49010f5SJon Dowland { KE_KEY, 0x17f, { KEY_FN } },
265384a7cd9SDmitry Torokhov { KE_KEY, 0xb05, { KEY_PROG2 } },
266384a7cd9SDmitry Torokhov { KE_KEY, 0xb06, { KEY_WWW } },
267384a7cd9SDmitry Torokhov { KE_KEY, 0xb07, { KEY_MAIL } },
268384a7cd9SDmitry Torokhov { KE_KEY, 0xb30, { KEY_STOP } },
269384a7cd9SDmitry Torokhov { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } },
270384a7cd9SDmitry Torokhov { KE_KEY, 0xb32, { KEY_NEXTSONG } },
271384a7cd9SDmitry Torokhov { KE_KEY, 0xb33, { KEY_PLAYPAUSE } },
272384a7cd9SDmitry Torokhov { KE_KEY, 0xb5a, { KEY_MEDIA } },
2730dd50b3eSHans de Goede { KE_IGNORE, 0x0e00, { KEY_RESERVED } }, /* Wake from sleep */
274408a5d13SAzael Avalos { KE_IGNORE, 0x1430, { KEY_RESERVED } }, /* Wake from sleep */
275408a5d13SAzael Avalos { KE_IGNORE, 0x1501, { KEY_RESERVED } }, /* Output changed */
276408a5d13SAzael Avalos { KE_IGNORE, 0x1502, { KEY_RESERVED } }, /* HDMI plugged/unplugged */
277408a5d13SAzael Avalos { KE_IGNORE, 0x1ABE, { KEY_RESERVED } }, /* Protection level set */
278408a5d13SAzael Avalos { KE_IGNORE, 0x1ABF, { KEY_RESERVED } }, /* Protection level off */
279384a7cd9SDmitry Torokhov { KE_END, 0 },
2806335e4d5SMatthew Garrett };
2816335e4d5SMatthew Garrett
282fe808bfbSTakashi Iwai static const struct key_entry toshiba_acpi_alt_keymap[] = {
283fe808bfbSTakashi Iwai { KE_KEY, 0x102, { KEY_ZOOMOUT } },
284fe808bfbSTakashi Iwai { KE_KEY, 0x103, { KEY_ZOOMIN } },
285e6efad7fSAzael Avalos { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
286fe808bfbSTakashi Iwai { KE_KEY, 0x139, { KEY_ZOOMRESET } },
287fe808bfbSTakashi Iwai { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } },
288fe808bfbSTakashi Iwai { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } },
289d50c9005SAzael Avalos { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } },
290fe808bfbSTakashi Iwai { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } },
291d50c9005SAzael Avalos { KE_KEY, 0x157, { KEY_MUTE } },
292d50c9005SAzael Avalos { KE_KEY, 0x158, { KEY_WLAN } },
293fe808bfbSTakashi Iwai { KE_END, 0 },
294fe808bfbSTakashi Iwai };
295fe808bfbSTakashi Iwai
296e0769fe6SDarren Hart /*
297e0769fe6SDarren Hart * Utility
298b4f9fe12SLen Brown */
299b4f9fe12SLen Brown
_set_bit(u32 * word,u32 mask,int value)300b5163992SAzael Avalos static inline void _set_bit(u32 *word, u32 mask, int value)
301b4f9fe12SLen Brown {
302b4f9fe12SLen Brown *word = (*word & ~mask) | (mask * value);
303b4f9fe12SLen Brown }
304b4f9fe12SLen Brown
305e0769fe6SDarren Hart /*
306e0769fe6SDarren Hart * ACPI interface wrappers
307b4f9fe12SLen Brown */
308b4f9fe12SLen Brown
write_acpi_int(const char * methodName,int val)309b4f9fe12SLen Brown static int write_acpi_int(const char *methodName, int val)
310b4f9fe12SLen Brown {
311b4f9fe12SLen Brown acpi_status status;
312b4f9fe12SLen Brown
313619400daSZhang Rui status = acpi_execute_simple_method(NULL, (char *)methodName, val);
31432bcd5cbSSeth Forshee return (status == AE_OK) ? 0 : -EIO;
315b4f9fe12SLen Brown }
316b4f9fe12SLen Brown
317e0769fe6SDarren Hart /*
318e0769fe6SDarren Hart * Perform a raw configuration call. Here we don't care about input or output
319258c5903SAzael Avalos * buffer format.
320b4f9fe12SLen Brown */
tci_raw(struct toshiba_acpi_dev * dev,const u32 in[TCI_WORDS],u32 out[TCI_WORDS])321258c5903SAzael Avalos static acpi_status tci_raw(struct toshiba_acpi_dev *dev,
322258c5903SAzael Avalos const u32 in[TCI_WORDS], u32 out[TCI_WORDS])
323b4f9fe12SLen Brown {
32478429e55SAzael Avalos union acpi_object in_objs[TCI_WORDS], out_objs[TCI_WORDS + 1];
325b4f9fe12SLen Brown struct acpi_object_list params;
326b4f9fe12SLen Brown struct acpi_buffer results;
327b4f9fe12SLen Brown acpi_status status;
328b4f9fe12SLen Brown int i;
329b4f9fe12SLen Brown
330258c5903SAzael Avalos params.count = TCI_WORDS;
331b4f9fe12SLen Brown params.pointer = in_objs;
332258c5903SAzael Avalos for (i = 0; i < TCI_WORDS; ++i) {
333b4f9fe12SLen Brown in_objs[i].type = ACPI_TYPE_INTEGER;
334b4f9fe12SLen Brown in_objs[i].integer.value = in[i];
335b4f9fe12SLen Brown }
336b4f9fe12SLen Brown
337b4f9fe12SLen Brown results.length = sizeof(out_objs);
338b4f9fe12SLen Brown results.pointer = out_objs;
339b4f9fe12SLen Brown
3406e02cc7eSSeth Forshee status = acpi_evaluate_object(dev->acpi_dev->handle,
3416e02cc7eSSeth Forshee (char *)dev->method_hci, ¶ms,
342b4f9fe12SLen Brown &results);
343258c5903SAzael Avalos if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) {
344b5163992SAzael Avalos for (i = 0; i < out_objs->package.count; ++i)
345b4f9fe12SLen Brown out[i] = out_objs->package.elements[i].integer.value;
346b4f9fe12SLen Brown }
347b4f9fe12SLen Brown
348b4f9fe12SLen Brown return status;
349b4f9fe12SLen Brown }
350b4f9fe12SLen Brown
351e0769fe6SDarren Hart /*
352d37782bdSAzael Avalos * Common hci tasks
353b4f9fe12SLen Brown *
354b4f9fe12SLen Brown * In addition to the ACPI status, the HCI system returns a result which
355b4f9fe12SLen Brown * may be useful (such as "not supported").
356b4f9fe12SLen Brown */
357b4f9fe12SLen Brown
hci_write(struct toshiba_acpi_dev * dev,u32 reg,u32 in1)358d37782bdSAzael Avalos static u32 hci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1)
359b4f9fe12SLen Brown {
360258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 };
361258c5903SAzael Avalos u32 out[TCI_WORDS];
362258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out);
363893f3f62SAzael Avalos
364893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE;
365b4f9fe12SLen Brown }
366b4f9fe12SLen Brown
hci_read(struct toshiba_acpi_dev * dev,u32 reg,u32 * out1)367d37782bdSAzael Avalos static u32 hci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1)
368b4f9fe12SLen Brown {
369258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 };
370258c5903SAzael Avalos u32 out[TCI_WORDS];
371258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out);
372b5163992SAzael Avalos
373893f3f62SAzael Avalos if (ACPI_FAILURE(status))
374893f3f62SAzael Avalos return TOS_FAILURE;
375893f3f62SAzael Avalos
376b4f9fe12SLen Brown *out1 = out[2];
377893f3f62SAzael Avalos
378893f3f62SAzael Avalos return out[0];
379b4f9fe12SLen Brown }
380b4f9fe12SLen Brown
381e0769fe6SDarren Hart /*
382e0769fe6SDarren Hart * Common sci tasks
38384a6273fSAzael Avalos */
38484a6273fSAzael Avalos
sci_open(struct toshiba_acpi_dev * dev)38584a6273fSAzael Avalos static int sci_open(struct toshiba_acpi_dev *dev)
38684a6273fSAzael Avalos {
387258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 };
388258c5903SAzael Avalos u32 out[TCI_WORDS];
38978429e55SAzael Avalos acpi_status status = tci_raw(dev, in, out);
39084a6273fSAzael Avalos
3918baec45dSAzael Avalos if (ACPI_FAILURE(status)) {
39284a6273fSAzael Avalos pr_err("ACPI call to open SCI failed\n");
39384a6273fSAzael Avalos return 0;
39484a6273fSAzael Avalos }
39584a6273fSAzael Avalos
3961864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK) {
39784a6273fSAzael Avalos return 1;
3981864bbc2SAzael Avalos } else if (out[0] == TOS_ALREADY_OPEN) {
39984a6273fSAzael Avalos pr_info("Toshiba SCI already opened\n");
40084a6273fSAzael Avalos return 1;
401fa465739SAzael Avalos } else if (out[0] == TOS_NOT_SUPPORTED) {
402e0769fe6SDarren Hart /*
403e0769fe6SDarren Hart * Some BIOSes do not have the SCI open/close functions
404fa465739SAzael Avalos * implemented and return 0x8000 (Not Supported), failing to
405fa465739SAzael Avalos * register some supported features.
406fa465739SAzael Avalos *
407fa465739SAzael Avalos * Simply return 1 if we hit those affected laptops to make the
408fa465739SAzael Avalos * supported features work.
409fa465739SAzael Avalos *
410fa465739SAzael Avalos * In the case that some laptops really do not support the SCI,
411fa465739SAzael Avalos * all the SCI dependent functions check for TOS_NOT_SUPPORTED,
412fa465739SAzael Avalos * and thus, not registering support for the queried feature.
413fa465739SAzael Avalos */
414fa465739SAzael Avalos return 1;
4151864bbc2SAzael Avalos } else if (out[0] == TOS_NOT_PRESENT) {
41684a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n");
41784a6273fSAzael Avalos }
41884a6273fSAzael Avalos
41984a6273fSAzael Avalos return 0;
42084a6273fSAzael Avalos }
42184a6273fSAzael Avalos
sci_close(struct toshiba_acpi_dev * dev)42284a6273fSAzael Avalos static void sci_close(struct toshiba_acpi_dev *dev)
42384a6273fSAzael Avalos {
424258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 };
425258c5903SAzael Avalos u32 out[TCI_WORDS];
42678429e55SAzael Avalos acpi_status status = tci_raw(dev, in, out);
42784a6273fSAzael Avalos
4288baec45dSAzael Avalos if (ACPI_FAILURE(status)) {
42984a6273fSAzael Avalos pr_err("ACPI call to close SCI failed\n");
43084a6273fSAzael Avalos return;
43184a6273fSAzael Avalos }
43284a6273fSAzael Avalos
4331864bbc2SAzael Avalos if (out[0] == TOS_OPEN_CLOSE_OK)
43484a6273fSAzael Avalos return;
4351864bbc2SAzael Avalos else if (out[0] == TOS_NOT_OPENED)
43684a6273fSAzael Avalos pr_info("Toshiba SCI not opened\n");
4371864bbc2SAzael Avalos else if (out[0] == TOS_NOT_PRESENT)
43884a6273fSAzael Avalos pr_info("Toshiba SCI is not present\n");
43984a6273fSAzael Avalos }
44084a6273fSAzael Avalos
sci_read(struct toshiba_acpi_dev * dev,u32 reg,u32 * out1)441893f3f62SAzael Avalos static u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1)
44284a6273fSAzael Avalos {
443258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 };
444258c5903SAzael Avalos u32 out[TCI_WORDS];
445258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out);
446b5163992SAzael Avalos
447893f3f62SAzael Avalos if (ACPI_FAILURE(status))
448893f3f62SAzael Avalos return TOS_FAILURE;
449893f3f62SAzael Avalos
45084a6273fSAzael Avalos *out1 = out[2];
451893f3f62SAzael Avalos
452893f3f62SAzael Avalos return out[0];
45384a6273fSAzael Avalos }
45484a6273fSAzael Avalos
sci_write(struct toshiba_acpi_dev * dev,u32 reg,u32 in1)455893f3f62SAzael Avalos static u32 sci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1)
45684a6273fSAzael Avalos {
457258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 };
458258c5903SAzael Avalos u32 out[TCI_WORDS];
459258c5903SAzael Avalos acpi_status status = tci_raw(dev, in, out);
460893f3f62SAzael Avalos
461893f3f62SAzael Avalos return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE;
46284a6273fSAzael Avalos }
46384a6273fSAzael Avalos
4646c3f6e6cSPierre Ducroquet /* Illumination support */
toshiba_illumination_available(struct toshiba_acpi_dev * dev)465ea215a3fSAzael Avalos static void toshiba_illumination_available(struct toshiba_acpi_dev *dev)
4666c3f6e6cSPierre Ducroquet {
467258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 };
468258c5903SAzael Avalos u32 out[TCI_WORDS];
4696c3f6e6cSPierre Ducroquet acpi_status status;
4706c3f6e6cSPierre Ducroquet
471ea215a3fSAzael Avalos dev->illumination_supported = 0;
472ea215a3fSAzael Avalos
473fdb79081SAzael Avalos if (!sci_open(dev))
474ea215a3fSAzael Avalos return;
475fdb79081SAzael Avalos
476258c5903SAzael Avalos status = tci_raw(dev, in, out);
477fdb79081SAzael Avalos sci_close(dev);
478513ee146SAzael Avalos if (ACPI_FAILURE(status)) {
479fdb79081SAzael Avalos pr_err("ACPI call to query Illumination support failed\n");
480513ee146SAzael Avalos return;
481513ee146SAzael Avalos }
482513ee146SAzael Avalos
483513ee146SAzael Avalos if (out[0] != TOS_SUCCESS)
484513ee146SAzael Avalos return;
485513ee146SAzael Avalos
486ea215a3fSAzael Avalos dev->illumination_supported = 1;
4876c3f6e6cSPierre Ducroquet }
4886c3f6e6cSPierre Ducroquet
toshiba_illumination_set(struct led_classdev * cdev,enum led_brightness brightness)4896c3f6e6cSPierre Ducroquet static void toshiba_illumination_set(struct led_classdev *cdev,
4906c3f6e6cSPierre Ducroquet enum led_brightness brightness)
4916c3f6e6cSPierre Ducroquet {
492135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev,
493135740deSSeth Forshee struct toshiba_acpi_dev, led_dev);
494e1a949c1SAzael Avalos u32 result;
495e1a949c1SAzael Avalos u32 state;
4966c3f6e6cSPierre Ducroquet
4976c3f6e6cSPierre Ducroquet /* First request : initialize communication. */
498fdb79081SAzael Avalos if (!sci_open(dev))
4996c3f6e6cSPierre Ducroquet return;
5006c3f6e6cSPierre Ducroquet
501fdb79081SAzael Avalos /* Switch the illumination on/off */
502fdb79081SAzael Avalos state = brightness ? 1 : 0;
503893f3f62SAzael Avalos result = sci_write(dev, SCI_ILLUMINATION, state);
504fdb79081SAzael Avalos sci_close(dev);
505a6b5354fSAzael Avalos if (result == TOS_FAILURE)
506fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n");
5076c3f6e6cSPierre Ducroquet }
5086c3f6e6cSPierre Ducroquet
toshiba_illumination_get(struct led_classdev * cdev)5096c3f6e6cSPierre Ducroquet static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
5106c3f6e6cSPierre Ducroquet {
511135740deSSeth Forshee struct toshiba_acpi_dev *dev = container_of(cdev,
512135740deSSeth Forshee struct toshiba_acpi_dev, led_dev);
51378429e55SAzael Avalos u32 result;
51478429e55SAzael Avalos u32 state;
5156c3f6e6cSPierre Ducroquet
5163f75bbe9SAzael Avalos /* First request : initialize communication. */
517fdb79081SAzael Avalos if (!sci_open(dev))
5186c3f6e6cSPierre Ducroquet return LED_OFF;
5196c3f6e6cSPierre Ducroquet
5206c3f6e6cSPierre Ducroquet /* Check the illumination */
521893f3f62SAzael Avalos result = sci_read(dev, SCI_ILLUMINATION, &state);
522fdb79081SAzael Avalos sci_close(dev);
523a6b5354fSAzael Avalos if (result == TOS_FAILURE) {
524fdb79081SAzael Avalos pr_err("ACPI call for illumination failed\n");
525fdb79081SAzael Avalos return LED_OFF;
526e1a949c1SAzael Avalos } else if (result != TOS_SUCCESS) {
5276c3f6e6cSPierre Ducroquet return LED_OFF;
5286c3f6e6cSPierre Ducroquet }
5296c3f6e6cSPierre Ducroquet
530fdb79081SAzael Avalos return state ? LED_FULL : LED_OFF;
5316c3f6e6cSPierre Ducroquet }
5326c3f6e6cSPierre Ducroquet
533360f0f39SAzael Avalos /* KBD Illumination */
toshiba_kbd_illum_available(struct toshiba_acpi_dev * dev)534ea215a3fSAzael Avalos static void toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev)
53593f8c16dSAzael Avalos {
536258c5903SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 };
537258c5903SAzael Avalos u32 out[TCI_WORDS];
53893f8c16dSAzael Avalos acpi_status status;
53993f8c16dSAzael Avalos
540ea215a3fSAzael Avalos dev->kbd_illum_supported = 0;
54165e3cf9cSAzael Avalos dev->kbd_event_generated = false;
542ea215a3fSAzael Avalos
54393f8c16dSAzael Avalos if (!sci_open(dev))
544ea215a3fSAzael Avalos return;
54593f8c16dSAzael Avalos
546258c5903SAzael Avalos status = tci_raw(dev, in, out);
54793f8c16dSAzael Avalos sci_close(dev);
548a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) {
54993f8c16dSAzael Avalos pr_err("ACPI call to query kbd illumination support failed\n");
550513ee146SAzael Avalos return;
551513ee146SAzael Avalos }
552513ee146SAzael Avalos
553513ee146SAzael Avalos if (out[0] != TOS_SUCCESS)
554513ee146SAzael Avalos return;
555513ee146SAzael Avalos
556e0769fe6SDarren Hart /*
557e0769fe6SDarren Hart * Check for keyboard backlight timeout max value,
55893f8c16dSAzael Avalos * previous kbd backlight implementation set this to
55993f8c16dSAzael Avalos * 0x3c0003, and now the new implementation set this
560e0769fe6SDarren Hart * to 0x3c001a, use this to distinguish between them.
56193f8c16dSAzael Avalos */
56293f8c16dSAzael Avalos if (out[3] == SCI_KBD_TIME_MAX)
56393f8c16dSAzael Avalos dev->kbd_type = 2;
56493f8c16dSAzael Avalos else
56593f8c16dSAzael Avalos dev->kbd_type = 1;
56693f8c16dSAzael Avalos /* Get the current keyboard backlight mode */
56793f8c16dSAzael Avalos dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK;
56893f8c16dSAzael Avalos /* Get the current time (1-60 seconds) */
56993f8c16dSAzael Avalos dev->kbd_time = out[2] >> HCI_MISC_SHIFT;
570ea215a3fSAzael Avalos /* Flag as supported */
571ea215a3fSAzael Avalos dev->kbd_illum_supported = 1;
572ea215a3fSAzael Avalos }
57393f8c16dSAzael Avalos
toshiba_kbd_illum_status_set(struct toshiba_acpi_dev * dev,u32 time)574360f0f39SAzael Avalos static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time)
575360f0f39SAzael Avalos {
576360f0f39SAzael Avalos u32 result;
577360f0f39SAzael Avalos
578360f0f39SAzael Avalos if (!sci_open(dev))
579360f0f39SAzael Avalos return -EIO;
580360f0f39SAzael Avalos
581893f3f62SAzael Avalos result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time);
582360f0f39SAzael Avalos sci_close(dev);
583a6b5354fSAzael Avalos if (result == TOS_FAILURE)
584360f0f39SAzael Avalos pr_err("ACPI call to set KBD backlight status failed\n");
585a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED)
586360f0f39SAzael Avalos return -ENODEV;
587360f0f39SAzael Avalos
588e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO;
589360f0f39SAzael Avalos }
590360f0f39SAzael Avalos
toshiba_kbd_illum_status_get(struct toshiba_acpi_dev * dev,u32 * time)591360f0f39SAzael Avalos static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time)
592360f0f39SAzael Avalos {
593360f0f39SAzael Avalos u32 result;
594360f0f39SAzael Avalos
595360f0f39SAzael Avalos if (!sci_open(dev))
596360f0f39SAzael Avalos return -EIO;
597360f0f39SAzael Avalos
598893f3f62SAzael Avalos result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time);
599360f0f39SAzael Avalos sci_close(dev);
600a6b5354fSAzael Avalos if (result == TOS_FAILURE)
601360f0f39SAzael Avalos pr_err("ACPI call to get KBD backlight status failed\n");
602a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED)
603360f0f39SAzael Avalos return -ENODEV;
604360f0f39SAzael Avalos
605e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO;
606360f0f39SAzael Avalos }
607360f0f39SAzael Avalos
toshiba_kbd_backlight_get(struct led_classdev * cdev)608360f0f39SAzael Avalos static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev)
609360f0f39SAzael Avalos {
610360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev,
611360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led);
612e1a949c1SAzael Avalos u32 result;
613e1a949c1SAzael Avalos u32 state;
614360f0f39SAzael Avalos
615360f0f39SAzael Avalos /* Check the keyboard backlight state */
616d37782bdSAzael Avalos result = hci_read(dev, HCI_KBD_ILLUMINATION, &state);
617a6b5354fSAzael Avalos if (result == TOS_FAILURE) {
618360f0f39SAzael Avalos pr_err("ACPI call to get the keyboard backlight failed\n");
619360f0f39SAzael Avalos return LED_OFF;
620e1a949c1SAzael Avalos } else if (result != TOS_SUCCESS) {
621360f0f39SAzael Avalos return LED_OFF;
622360f0f39SAzael Avalos }
623360f0f39SAzael Avalos
624360f0f39SAzael Avalos return state ? LED_FULL : LED_OFF;
625360f0f39SAzael Avalos }
626360f0f39SAzael Avalos
toshiba_kbd_backlight_set(struct led_classdev * cdev,enum led_brightness brightness)627360f0f39SAzael Avalos static void toshiba_kbd_backlight_set(struct led_classdev *cdev,
628360f0f39SAzael Avalos enum led_brightness brightness)
629360f0f39SAzael Avalos {
630360f0f39SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev,
631360f0f39SAzael Avalos struct toshiba_acpi_dev, kbd_led);
632e1a949c1SAzael Avalos u32 result;
633e1a949c1SAzael Avalos u32 state;
634360f0f39SAzael Avalos
635360f0f39SAzael Avalos /* Set the keyboard backlight state */
636360f0f39SAzael Avalos state = brightness ? 1 : 0;
637d37782bdSAzael Avalos result = hci_write(dev, HCI_KBD_ILLUMINATION, state);
638a6b5354fSAzael Avalos if (result == TOS_FAILURE)
639360f0f39SAzael Avalos pr_err("ACPI call to set KBD Illumination mode failed\n");
640360f0f39SAzael Avalos }
641360f0f39SAzael Avalos
6429d8658acSAzael Avalos /* TouchPad support */
toshiba_touchpad_set(struct toshiba_acpi_dev * dev,u32 state)6439d8658acSAzael Avalos static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state)
6449d8658acSAzael Avalos {
6459d8658acSAzael Avalos u32 result;
6469d8658acSAzael Avalos
6479d8658acSAzael Avalos if (!sci_open(dev))
6489d8658acSAzael Avalos return -EIO;
6499d8658acSAzael Avalos
650893f3f62SAzael Avalos result = sci_write(dev, SCI_TOUCHPAD, state);
6519d8658acSAzael Avalos sci_close(dev);
652a6b5354fSAzael Avalos if (result == TOS_FAILURE)
6539d8658acSAzael Avalos pr_err("ACPI call to set the touchpad failed\n");
654a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED)
6559d8658acSAzael Avalos return -ENODEV;
6569d8658acSAzael Avalos
657e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO;
6589d8658acSAzael Avalos }
6599d8658acSAzael Avalos
toshiba_touchpad_get(struct toshiba_acpi_dev * dev,u32 * state)6609d8658acSAzael Avalos static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state)
6619d8658acSAzael Avalos {
6629d8658acSAzael Avalos u32 result;
6639d8658acSAzael Avalos
6649d8658acSAzael Avalos if (!sci_open(dev))
6659d8658acSAzael Avalos return -EIO;
6669d8658acSAzael Avalos
667893f3f62SAzael Avalos result = sci_read(dev, SCI_TOUCHPAD, state);
6689d8658acSAzael Avalos sci_close(dev);
669a6b5354fSAzael Avalos if (result == TOS_FAILURE)
6709d8658acSAzael Avalos pr_err("ACPI call to query the touchpad failed\n");
671a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED)
6729d8658acSAzael Avalos return -ENODEV;
6739d8658acSAzael Avalos
674e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO;
6759d8658acSAzael Avalos }
6769d8658acSAzael Avalos
677def6c4e2SAzael Avalos /* Eco Mode support */
toshiba_eco_mode_available(struct toshiba_acpi_dev * dev)678ea215a3fSAzael Avalos static void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev)
679def6c4e2SAzael Avalos {
68098fc4ec6SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 };
681258c5903SAzael Avalos u32 out[TCI_WORDS];
68278429e55SAzael Avalos acpi_status status;
683def6c4e2SAzael Avalos
684ea215a3fSAzael Avalos dev->eco_supported = 0;
685ea215a3fSAzael Avalos
686258c5903SAzael Avalos status = tci_raw(dev, in, out);
6878baec45dSAzael Avalos if (ACPI_FAILURE(status)) {
68898fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n");
689513ee146SAzael Avalos return;
690513ee146SAzael Avalos }
691513ee146SAzael Avalos
6924058ea22SArvid Norlander if (out[0] == TOS_INPUT_DATA_ERROR || out[0] == TOS_NOT_SUPPORTED) {
693e0769fe6SDarren Hart /*
694e0769fe6SDarren Hart * If we receive 0x8300 (Input Data Error), it means that the
69598fc4ec6SAzael Avalos * LED device is present, but that we just screwed the input
69698fc4ec6SAzael Avalos * parameters.
69798fc4ec6SAzael Avalos *
6984058ea22SArvid Norlander * On some laptops 0x8000 (Not supported) is also returned in
6994058ea22SArvid Norlander * this case, so we need to allow for that as well.
7004058ea22SArvid Norlander *
70198fc4ec6SAzael Avalos * Let's query the status of the LED to see if we really have a
70298fc4ec6SAzael Avalos * success response, indicating the actual presense of the LED,
70398fc4ec6SAzael Avalos * bail out otherwise.
70498fc4ec6SAzael Avalos */
70598fc4ec6SAzael Avalos in[3] = 1;
70698fc4ec6SAzael Avalos status = tci_raw(dev, in, out);
707513ee146SAzael Avalos if (ACPI_FAILURE(status)) {
70898fc4ec6SAzael Avalos pr_err("ACPI call to get ECO led failed\n");
709513ee146SAzael Avalos return;
710513ee146SAzael Avalos }
711513ee146SAzael Avalos
712513ee146SAzael Avalos if (out[0] != TOS_SUCCESS)
713513ee146SAzael Avalos return;
714513ee146SAzael Avalos
715ea215a3fSAzael Avalos dev->eco_supported = 1;
716def6c4e2SAzael Avalos }
717def6c4e2SAzael Avalos }
718def6c4e2SAzael Avalos
719b5163992SAzael Avalos static enum led_brightness
toshiba_eco_mode_get_status(struct led_classdev * cdev)720b5163992SAzael Avalos toshiba_eco_mode_get_status(struct led_classdev *cdev)
721def6c4e2SAzael Avalos {
722def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev,
723def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led);
724258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 };
725258c5903SAzael Avalos u32 out[TCI_WORDS];
726def6c4e2SAzael Avalos acpi_status status;
727def6c4e2SAzael Avalos
728258c5903SAzael Avalos status = tci_raw(dev, in, out);
729a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) {
730def6c4e2SAzael Avalos pr_err("ACPI call to get ECO led failed\n");
731def6c4e2SAzael Avalos return LED_OFF;
732def6c4e2SAzael Avalos }
733def6c4e2SAzael Avalos
734513ee146SAzael Avalos if (out[0] != TOS_SUCCESS)
735513ee146SAzael Avalos return LED_OFF;
736513ee146SAzael Avalos
737def6c4e2SAzael Avalos return out[2] ? LED_FULL : LED_OFF;
738def6c4e2SAzael Avalos }
739def6c4e2SAzael Avalos
toshiba_eco_mode_set_status(struct led_classdev * cdev,enum led_brightness brightness)740def6c4e2SAzael Avalos static void toshiba_eco_mode_set_status(struct led_classdev *cdev,
741def6c4e2SAzael Avalos enum led_brightness brightness)
742def6c4e2SAzael Avalos {
743def6c4e2SAzael Avalos struct toshiba_acpi_dev *dev = container_of(cdev,
744def6c4e2SAzael Avalos struct toshiba_acpi_dev, eco_led);
745258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 };
746258c5903SAzael Avalos u32 out[TCI_WORDS];
747def6c4e2SAzael Avalos acpi_status status;
748def6c4e2SAzael Avalos
749def6c4e2SAzael Avalos /* Switch the Eco Mode led on/off */
750def6c4e2SAzael Avalos in[2] = (brightness) ? 1 : 0;
751258c5903SAzael Avalos status = tci_raw(dev, in, out);
752a6b5354fSAzael Avalos if (ACPI_FAILURE(status))
753def6c4e2SAzael Avalos pr_err("ACPI call to set ECO led failed\n");
754def6c4e2SAzael Avalos }
755def6c4e2SAzael Avalos
7565a2813e9SAzael Avalos /* Accelerometer support */
toshiba_accelerometer_available(struct toshiba_acpi_dev * dev)757ea215a3fSAzael Avalos static void toshiba_accelerometer_available(struct toshiba_acpi_dev *dev)
7585a2813e9SAzael Avalos {
759258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 };
760258c5903SAzael Avalos u32 out[TCI_WORDS];
7615a2813e9SAzael Avalos acpi_status status;
7625a2813e9SAzael Avalos
763ea215a3fSAzael Avalos dev->accelerometer_supported = 0;
764ea215a3fSAzael Avalos
765e0769fe6SDarren Hart /*
766e0769fe6SDarren Hart * Check if the accelerometer call exists,
7675a2813e9SAzael Avalos * this call also serves as initialization
7685a2813e9SAzael Avalos */
769258c5903SAzael Avalos status = tci_raw(dev, in, out);
770513ee146SAzael Avalos if (ACPI_FAILURE(status)) {
7715a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n");
772513ee146SAzael Avalos return;
773513ee146SAzael Avalos }
774513ee146SAzael Avalos
775513ee146SAzael Avalos if (out[0] != TOS_SUCCESS)
776513ee146SAzael Avalos return;
777513ee146SAzael Avalos
778ea215a3fSAzael Avalos dev->accelerometer_supported = 1;
7795a2813e9SAzael Avalos }
7805a2813e9SAzael Avalos
toshiba_accelerometer_get(struct toshiba_acpi_dev * dev,u32 * xy,u32 * z)7815a2813e9SAzael Avalos static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev,
7825a2813e9SAzael Avalos u32 *xy, u32 *z)
7835a2813e9SAzael Avalos {
784258c5903SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 };
785258c5903SAzael Avalos u32 out[TCI_WORDS];
7865a2813e9SAzael Avalos acpi_status status;
7875a2813e9SAzael Avalos
7885a2813e9SAzael Avalos /* Check the Accelerometer status */
789258c5903SAzael Avalos status = tci_raw(dev, in, out);
790a6b5354fSAzael Avalos if (ACPI_FAILURE(status)) {
7915a2813e9SAzael Avalos pr_err("ACPI call to query the accelerometer failed\n");
7925a2813e9SAzael Avalos return -EIO;
7935a2813e9SAzael Avalos }
7945a2813e9SAzael Avalos
795513ee146SAzael Avalos if (out[0] == TOS_NOT_SUPPORTED)
796513ee146SAzael Avalos return -ENODEV;
797513ee146SAzael Avalos
798513ee146SAzael Avalos if (out[0] != TOS_SUCCESS)
799e1a949c1SAzael Avalos return -EIO;
800513ee146SAzael Avalos
801513ee146SAzael Avalos *xy = out[2];
802513ee146SAzael Avalos *z = out[4];
803513ee146SAzael Avalos
804513ee146SAzael Avalos return 0;
805e1a949c1SAzael Avalos }
806e1a949c1SAzael Avalos
807e26ffe51SAzael Avalos /* Sleep (Charge and Music) utilities support */
toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev * dev)808c8c91842SAzael Avalos static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev)
809c8c91842SAzael Avalos {
810c8c91842SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
811c8c91842SAzael Avalos u32 out[TCI_WORDS];
812c8c91842SAzael Avalos acpi_status status;
813c8c91842SAzael Avalos
814c8c91842SAzael Avalos dev->usb_sleep_charge_supported = 0;
815c8c91842SAzael Avalos
816c8c91842SAzael Avalos if (!sci_open(dev))
817c8c91842SAzael Avalos return;
818c8c91842SAzael Avalos
819c8c91842SAzael Avalos status = tci_raw(dev, in, out);
8208baec45dSAzael Avalos if (ACPI_FAILURE(status)) {
821c8c91842SAzael Avalos pr_err("ACPI call to get USB Sleep and Charge mode failed\n");
822c8c91842SAzael Avalos sci_close(dev);
823c8c91842SAzael Avalos return;
824513ee146SAzael Avalos }
825513ee146SAzael Avalos
826513ee146SAzael Avalos if (out[0] != TOS_SUCCESS) {
827c8c91842SAzael Avalos sci_close(dev);
828c8c91842SAzael Avalos return;
829c8c91842SAzael Avalos }
830c8c91842SAzael Avalos
831513ee146SAzael Avalos dev->usbsc_mode_base = out[4];
832513ee146SAzael Avalos
833c8c91842SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL;
834c8c91842SAzael Avalos status = tci_raw(dev, in, out);
835ea215a3fSAzael Avalos sci_close(dev);
8368baec45dSAzael Avalos if (ACPI_FAILURE(status)) {
837c8c91842SAzael Avalos pr_err("ACPI call to get USB Sleep and Charge mode failed\n");
838513ee146SAzael Avalos return;
839513ee146SAzael Avalos }
840513ee146SAzael Avalos
841513ee146SAzael Avalos if (out[0] != TOS_SUCCESS)
842513ee146SAzael Avalos return;
843513ee146SAzael Avalos
844c8c91842SAzael Avalos dev->usbsc_bat_level = out[2];
845ea215a3fSAzael Avalos /* Flag as supported */
846c8c91842SAzael Avalos dev->usb_sleep_charge_supported = 1;
847c8c91842SAzael Avalos }
848c8c91842SAzael Avalos
toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev * dev,u32 * mode)849e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev,
850e26ffe51SAzael Avalos u32 *mode)
851e26ffe51SAzael Avalos {
852e26ffe51SAzael Avalos u32 result;
853e26ffe51SAzael Avalos
854e26ffe51SAzael Avalos if (!sci_open(dev))
855e26ffe51SAzael Avalos return -EIO;
856e26ffe51SAzael Avalos
857e26ffe51SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode);
858e26ffe51SAzael Avalos sci_close(dev);
859a6b5354fSAzael Avalos if (result == TOS_FAILURE)
860e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n");
861a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED)
862e26ffe51SAzael Avalos return -ENODEV;
863e26ffe51SAzael Avalos
864e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO;
865e26ffe51SAzael Avalos }
866e26ffe51SAzael Avalos
toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev * dev,u32 mode)867e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev,
868e26ffe51SAzael Avalos u32 mode)
869e26ffe51SAzael Avalos {
870e26ffe51SAzael Avalos u32 result;
871e26ffe51SAzael Avalos
872e26ffe51SAzael Avalos if (!sci_open(dev))
873e26ffe51SAzael Avalos return -EIO;
874e26ffe51SAzael Avalos
875e26ffe51SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode);
876e26ffe51SAzael Avalos sci_close(dev);
877a6b5354fSAzael Avalos if (result == TOS_FAILURE)
878e26ffe51SAzael Avalos pr_err("ACPI call to set USB S&C mode failed\n");
879a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED)
880e26ffe51SAzael Avalos return -ENODEV;
881e26ffe51SAzael Avalos
882e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO;
883e26ffe51SAzael Avalos }
884e26ffe51SAzael Avalos
toshiba_sleep_functions_status_get(struct toshiba_acpi_dev * dev,u32 * mode)885182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev,
886182bcaa5SAzael Avalos u32 *mode)
887182bcaa5SAzael Avalos {
888182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
889182bcaa5SAzael Avalos u32 out[TCI_WORDS];
890182bcaa5SAzael Avalos acpi_status status;
891182bcaa5SAzael Avalos
892182bcaa5SAzael Avalos if (!sci_open(dev))
893182bcaa5SAzael Avalos return -EIO;
894182bcaa5SAzael Avalos
895182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL;
896182bcaa5SAzael Avalos status = tci_raw(dev, in, out);
897182bcaa5SAzael Avalos sci_close(dev);
8988baec45dSAzael Avalos if (ACPI_FAILURE(status)) {
899182bcaa5SAzael Avalos pr_err("ACPI call to get USB S&C battery level failed\n");
900513ee146SAzael Avalos return -EIO;
901182bcaa5SAzael Avalos }
902182bcaa5SAzael Avalos
903513ee146SAzael Avalos if (out[0] == TOS_NOT_SUPPORTED)
904513ee146SAzael Avalos return -ENODEV;
905513ee146SAzael Avalos
906513ee146SAzael Avalos if (out[0] != TOS_SUCCESS)
907e1a949c1SAzael Avalos return -EIO;
908513ee146SAzael Avalos
909513ee146SAzael Avalos *mode = out[2];
910513ee146SAzael Avalos
911513ee146SAzael Avalos return 0;
912513ee146SAzael Avalos
913182bcaa5SAzael Avalos }
914182bcaa5SAzael Avalos
toshiba_sleep_functions_status_set(struct toshiba_acpi_dev * dev,u32 mode)915182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev,
916182bcaa5SAzael Avalos u32 mode)
917182bcaa5SAzael Avalos {
918182bcaa5SAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
919182bcaa5SAzael Avalos u32 out[TCI_WORDS];
920182bcaa5SAzael Avalos acpi_status status;
921182bcaa5SAzael Avalos
922182bcaa5SAzael Avalos if (!sci_open(dev))
923182bcaa5SAzael Avalos return -EIO;
924182bcaa5SAzael Avalos
925182bcaa5SAzael Avalos in[2] = mode;
926182bcaa5SAzael Avalos in[5] = SCI_USB_CHARGE_BAT_LVL;
927182bcaa5SAzael Avalos status = tci_raw(dev, in, out);
928182bcaa5SAzael Avalos sci_close(dev);
929513ee146SAzael Avalos if (ACPI_FAILURE(status)) {
930182bcaa5SAzael Avalos pr_err("ACPI call to set USB S&C battery level failed\n");
931513ee146SAzael Avalos return -EIO;
932513ee146SAzael Avalos }
933513ee146SAzael Avalos
934513ee146SAzael Avalos if (out[0] == TOS_NOT_SUPPORTED)
935182bcaa5SAzael Avalos return -ENODEV;
936182bcaa5SAzael Avalos
937e1a949c1SAzael Avalos return out[0] == TOS_SUCCESS ? 0 : -EIO;
938182bcaa5SAzael Avalos }
939182bcaa5SAzael Avalos
toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev * dev,u32 * state)940bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev,
941bb3fe01fSAzael Avalos u32 *state)
942bb3fe01fSAzael Avalos {
943bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
944bb3fe01fSAzael Avalos u32 out[TCI_WORDS];
945bb3fe01fSAzael Avalos acpi_status status;
946bb3fe01fSAzael Avalos
947bb3fe01fSAzael Avalos if (!sci_open(dev))
948bb3fe01fSAzael Avalos return -EIO;
949bb3fe01fSAzael Avalos
950bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP;
951bb3fe01fSAzael Avalos status = tci_raw(dev, in, out);
952bb3fe01fSAzael Avalos sci_close(dev);
9538baec45dSAzael Avalos if (ACPI_FAILURE(status)) {
954bb26f189SAzael Avalos pr_err("ACPI call to get USB Rapid Charge failed\n");
955513ee146SAzael Avalos return -EIO;
956bb3fe01fSAzael Avalos }
957bb3fe01fSAzael Avalos
958513ee146SAzael Avalos if (out[0] == TOS_NOT_SUPPORTED)
959513ee146SAzael Avalos return -ENODEV;
960513ee146SAzael Avalos
961513ee146SAzael Avalos if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2)
962e1a949c1SAzael Avalos return -EIO;
963513ee146SAzael Avalos
964513ee146SAzael Avalos *state = out[2];
965513ee146SAzael Avalos
966513ee146SAzael Avalos return 0;
967bb3fe01fSAzael Avalos }
968bb3fe01fSAzael Avalos
toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev * dev,u32 state)969bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev,
970bb3fe01fSAzael Avalos u32 state)
971bb3fe01fSAzael Avalos {
972bb3fe01fSAzael Avalos u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
973bb3fe01fSAzael Avalos u32 out[TCI_WORDS];
974bb3fe01fSAzael Avalos acpi_status status;
975bb3fe01fSAzael Avalos
976bb3fe01fSAzael Avalos if (!sci_open(dev))
977bb3fe01fSAzael Avalos return -EIO;
978bb3fe01fSAzael Avalos
979bb3fe01fSAzael Avalos in[2] = state;
980bb3fe01fSAzael Avalos in[5] = SCI_USB_CHARGE_RAPID_DSP;
981bb3fe01fSAzael Avalos status = tci_raw(dev, in, out);
982bb3fe01fSAzael Avalos sci_close(dev);
983513ee146SAzael Avalos if (ACPI_FAILURE(status)) {
984bb26f189SAzael Avalos pr_err("ACPI call to set USB Rapid Charge failed\n");
985513ee146SAzael Avalos return -EIO;
986513ee146SAzael Avalos }
987513ee146SAzael Avalos
988513ee146SAzael Avalos if (out[0] == TOS_NOT_SUPPORTED)
989bb3fe01fSAzael Avalos return -ENODEV;
990bb3fe01fSAzael Avalos
991e1a949c1SAzael Avalos return (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) ? 0 : -EIO;
992bb3fe01fSAzael Avalos }
993bb3fe01fSAzael Avalos
toshiba_usb_sleep_music_get(struct toshiba_acpi_dev * dev,u32 * state)994172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state)
995172ce0a9SAzael Avalos {
996172ce0a9SAzael Avalos u32 result;
997172ce0a9SAzael Avalos
998172ce0a9SAzael Avalos if (!sci_open(dev))
999172ce0a9SAzael Avalos return -EIO;
1000172ce0a9SAzael Avalos
1001172ce0a9SAzael Avalos result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state);
1002172ce0a9SAzael Avalos sci_close(dev);
1003a6b5354fSAzael Avalos if (result == TOS_FAILURE)
1004bb26f189SAzael Avalos pr_err("ACPI call to get Sleep and Music failed\n");
1005a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED)
1006172ce0a9SAzael Avalos return -ENODEV;
1007172ce0a9SAzael Avalos
1008cf680eaeSAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO;
1009172ce0a9SAzael Avalos }
1010172ce0a9SAzael Avalos
toshiba_usb_sleep_music_set(struct toshiba_acpi_dev * dev,u32 state)1011172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state)
1012172ce0a9SAzael Avalos {
1013172ce0a9SAzael Avalos u32 result;
1014172ce0a9SAzael Avalos
1015172ce0a9SAzael Avalos if (!sci_open(dev))
1016172ce0a9SAzael Avalos return -EIO;
1017172ce0a9SAzael Avalos
1018172ce0a9SAzael Avalos result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state);
1019172ce0a9SAzael Avalos sci_close(dev);
1020a6b5354fSAzael Avalos if (result == TOS_FAILURE)
1021bb26f189SAzael Avalos pr_err("ACPI call to set Sleep and Music failed\n");
1022a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED)
1023172ce0a9SAzael Avalos return -ENODEV;
1024172ce0a9SAzael Avalos
1025e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO;
1026172ce0a9SAzael Avalos }
1027172ce0a9SAzael Avalos
1028bae84195SAzael Avalos /* Keyboard function keys */
toshiba_function_keys_get(struct toshiba_acpi_dev * dev,u32 * mode)1029bae84195SAzael Avalos static int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode)
1030bae84195SAzael Avalos {
1031bae84195SAzael Avalos u32 result;
1032bae84195SAzael Avalos
1033bae84195SAzael Avalos if (!sci_open(dev))
1034bae84195SAzael Avalos return -EIO;
1035bae84195SAzael Avalos
1036bae84195SAzael Avalos result = sci_read(dev, SCI_KBD_FUNCTION_KEYS, mode);
1037bae84195SAzael Avalos sci_close(dev);
1038a6b5354fSAzael Avalos if (result == TOS_FAILURE)
1039bae84195SAzael Avalos pr_err("ACPI call to get KBD function keys failed\n");
1040a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED)
1041bae84195SAzael Avalos return -ENODEV;
1042bae84195SAzael Avalos
1043e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
1044bae84195SAzael Avalos }
1045bae84195SAzael Avalos
toshiba_function_keys_set(struct toshiba_acpi_dev * dev,u32 mode)1046bae84195SAzael Avalos static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode)
1047bae84195SAzael Avalos {
1048bae84195SAzael Avalos u32 result;
1049bae84195SAzael Avalos
1050bae84195SAzael Avalos if (!sci_open(dev))
1051bae84195SAzael Avalos return -EIO;
1052bae84195SAzael Avalos
1053bae84195SAzael Avalos result = sci_write(dev, SCI_KBD_FUNCTION_KEYS, mode);
1054bae84195SAzael Avalos sci_close(dev);
1055a6b5354fSAzael Avalos if (result == TOS_FAILURE)
1056bae84195SAzael Avalos pr_err("ACPI call to set KBD function keys failed\n");
1057a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED)
1058bae84195SAzael Avalos return -ENODEV;
1059bae84195SAzael Avalos
1060e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
1061bae84195SAzael Avalos }
1062bae84195SAzael Avalos
106335d53ceaSAzael Avalos /* Panel Power ON */
toshiba_panel_power_on_get(struct toshiba_acpi_dev * dev,u32 * state)106435d53ceaSAzael Avalos static int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state)
106535d53ceaSAzael Avalos {
106635d53ceaSAzael Avalos u32 result;
106735d53ceaSAzael Avalos
106835d53ceaSAzael Avalos if (!sci_open(dev))
106935d53ceaSAzael Avalos return -EIO;
107035d53ceaSAzael Avalos
107135d53ceaSAzael Avalos result = sci_read(dev, SCI_PANEL_POWER_ON, state);
107235d53ceaSAzael Avalos sci_close(dev);
1073a6b5354fSAzael Avalos if (result == TOS_FAILURE)
107435d53ceaSAzael Avalos pr_err("ACPI call to get Panel Power ON failed\n");
1075a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED)
107635d53ceaSAzael Avalos return -ENODEV;
107735d53ceaSAzael Avalos
1078e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO;
107935d53ceaSAzael Avalos }
108035d53ceaSAzael Avalos
toshiba_panel_power_on_set(struct toshiba_acpi_dev * dev,u32 state)108135d53ceaSAzael Avalos static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state)
108235d53ceaSAzael Avalos {
108335d53ceaSAzael Avalos u32 result;
108435d53ceaSAzael Avalos
108535d53ceaSAzael Avalos if (!sci_open(dev))
108635d53ceaSAzael Avalos return -EIO;
108735d53ceaSAzael Avalos
108835d53ceaSAzael Avalos result = sci_write(dev, SCI_PANEL_POWER_ON, state);
108935d53ceaSAzael Avalos sci_close(dev);
1090a6b5354fSAzael Avalos if (result == TOS_FAILURE)
109135d53ceaSAzael Avalos pr_err("ACPI call to set Panel Power ON failed\n");
1092a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED)
109335d53ceaSAzael Avalos return -ENODEV;
109435d53ceaSAzael Avalos
1095e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO;
109635d53ceaSAzael Avalos }
109735d53ceaSAzael Avalos
109817fe4b3dSAzael Avalos /* USB Three */
toshiba_usb_three_get(struct toshiba_acpi_dev * dev,u32 * state)109917fe4b3dSAzael Avalos static int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state)
110017fe4b3dSAzael Avalos {
110117fe4b3dSAzael Avalos u32 result;
110217fe4b3dSAzael Avalos
110317fe4b3dSAzael Avalos if (!sci_open(dev))
110417fe4b3dSAzael Avalos return -EIO;
110517fe4b3dSAzael Avalos
110617fe4b3dSAzael Avalos result = sci_read(dev, SCI_USB_THREE, state);
110717fe4b3dSAzael Avalos sci_close(dev);
1108a6b5354fSAzael Avalos if (result == TOS_FAILURE)
110917fe4b3dSAzael Avalos pr_err("ACPI call to get USB 3 failed\n");
1110a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED)
111117fe4b3dSAzael Avalos return -ENODEV;
111217fe4b3dSAzael Avalos
1113e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
111417fe4b3dSAzael Avalos }
111517fe4b3dSAzael Avalos
toshiba_usb_three_set(struct toshiba_acpi_dev * dev,u32 state)111617fe4b3dSAzael Avalos static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state)
111717fe4b3dSAzael Avalos {
111817fe4b3dSAzael Avalos u32 result;
111917fe4b3dSAzael Avalos
112017fe4b3dSAzael Avalos if (!sci_open(dev))
112117fe4b3dSAzael Avalos return -EIO;
112217fe4b3dSAzael Avalos
112317fe4b3dSAzael Avalos result = sci_write(dev, SCI_USB_THREE, state);
112417fe4b3dSAzael Avalos sci_close(dev);
1125a6b5354fSAzael Avalos if (result == TOS_FAILURE)
112617fe4b3dSAzael Avalos pr_err("ACPI call to set USB 3 failed\n");
1127a6b5354fSAzael Avalos else if (result == TOS_NOT_SUPPORTED)
112817fe4b3dSAzael Avalos return -ENODEV;
112917fe4b3dSAzael Avalos
1130e1a949c1SAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
113117fe4b3dSAzael Avalos }
113217fe4b3dSAzael Avalos
113356e6b353SAzael Avalos /* Hotkey Event type */
toshiba_hotkey_event_type_get(struct toshiba_acpi_dev * dev,u32 * type)113456e6b353SAzael Avalos static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev,
113556e6b353SAzael Avalos u32 *type)
113656e6b353SAzael Avalos {
11373b876000SAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_SYSTEM_INFO, 0x03, 0, 0, 0 };
11383b876000SAzael Avalos u32 out[TCI_WORDS];
11393b876000SAzael Avalos acpi_status status;
114056e6b353SAzael Avalos
11413b876000SAzael Avalos status = tci_raw(dev, in, out);
11423b876000SAzael Avalos if (ACPI_FAILURE(status)) {
114356e6b353SAzael Avalos pr_err("ACPI call to get System type failed\n");
1144513ee146SAzael Avalos return -EIO;
114556e6b353SAzael Avalos }
114656e6b353SAzael Avalos
1147513ee146SAzael Avalos if (out[0] == TOS_NOT_SUPPORTED)
1148513ee146SAzael Avalos return -ENODEV;
1149513ee146SAzael Avalos
1150513ee146SAzael Avalos if (out[0] != TOS_SUCCESS)
1151e1a949c1SAzael Avalos return -EIO;
1152513ee146SAzael Avalos
1153513ee146SAzael Avalos *type = out[3];
1154513ee146SAzael Avalos
1155513ee146SAzael Avalos return 0;
115656e6b353SAzael Avalos }
115756e6b353SAzael Avalos
11586873f46aSAzael Avalos /* Wireless status (RFKill, WLAN, BT, WWAN) */
toshiba_wireless_status(struct toshiba_acpi_dev * dev)11596873f46aSAzael Avalos static int toshiba_wireless_status(struct toshiba_acpi_dev *dev)
11606873f46aSAzael Avalos {
11616873f46aSAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_WIRELESS, 0, 0, 0, 0 };
11626873f46aSAzael Avalos u32 out[TCI_WORDS];
11636873f46aSAzael Avalos acpi_status status;
11646873f46aSAzael Avalos
11656873f46aSAzael Avalos in[3] = HCI_WIRELESS_STATUS;
11666873f46aSAzael Avalos status = tci_raw(dev, in, out);
11676873f46aSAzael Avalos
11686873f46aSAzael Avalos if (ACPI_FAILURE(status)) {
11696873f46aSAzael Avalos pr_err("ACPI call to get Wireless status failed\n");
11706873f46aSAzael Avalos return -EIO;
11716873f46aSAzael Avalos }
11726873f46aSAzael Avalos
11736873f46aSAzael Avalos if (out[0] == TOS_NOT_SUPPORTED)
11746873f46aSAzael Avalos return -ENODEV;
11756873f46aSAzael Avalos
11766873f46aSAzael Avalos if (out[0] != TOS_SUCCESS)
11776873f46aSAzael Avalos return -EIO;
11786873f46aSAzael Avalos
11796873f46aSAzael Avalos dev->killswitch = !!(out[2] & HCI_WIRELESS_STATUS);
11806873f46aSAzael Avalos
11816873f46aSAzael Avalos return 0;
11826873f46aSAzael Avalos }
11836873f46aSAzael Avalos
11846873f46aSAzael Avalos /* WWAN */
toshiba_wwan_available(struct toshiba_acpi_dev * dev)11856873f46aSAzael Avalos static void toshiba_wwan_available(struct toshiba_acpi_dev *dev)
11866873f46aSAzael Avalos {
11876873f46aSAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_WIRELESS, 0, 0, 0, 0 };
11886873f46aSAzael Avalos u32 out[TCI_WORDS];
11896873f46aSAzael Avalos acpi_status status;
11906873f46aSAzael Avalos
11916873f46aSAzael Avalos dev->wwan_supported = 0;
11926873f46aSAzael Avalos
11936873f46aSAzael Avalos /*
11946873f46aSAzael Avalos * WWAN support can be queried by setting the in[3] value to
11956873f46aSAzael Avalos * HCI_WIRELESS_WWAN (0x03).
11966873f46aSAzael Avalos *
11976873f46aSAzael Avalos * If supported, out[0] contains TOS_SUCCESS and out[2] contains
11986873f46aSAzael Avalos * HCI_WIRELESS_WWAN_STATUS (0x2000).
11996873f46aSAzael Avalos *
12006873f46aSAzael Avalos * If not supported, out[0] contains TOS_INPUT_DATA_ERROR (0x8300)
12016873f46aSAzael Avalos * or TOS_NOT_SUPPORTED (0x8000).
12026873f46aSAzael Avalos */
12036873f46aSAzael Avalos in[3] = HCI_WIRELESS_WWAN;
12046873f46aSAzael Avalos status = tci_raw(dev, in, out);
12056873f46aSAzael Avalos if (ACPI_FAILURE(status)) {
12066873f46aSAzael Avalos pr_err("ACPI call to get WWAN status failed\n");
12076873f46aSAzael Avalos return;
12086873f46aSAzael Avalos }
12096873f46aSAzael Avalos
12106873f46aSAzael Avalos if (out[0] != TOS_SUCCESS)
12116873f46aSAzael Avalos return;
12126873f46aSAzael Avalos
12136873f46aSAzael Avalos dev->wwan_supported = (out[2] == HCI_WIRELESS_WWAN_STATUS);
12146873f46aSAzael Avalos }
12156873f46aSAzael Avalos
toshiba_wwan_set(struct toshiba_acpi_dev * dev,u32 state)12166873f46aSAzael Avalos static int toshiba_wwan_set(struct toshiba_acpi_dev *dev, u32 state)
12176873f46aSAzael Avalos {
12186873f46aSAzael Avalos u32 in[TCI_WORDS] = { HCI_SET, HCI_WIRELESS, state, 0, 0, 0 };
12196873f46aSAzael Avalos u32 out[TCI_WORDS];
12206873f46aSAzael Avalos acpi_status status;
12216873f46aSAzael Avalos
12226873f46aSAzael Avalos in[3] = HCI_WIRELESS_WWAN_STATUS;
12236873f46aSAzael Avalos status = tci_raw(dev, in, out);
12246873f46aSAzael Avalos if (ACPI_FAILURE(status)) {
12256873f46aSAzael Avalos pr_err("ACPI call to set WWAN status failed\n");
12266873f46aSAzael Avalos return -EIO;
12276873f46aSAzael Avalos }
12286873f46aSAzael Avalos
12296873f46aSAzael Avalos if (out[0] == TOS_NOT_SUPPORTED)
12306873f46aSAzael Avalos return -ENODEV;
12316873f46aSAzael Avalos
12326873f46aSAzael Avalos if (out[0] != TOS_SUCCESS)
12336873f46aSAzael Avalos return -EIO;
12346873f46aSAzael Avalos
12356873f46aSAzael Avalos /*
12366873f46aSAzael Avalos * Some devices only need to call HCI_WIRELESS_WWAN_STATUS to
12376873f46aSAzael Avalos * (de)activate the device, but some others need the
12386873f46aSAzael Avalos * HCI_WIRELESS_WWAN_POWER call as well.
12396873f46aSAzael Avalos */
12406873f46aSAzael Avalos in[3] = HCI_WIRELESS_WWAN_POWER;
12416873f46aSAzael Avalos status = tci_raw(dev, in, out);
12426873f46aSAzael Avalos if (ACPI_FAILURE(status)) {
12436873f46aSAzael Avalos pr_err("ACPI call to set WWAN power failed\n");
12446873f46aSAzael Avalos return -EIO;
12456873f46aSAzael Avalos }
12466873f46aSAzael Avalos
12476873f46aSAzael Avalos if (out[0] == TOS_NOT_SUPPORTED)
12486873f46aSAzael Avalos return -ENODEV;
12496873f46aSAzael Avalos
12506873f46aSAzael Avalos return out[0] == TOS_SUCCESS ? 0 : -EIO;
12516873f46aSAzael Avalos }
12526873f46aSAzael Avalos
1253763ff32fSAzael Avalos /* Cooling Method */
toshiba_cooling_method_available(struct toshiba_acpi_dev * dev)1254763ff32fSAzael Avalos static void toshiba_cooling_method_available(struct toshiba_acpi_dev *dev)
1255763ff32fSAzael Avalos {
1256763ff32fSAzael Avalos u32 in[TCI_WORDS] = { HCI_GET, HCI_COOLING_METHOD, 0, 0, 0, 0 };
1257763ff32fSAzael Avalos u32 out[TCI_WORDS];
1258763ff32fSAzael Avalos acpi_status status;
1259763ff32fSAzael Avalos
1260763ff32fSAzael Avalos dev->cooling_method_supported = 0;
1261763ff32fSAzael Avalos dev->max_cooling_method = 0;
1262763ff32fSAzael Avalos
1263763ff32fSAzael Avalos status = tci_raw(dev, in, out);
1264513ee146SAzael Avalos if (ACPI_FAILURE(status)) {
1265763ff32fSAzael Avalos pr_err("ACPI call to get Cooling Method failed\n");
1266513ee146SAzael Avalos return;
1267513ee146SAzael Avalos }
1268763ff32fSAzael Avalos
1269763ff32fSAzael Avalos if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2)
1270763ff32fSAzael Avalos return;
1271763ff32fSAzael Avalos
1272763ff32fSAzael Avalos dev->cooling_method_supported = 1;
1273763ff32fSAzael Avalos dev->max_cooling_method = out[3];
1274763ff32fSAzael Avalos }
1275763ff32fSAzael Avalos
toshiba_cooling_method_get(struct toshiba_acpi_dev * dev,u32 * state)1276763ff32fSAzael Avalos static int toshiba_cooling_method_get(struct toshiba_acpi_dev *dev, u32 *state)
1277763ff32fSAzael Avalos {
1278763ff32fSAzael Avalos u32 result = hci_read(dev, HCI_COOLING_METHOD, state);
1279763ff32fSAzael Avalos
1280763ff32fSAzael Avalos if (result == TOS_FAILURE)
1281763ff32fSAzael Avalos pr_err("ACPI call to get Cooling Method failed\n");
1282763ff32fSAzael Avalos
1283763ff32fSAzael Avalos if (result == TOS_NOT_SUPPORTED)
1284763ff32fSAzael Avalos return -ENODEV;
1285763ff32fSAzael Avalos
1286763ff32fSAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
1287763ff32fSAzael Avalos }
1288763ff32fSAzael Avalos
toshiba_cooling_method_set(struct toshiba_acpi_dev * dev,u32 state)1289763ff32fSAzael Avalos static int toshiba_cooling_method_set(struct toshiba_acpi_dev *dev, u32 state)
1290763ff32fSAzael Avalos {
1291763ff32fSAzael Avalos u32 result = hci_write(dev, HCI_COOLING_METHOD, state);
1292763ff32fSAzael Avalos
1293763ff32fSAzael Avalos if (result == TOS_FAILURE)
1294fa1bc2a0SAzael Avalos pr_err("ACPI call to set Cooling Method failed\n");
1295763ff32fSAzael Avalos
1296763ff32fSAzael Avalos if (result == TOS_NOT_SUPPORTED)
1297763ff32fSAzael Avalos return -ENODEV;
1298763ff32fSAzael Avalos
1299763ff32fSAzael Avalos return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
1300763ff32fSAzael Avalos }
1301763ff32fSAzael Avalos
130289655fbbSArvid Norlander /* Battery charge control */
toshiba_battery_charge_mode_available(struct toshiba_acpi_dev * dev)130389655fbbSArvid Norlander static void toshiba_battery_charge_mode_available(struct toshiba_acpi_dev *dev)
130489655fbbSArvid Norlander {
130589655fbbSArvid Norlander u32 in[TCI_WORDS] = { HCI_GET, HCI_BATTERY_CHARGE_MODE, 0, 0, 0, 0 };
130689655fbbSArvid Norlander u32 out[TCI_WORDS];
130789655fbbSArvid Norlander acpi_status status;
130889655fbbSArvid Norlander
130989655fbbSArvid Norlander dev->battery_charge_mode_supported = 0;
131089655fbbSArvid Norlander
131189655fbbSArvid Norlander status = tci_raw(dev, in, out);
131289655fbbSArvid Norlander if (ACPI_FAILURE(status)) {
131389655fbbSArvid Norlander pr_err("ACPI call to get Battery Charge Mode failed\n");
131489655fbbSArvid Norlander return;
131589655fbbSArvid Norlander }
131689655fbbSArvid Norlander
131789655fbbSArvid Norlander if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2)
131889655fbbSArvid Norlander return;
131989655fbbSArvid Norlander
132089655fbbSArvid Norlander dev->battery_charge_mode_supported = 1;
132189655fbbSArvid Norlander }
132289655fbbSArvid Norlander
toshiba_battery_charge_mode_get(struct toshiba_acpi_dev * dev,u32 * state)132389655fbbSArvid Norlander static int toshiba_battery_charge_mode_get(struct toshiba_acpi_dev *dev, u32 *state)
132489655fbbSArvid Norlander {
132589655fbbSArvid Norlander u32 in[TCI_WORDS] = { HCI_GET, HCI_BATTERY_CHARGE_MODE, 0, 0, 0, 0x1 };
132689655fbbSArvid Norlander u32 out[TCI_WORDS];
132789655fbbSArvid Norlander int retries = 3;
132889655fbbSArvid Norlander
132989655fbbSArvid Norlander do {
133089655fbbSArvid Norlander acpi_status status = tci_raw(dev, in, out);
133189655fbbSArvid Norlander
133289655fbbSArvid Norlander if (ACPI_FAILURE(status))
133389655fbbSArvid Norlander pr_err("ACPI call to get Battery Charge Mode failed\n");
133489655fbbSArvid Norlander switch (out[0]) {
133589655fbbSArvid Norlander case TOS_SUCCESS:
133689655fbbSArvid Norlander case TOS_SUCCESS2:
133789655fbbSArvid Norlander *state = out[2];
133889655fbbSArvid Norlander return 0;
133989655fbbSArvid Norlander case TOS_NOT_SUPPORTED:
134089655fbbSArvid Norlander return -ENODEV;
134189655fbbSArvid Norlander case TOS_DATA_NOT_AVAILABLE:
134289655fbbSArvid Norlander retries--;
134389655fbbSArvid Norlander break;
134489655fbbSArvid Norlander default:
134589655fbbSArvid Norlander return -EIO;
134689655fbbSArvid Norlander }
134789655fbbSArvid Norlander } while (retries);
134889655fbbSArvid Norlander
134989655fbbSArvid Norlander return -EIO;
135089655fbbSArvid Norlander }
135189655fbbSArvid Norlander
toshiba_battery_charge_mode_set(struct toshiba_acpi_dev * dev,u32 state)135289655fbbSArvid Norlander static int toshiba_battery_charge_mode_set(struct toshiba_acpi_dev *dev, u32 state)
135389655fbbSArvid Norlander {
135489655fbbSArvid Norlander u32 result = hci_write(dev, HCI_BATTERY_CHARGE_MODE, state);
135589655fbbSArvid Norlander
135689655fbbSArvid Norlander if (result == TOS_FAILURE)
135789655fbbSArvid Norlander pr_err("ACPI call to set Battery Charge Mode failed\n");
135889655fbbSArvid Norlander
135989655fbbSArvid Norlander if (result == TOS_NOT_SUPPORTED)
136089655fbbSArvid Norlander return -ENODEV;
136189655fbbSArvid Norlander
136289655fbbSArvid Norlander return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
136389655fbbSArvid Norlander }
136489655fbbSArvid Norlander
13653f75bbe9SAzael Avalos /* Transflective Backlight */
get_tr_backlight_status(struct toshiba_acpi_dev * dev,u32 * status)1366695f6060SAzael Avalos static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status)
1367121b7b0dSAkio Idehara {
1368e1a949c1SAzael Avalos u32 result = hci_read(dev, HCI_TR_BACKLIGHT, status);
1369121b7b0dSAkio Idehara
1370e1a949c1SAzael Avalos if (result == TOS_FAILURE)
1371e1a949c1SAzael Avalos pr_err("ACPI call to get Transflective Backlight failed\n");
1372e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED)
1373e1a949c1SAzael Avalos return -ENODEV;
1374e1a949c1SAzael Avalos
1375e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO;
1376121b7b0dSAkio Idehara }
1377121b7b0dSAkio Idehara
set_tr_backlight_status(struct toshiba_acpi_dev * dev,u32 status)1378695f6060SAzael Avalos static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 status)
1379121b7b0dSAkio Idehara {
1380e1a949c1SAzael Avalos u32 result = hci_write(dev, HCI_TR_BACKLIGHT, !status);
1381121b7b0dSAkio Idehara
1382e1a949c1SAzael Avalos if (result == TOS_FAILURE)
1383e1a949c1SAzael Avalos pr_err("ACPI call to set Transflective Backlight failed\n");
1384e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED)
1385e1a949c1SAzael Avalos return -ENODEV;
1386e1a949c1SAzael Avalos
1387e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO;
1388121b7b0dSAkio Idehara }
1389121b7b0dSAkio Idehara
13903f75bbe9SAzael Avalos static struct proc_dir_entry *toshiba_proc_dir;
1391b4f9fe12SLen Brown
13923f75bbe9SAzael Avalos /* LCD Brightness */
__get_lcd_brightness(struct toshiba_acpi_dev * dev)139362cce752SSeth Forshee static int __get_lcd_brightness(struct toshiba_acpi_dev *dev)
1394b4f9fe12SLen Brown {
139578429e55SAzael Avalos int brightness = 0;
1396e1a949c1SAzael Avalos u32 result;
1397b4f9fe12SLen Brown u32 value;
1398121b7b0dSAkio Idehara
1399121b7b0dSAkio Idehara if (dev->tr_backlight_supported) {
1400695f6060SAzael Avalos int ret = get_tr_backlight_status(dev, &value);
1401b5163992SAzael Avalos
1402121b7b0dSAkio Idehara if (ret)
1403121b7b0dSAkio Idehara return ret;
1404695f6060SAzael Avalos if (value)
1405121b7b0dSAkio Idehara return 0;
1406121b7b0dSAkio Idehara brightness++;
1407121b7b0dSAkio Idehara }
1408b4f9fe12SLen Brown
1409e1a949c1SAzael Avalos result = hci_read(dev, HCI_LCD_BRIGHTNESS, &value);
1410e1a949c1SAzael Avalos if (result == TOS_FAILURE)
1411e1a949c1SAzael Avalos pr_err("ACPI call to get LCD Brightness failed\n");
1412e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED)
1413e1a949c1SAzael Avalos return -ENODEV;
141432bcd5cbSSeth Forshee
1415513ee146SAzael Avalos return result == TOS_SUCCESS ?
1416513ee146SAzael Avalos brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT) :
1417513ee146SAzael Avalos -EIO;
1418b4f9fe12SLen Brown }
1419b4f9fe12SLen Brown
get_lcd_brightness(struct backlight_device * bd)142062cce752SSeth Forshee static int get_lcd_brightness(struct backlight_device *bd)
142162cce752SSeth Forshee {
142262cce752SSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd);
1423b5163992SAzael Avalos
142462cce752SSeth Forshee return __get_lcd_brightness(dev);
142562cce752SSeth Forshee }
142662cce752SSeth Forshee
lcd_proc_show(struct seq_file * m,void * v)1427936c8bcdSAlexey Dobriyan static int lcd_proc_show(struct seq_file *m, void *v)
1428b4f9fe12SLen Brown {
1429135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private;
1430121b7b0dSAkio Idehara int levels;
1431e1a949c1SAzael Avalos int value;
1432b4f9fe12SLen Brown
1433135740deSSeth Forshee if (!dev->backlight_dev)
1434135740deSSeth Forshee return -ENODEV;
1435135740deSSeth Forshee
1436121b7b0dSAkio Idehara levels = dev->backlight_dev->props.max_brightness + 1;
143762cce752SSeth Forshee value = get_lcd_brightness(dev->backlight_dev);
1438513ee146SAzael Avalos if (value < 0) {
1439513ee146SAzael Avalos pr_err("Error reading LCD brightness\n");
1440513ee146SAzael Avalos return value;
1441b4f9fe12SLen Brown }
1442b4f9fe12SLen Brown
1443513ee146SAzael Avalos seq_printf(m, "brightness: %d\n", value);
1444513ee146SAzael Avalos seq_printf(m, "brightness_levels: %d\n", levels);
1445e1a949c1SAzael Avalos
1446513ee146SAzael Avalos return 0;
1447936c8bcdSAlexey Dobriyan }
1448936c8bcdSAlexey Dobriyan
lcd_proc_open(struct inode * inode,struct file * file)1449936c8bcdSAlexey Dobriyan static int lcd_proc_open(struct inode *inode, struct file *file)
1450936c8bcdSAlexey Dobriyan {
1451359745d7SMuchun Song return single_open(file, lcd_proc_show, pde_data(inode));
1452b4f9fe12SLen Brown }
1453b4f9fe12SLen Brown
set_lcd_brightness(struct toshiba_acpi_dev * dev,int value)145462cce752SSeth Forshee static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
1455b4f9fe12SLen Brown {
1456e1a949c1SAzael Avalos u32 result;
1457b4f9fe12SLen Brown
1458121b7b0dSAkio Idehara if (dev->tr_backlight_supported) {
1459695f6060SAzael Avalos int ret = set_tr_backlight_status(dev, !value);
1460b5163992SAzael Avalos
1461121b7b0dSAkio Idehara if (ret)
1462121b7b0dSAkio Idehara return ret;
1463121b7b0dSAkio Idehara if (value)
1464121b7b0dSAkio Idehara value--;
1465121b7b0dSAkio Idehara }
1466121b7b0dSAkio Idehara
1467a39f46dfSAzael Avalos value = value << HCI_LCD_BRIGHTNESS_SHIFT;
1468e1a949c1SAzael Avalos result = hci_write(dev, HCI_LCD_BRIGHTNESS, value);
1469e1a949c1SAzael Avalos if (result == TOS_FAILURE)
1470e1a949c1SAzael Avalos pr_err("ACPI call to set LCD Brightness failed\n");
1471e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED)
1472e1a949c1SAzael Avalos return -ENODEV;
1473e1a949c1SAzael Avalos
1474e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO;
1475b4f9fe12SLen Brown }
1476b4f9fe12SLen Brown
set_lcd_status(struct backlight_device * bd)1477b4f9fe12SLen Brown static int set_lcd_status(struct backlight_device *bd)
1478b4f9fe12SLen Brown {
1479135740deSSeth Forshee struct toshiba_acpi_dev *dev = bl_get_data(bd);
1480b5163992SAzael Avalos
148162cce752SSeth Forshee return set_lcd_brightness(dev, bd->props.brightness);
1482b4f9fe12SLen Brown }
1483b4f9fe12SLen Brown
lcd_proc_write(struct file * file,const char __user * buf,size_t count,loff_t * pos)1484936c8bcdSAlexey Dobriyan static ssize_t lcd_proc_write(struct file *file, const char __user *buf,
1485936c8bcdSAlexey Dobriyan size_t count, loff_t *pos)
1486b4f9fe12SLen Brown {
1487359745d7SMuchun Song struct toshiba_acpi_dev *dev = pde_data(file_inode(file));
1488936c8bcdSAlexey Dobriyan char cmd[42];
1489936c8bcdSAlexey Dobriyan size_t len;
149078429e55SAzael Avalos int levels;
1491e1a949c1SAzael Avalos int value;
1492b4f9fe12SLen Brown
1493936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1);
1494936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len))
1495936c8bcdSAlexey Dobriyan return -EFAULT;
1496936c8bcdSAlexey Dobriyan cmd[len] = '\0';
1497936c8bcdSAlexey Dobriyan
149878429e55SAzael Avalos levels = dev->backlight_dev->props.max_brightness + 1;
1499e1a949c1SAzael Avalos if (sscanf(cmd, " brightness : %i", &value) != 1 &&
1500e1a949c1SAzael Avalos value < 0 && value > levels)
1501e1a949c1SAzael Avalos return -EINVAL;
1502e1a949c1SAzael Avalos
1503e1a949c1SAzael Avalos if (set_lcd_brightness(dev, value))
1504e1a949c1SAzael Avalos return -EIO;
1505e1a949c1SAzael Avalos
1506e1a949c1SAzael Avalos return count;
1507b4f9fe12SLen Brown }
1508b4f9fe12SLen Brown
150997a32539SAlexey Dobriyan static const struct proc_ops lcd_proc_ops = {
151097a32539SAlexey Dobriyan .proc_open = lcd_proc_open,
151197a32539SAlexey Dobriyan .proc_read = seq_read,
151297a32539SAlexey Dobriyan .proc_lseek = seq_lseek,
151397a32539SAlexey Dobriyan .proc_release = single_release,
151497a32539SAlexey Dobriyan .proc_write = lcd_proc_write,
1515936c8bcdSAlexey Dobriyan };
1516936c8bcdSAlexey Dobriyan
1517e1a949c1SAzael Avalos /* Video-Out */
get_video_status(struct toshiba_acpi_dev * dev,u32 * status)151836d03f93SSeth Forshee static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status)
151936d03f93SSeth Forshee {
1520e1a949c1SAzael Avalos u32 result = hci_read(dev, HCI_VIDEO_OUT, status);
152136d03f93SSeth Forshee
1522e1a949c1SAzael Avalos if (result == TOS_FAILURE)
1523e1a949c1SAzael Avalos pr_err("ACPI call to get Video-Out failed\n");
1524e1a949c1SAzael Avalos else if (result == TOS_NOT_SUPPORTED)
1525e1a949c1SAzael Avalos return -ENODEV;
1526e1a949c1SAzael Avalos
1527e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO;
152836d03f93SSeth Forshee }
152936d03f93SSeth Forshee
video_proc_show(struct seq_file * m,void * v)1530936c8bcdSAlexey Dobriyan static int video_proc_show(struct seq_file *m, void *v)
1531b4f9fe12SLen Brown {
1532135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private;
1533513ee146SAzael Avalos int is_lcd, is_crt, is_tv;
1534b4f9fe12SLen Brown u32 value;
1535b4f9fe12SLen Brown
1536513ee146SAzael Avalos if (get_video_status(dev, &value))
1537513ee146SAzael Avalos return -EIO;
1538513ee146SAzael Avalos
1539513ee146SAzael Avalos is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0;
1540513ee146SAzael Avalos is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0;
1541513ee146SAzael Avalos is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0;
1542b5163992SAzael Avalos
1543936c8bcdSAlexey Dobriyan seq_printf(m, "lcd_out: %d\n", is_lcd);
1544936c8bcdSAlexey Dobriyan seq_printf(m, "crt_out: %d\n", is_crt);
1545936c8bcdSAlexey Dobriyan seq_printf(m, "tv_out: %d\n", is_tv);
1546b4f9fe12SLen Brown
1547513ee146SAzael Avalos return 0;
1548b4f9fe12SLen Brown }
1549b4f9fe12SLen Brown
video_proc_open(struct inode * inode,struct file * file)1550936c8bcdSAlexey Dobriyan static int video_proc_open(struct inode *inode, struct file *file)
1551b4f9fe12SLen Brown {
1552359745d7SMuchun Song return single_open(file, video_proc_show, pde_data(inode));
1553936c8bcdSAlexey Dobriyan }
1554936c8bcdSAlexey Dobriyan
video_proc_write(struct file * file,const char __user * buf,size_t count,loff_t * pos)1555936c8bcdSAlexey Dobriyan static ssize_t video_proc_write(struct file *file, const char __user *buf,
1556936c8bcdSAlexey Dobriyan size_t count, loff_t *pos)
1557936c8bcdSAlexey Dobriyan {
1558359745d7SMuchun Song struct toshiba_acpi_dev *dev = pde_data(file_inode(file));
1559e1a949c1SAzael Avalos char *buffer;
1560e1a949c1SAzael Avalos char *cmd;
15612a72c46aSKaixu Xia int lcd_out = -1, crt_out = -1, tv_out = -1;
1562b4f9fe12SLen Brown int remain = count;
1563e1a949c1SAzael Avalos int value;
1564e1a949c1SAzael Avalos int ret;
1565b4f9fe12SLen Brown u32 video_out;
1566b4f9fe12SLen Brown
1567f0ee1a6dSGeliang Tang cmd = memdup_user_nul(buf, count);
1568f0ee1a6dSGeliang Tang if (IS_ERR(cmd))
1569f0ee1a6dSGeliang Tang return PTR_ERR(cmd);
1570936c8bcdSAlexey Dobriyan
1571936c8bcdSAlexey Dobriyan buffer = cmd;
1572936c8bcdSAlexey Dobriyan
1573e0769fe6SDarren Hart /*
1574e0769fe6SDarren Hart * Scan expression. Multiple expressions may be delimited with ;
1575e0769fe6SDarren Hart * NOTE: To keep scanning simple, invalid fields are ignored.
1576b4f9fe12SLen Brown */
1577b4f9fe12SLen Brown while (remain) {
1578b4f9fe12SLen Brown if (sscanf(buffer, " lcd_out : %i", &value) == 1)
1579b4f9fe12SLen Brown lcd_out = value & 1;
1580b4f9fe12SLen Brown else if (sscanf(buffer, " crt_out : %i", &value) == 1)
1581b4f9fe12SLen Brown crt_out = value & 1;
1582b4f9fe12SLen Brown else if (sscanf(buffer, " tv_out : %i", &value) == 1)
1583b4f9fe12SLen Brown tv_out = value & 1;
1584e0769fe6SDarren Hart /* Advance to one character past the next ; */
1585b4f9fe12SLen Brown do {
1586b4f9fe12SLen Brown ++buffer;
1587b4f9fe12SLen Brown --remain;
1588b5163992SAzael Avalos } while (remain && *(buffer - 1) != ';');
1589b4f9fe12SLen Brown }
1590b4f9fe12SLen Brown
1591936c8bcdSAlexey Dobriyan kfree(cmd);
1592936c8bcdSAlexey Dobriyan
159336d03f93SSeth Forshee ret = get_video_status(dev, &video_out);
159436d03f93SSeth Forshee if (!ret) {
1595b4f9fe12SLen Brown unsigned int new_video_out = video_out;
1596b5163992SAzael Avalos
1597b4f9fe12SLen Brown if (lcd_out != -1)
1598b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out);
1599b4f9fe12SLen Brown if (crt_out != -1)
1600b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out);
1601b4f9fe12SLen Brown if (tv_out != -1)
1602b4f9fe12SLen Brown _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out);
1603e0769fe6SDarren Hart /*
1604e0769fe6SDarren Hart * To avoid unnecessary video disruption, only write the new
16053f75bbe9SAzael Avalos * video setting if something changed.
16063f75bbe9SAzael Avalos */
1607b4f9fe12SLen Brown if (new_video_out != video_out)
160832bcd5cbSSeth Forshee ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out);
1609b4f9fe12SLen Brown }
1610b4f9fe12SLen Brown
1611e1a949c1SAzael Avalos return ret ? -EIO : count;
1612b4f9fe12SLen Brown }
1613b4f9fe12SLen Brown
161497a32539SAlexey Dobriyan static const struct proc_ops video_proc_ops = {
161597a32539SAlexey Dobriyan .proc_open = video_proc_open,
161697a32539SAlexey Dobriyan .proc_read = seq_read,
161797a32539SAlexey Dobriyan .proc_lseek = seq_lseek,
161897a32539SAlexey Dobriyan .proc_release = single_release,
161997a32539SAlexey Dobriyan .proc_write = video_proc_write,
1620936c8bcdSAlexey Dobriyan };
1621936c8bcdSAlexey Dobriyan
16223e07e5baSAzael Avalos /* Fan status */
get_fan_status(struct toshiba_acpi_dev * dev,u32 * status)162336d03f93SSeth Forshee static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status)
162436d03f93SSeth Forshee {
16253e07e5baSAzael Avalos u32 result = hci_read(dev, HCI_FAN, status);
162636d03f93SSeth Forshee
16273e07e5baSAzael Avalos if (result == TOS_FAILURE)
16283e07e5baSAzael Avalos pr_err("ACPI call to get Fan status failed\n");
16293e07e5baSAzael Avalos else if (result == TOS_NOT_SUPPORTED)
16303e07e5baSAzael Avalos return -ENODEV;
16313e07e5baSAzael Avalos
1632e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO;
16333e07e5baSAzael Avalos }
16343e07e5baSAzael Avalos
set_fan_status(struct toshiba_acpi_dev * dev,u32 status)16353e07e5baSAzael Avalos static int set_fan_status(struct toshiba_acpi_dev *dev, u32 status)
16363e07e5baSAzael Avalos {
16373e07e5baSAzael Avalos u32 result = hci_write(dev, HCI_FAN, status);
16383e07e5baSAzael Avalos
16393e07e5baSAzael Avalos if (result == TOS_FAILURE)
16403e07e5baSAzael Avalos pr_err("ACPI call to set Fan status failed\n");
16413e07e5baSAzael Avalos else if (result == TOS_NOT_SUPPORTED)
16423e07e5baSAzael Avalos return -ENODEV;
16433e07e5baSAzael Avalos
1644e1a949c1SAzael Avalos return result == TOS_SUCCESS ? 0 : -EIO;
164536d03f93SSeth Forshee }
164636d03f93SSeth Forshee
fan_proc_show(struct seq_file * m,void * v)1647936c8bcdSAlexey Dobriyan static int fan_proc_show(struct seq_file *m, void *v)
1648b4f9fe12SLen Brown {
1649135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private;
1650b4f9fe12SLen Brown u32 value;
1651b4f9fe12SLen Brown
16523e07e5baSAzael Avalos if (get_fan_status(dev, &value))
16533e07e5baSAzael Avalos return -EIO;
16543e07e5baSAzael Avalos
1655936c8bcdSAlexey Dobriyan seq_printf(m, "running: %d\n", (value > 0));
1656135740deSSeth Forshee seq_printf(m, "force_on: %d\n", dev->force_fan);
1657b4f9fe12SLen Brown
16583e07e5baSAzael Avalos return 0;
1659b4f9fe12SLen Brown }
1660b4f9fe12SLen Brown
fan_proc_open(struct inode * inode,struct file * file)1661936c8bcdSAlexey Dobriyan static int fan_proc_open(struct inode *inode, struct file *file)
1662b4f9fe12SLen Brown {
1663359745d7SMuchun Song return single_open(file, fan_proc_show, pde_data(inode));
1664936c8bcdSAlexey Dobriyan }
1665936c8bcdSAlexey Dobriyan
fan_proc_write(struct file * file,const char __user * buf,size_t count,loff_t * pos)1666936c8bcdSAlexey Dobriyan static ssize_t fan_proc_write(struct file *file, const char __user *buf,
1667936c8bcdSAlexey Dobriyan size_t count, loff_t *pos)
1668936c8bcdSAlexey Dobriyan {
1669359745d7SMuchun Song struct toshiba_acpi_dev *dev = pde_data(file_inode(file));
1670936c8bcdSAlexey Dobriyan char cmd[42];
1671936c8bcdSAlexey Dobriyan size_t len;
1672b4f9fe12SLen Brown int value;
1673b4f9fe12SLen Brown
1674936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1);
1675936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len))
1676936c8bcdSAlexey Dobriyan return -EFAULT;
1677936c8bcdSAlexey Dobriyan cmd[len] = '\0';
1678936c8bcdSAlexey Dobriyan
16793e07e5baSAzael Avalos if (sscanf(cmd, " force_on : %i", &value) != 1 &&
16803e07e5baSAzael Avalos value != 0 && value != 1)
1681b4f9fe12SLen Brown return -EINVAL;
16823e07e5baSAzael Avalos
16833e07e5baSAzael Avalos if (set_fan_status(dev, value))
16843e07e5baSAzael Avalos return -EIO;
16853e07e5baSAzael Avalos
16863e07e5baSAzael Avalos dev->force_fan = value;
1687b4f9fe12SLen Brown
1688b4f9fe12SLen Brown return count;
1689b4f9fe12SLen Brown }
1690b4f9fe12SLen Brown
169197a32539SAlexey Dobriyan static const struct proc_ops fan_proc_ops = {
169297a32539SAlexey Dobriyan .proc_open = fan_proc_open,
169397a32539SAlexey Dobriyan .proc_read = seq_read,
169497a32539SAlexey Dobriyan .proc_lseek = seq_lseek,
169597a32539SAlexey Dobriyan .proc_release = single_release,
169697a32539SAlexey Dobriyan .proc_write = fan_proc_write,
1697936c8bcdSAlexey Dobriyan };
1698936c8bcdSAlexey Dobriyan
1699dd193dcdSArvid Norlander /* Fan RPM */
get_fan_rpm(struct toshiba_acpi_dev * dev,u32 * rpm)1700dd193dcdSArvid Norlander static int get_fan_rpm(struct toshiba_acpi_dev *dev, u32 *rpm)
1701dd193dcdSArvid Norlander {
1702dd193dcdSArvid Norlander u32 in[TCI_WORDS] = { HCI_GET, HCI_FAN_RPM, 0, 1, 0, 0 };
1703dd193dcdSArvid Norlander u32 out[TCI_WORDS];
1704dd193dcdSArvid Norlander acpi_status status = tci_raw(dev, in, out);
1705dd193dcdSArvid Norlander
1706dd193dcdSArvid Norlander if (ACPI_FAILURE(status)) {
1707dd193dcdSArvid Norlander pr_err("ACPI call to get Fan speed failed\n");
1708dd193dcdSArvid Norlander return -EIO;
1709dd193dcdSArvid Norlander }
1710dd193dcdSArvid Norlander
1711dd193dcdSArvid Norlander if (out[0] == TOS_NOT_SUPPORTED)
1712dd193dcdSArvid Norlander return -ENODEV;
1713dd193dcdSArvid Norlander
1714dd193dcdSArvid Norlander if (out[0] == TOS_SUCCESS) {
1715dd193dcdSArvid Norlander *rpm = out[2];
1716dd193dcdSArvid Norlander return 0;
1717dd193dcdSArvid Norlander }
1718dd193dcdSArvid Norlander
1719dd193dcdSArvid Norlander return -EIO;
1720dd193dcdSArvid Norlander }
1721dd193dcdSArvid Norlander
keys_proc_show(struct seq_file * m,void * v)1722936c8bcdSAlexey Dobriyan static int keys_proc_show(struct seq_file *m, void *v)
1723b4f9fe12SLen Brown {
1724135740deSSeth Forshee struct toshiba_acpi_dev *dev = m->private;
1725b4f9fe12SLen Brown
1726135740deSSeth Forshee seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid);
1727135740deSSeth Forshee seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event);
17287deef550SAzael Avalos
1729936c8bcdSAlexey Dobriyan return 0;
1730b4f9fe12SLen Brown }
1731b4f9fe12SLen Brown
keys_proc_open(struct inode * inode,struct file * file)1732936c8bcdSAlexey Dobriyan static int keys_proc_open(struct inode *inode, struct file *file)
1733b4f9fe12SLen Brown {
1734359745d7SMuchun Song return single_open(file, keys_proc_show, pde_data(inode));
1735936c8bcdSAlexey Dobriyan }
1736936c8bcdSAlexey Dobriyan
keys_proc_write(struct file * file,const char __user * buf,size_t count,loff_t * pos)1737936c8bcdSAlexey Dobriyan static ssize_t keys_proc_write(struct file *file, const char __user *buf,
1738936c8bcdSAlexey Dobriyan size_t count, loff_t *pos)
1739936c8bcdSAlexey Dobriyan {
1740359745d7SMuchun Song struct toshiba_acpi_dev *dev = pde_data(file_inode(file));
1741936c8bcdSAlexey Dobriyan char cmd[42];
1742936c8bcdSAlexey Dobriyan size_t len;
1743b4f9fe12SLen Brown int value;
1744b4f9fe12SLen Brown
1745936c8bcdSAlexey Dobriyan len = min(count, sizeof(cmd) - 1);
1746936c8bcdSAlexey Dobriyan if (copy_from_user(cmd, buf, len))
1747936c8bcdSAlexey Dobriyan return -EFAULT;
1748936c8bcdSAlexey Dobriyan cmd[len] = '\0';
1749936c8bcdSAlexey Dobriyan
1750b5163992SAzael Avalos if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0)
1751135740deSSeth Forshee dev->key_event_valid = 0;
1752b5163992SAzael Avalos else
1753b4f9fe12SLen Brown return -EINVAL;
1754b4f9fe12SLen Brown
1755b4f9fe12SLen Brown return count;
1756b4f9fe12SLen Brown }
1757b4f9fe12SLen Brown
175897a32539SAlexey Dobriyan static const struct proc_ops keys_proc_ops = {
175997a32539SAlexey Dobriyan .proc_open = keys_proc_open,
176097a32539SAlexey Dobriyan .proc_read = seq_read,
176197a32539SAlexey Dobriyan .proc_lseek = seq_lseek,
176297a32539SAlexey Dobriyan .proc_release = single_release,
176397a32539SAlexey Dobriyan .proc_write = keys_proc_write,
1764936c8bcdSAlexey Dobriyan };
1765936c8bcdSAlexey Dobriyan
version_proc_show(struct seq_file * m,void * v)1766c2e2a618SRandy Dunlap static int __maybe_unused version_proc_show(struct seq_file *m, void *v)
1767b4f9fe12SLen Brown {
1768936c8bcdSAlexey Dobriyan seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION);
1769936c8bcdSAlexey Dobriyan seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION);
1770936c8bcdSAlexey Dobriyan return 0;
1771b4f9fe12SLen Brown }
1772b4f9fe12SLen Brown
1773e0769fe6SDarren Hart /*
1774e0769fe6SDarren Hart * Proc and module init
1775b4f9fe12SLen Brown */
1776b4f9fe12SLen Brown
1777b4f9fe12SLen Brown #define PROC_TOSHIBA "toshiba"
1778b4f9fe12SLen Brown
create_toshiba_proc_entries(struct toshiba_acpi_dev * dev)1779b859f159SGreg Kroah-Hartman static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
1780b4f9fe12SLen Brown {
178136d03f93SSeth Forshee if (dev->backlight_dev)
1782135740deSSeth Forshee proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir,
178397a32539SAlexey Dobriyan &lcd_proc_ops, dev);
178436d03f93SSeth Forshee if (dev->video_supported)
1785135740deSSeth Forshee proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir,
178697a32539SAlexey Dobriyan &video_proc_ops, dev);
178736d03f93SSeth Forshee if (dev->fan_supported)
1788135740deSSeth Forshee proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir,
178997a32539SAlexey Dobriyan &fan_proc_ops, dev);
179036d03f93SSeth Forshee if (dev->hotkey_dev)
1791135740deSSeth Forshee proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir,
179297a32539SAlexey Dobriyan &keys_proc_ops, dev);
17933f3942acSChristoph Hellwig proc_create_single_data("version", S_IRUGO, toshiba_proc_dir,
17943f3942acSChristoph Hellwig version_proc_show, dev);
1795b4f9fe12SLen Brown }
1796b4f9fe12SLen Brown
remove_toshiba_proc_entries(struct toshiba_acpi_dev * dev)179736d03f93SSeth Forshee static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
1798b4f9fe12SLen Brown {
179936d03f93SSeth Forshee if (dev->backlight_dev)
1800936c8bcdSAlexey Dobriyan remove_proc_entry("lcd", toshiba_proc_dir);
180136d03f93SSeth Forshee if (dev->video_supported)
1802936c8bcdSAlexey Dobriyan remove_proc_entry("video", toshiba_proc_dir);
180336d03f93SSeth Forshee if (dev->fan_supported)
1804936c8bcdSAlexey Dobriyan remove_proc_entry("fan", toshiba_proc_dir);
180536d03f93SSeth Forshee if (dev->hotkey_dev)
1806936c8bcdSAlexey Dobriyan remove_proc_entry("keys", toshiba_proc_dir);
1807936c8bcdSAlexey Dobriyan remove_proc_entry("version", toshiba_proc_dir);
1808b4f9fe12SLen Brown }
1809b4f9fe12SLen Brown
1810acc2472eSLionel Debroux static const struct backlight_ops toshiba_backlight_data = {
1811121b7b0dSAkio Idehara .options = BL_CORE_SUSPENDRESUME,
181262cce752SSeth Forshee .get_brightness = get_lcd_brightness,
1813b4f9fe12SLen Brown .update_status = set_lcd_status,
1814b4f9fe12SLen Brown };
1815b4f9fe12SLen Brown
181665e3cf9cSAzael Avalos /* Keyboard backlight work */
181765e3cf9cSAzael Avalos static void toshiba_acpi_kbd_bl_work(struct work_struct *work);
181865e3cf9cSAzael Avalos
181965e3cf9cSAzael Avalos static DECLARE_WORK(kbd_bl_work, toshiba_acpi_kbd_bl_work);
182065e3cf9cSAzael Avalos
1821360f0f39SAzael Avalos /*
1822360f0f39SAzael Avalos * Sysfs files
1823360f0f39SAzael Avalos */
18243182459bSLukas Wunner static DEVICE_STRING_ATTR_RO(version, 0444, TOSHIBA_ACPI_VERSION);
1825c6c68ff8SAzael Avalos
fan_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)18269d309848SAzael Avalos static ssize_t fan_store(struct device *dev,
182794477d4cSAzael Avalos struct device_attribute *attr,
182894477d4cSAzael Avalos const char *buf, size_t count)
182994477d4cSAzael Avalos {
183094477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
183194477d4cSAzael Avalos int state;
183294477d4cSAzael Avalos int ret;
183394477d4cSAzael Avalos
183494477d4cSAzael Avalos ret = kstrtoint(buf, 0, &state);
183594477d4cSAzael Avalos if (ret)
183694477d4cSAzael Avalos return ret;
183794477d4cSAzael Avalos
183894477d4cSAzael Avalos if (state != 0 && state != 1)
183994477d4cSAzael Avalos return -EINVAL;
184094477d4cSAzael Avalos
18413e07e5baSAzael Avalos ret = set_fan_status(toshiba, state);
18423e07e5baSAzael Avalos if (ret)
18433e07e5baSAzael Avalos return ret;
184494477d4cSAzael Avalos
184594477d4cSAzael Avalos return count;
184694477d4cSAzael Avalos }
184794477d4cSAzael Avalos
fan_show(struct device * dev,struct device_attribute * attr,char * buf)18489d309848SAzael Avalos static ssize_t fan_show(struct device *dev,
184994477d4cSAzael Avalos struct device_attribute *attr, char *buf)
185094477d4cSAzael Avalos {
185194477d4cSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
185294477d4cSAzael Avalos u32 value;
185394477d4cSAzael Avalos int ret;
185494477d4cSAzael Avalos
185594477d4cSAzael Avalos ret = get_fan_status(toshiba, &value);
185694477d4cSAzael Avalos if (ret)
185794477d4cSAzael Avalos return ret;
185894477d4cSAzael Avalos
185994477d4cSAzael Avalos return sprintf(buf, "%d\n", value);
186094477d4cSAzael Avalos }
18610c3c0f10SAzael Avalos static DEVICE_ATTR_RW(fan);
186294477d4cSAzael Avalos
kbd_backlight_mode_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)18639d309848SAzael Avalos static ssize_t kbd_backlight_mode_store(struct device *dev,
1864360f0f39SAzael Avalos struct device_attribute *attr,
1865360f0f39SAzael Avalos const char *buf, size_t count)
1866360f0f39SAzael Avalos {
1867360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1868aeaac098SDan Carpenter int mode;
1869aeaac098SDan Carpenter int ret;
1870360f0f39SAzael Avalos
1871aeaac098SDan Carpenter
1872aeaac098SDan Carpenter ret = kstrtoint(buf, 0, &mode);
1873aeaac098SDan Carpenter if (ret)
1874aeaac098SDan Carpenter return ret;
187593f8c16dSAzael Avalos
187693f8c16dSAzael Avalos /* Check for supported modes depending on keyboard backlight type */
187793f8c16dSAzael Avalos if (toshiba->kbd_type == 1) {
187893f8c16dSAzael Avalos /* Type 1 supports SCI_KBD_MODE_FNZ and SCI_KBD_MODE_AUTO */
1879aeaac098SDan Carpenter if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO)
1880360f0f39SAzael Avalos return -EINVAL;
188193f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) {
188293f8c16dSAzael Avalos /* Type 2 doesn't support SCI_KBD_MODE_FNZ */
188393f8c16dSAzael Avalos if (mode != SCI_KBD_MODE_AUTO && mode != SCI_KBD_MODE_ON &&
188493f8c16dSAzael Avalos mode != SCI_KBD_MODE_OFF)
188593f8c16dSAzael Avalos return -EINVAL;
188693f8c16dSAzael Avalos }
1887360f0f39SAzael Avalos
1888e0769fe6SDarren Hart /*
1889e0769fe6SDarren Hart * Set the Keyboard Backlight Mode where:
1890360f0f39SAzael Avalos * Auto - KBD backlight turns off automatically in given time
1891360f0f39SAzael Avalos * FN-Z - KBD backlight "toggles" when hotkey pressed
189293f8c16dSAzael Avalos * ON - KBD backlight is always on
189393f8c16dSAzael Avalos * OFF - KBD backlight is always off
1894360f0f39SAzael Avalos */
189593f8c16dSAzael Avalos
189693f8c16dSAzael Avalos /* Only make a change if the actual mode has changed */
1897aeaac098SDan Carpenter if (toshiba->kbd_mode != mode) {
189893f8c16dSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */
18991e574dbfSAzael Avalos int time = toshiba->kbd_time << HCI_MISC_SHIFT;
190093f8c16dSAzael Avalos
190193f8c16dSAzael Avalos /* OR the "base time" to the actual method format */
190293f8c16dSAzael Avalos if (toshiba->kbd_type == 1) {
190393f8c16dSAzael Avalos /* Type 1 requires the current mode */
190493f8c16dSAzael Avalos time |= toshiba->kbd_mode;
190593f8c16dSAzael Avalos } else if (toshiba->kbd_type == 2) {
190693f8c16dSAzael Avalos /* Type 2 requires the desired mode */
190793f8c16dSAzael Avalos time |= mode;
190893f8c16dSAzael Avalos }
190993f8c16dSAzael Avalos
1910aeaac098SDan Carpenter ret = toshiba_kbd_illum_status_set(toshiba, time);
1911aeaac098SDan Carpenter if (ret)
1912aeaac098SDan Carpenter return ret;
191393f8c16dSAzael Avalos
1914360f0f39SAzael Avalos toshiba->kbd_mode = mode;
1915147288e6SAzael Avalos toshiba_acpi->kbd_mode = mode;
191665e3cf9cSAzael Avalos
191765e3cf9cSAzael Avalos /*
191865e3cf9cSAzael Avalos * Some laptop models with the second generation backlit
191965e3cf9cSAzael Avalos * keyboard (type 2) do not generate the keyboard backlight
192065e3cf9cSAzael Avalos * changed event (0x92), and thus, the driver will never update
192165e3cf9cSAzael Avalos * the sysfs entries.
192265e3cf9cSAzael Avalos *
192365e3cf9cSAzael Avalos * The event is generated right when changing the keyboard
192465e3cf9cSAzael Avalos * backlight mode and the *notify function will set the
192565e3cf9cSAzael Avalos * kbd_event_generated to true.
192665e3cf9cSAzael Avalos *
192765e3cf9cSAzael Avalos * In case the event is not generated, schedule the keyboard
192865e3cf9cSAzael Avalos * backlight work to update the sysfs entries and emulate the
192965e3cf9cSAzael Avalos * event via genetlink.
193065e3cf9cSAzael Avalos */
193165e3cf9cSAzael Avalos if (toshiba->kbd_type == 2 &&
1932147288e6SAzael Avalos !toshiba->kbd_event_generated)
193365e3cf9cSAzael Avalos schedule_work(&kbd_bl_work);
1934360f0f39SAzael Avalos }
1935360f0f39SAzael Avalos
1936360f0f39SAzael Avalos return count;
1937360f0f39SAzael Avalos }
1938360f0f39SAzael Avalos
kbd_backlight_mode_show(struct device * dev,struct device_attribute * attr,char * buf)19399d309848SAzael Avalos static ssize_t kbd_backlight_mode_show(struct device *dev,
1940360f0f39SAzael Avalos struct device_attribute *attr,
1941360f0f39SAzael Avalos char *buf)
1942360f0f39SAzael Avalos {
1943360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1944360f0f39SAzael Avalos u32 time;
1945360f0f39SAzael Avalos
1946360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0)
1947360f0f39SAzael Avalos return -EIO;
1948360f0f39SAzael Avalos
194993f8c16dSAzael Avalos return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK);
195093f8c16dSAzael Avalos }
19510c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_mode);
195293f8c16dSAzael Avalos
kbd_type_show(struct device * dev,struct device_attribute * attr,char * buf)19539d309848SAzael Avalos static ssize_t kbd_type_show(struct device *dev,
19549d309848SAzael Avalos struct device_attribute *attr, char *buf)
195593f8c16dSAzael Avalos {
195693f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
195793f8c16dSAzael Avalos
195893f8c16dSAzael Avalos return sprintf(buf, "%d\n", toshiba->kbd_type);
195993f8c16dSAzael Avalos }
19600c3c0f10SAzael Avalos static DEVICE_ATTR_RO(kbd_type);
196193f8c16dSAzael Avalos
available_kbd_modes_show(struct device * dev,struct device_attribute * attr,char * buf)19629d309848SAzael Avalos static ssize_t available_kbd_modes_show(struct device *dev,
196393f8c16dSAzael Avalos struct device_attribute *attr,
196493f8c16dSAzael Avalos char *buf)
196593f8c16dSAzael Avalos {
196693f8c16dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
196793f8c16dSAzael Avalos
196893f8c16dSAzael Avalos if (toshiba->kbd_type == 1)
19690b498201SAzael Avalos return sprintf(buf, "0x%x 0x%x\n",
197093f8c16dSAzael Avalos SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO);
197193f8c16dSAzael Avalos
19720b498201SAzael Avalos return sprintf(buf, "0x%x 0x%x 0x%x\n",
197393f8c16dSAzael Avalos SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF);
1974360f0f39SAzael Avalos }
19750c3c0f10SAzael Avalos static DEVICE_ATTR_RO(available_kbd_modes);
1976360f0f39SAzael Avalos
kbd_backlight_timeout_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)19779d309848SAzael Avalos static ssize_t kbd_backlight_timeout_store(struct device *dev,
1978360f0f39SAzael Avalos struct device_attribute *attr,
1979360f0f39SAzael Avalos const char *buf, size_t count)
1980360f0f39SAzael Avalos {
1981360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1982eabde0faSAzael Avalos int time;
1983eabde0faSAzael Avalos int ret;
1984360f0f39SAzael Avalos
1985eabde0faSAzael Avalos ret = kstrtoint(buf, 0, &time);
1986eabde0faSAzael Avalos if (ret)
1987eabde0faSAzael Avalos return ret;
1988eabde0faSAzael Avalos
1989eabde0faSAzael Avalos /* Check for supported values depending on kbd_type */
1990eabde0faSAzael Avalos if (toshiba->kbd_type == 1) {
1991eabde0faSAzael Avalos if (time < 0 || time > 60)
1992360f0f39SAzael Avalos return -EINVAL;
1993eabde0faSAzael Avalos } else if (toshiba->kbd_type == 2) {
1994eabde0faSAzael Avalos if (time < 1 || time > 60)
1995eabde0faSAzael Avalos return -EINVAL;
1996eabde0faSAzael Avalos }
1997360f0f39SAzael Avalos
1998eabde0faSAzael Avalos /* Set the Keyboard Backlight Timeout */
1999eabde0faSAzael Avalos
2000eabde0faSAzael Avalos /* Only make a change if the actual timeout has changed */
2001eabde0faSAzael Avalos if (toshiba->kbd_time != time) {
2002eabde0faSAzael Avalos /* Shift the time to "base time" (0x3c0000 == 60 seconds) */
2003360f0f39SAzael Avalos time = time << HCI_MISC_SHIFT;
2004eabde0faSAzael Avalos /* OR the "base time" to the actual method format */
2005eabde0faSAzael Avalos if (toshiba->kbd_type == 1)
2006eabde0faSAzael Avalos time |= SCI_KBD_MODE_FNZ;
2007eabde0faSAzael Avalos else if (toshiba->kbd_type == 2)
2008eabde0faSAzael Avalos time |= SCI_KBD_MODE_AUTO;
2009eabde0faSAzael Avalos
2010eabde0faSAzael Avalos ret = toshiba_kbd_illum_status_set(toshiba, time);
2011eabde0faSAzael Avalos if (ret)
2012eabde0faSAzael Avalos return ret;
2013eabde0faSAzael Avalos
2014360f0f39SAzael Avalos toshiba->kbd_time = time >> HCI_MISC_SHIFT;
2015360f0f39SAzael Avalos }
2016360f0f39SAzael Avalos
2017360f0f39SAzael Avalos return count;
2018360f0f39SAzael Avalos }
2019360f0f39SAzael Avalos
kbd_backlight_timeout_show(struct device * dev,struct device_attribute * attr,char * buf)20209d309848SAzael Avalos static ssize_t kbd_backlight_timeout_show(struct device *dev,
2021360f0f39SAzael Avalos struct device_attribute *attr,
2022360f0f39SAzael Avalos char *buf)
2023360f0f39SAzael Avalos {
2024360f0f39SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2025360f0f39SAzael Avalos u32 time;
2026360f0f39SAzael Avalos
2027360f0f39SAzael Avalos if (toshiba_kbd_illum_status_get(toshiba, &time) < 0)
2028360f0f39SAzael Avalos return -EIO;
2029360f0f39SAzael Avalos
2030360f0f39SAzael Avalos return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT);
2031360f0f39SAzael Avalos }
20320c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_backlight_timeout);
2033360f0f39SAzael Avalos
touchpad_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)20349d309848SAzael Avalos static ssize_t touchpad_store(struct device *dev,
20359d8658acSAzael Avalos struct device_attribute *attr,
20369d8658acSAzael Avalos const char *buf, size_t count)
20379d8658acSAzael Avalos {
20389d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
20399d8658acSAzael Avalos int state;
2040c8a41669SAzael Avalos int ret;
20419d8658acSAzael Avalos
20429d8658acSAzael Avalos /* Set the TouchPad on/off, 0 - Disable | 1 - Enable */
2043c8a41669SAzael Avalos ret = kstrtoint(buf, 0, &state);
2044c8a41669SAzael Avalos if (ret)
2045c8a41669SAzael Avalos return ret;
2046c8a41669SAzael Avalos if (state != 0 && state != 1)
2047c8a41669SAzael Avalos return -EINVAL;
2048c8a41669SAzael Avalos
2049c8a41669SAzael Avalos ret = toshiba_touchpad_set(toshiba, state);
2050c8a41669SAzael Avalos if (ret)
2051c8a41669SAzael Avalos return ret;
20529d8658acSAzael Avalos
20539d8658acSAzael Avalos return count;
20549d8658acSAzael Avalos }
20559d8658acSAzael Avalos
touchpad_show(struct device * dev,struct device_attribute * attr,char * buf)20569d309848SAzael Avalos static ssize_t touchpad_show(struct device *dev,
20579d8658acSAzael Avalos struct device_attribute *attr, char *buf)
20589d8658acSAzael Avalos {
20599d8658acSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
20609d8658acSAzael Avalos u32 state;
20619d8658acSAzael Avalos int ret;
20629d8658acSAzael Avalos
20639d8658acSAzael Avalos ret = toshiba_touchpad_get(toshiba, &state);
20649d8658acSAzael Avalos if (ret < 0)
20659d8658acSAzael Avalos return ret;
20669d8658acSAzael Avalos
20679d8658acSAzael Avalos return sprintf(buf, "%i\n", state);
20689d8658acSAzael Avalos }
20690c3c0f10SAzael Avalos static DEVICE_ATTR_RW(touchpad);
20709d8658acSAzael Avalos
usb_sleep_charge_show(struct device * dev,struct device_attribute * attr,char * buf)20719d309848SAzael Avalos static ssize_t usb_sleep_charge_show(struct device *dev,
20729d309848SAzael Avalos struct device_attribute *attr, char *buf)
2073e26ffe51SAzael Avalos {
2074e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2075e26ffe51SAzael Avalos u32 mode;
2076e26ffe51SAzael Avalos int ret;
2077e26ffe51SAzael Avalos
2078e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_get(toshiba, &mode);
2079e26ffe51SAzael Avalos if (ret < 0)
2080e26ffe51SAzael Avalos return ret;
2081e26ffe51SAzael Avalos
2082e26ffe51SAzael Avalos return sprintf(buf, "%x\n", mode & SCI_USB_CHARGE_MODE_MASK);
2083e26ffe51SAzael Avalos }
2084e26ffe51SAzael Avalos
usb_sleep_charge_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)20859d309848SAzael Avalos static ssize_t usb_sleep_charge_store(struct device *dev,
2086e26ffe51SAzael Avalos struct device_attribute *attr,
2087e26ffe51SAzael Avalos const char *buf, size_t count)
2088e26ffe51SAzael Avalos {
2089e26ffe51SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2090e26ffe51SAzael Avalos int state;
209178429e55SAzael Avalos u32 mode;
2092e26ffe51SAzael Avalos int ret;
2093e26ffe51SAzael Avalos
2094e26ffe51SAzael Avalos ret = kstrtoint(buf, 0, &state);
2095e26ffe51SAzael Avalos if (ret)
2096e26ffe51SAzael Avalos return ret;
2097e0769fe6SDarren Hart /*
2098e0769fe6SDarren Hart * Check for supported values, where:
2099e26ffe51SAzael Avalos * 0 - Disabled
2100e26ffe51SAzael Avalos * 1 - Alternate (Non USB conformant devices that require more power)
2101e26ffe51SAzael Avalos * 2 - Auto (USB conformant devices)
2102c8c91842SAzael Avalos * 3 - Typical
2103e26ffe51SAzael Avalos */
2104c8c91842SAzael Avalos if (state != 0 && state != 1 && state != 2 && state != 3)
2105e26ffe51SAzael Avalos return -EINVAL;
2106e26ffe51SAzael Avalos
2107e26ffe51SAzael Avalos /* Set the USB charging mode to internal value */
2108c8c91842SAzael Avalos mode = toshiba->usbsc_mode_base;
2109e26ffe51SAzael Avalos if (state == 0)
2110c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_DISABLED;
2111e26ffe51SAzael Avalos else if (state == 1)
2112c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_ALTERNATE;
2113e26ffe51SAzael Avalos else if (state == 2)
2114c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_AUTO;
2115c8c91842SAzael Avalos else if (state == 3)
2116c8c91842SAzael Avalos mode |= SCI_USB_CHARGE_TYPICAL;
2117e26ffe51SAzael Avalos
2118e26ffe51SAzael Avalos ret = toshiba_usb_sleep_charge_set(toshiba, mode);
2119e26ffe51SAzael Avalos if (ret)
2120e26ffe51SAzael Avalos return ret;
2121e26ffe51SAzael Avalos
2122e26ffe51SAzael Avalos return count;
2123e26ffe51SAzael Avalos }
21240c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_charge);
2125e26ffe51SAzael Avalos
sleep_functions_on_battery_show(struct device * dev,struct device_attribute * attr,char * buf)2126182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_show(struct device *dev,
2127182bcaa5SAzael Avalos struct device_attribute *attr,
2128182bcaa5SAzael Avalos char *buf)
2129182bcaa5SAzael Avalos {
2130182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
213178429e55SAzael Avalos int bat_lvl, status;
2132182bcaa5SAzael Avalos u32 state;
2133182bcaa5SAzael Avalos int ret;
2134182bcaa5SAzael Avalos int tmp;
2135182bcaa5SAzael Avalos
2136182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_get(toshiba, &state);
2137182bcaa5SAzael Avalos if (ret < 0)
2138182bcaa5SAzael Avalos return ret;
2139182bcaa5SAzael Avalos
2140182bcaa5SAzael Avalos /* Determine the status: 0x4 - Enabled | 0x1 - Disabled */
2141182bcaa5SAzael Avalos tmp = state & SCI_USB_CHARGE_BAT_MASK;
2142182bcaa5SAzael Avalos status = (tmp == 0x4) ? 1 : 0;
2143182bcaa5SAzael Avalos /* Determine the battery level set */
2144182bcaa5SAzael Avalos bat_lvl = state >> HCI_MISC_SHIFT;
2145182bcaa5SAzael Avalos
2146182bcaa5SAzael Avalos return sprintf(buf, "%d %d\n", status, bat_lvl);
2147182bcaa5SAzael Avalos }
2148182bcaa5SAzael Avalos
sleep_functions_on_battery_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)2149182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_store(struct device *dev,
2150182bcaa5SAzael Avalos struct device_attribute *attr,
2151182bcaa5SAzael Avalos const char *buf, size_t count)
2152182bcaa5SAzael Avalos {
2153182bcaa5SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2154182bcaa5SAzael Avalos u32 status;
2155182bcaa5SAzael Avalos int value;
2156182bcaa5SAzael Avalos int ret;
2157182bcaa5SAzael Avalos int tmp;
2158182bcaa5SAzael Avalos
2159182bcaa5SAzael Avalos ret = kstrtoint(buf, 0, &value);
2160182bcaa5SAzael Avalos if (ret)
2161182bcaa5SAzael Avalos return ret;
2162182bcaa5SAzael Avalos
2163e0769fe6SDarren Hart /*
2164e0769fe6SDarren Hart * Set the status of the function:
2165182bcaa5SAzael Avalos * 0 - Disabled
2166182bcaa5SAzael Avalos * 1-100 - Enabled
2167182bcaa5SAzael Avalos */
2168182bcaa5SAzael Avalos if (value < 0 || value > 100)
2169182bcaa5SAzael Avalos return -EINVAL;
2170182bcaa5SAzael Avalos
2171182bcaa5SAzael Avalos if (value == 0) {
2172182bcaa5SAzael Avalos tmp = toshiba->usbsc_bat_level << HCI_MISC_SHIFT;
2173182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_OFF;
2174182bcaa5SAzael Avalos } else {
2175182bcaa5SAzael Avalos tmp = value << HCI_MISC_SHIFT;
2176182bcaa5SAzael Avalos status = tmp | SCI_USB_CHARGE_BAT_LVL_ON;
2177182bcaa5SAzael Avalos }
2178182bcaa5SAzael Avalos ret = toshiba_sleep_functions_status_set(toshiba, status);
2179182bcaa5SAzael Avalos if (ret < 0)
2180182bcaa5SAzael Avalos return ret;
2181182bcaa5SAzael Avalos
2182182bcaa5SAzael Avalos toshiba->usbsc_bat_level = status >> HCI_MISC_SHIFT;
2183182bcaa5SAzael Avalos
2184182bcaa5SAzael Avalos return count;
2185182bcaa5SAzael Avalos }
21860c3c0f10SAzael Avalos static DEVICE_ATTR_RW(sleep_functions_on_battery);
2187182bcaa5SAzael Avalos
usb_rapid_charge_show(struct device * dev,struct device_attribute * attr,char * buf)21889d309848SAzael Avalos static ssize_t usb_rapid_charge_show(struct device *dev,
21899d309848SAzael Avalos struct device_attribute *attr, char *buf)
2190bb3fe01fSAzael Avalos {
2191bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2192bb3fe01fSAzael Avalos u32 state;
2193bb3fe01fSAzael Avalos int ret;
2194bb3fe01fSAzael Avalos
2195bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(toshiba, &state);
2196bb3fe01fSAzael Avalos if (ret < 0)
2197bb3fe01fSAzael Avalos return ret;
2198bb3fe01fSAzael Avalos
2199bb3fe01fSAzael Avalos return sprintf(buf, "%d\n", state);
2200bb3fe01fSAzael Avalos }
2201bb3fe01fSAzael Avalos
usb_rapid_charge_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)22029d309848SAzael Avalos static ssize_t usb_rapid_charge_store(struct device *dev,
2203bb3fe01fSAzael Avalos struct device_attribute *attr,
2204bb3fe01fSAzael Avalos const char *buf, size_t count)
2205bb3fe01fSAzael Avalos {
2206bb3fe01fSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2207bb3fe01fSAzael Avalos int state;
2208bb3fe01fSAzael Avalos int ret;
2209bb3fe01fSAzael Avalos
2210bb3fe01fSAzael Avalos ret = kstrtoint(buf, 0, &state);
2211bb3fe01fSAzael Avalos if (ret)
2212bb3fe01fSAzael Avalos return ret;
2213bb3fe01fSAzael Avalos if (state != 0 && state != 1)
2214bb3fe01fSAzael Avalos return -EINVAL;
2215bb3fe01fSAzael Avalos
2216bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_set(toshiba, state);
2217bb3fe01fSAzael Avalos if (ret)
2218bb3fe01fSAzael Avalos return ret;
2219bb3fe01fSAzael Avalos
2220bb3fe01fSAzael Avalos return count;
2221bb3fe01fSAzael Avalos }
22220c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_rapid_charge);
2223bb3fe01fSAzael Avalos
usb_sleep_music_show(struct device * dev,struct device_attribute * attr,char * buf)22249d309848SAzael Avalos static ssize_t usb_sleep_music_show(struct device *dev,
22259d309848SAzael Avalos struct device_attribute *attr, char *buf)
2226172ce0a9SAzael Avalos {
2227172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2228172ce0a9SAzael Avalos u32 state;
2229172ce0a9SAzael Avalos int ret;
2230172ce0a9SAzael Avalos
2231172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(toshiba, &state);
2232172ce0a9SAzael Avalos if (ret < 0)
2233172ce0a9SAzael Avalos return ret;
2234172ce0a9SAzael Avalos
2235172ce0a9SAzael Avalos return sprintf(buf, "%d\n", state);
2236172ce0a9SAzael Avalos }
2237172ce0a9SAzael Avalos
usb_sleep_music_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)22389d309848SAzael Avalos static ssize_t usb_sleep_music_store(struct device *dev,
2239172ce0a9SAzael Avalos struct device_attribute *attr,
2240172ce0a9SAzael Avalos const char *buf, size_t count)
2241172ce0a9SAzael Avalos {
2242172ce0a9SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2243172ce0a9SAzael Avalos int state;
2244172ce0a9SAzael Avalos int ret;
2245172ce0a9SAzael Avalos
2246172ce0a9SAzael Avalos ret = kstrtoint(buf, 0, &state);
2247172ce0a9SAzael Avalos if (ret)
2248172ce0a9SAzael Avalos return ret;
2249172ce0a9SAzael Avalos if (state != 0 && state != 1)
2250172ce0a9SAzael Avalos return -EINVAL;
2251172ce0a9SAzael Avalos
2252172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_set(toshiba, state);
2253172ce0a9SAzael Avalos if (ret)
2254172ce0a9SAzael Avalos return ret;
2255172ce0a9SAzael Avalos
2256172ce0a9SAzael Avalos return count;
2257172ce0a9SAzael Avalos }
22580c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_sleep_music);
2259172ce0a9SAzael Avalos
kbd_function_keys_show(struct device * dev,struct device_attribute * attr,char * buf)22609d309848SAzael Avalos static ssize_t kbd_function_keys_show(struct device *dev,
22619d309848SAzael Avalos struct device_attribute *attr, char *buf)
2262bae84195SAzael Avalos {
2263bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2264bae84195SAzael Avalos int mode;
2265bae84195SAzael Avalos int ret;
2266bae84195SAzael Avalos
2267bae84195SAzael Avalos ret = toshiba_function_keys_get(toshiba, &mode);
2268bae84195SAzael Avalos if (ret < 0)
2269bae84195SAzael Avalos return ret;
2270bae84195SAzael Avalos
2271bae84195SAzael Avalos return sprintf(buf, "%d\n", mode);
2272bae84195SAzael Avalos }
2273bae84195SAzael Avalos
kbd_function_keys_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)22749d309848SAzael Avalos static ssize_t kbd_function_keys_store(struct device *dev,
2275bae84195SAzael Avalos struct device_attribute *attr,
2276bae84195SAzael Avalos const char *buf, size_t count)
2277bae84195SAzael Avalos {
2278bae84195SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2279bae84195SAzael Avalos int mode;
2280bae84195SAzael Avalos int ret;
2281bae84195SAzael Avalos
2282bae84195SAzael Avalos ret = kstrtoint(buf, 0, &mode);
2283bae84195SAzael Avalos if (ret)
2284bae84195SAzael Avalos return ret;
2285e0769fe6SDarren Hart /*
2286e0769fe6SDarren Hart * Check for the function keys mode where:
2287bae84195SAzael Avalos * 0 - Normal operation (F{1-12} as usual and hotkeys via FN-F{1-12})
2288bae84195SAzael Avalos * 1 - Special functions (Opposite of the above setting)
2289bae84195SAzael Avalos */
2290bae84195SAzael Avalos if (mode != 0 && mode != 1)
2291bae84195SAzael Avalos return -EINVAL;
2292bae84195SAzael Avalos
2293bae84195SAzael Avalos ret = toshiba_function_keys_set(toshiba, mode);
2294bae84195SAzael Avalos if (ret)
2295bae84195SAzael Avalos return ret;
2296bae84195SAzael Avalos
2297bae84195SAzael Avalos pr_info("Reboot for changes to KBD Function Keys to take effect");
2298bae84195SAzael Avalos
2299bae84195SAzael Avalos return count;
2300bae84195SAzael Avalos }
23010c3c0f10SAzael Avalos static DEVICE_ATTR_RW(kbd_function_keys);
2302bae84195SAzael Avalos
panel_power_on_show(struct device * dev,struct device_attribute * attr,char * buf)23039d309848SAzael Avalos static ssize_t panel_power_on_show(struct device *dev,
23049d309848SAzael Avalos struct device_attribute *attr, char *buf)
230535d53ceaSAzael Avalos {
230635d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
230735d53ceaSAzael Avalos u32 state;
230835d53ceaSAzael Avalos int ret;
230935d53ceaSAzael Avalos
231035d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(toshiba, &state);
231135d53ceaSAzael Avalos if (ret < 0)
231235d53ceaSAzael Avalos return ret;
231335d53ceaSAzael Avalos
231435d53ceaSAzael Avalos return sprintf(buf, "%d\n", state);
231535d53ceaSAzael Avalos }
231635d53ceaSAzael Avalos
panel_power_on_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)23179d309848SAzael Avalos static ssize_t panel_power_on_store(struct device *dev,
231835d53ceaSAzael Avalos struct device_attribute *attr,
231935d53ceaSAzael Avalos const char *buf, size_t count)
232035d53ceaSAzael Avalos {
232135d53ceaSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
232235d53ceaSAzael Avalos int state;
232335d53ceaSAzael Avalos int ret;
232435d53ceaSAzael Avalos
232535d53ceaSAzael Avalos ret = kstrtoint(buf, 0, &state);
232635d53ceaSAzael Avalos if (ret)
232735d53ceaSAzael Avalos return ret;
232835d53ceaSAzael Avalos if (state != 0 && state != 1)
232935d53ceaSAzael Avalos return -EINVAL;
233035d53ceaSAzael Avalos
233135d53ceaSAzael Avalos ret = toshiba_panel_power_on_set(toshiba, state);
233235d53ceaSAzael Avalos if (ret)
233335d53ceaSAzael Avalos return ret;
233435d53ceaSAzael Avalos
233535d53ceaSAzael Avalos pr_info("Reboot for changes to Panel Power ON to take effect");
233635d53ceaSAzael Avalos
233735d53ceaSAzael Avalos return count;
233835d53ceaSAzael Avalos }
23390c3c0f10SAzael Avalos static DEVICE_ATTR_RW(panel_power_on);
234035d53ceaSAzael Avalos
usb_three_show(struct device * dev,struct device_attribute * attr,char * buf)23419d309848SAzael Avalos static ssize_t usb_three_show(struct device *dev,
23429d309848SAzael Avalos struct device_attribute *attr, char *buf)
234317fe4b3dSAzael Avalos {
234417fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
234517fe4b3dSAzael Avalos u32 state;
234617fe4b3dSAzael Avalos int ret;
234717fe4b3dSAzael Avalos
234817fe4b3dSAzael Avalos ret = toshiba_usb_three_get(toshiba, &state);
234917fe4b3dSAzael Avalos if (ret < 0)
235017fe4b3dSAzael Avalos return ret;
235117fe4b3dSAzael Avalos
235217fe4b3dSAzael Avalos return sprintf(buf, "%d\n", state);
235317fe4b3dSAzael Avalos }
235417fe4b3dSAzael Avalos
usb_three_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)23559d309848SAzael Avalos static ssize_t usb_three_store(struct device *dev,
235617fe4b3dSAzael Avalos struct device_attribute *attr,
235717fe4b3dSAzael Avalos const char *buf, size_t count)
235817fe4b3dSAzael Avalos {
235917fe4b3dSAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
236017fe4b3dSAzael Avalos int state;
236117fe4b3dSAzael Avalos int ret;
236217fe4b3dSAzael Avalos
236317fe4b3dSAzael Avalos ret = kstrtoint(buf, 0, &state);
236417fe4b3dSAzael Avalos if (ret)
236517fe4b3dSAzael Avalos return ret;
2366e0769fe6SDarren Hart /*
2367e0769fe6SDarren Hart * Check for USB 3 mode where:
236817fe4b3dSAzael Avalos * 0 - Disabled (Acts like a USB 2 port, saving power)
236917fe4b3dSAzael Avalos * 1 - Enabled
237017fe4b3dSAzael Avalos */
237117fe4b3dSAzael Avalos if (state != 0 && state != 1)
237217fe4b3dSAzael Avalos return -EINVAL;
237317fe4b3dSAzael Avalos
237417fe4b3dSAzael Avalos ret = toshiba_usb_three_set(toshiba, state);
237517fe4b3dSAzael Avalos if (ret)
237617fe4b3dSAzael Avalos return ret;
237717fe4b3dSAzael Avalos
237817fe4b3dSAzael Avalos pr_info("Reboot for changes to USB 3 to take effect");
237917fe4b3dSAzael Avalos
238017fe4b3dSAzael Avalos return count;
238117fe4b3dSAzael Avalos }
23820c3c0f10SAzael Avalos static DEVICE_ATTR_RW(usb_three);
23839bd1213bSAzael Avalos
cooling_method_show(struct device * dev,struct device_attribute * attr,char * buf)2384b1009b91SAzael Avalos static ssize_t cooling_method_show(struct device *dev,
2385b1009b91SAzael Avalos struct device_attribute *attr, char *buf)
2386b1009b91SAzael Avalos {
2387b1009b91SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2388b1009b91SAzael Avalos int state;
2389b1009b91SAzael Avalos int ret;
2390b1009b91SAzael Avalos
2391b1009b91SAzael Avalos ret = toshiba_cooling_method_get(toshiba, &state);
2392b1009b91SAzael Avalos if (ret < 0)
2393b1009b91SAzael Avalos return ret;
2394b1009b91SAzael Avalos
2395b1009b91SAzael Avalos return sprintf(buf, "%d %d\n", state, toshiba->max_cooling_method);
2396b1009b91SAzael Avalos }
2397b1009b91SAzael Avalos
cooling_method_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)2398b1009b91SAzael Avalos static ssize_t cooling_method_store(struct device *dev,
2399b1009b91SAzael Avalos struct device_attribute *attr,
2400b1009b91SAzael Avalos const char *buf, size_t count)
2401b1009b91SAzael Avalos {
2402b1009b91SAzael Avalos struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2403b1009b91SAzael Avalos int state;
2404b1009b91SAzael Avalos int ret;
2405b1009b91SAzael Avalos
2406b1009b91SAzael Avalos ret = kstrtoint(buf, 0, &state);
2407b1009b91SAzael Avalos if (ret)
2408b1009b91SAzael Avalos return ret;
2409b1009b91SAzael Avalos
2410b1009b91SAzael Avalos /*
2411b1009b91SAzael Avalos * Check for supported values
2412b1009b91SAzael Avalos * Depending on the laptop model, some only support these two:
2413b1009b91SAzael Avalos * 0 - Maximum Performance
2414b1009b91SAzael Avalos * 1 - Battery Optimized
2415b1009b91SAzael Avalos *
2416b1009b91SAzael Avalos * While some others support all three methods:
2417b1009b91SAzael Avalos * 0 - Maximum Performance
2418b1009b91SAzael Avalos * 1 - Performance
2419b1009b91SAzael Avalos * 2 - Battery Optimized
2420b1009b91SAzael Avalos */
2421b1009b91SAzael Avalos if (state < 0 || state > toshiba->max_cooling_method)
2422b1009b91SAzael Avalos return -EINVAL;
2423b1009b91SAzael Avalos
2424b1009b91SAzael Avalos ret = toshiba_cooling_method_set(toshiba, state);
2425b1009b91SAzael Avalos if (ret)
2426b1009b91SAzael Avalos return ret;
2427b1009b91SAzael Avalos
2428b1009b91SAzael Avalos return count;
2429b1009b91SAzael Avalos }
2430b1009b91SAzael Avalos static DEVICE_ATTR_RW(cooling_method);
2431b1009b91SAzael Avalos
24329bd1213bSAzael Avalos static struct attribute *toshiba_attributes[] = {
24333182459bSLukas Wunner &dev_attr_version.attr.attr,
24349bd1213bSAzael Avalos &dev_attr_fan.attr,
24359bd1213bSAzael Avalos &dev_attr_kbd_backlight_mode.attr,
24369bd1213bSAzael Avalos &dev_attr_kbd_type.attr,
24379bd1213bSAzael Avalos &dev_attr_available_kbd_modes.attr,
24389bd1213bSAzael Avalos &dev_attr_kbd_backlight_timeout.attr,
24399bd1213bSAzael Avalos &dev_attr_touchpad.attr,
24409bd1213bSAzael Avalos &dev_attr_usb_sleep_charge.attr,
24419bd1213bSAzael Avalos &dev_attr_sleep_functions_on_battery.attr,
24429bd1213bSAzael Avalos &dev_attr_usb_rapid_charge.attr,
24439bd1213bSAzael Avalos &dev_attr_usb_sleep_music.attr,
24449bd1213bSAzael Avalos &dev_attr_kbd_function_keys.attr,
24459bd1213bSAzael Avalos &dev_attr_panel_power_on.attr,
24469bd1213bSAzael Avalos &dev_attr_usb_three.attr,
2447b1009b91SAzael Avalos &dev_attr_cooling_method.attr,
24489bd1213bSAzael Avalos NULL,
24499bd1213bSAzael Avalos };
24509bd1213bSAzael Avalos
toshiba_sysfs_is_visible(struct kobject * kobj,struct attribute * attr,int idx)2451360f0f39SAzael Avalos static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
2452360f0f39SAzael Avalos struct attribute *attr, int idx)
2453360f0f39SAzael Avalos {
245446ecf720SMinghao Chi struct device *dev = kobj_to_dev(kobj);
2455360f0f39SAzael Avalos struct toshiba_acpi_dev *drv = dev_get_drvdata(dev);
2456360f0f39SAzael Avalos bool exists = true;
2457360f0f39SAzael Avalos
245894477d4cSAzael Avalos if (attr == &dev_attr_fan.attr)
245994477d4cSAzael Avalos exists = (drv->fan_supported) ? true : false;
246094477d4cSAzael Avalos else if (attr == &dev_attr_kbd_backlight_mode.attr)
2461360f0f39SAzael Avalos exists = (drv->kbd_illum_supported) ? true : false;
2462360f0f39SAzael Avalos else if (attr == &dev_attr_kbd_backlight_timeout.attr)
2463360f0f39SAzael Avalos exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false;
24649d8658acSAzael Avalos else if (attr == &dev_attr_touchpad.attr)
24659d8658acSAzael Avalos exists = (drv->touchpad_supported) ? true : false;
2466e26ffe51SAzael Avalos else if (attr == &dev_attr_usb_sleep_charge.attr)
2467e26ffe51SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false;
2468182bcaa5SAzael Avalos else if (attr == &dev_attr_sleep_functions_on_battery.attr)
2469182bcaa5SAzael Avalos exists = (drv->usb_sleep_charge_supported) ? true : false;
2470bb3fe01fSAzael Avalos else if (attr == &dev_attr_usb_rapid_charge.attr)
2471bb3fe01fSAzael Avalos exists = (drv->usb_rapid_charge_supported) ? true : false;
2472172ce0a9SAzael Avalos else if (attr == &dev_attr_usb_sleep_music.attr)
2473172ce0a9SAzael Avalos exists = (drv->usb_sleep_music_supported) ? true : false;
2474bae84195SAzael Avalos else if (attr == &dev_attr_kbd_function_keys.attr)
2475bae84195SAzael Avalos exists = (drv->kbd_function_keys_supported) ? true : false;
247635d53ceaSAzael Avalos else if (attr == &dev_attr_panel_power_on.attr)
247735d53ceaSAzael Avalos exists = (drv->panel_power_on_supported) ? true : false;
247817fe4b3dSAzael Avalos else if (attr == &dev_attr_usb_three.attr)
247917fe4b3dSAzael Avalos exists = (drv->usb_three_supported) ? true : false;
2480b1009b91SAzael Avalos else if (attr == &dev_attr_cooling_method.attr)
2481b1009b91SAzael Avalos exists = (drv->cooling_method_supported) ? true : false;
2482360f0f39SAzael Avalos
2483360f0f39SAzael Avalos return exists ? attr->mode : 0;
2484360f0f39SAzael Avalos }
2485360f0f39SAzael Avalos
248644bd76d0SArvind Yadav static const struct attribute_group toshiba_attr_group = {
24879bd1213bSAzael Avalos .is_visible = toshiba_sysfs_is_visible,
24889bd1213bSAzael Avalos .attrs = toshiba_attributes,
24899bd1213bSAzael Avalos };
24909bd1213bSAzael Avalos
toshiba_acpi_kbd_bl_work(struct work_struct * work)249165e3cf9cSAzael Avalos static void toshiba_acpi_kbd_bl_work(struct work_struct *work)
249265e3cf9cSAzael Avalos {
249365e3cf9cSAzael Avalos /* Update the sysfs entries */
2494147288e6SAzael Avalos if (sysfs_update_group(&toshiba_acpi->acpi_dev->dev.kobj,
249565e3cf9cSAzael Avalos &toshiba_attr_group))
249665e3cf9cSAzael Avalos pr_err("Unable to update sysfs entries\n");
249765e3cf9cSAzael Avalos
2498147288e6SAzael Avalos /* Notify LED subsystem about keyboard backlight change */
2499147288e6SAzael Avalos if (toshiba_acpi->kbd_type == 2 &&
2500147288e6SAzael Avalos toshiba_acpi->kbd_mode != SCI_KBD_MODE_AUTO)
2501147288e6SAzael Avalos led_classdev_notify_brightness_hw_changed(&toshiba_acpi->kbd_led,
2502147288e6SAzael Avalos (toshiba_acpi->kbd_mode == SCI_KBD_MODE_ON) ?
2503147288e6SAzael Avalos LED_FULL : LED_OFF);
2504147288e6SAzael Avalos
250565e3cf9cSAzael Avalos /* Emulate the keyboard backlight event */
2506147288e6SAzael Avalos acpi_bus_generate_netlink_event(toshiba_acpi->acpi_dev->pnp.device_class,
2507147288e6SAzael Avalos dev_name(&toshiba_acpi->acpi_dev->dev),
250865e3cf9cSAzael Avalos 0x92, 0);
250965e3cf9cSAzael Avalos }
251065e3cf9cSAzael Avalos
25111f28f290SAzael Avalos /*
251298010f1eSAzael Avalos * IIO device
251398010f1eSAzael Avalos */
251498010f1eSAzael Avalos
251598010f1eSAzael Avalos enum toshiba_iio_accel_chan {
251698010f1eSAzael Avalos AXIS_X,
251798010f1eSAzael Avalos AXIS_Y,
251898010f1eSAzael Avalos AXIS_Z
251998010f1eSAzael Avalos };
252098010f1eSAzael Avalos
toshiba_iio_accel_get_axis(enum toshiba_iio_accel_chan chan)252198010f1eSAzael Avalos static int toshiba_iio_accel_get_axis(enum toshiba_iio_accel_chan chan)
252298010f1eSAzael Avalos {
252398010f1eSAzael Avalos u32 xyval, zval;
252498010f1eSAzael Avalos int ret;
252598010f1eSAzael Avalos
252698010f1eSAzael Avalos ret = toshiba_accelerometer_get(toshiba_acpi, &xyval, &zval);
252798010f1eSAzael Avalos if (ret < 0)
252898010f1eSAzael Avalos return ret;
252998010f1eSAzael Avalos
253098010f1eSAzael Avalos switch (chan) {
253198010f1eSAzael Avalos case AXIS_X:
253298010f1eSAzael Avalos return xyval & HCI_ACCEL_DIRECTION_MASK ?
253398010f1eSAzael Avalos -(xyval & HCI_ACCEL_MASK) : xyval & HCI_ACCEL_MASK;
253498010f1eSAzael Avalos case AXIS_Y:
253598010f1eSAzael Avalos return (xyval >> HCI_MISC_SHIFT) & HCI_ACCEL_DIRECTION_MASK ?
253698010f1eSAzael Avalos -((xyval >> HCI_MISC_SHIFT) & HCI_ACCEL_MASK) :
253798010f1eSAzael Avalos (xyval >> HCI_MISC_SHIFT) & HCI_ACCEL_MASK;
253898010f1eSAzael Avalos case AXIS_Z:
253998010f1eSAzael Avalos return zval & HCI_ACCEL_DIRECTION_MASK ?
254098010f1eSAzael Avalos -(zval & HCI_ACCEL_MASK) : zval & HCI_ACCEL_MASK;
254198010f1eSAzael Avalos }
254298010f1eSAzael Avalos
254398010f1eSAzael Avalos return ret;
254498010f1eSAzael Avalos }
254598010f1eSAzael Avalos
toshiba_iio_accel_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)254698010f1eSAzael Avalos static int toshiba_iio_accel_read_raw(struct iio_dev *indio_dev,
254798010f1eSAzael Avalos struct iio_chan_spec const *chan,
254898010f1eSAzael Avalos int *val, int *val2, long mask)
254998010f1eSAzael Avalos {
255098010f1eSAzael Avalos int ret;
255198010f1eSAzael Avalos
255298010f1eSAzael Avalos switch (mask) {
255398010f1eSAzael Avalos case IIO_CHAN_INFO_RAW:
255498010f1eSAzael Avalos ret = toshiba_iio_accel_get_axis(chan->channel);
255598010f1eSAzael Avalos if (ret == -EIO || ret == -ENODEV)
255698010f1eSAzael Avalos return ret;
255798010f1eSAzael Avalos
255898010f1eSAzael Avalos *val = ret;
255998010f1eSAzael Avalos
256098010f1eSAzael Avalos return IIO_VAL_INT;
256198010f1eSAzael Avalos }
256298010f1eSAzael Avalos
256398010f1eSAzael Avalos return -EINVAL;
256498010f1eSAzael Avalos }
256598010f1eSAzael Avalos
256698010f1eSAzael Avalos #define TOSHIBA_IIO_ACCEL_CHANNEL(axis, chan) { \
256798010f1eSAzael Avalos .type = IIO_ACCEL, \
256898010f1eSAzael Avalos .modified = 1, \
256998010f1eSAzael Avalos .channel = chan, \
257098010f1eSAzael Avalos .channel2 = IIO_MOD_##axis, \
257198010f1eSAzael Avalos .output = 1, \
257298010f1eSAzael Avalos .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
257398010f1eSAzael Avalos }
257498010f1eSAzael Avalos
257598010f1eSAzael Avalos static const struct iio_chan_spec toshiba_iio_accel_channels[] = {
257698010f1eSAzael Avalos TOSHIBA_IIO_ACCEL_CHANNEL(X, AXIS_X),
257798010f1eSAzael Avalos TOSHIBA_IIO_ACCEL_CHANNEL(Y, AXIS_Y),
257898010f1eSAzael Avalos TOSHIBA_IIO_ACCEL_CHANNEL(Z, AXIS_Z),
257998010f1eSAzael Avalos };
258098010f1eSAzael Avalos
258198010f1eSAzael Avalos static const struct iio_info toshiba_iio_accel_info = {
258298010f1eSAzael Avalos .read_raw = &toshiba_iio_accel_read_raw,
258398010f1eSAzael Avalos };
258498010f1eSAzael Avalos
258598010f1eSAzael Avalos /*
2586fc5462f8SAzael Avalos * Misc device
2587fc5462f8SAzael Avalos */
toshiba_acpi_smm_bridge(SMMRegisters * regs)2588fc5462f8SAzael Avalos static int toshiba_acpi_smm_bridge(SMMRegisters *regs)
2589fc5462f8SAzael Avalos {
2590fc5462f8SAzael Avalos u32 in[TCI_WORDS] = { regs->eax, regs->ebx, regs->ecx,
2591fc5462f8SAzael Avalos regs->edx, regs->esi, regs->edi };
2592fc5462f8SAzael Avalos u32 out[TCI_WORDS];
2593fc5462f8SAzael Avalos acpi_status status;
2594fc5462f8SAzael Avalos
2595fc5462f8SAzael Avalos status = tci_raw(toshiba_acpi, in, out);
2596fc5462f8SAzael Avalos if (ACPI_FAILURE(status)) {
2597fc5462f8SAzael Avalos pr_err("ACPI call to query SMM registers failed\n");
2598fc5462f8SAzael Avalos return -EIO;
2599fc5462f8SAzael Avalos }
2600fc5462f8SAzael Avalos
2601fc5462f8SAzael Avalos /* Fillout the SMM struct with the TCI call results */
2602fc5462f8SAzael Avalos regs->eax = out[0];
2603fc5462f8SAzael Avalos regs->ebx = out[1];
2604fc5462f8SAzael Avalos regs->ecx = out[2];
2605fc5462f8SAzael Avalos regs->edx = out[3];
2606fc5462f8SAzael Avalos regs->esi = out[4];
2607fc5462f8SAzael Avalos regs->edi = out[5];
2608fc5462f8SAzael Avalos
2609fc5462f8SAzael Avalos return 0;
2610fc5462f8SAzael Avalos }
2611fc5462f8SAzael Avalos
toshiba_acpi_ioctl(struct file * fp,unsigned int cmd,unsigned long arg)2612fc5462f8SAzael Avalos static long toshiba_acpi_ioctl(struct file *fp, unsigned int cmd,
2613fc5462f8SAzael Avalos unsigned long arg)
2614fc5462f8SAzael Avalos {
2615fc5462f8SAzael Avalos SMMRegisters __user *argp = (SMMRegisters __user *)arg;
2616fc5462f8SAzael Avalos SMMRegisters regs;
2617fc5462f8SAzael Avalos int ret;
2618fc5462f8SAzael Avalos
2619fc5462f8SAzael Avalos if (!argp)
2620fc5462f8SAzael Avalos return -EINVAL;
2621fc5462f8SAzael Avalos
2622fc5462f8SAzael Avalos switch (cmd) {
2623fc5462f8SAzael Avalos case TOSH_SMM:
2624fc5462f8SAzael Avalos if (copy_from_user(®s, argp, sizeof(SMMRegisters)))
2625fc5462f8SAzael Avalos return -EFAULT;
2626fc5462f8SAzael Avalos ret = toshiba_acpi_smm_bridge(®s);
2627fc5462f8SAzael Avalos if (ret)
2628fc5462f8SAzael Avalos return ret;
2629fc5462f8SAzael Avalos if (copy_to_user(argp, ®s, sizeof(SMMRegisters)))
2630fc5462f8SAzael Avalos return -EFAULT;
2631fc5462f8SAzael Avalos break;
2632fc5462f8SAzael Avalos case TOSHIBA_ACPI_SCI:
2633fc5462f8SAzael Avalos if (copy_from_user(®s, argp, sizeof(SMMRegisters)))
2634fc5462f8SAzael Avalos return -EFAULT;
2635fc5462f8SAzael Avalos /* Ensure we are being called with a SCI_{GET, SET} register */
2636fc5462f8SAzael Avalos if (regs.eax != SCI_GET && regs.eax != SCI_SET)
2637fc5462f8SAzael Avalos return -EINVAL;
2638fc5462f8SAzael Avalos if (!sci_open(toshiba_acpi))
2639fc5462f8SAzael Avalos return -EIO;
2640fc5462f8SAzael Avalos ret = toshiba_acpi_smm_bridge(®s);
2641fc5462f8SAzael Avalos sci_close(toshiba_acpi);
2642fc5462f8SAzael Avalos if (ret)
2643fc5462f8SAzael Avalos return ret;
2644fc5462f8SAzael Avalos if (copy_to_user(argp, ®s, sizeof(SMMRegisters)))
2645fc5462f8SAzael Avalos return -EFAULT;
2646fc5462f8SAzael Avalos break;
2647fc5462f8SAzael Avalos default:
2648fc5462f8SAzael Avalos return -EINVAL;
2649fc5462f8SAzael Avalos }
2650fc5462f8SAzael Avalos
2651fc5462f8SAzael Avalos return 0;
2652fc5462f8SAzael Avalos }
2653fc5462f8SAzael Avalos
2654fc5462f8SAzael Avalos static const struct file_operations toshiba_acpi_fops = {
2655fc5462f8SAzael Avalos .owner = THIS_MODULE,
2656fc5462f8SAzael Avalos .unlocked_ioctl = toshiba_acpi_ioctl,
2657fc5462f8SAzael Avalos .llseek = noop_llseek,
2658fc5462f8SAzael Avalos };
2659fc5462f8SAzael Avalos
2660fc5462f8SAzael Avalos /*
26612fdde834SAzael Avalos * WWAN RFKill handlers
26622fdde834SAzael Avalos */
toshiba_acpi_wwan_set_block(void * data,bool blocked)26632fdde834SAzael Avalos static int toshiba_acpi_wwan_set_block(void *data, bool blocked)
26642fdde834SAzael Avalos {
26652fdde834SAzael Avalos struct toshiba_acpi_dev *dev = data;
26662fdde834SAzael Avalos int ret;
26672fdde834SAzael Avalos
26682fdde834SAzael Avalos ret = toshiba_wireless_status(dev);
26692fdde834SAzael Avalos if (ret)
26702fdde834SAzael Avalos return ret;
26712fdde834SAzael Avalos
26722fdde834SAzael Avalos if (!dev->killswitch)
26732fdde834SAzael Avalos return 0;
26742fdde834SAzael Avalos
26752fdde834SAzael Avalos return toshiba_wwan_set(dev, !blocked);
26762fdde834SAzael Avalos }
26772fdde834SAzael Avalos
toshiba_acpi_wwan_poll(struct rfkill * rfkill,void * data)26782fdde834SAzael Avalos static void toshiba_acpi_wwan_poll(struct rfkill *rfkill, void *data)
26792fdde834SAzael Avalos {
26802fdde834SAzael Avalos struct toshiba_acpi_dev *dev = data;
26812fdde834SAzael Avalos
26822fdde834SAzael Avalos if (toshiba_wireless_status(dev))
26832fdde834SAzael Avalos return;
26842fdde834SAzael Avalos
26852fdde834SAzael Avalos rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch);
26862fdde834SAzael Avalos }
26872fdde834SAzael Avalos
26882fdde834SAzael Avalos static const struct rfkill_ops wwan_rfk_ops = {
26892fdde834SAzael Avalos .set_block = toshiba_acpi_wwan_set_block,
26902fdde834SAzael Avalos .poll = toshiba_acpi_wwan_poll,
26912fdde834SAzael Avalos };
26922fdde834SAzael Avalos
toshiba_acpi_setup_wwan_rfkill(struct toshiba_acpi_dev * dev)26932fdde834SAzael Avalos static int toshiba_acpi_setup_wwan_rfkill(struct toshiba_acpi_dev *dev)
26942fdde834SAzael Avalos {
26952fdde834SAzael Avalos int ret = toshiba_wireless_status(dev);
26962fdde834SAzael Avalos
26972fdde834SAzael Avalos if (ret)
26982fdde834SAzael Avalos return ret;
26992fdde834SAzael Avalos
27002fdde834SAzael Avalos dev->wwan_rfk = rfkill_alloc("Toshiba WWAN",
27012fdde834SAzael Avalos &dev->acpi_dev->dev,
27022fdde834SAzael Avalos RFKILL_TYPE_WWAN,
27032fdde834SAzael Avalos &wwan_rfk_ops,
27042fdde834SAzael Avalos dev);
27052fdde834SAzael Avalos if (!dev->wwan_rfk) {
27062fdde834SAzael Avalos pr_err("Unable to allocate WWAN rfkill device\n");
27072fdde834SAzael Avalos return -ENOMEM;
27082fdde834SAzael Avalos }
27092fdde834SAzael Avalos
27102fdde834SAzael Avalos rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch);
27112fdde834SAzael Avalos
27122fdde834SAzael Avalos ret = rfkill_register(dev->wwan_rfk);
27132fdde834SAzael Avalos if (ret) {
27142fdde834SAzael Avalos pr_err("Unable to register WWAN rfkill device\n");
27152fdde834SAzael Avalos rfkill_destroy(dev->wwan_rfk);
27162fdde834SAzael Avalos }
27172fdde834SAzael Avalos
27182fdde834SAzael Avalos return ret;
27192fdde834SAzael Avalos }
27202fdde834SAzael Avalos
27212fdde834SAzael Avalos /*
27221f28f290SAzael Avalos * Hotkeys
27231f28f290SAzael Avalos */
toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev * dev)27241f28f290SAzael Avalos static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev)
27251f28f290SAzael Avalos {
27261f28f290SAzael Avalos acpi_status status;
27271f28f290SAzael Avalos u32 result;
27281f28f290SAzael Avalos
27291f28f290SAzael Avalos status = acpi_evaluate_object(dev->acpi_dev->handle,
27301f28f290SAzael Avalos "ENAB", NULL, NULL);
27311f28f290SAzael Avalos if (ACPI_FAILURE(status))
27321f28f290SAzael Avalos return -ENODEV;
27331f28f290SAzael Avalos
2734b116fd00SAzael Avalos /*
273523f1d8b4SArvid Norlander * Enable quickstart buttons if supported.
273623f1d8b4SArvid Norlander *
2737b116fd00SAzael Avalos * Enable the "Special Functions" mode only if they are
2738b116fd00SAzael Avalos * supported and if they are activated.
2739b116fd00SAzael Avalos */
274023f1d8b4SArvid Norlander if (hci_hotkey_quickstart)
274123f1d8b4SArvid Norlander result = hci_write(dev, HCI_HOTKEY_EVENT,
274223f1d8b4SArvid Norlander HCI_HOTKEY_ENABLE_QUICKSTART);
274323f1d8b4SArvid Norlander else if (dev->kbd_function_keys_supported && dev->special_functions)
2744b116fd00SAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT,
2745b116fd00SAzael Avalos HCI_HOTKEY_SPECIAL_FUNCTIONS);
2746b116fd00SAzael Avalos else
2747d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE);
2748b116fd00SAzael Avalos
27491f28f290SAzael Avalos if (result == TOS_FAILURE)
27501f28f290SAzael Avalos return -EIO;
27511f28f290SAzael Avalos else if (result == TOS_NOT_SUPPORTED)
27521f28f290SAzael Avalos return -ENODEV;
27531f28f290SAzael Avalos
27541f28f290SAzael Avalos return 0;
27551f28f290SAzael Avalos }
27561f28f290SAzael Avalos
toshiba_acpi_i8042_filter(unsigned char data,unsigned char str,struct serio * port)275729cd293fSSeth Forshee static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
275829cd293fSSeth Forshee struct serio *port)
275929cd293fSSeth Forshee {
276098280374SGiedrius Statkevičius if (str & I8042_STR_AUXDATA)
276129cd293fSSeth Forshee return false;
276229cd293fSSeth Forshee
276329cd293fSSeth Forshee if (unlikely(data == 0xe0))
276429cd293fSSeth Forshee return false;
276529cd293fSSeth Forshee
276629cd293fSSeth Forshee if ((data & 0x7f) == TOS1900_FN_SCAN) {
276729cd293fSSeth Forshee schedule_work(&toshiba_acpi->hotkey_work);
276829cd293fSSeth Forshee return true;
276929cd293fSSeth Forshee }
277029cd293fSSeth Forshee
277129cd293fSSeth Forshee return false;
277229cd293fSSeth Forshee }
277329cd293fSSeth Forshee
toshiba_acpi_hotkey_work(struct work_struct * work)277429cd293fSSeth Forshee static void toshiba_acpi_hotkey_work(struct work_struct *work)
277529cd293fSSeth Forshee {
277629cd293fSSeth Forshee acpi_handle ec_handle = ec_get_handle();
277729cd293fSSeth Forshee acpi_status status;
277829cd293fSSeth Forshee
277929cd293fSSeth Forshee if (!ec_handle)
278029cd293fSSeth Forshee return;
278129cd293fSSeth Forshee
278229cd293fSSeth Forshee status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL);
278329cd293fSSeth Forshee if (ACPI_FAILURE(status))
278429cd293fSSeth Forshee pr_err("ACPI NTFY method execution failed\n");
278529cd293fSSeth Forshee }
278629cd293fSSeth Forshee
278729cd293fSSeth Forshee /*
278829cd293fSSeth Forshee * Returns hotkey scancode, or < 0 on failure.
278929cd293fSSeth Forshee */
toshiba_acpi_query_hotkey(struct toshiba_acpi_dev * dev)279029cd293fSSeth Forshee static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev)
279129cd293fSSeth Forshee {
279274facaf7SZhang Rui unsigned long long value;
279329cd293fSSeth Forshee acpi_status status;
279429cd293fSSeth Forshee
279574facaf7SZhang Rui status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO",
279674facaf7SZhang Rui NULL, &value);
279774facaf7SZhang Rui if (ACPI_FAILURE(status)) {
279829cd293fSSeth Forshee pr_err("ACPI INFO method execution failed\n");
279929cd293fSSeth Forshee return -EIO;
280029cd293fSSeth Forshee }
280129cd293fSSeth Forshee
280274facaf7SZhang Rui return value;
280329cd293fSSeth Forshee }
280429cd293fSSeth Forshee
toshiba_acpi_report_hotkey(struct toshiba_acpi_dev * dev,int scancode)280529cd293fSSeth Forshee static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev,
280629cd293fSSeth Forshee int scancode)
280729cd293fSSeth Forshee {
280829cd293fSSeth Forshee if (scancode == 0x100)
280929cd293fSSeth Forshee return;
281029cd293fSSeth Forshee
2811e0769fe6SDarren Hart /* Act on key press; ignore key release */
281229cd293fSSeth Forshee if (scancode & 0x80)
281329cd293fSSeth Forshee return;
281429cd293fSSeth Forshee
281529cd293fSSeth Forshee if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true))
281629cd293fSSeth Forshee pr_info("Unknown key %x\n", scancode);
281729cd293fSSeth Forshee }
281829cd293fSSeth Forshee
toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev * dev)281971454d78SAzael Avalos static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev)
282071454d78SAzael Avalos {
282171454d78SAzael Avalos if (dev->info_supported) {
28227deef550SAzael Avalos int scancode = toshiba_acpi_query_hotkey(dev);
28237deef550SAzael Avalos
28247deef550SAzael Avalos if (scancode < 0) {
282571454d78SAzael Avalos pr_err("Failed to query hotkey event\n");
28267deef550SAzael Avalos } else if (scancode != 0) {
282771454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, scancode);
28287deef550SAzael Avalos dev->key_event_valid = 1;
28297deef550SAzael Avalos dev->last_key_event = scancode;
28307deef550SAzael Avalos }
283171454d78SAzael Avalos } else if (dev->system_event_supported) {
28327deef550SAzael Avalos u32 result;
28337deef550SAzael Avalos u32 value;
28347deef550SAzael Avalos int retries = 3;
28357deef550SAzael Avalos
283671454d78SAzael Avalos do {
28377deef550SAzael Avalos result = hci_read(dev, HCI_SYSTEM_EVENT, &value);
28387deef550SAzael Avalos switch (result) {
283971454d78SAzael Avalos case TOS_SUCCESS:
284071454d78SAzael Avalos toshiba_acpi_report_hotkey(dev, (int)value);
28417deef550SAzael Avalos dev->key_event_valid = 1;
28427deef550SAzael Avalos dev->last_key_event = value;
284371454d78SAzael Avalos break;
284471454d78SAzael Avalos case TOS_NOT_SUPPORTED:
284571454d78SAzael Avalos /*
284671454d78SAzael Avalos * This is a workaround for an unresolved
284771454d78SAzael Avalos * issue on some machines where system events
284871454d78SAzael Avalos * sporadically become disabled.
284971454d78SAzael Avalos */
28507deef550SAzael Avalos result = hci_write(dev, HCI_SYSTEM_EVENT, 1);
28517deef550SAzael Avalos if (result == TOS_SUCCESS)
285271454d78SAzael Avalos pr_notice("Re-enabled hotkeys\n");
2853df561f66SGustavo A. R. Silva fallthrough;
285471454d78SAzael Avalos default:
285571454d78SAzael Avalos retries--;
285671454d78SAzael Avalos break;
285771454d78SAzael Avalos }
28587deef550SAzael Avalos } while (retries && result != TOS_FIFO_EMPTY);
285971454d78SAzael Avalos }
286071454d78SAzael Avalos }
286171454d78SAzael Avalos
toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev * dev)2862b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
28636335e4d5SMatthew Garrett {
2864fe808bfbSTakashi Iwai const struct key_entry *keymap = toshiba_acpi_keymap;
2865a2b3471bSAzael Avalos acpi_handle ec_handle;
2866a2b3471bSAzael Avalos int error;
2867a2b3471bSAzael Avalos
28687faa6a37SAzael Avalos if (disable_hotkeys) {
28697faa6a37SAzael Avalos pr_info("Hotkeys disabled by module parameter\n");
28707faa6a37SAzael Avalos return 0;
28717faa6a37SAzael Avalos }
28727faa6a37SAzael Avalos
2873a88bc06eSAzael Avalos if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) {
2874a88bc06eSAzael Avalos pr_info("WMI event detected, hotkeys will not be monitored\n");
2875a88bc06eSAzael Avalos return 0;
2876a88bc06eSAzael Avalos }
2877a88bc06eSAzael Avalos
2878a2b3471bSAzael Avalos error = toshiba_acpi_enable_hotkeys(dev);
2879a2b3471bSAzael Avalos if (error)
2880a2b3471bSAzael Avalos return error;
2881a2b3471bSAzael Avalos
288210e6aaabSAzael Avalos if (toshiba_hotkey_event_type_get(dev, &dev->hotkey_event_type))
288353147b6cSAzael Avalos pr_notice("Unable to query Hotkey Event Type\n");
288453147b6cSAzael Avalos
2885135740deSSeth Forshee dev->hotkey_dev = input_allocate_device();
2886b222cca6SJoe Perches if (!dev->hotkey_dev)
2887135740deSSeth Forshee return -ENOMEM;
2888135740deSSeth Forshee
2889135740deSSeth Forshee dev->hotkey_dev->name = "Toshiba input device";
28906e02cc7eSSeth Forshee dev->hotkey_dev->phys = "toshiba_acpi/input0";
2891135740deSSeth Forshee dev->hotkey_dev->id.bustype = BUS_HOST;
28924b93c6eaSArvid Norlander dev->hotkey_dev->dev.parent = &dev->acpi_dev->dev;
2893135740deSSeth Forshee
289410e6aaabSAzael Avalos if (dev->hotkey_event_type == HCI_SYSTEM_TYPE1 ||
2895a2b3471bSAzael Avalos !dev->kbd_function_keys_supported)
2896a2b3471bSAzael Avalos keymap = toshiba_acpi_keymap;
289710e6aaabSAzael Avalos else if (dev->hotkey_event_type == HCI_SYSTEM_TYPE2 ||
2898a2b3471bSAzael Avalos dev->kbd_function_keys_supported)
2899fe808bfbSTakashi Iwai keymap = toshiba_acpi_alt_keymap;
2900a2b3471bSAzael Avalos else
290110e6aaabSAzael Avalos pr_info("Unknown event type received %x\n",
290210e6aaabSAzael Avalos dev->hotkey_event_type);
2903fe808bfbSTakashi Iwai error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL);
2904135740deSSeth Forshee if (error)
2905135740deSSeth Forshee goto err_free_dev;
2906135740deSSeth Forshee
290729cd293fSSeth Forshee /*
290829cd293fSSeth Forshee * For some machines the SCI responsible for providing hotkey
290929cd293fSSeth Forshee * notification doesn't fire. We can trigger the notification
291029cd293fSSeth Forshee * whenever the Fn key is pressed using the NTFY method, if
291129cd293fSSeth Forshee * supported, so if it's present set up an i8042 key filter
291229cd293fSSeth Forshee * for this purpose.
291329cd293fSSeth Forshee */
291429cd293fSSeth Forshee ec_handle = ec_get_handle();
2915e2e19606SZhang Rui if (ec_handle && acpi_has_method(ec_handle, "NTFY")) {
291629cd293fSSeth Forshee INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work);
291729cd293fSSeth Forshee
291829cd293fSSeth Forshee error = i8042_install_filter(toshiba_acpi_i8042_filter);
291929cd293fSSeth Forshee if (error) {
292029cd293fSSeth Forshee pr_err("Error installing key filter\n");
2921db8f95d0SMichał Kępień goto err_free_dev;
292229cd293fSSeth Forshee }
292329cd293fSSeth Forshee
292429cd293fSSeth Forshee dev->ntfy_supported = 1;
292529cd293fSSeth Forshee }
292629cd293fSSeth Forshee
292729cd293fSSeth Forshee /*
292829cd293fSSeth Forshee * Determine hotkey query interface. Prefer using the INFO
292929cd293fSSeth Forshee * method when it is available.
293029cd293fSSeth Forshee */
2931e2e19606SZhang Rui if (acpi_has_method(dev->acpi_dev->handle, "INFO"))
293229cd293fSSeth Forshee dev->info_supported = 1;
293310e6aaabSAzael Avalos else if (hci_write(dev, HCI_SYSTEM_EVENT, 1) == TOS_SUCCESS)
293429cd293fSSeth Forshee dev->system_event_supported = 1;
293529cd293fSSeth Forshee
293629cd293fSSeth Forshee if (!dev->info_supported && !dev->system_event_supported) {
293729cd293fSSeth Forshee pr_warn("No hotkey query interface found\n");
293828e36712SJiapeng Chong error = -EINVAL;
293929cd293fSSeth Forshee goto err_remove_filter;
294029cd293fSSeth Forshee }
294129cd293fSSeth Forshee
2942135740deSSeth Forshee error = input_register_device(dev->hotkey_dev);
2943135740deSSeth Forshee if (error) {
2944135740deSSeth Forshee pr_info("Unable to register input device\n");
294529cd293fSSeth Forshee goto err_remove_filter;
2946135740deSSeth Forshee }
2947135740deSSeth Forshee
2948135740deSSeth Forshee return 0;
2949135740deSSeth Forshee
295029cd293fSSeth Forshee err_remove_filter:
295129cd293fSSeth Forshee if (dev->ntfy_supported)
295229cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter);
2953135740deSSeth Forshee err_free_dev:
2954135740deSSeth Forshee input_free_device(dev->hotkey_dev);
2955135740deSSeth Forshee dev->hotkey_dev = NULL;
2956135740deSSeth Forshee return error;
2957135740deSSeth Forshee }
2958135740deSSeth Forshee
toshiba_acpi_setup_backlight(struct toshiba_acpi_dev * dev)2959b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
296062cce752SSeth Forshee {
296162cce752SSeth Forshee struct backlight_properties props;
296262cce752SSeth Forshee int brightness;
296362cce752SSeth Forshee int ret;
296462cce752SSeth Forshee
296562cce752SSeth Forshee /*
296662cce752SSeth Forshee * Some machines don't support the backlight methods at all, and
296762cce752SSeth Forshee * others support it read-only. Either of these is pretty useless,
296862cce752SSeth Forshee * so only register the backlight device if the backlight method
296962cce752SSeth Forshee * supports both reads and writes.
297062cce752SSeth Forshee */
297162cce752SSeth Forshee brightness = __get_lcd_brightness(dev);
297262cce752SSeth Forshee if (brightness < 0)
297362cce752SSeth Forshee return 0;
2974bae5336fSAzael Avalos /*
2975bae5336fSAzael Avalos * If transflective backlight is supported and the brightness is zero
2976bae5336fSAzael Avalos * (lowest brightness level), the set_lcd_brightness function will
2977bae5336fSAzael Avalos * activate the transflective backlight, making the LCD appear to be
2978bae5336fSAzael Avalos * turned off, simply increment the brightness level to avoid that.
2979bae5336fSAzael Avalos */
2980bae5336fSAzael Avalos if (dev->tr_backlight_supported && brightness == 0)
2981bae5336fSAzael Avalos brightness++;
298262cce752SSeth Forshee ret = set_lcd_brightness(dev, brightness);
298362cce752SSeth Forshee if (ret) {
298462cce752SSeth Forshee pr_debug("Backlight method is read-only, disabling backlight support\n");
298562cce752SSeth Forshee return 0;
298662cce752SSeth Forshee }
298762cce752SSeth Forshee
2988234b7cf8SHans de Goede if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
2989358d6a2cSHans de Goede return 0;
2990358d6a2cSHans de Goede
299153039f22SMatthew Garrett memset(&props, 0, sizeof(props));
299262cce752SSeth Forshee props.type = BACKLIGHT_PLATFORM;
299362cce752SSeth Forshee props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
299462cce752SSeth Forshee
2995e0769fe6SDarren Hart /* Adding an extra level and having 0 change to transflective mode */
2996121b7b0dSAkio Idehara if (dev->tr_backlight_supported)
2997121b7b0dSAkio Idehara props.max_brightness++;
2998121b7b0dSAkio Idehara
299962cce752SSeth Forshee dev->backlight_dev = backlight_device_register("toshiba",
300062cce752SSeth Forshee &dev->acpi_dev->dev,
300162cce752SSeth Forshee dev,
300262cce752SSeth Forshee &toshiba_backlight_data,
300362cce752SSeth Forshee &props);
300462cce752SSeth Forshee if (IS_ERR(dev->backlight_dev)) {
300562cce752SSeth Forshee ret = PTR_ERR(dev->backlight_dev);
300662cce752SSeth Forshee pr_err("Could not register toshiba backlight device\n");
300762cce752SSeth Forshee dev->backlight_dev = NULL;
300862cce752SSeth Forshee return ret;
300962cce752SSeth Forshee }
301062cce752SSeth Forshee
301162cce752SSeth Forshee dev->backlight_dev->props.brightness = brightness;
301262cce752SSeth Forshee return 0;
301362cce752SSeth Forshee }
301462cce752SSeth Forshee
3015c727ba4cSArvid Norlander /* HWMON support for fan */
3016c727ba4cSArvid Norlander #if IS_ENABLED(CONFIG_HWMON)
toshiba_acpi_hwmon_is_visible(const void * drvdata,enum hwmon_sensor_types type,u32 attr,int channel)3017c727ba4cSArvid Norlander static umode_t toshiba_acpi_hwmon_is_visible(const void *drvdata,
3018c727ba4cSArvid Norlander enum hwmon_sensor_types type,
3019c727ba4cSArvid Norlander u32 attr, int channel)
3020c727ba4cSArvid Norlander {
3021c727ba4cSArvid Norlander return 0444;
3022c727ba4cSArvid Norlander }
3023c727ba4cSArvid Norlander
toshiba_acpi_hwmon_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)3024c727ba4cSArvid Norlander static int toshiba_acpi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
3025c727ba4cSArvid Norlander u32 attr, int channel, long *val)
3026c727ba4cSArvid Norlander {
3027c727ba4cSArvid Norlander /*
3028c727ba4cSArvid Norlander * There is only a single channel and single attribute (for the
3029c727ba4cSArvid Norlander * fan) at this point.
3030c727ba4cSArvid Norlander * This can be replaced with more advanced logic in the future,
3031c727ba4cSArvid Norlander * should the need arise.
3032c727ba4cSArvid Norlander */
3033c727ba4cSArvid Norlander if (type == hwmon_fan && channel == 0 && attr == hwmon_fan_input) {
3034c727ba4cSArvid Norlander u32 value;
3035c727ba4cSArvid Norlander int ret;
3036c727ba4cSArvid Norlander
3037c727ba4cSArvid Norlander ret = get_fan_rpm(toshiba_acpi, &value);
3038c727ba4cSArvid Norlander if (ret)
3039c727ba4cSArvid Norlander return ret;
3040c727ba4cSArvid Norlander
3041c727ba4cSArvid Norlander *val = value;
3042c727ba4cSArvid Norlander return 0;
3043c727ba4cSArvid Norlander }
3044c727ba4cSArvid Norlander return -EOPNOTSUPP;
3045c727ba4cSArvid Norlander }
3046c727ba4cSArvid Norlander
3047f5a08ed5SKrzysztof Kozlowski static const struct hwmon_channel_info * const toshiba_acpi_hwmon_info[] = {
3048c727ba4cSArvid Norlander HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT),
3049c727ba4cSArvid Norlander NULL
3050c727ba4cSArvid Norlander };
3051c727ba4cSArvid Norlander
3052c727ba4cSArvid Norlander static const struct hwmon_ops toshiba_acpi_hwmon_ops = {
3053c727ba4cSArvid Norlander .is_visible = toshiba_acpi_hwmon_is_visible,
3054c727ba4cSArvid Norlander .read = toshiba_acpi_hwmon_read,
3055c727ba4cSArvid Norlander };
3056c727ba4cSArvid Norlander
3057c727ba4cSArvid Norlander static const struct hwmon_chip_info toshiba_acpi_hwmon_chip_info = {
3058c727ba4cSArvid Norlander .ops = &toshiba_acpi_hwmon_ops,
3059c727ba4cSArvid Norlander .info = toshiba_acpi_hwmon_info,
3060c727ba4cSArvid Norlander };
3061c727ba4cSArvid Norlander #endif
3062c727ba4cSArvid Norlander
30638ef5db9eSArvid Norlander /* ACPI battery hooking */
charge_control_end_threshold_show(struct device * device,struct device_attribute * attr,char * buf)30648ef5db9eSArvid Norlander static ssize_t charge_control_end_threshold_show(struct device *device,
30658ef5db9eSArvid Norlander struct device_attribute *attr,
30668ef5db9eSArvid Norlander char *buf)
30678ef5db9eSArvid Norlander {
30688ef5db9eSArvid Norlander u32 state;
30698ef5db9eSArvid Norlander int status;
30708ef5db9eSArvid Norlander
30718ef5db9eSArvid Norlander if (toshiba_acpi == NULL) {
30728ef5db9eSArvid Norlander pr_err("Toshiba ACPI object invalid\n");
30738ef5db9eSArvid Norlander return -ENODEV;
30748ef5db9eSArvid Norlander }
30758ef5db9eSArvid Norlander
30768ef5db9eSArvid Norlander status = toshiba_battery_charge_mode_get(toshiba_acpi, &state);
30778ef5db9eSArvid Norlander
30788ef5db9eSArvid Norlander if (status != 0)
30798ef5db9eSArvid Norlander return status;
30808ef5db9eSArvid Norlander
30818ef5db9eSArvid Norlander if (state == 1)
30828ef5db9eSArvid Norlander return sprintf(buf, "80\n");
30838ef5db9eSArvid Norlander else
30848ef5db9eSArvid Norlander return sprintf(buf, "100\n");
30858ef5db9eSArvid Norlander }
30868ef5db9eSArvid Norlander
charge_control_end_threshold_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)30878ef5db9eSArvid Norlander static ssize_t charge_control_end_threshold_store(struct device *dev,
30888ef5db9eSArvid Norlander struct device_attribute *attr,
30898ef5db9eSArvid Norlander const char *buf,
30908ef5db9eSArvid Norlander size_t count)
30918ef5db9eSArvid Norlander {
30928ef5db9eSArvid Norlander u32 value;
30938ef5db9eSArvid Norlander int rval;
30948ef5db9eSArvid Norlander
30958ef5db9eSArvid Norlander if (toshiba_acpi == NULL) {
30968ef5db9eSArvid Norlander pr_err("Toshiba ACPI object invalid\n");
30978ef5db9eSArvid Norlander return -ENODEV;
30988ef5db9eSArvid Norlander }
30998ef5db9eSArvid Norlander
31008ef5db9eSArvid Norlander rval = kstrtou32(buf, 10, &value);
31018ef5db9eSArvid Norlander if (rval)
31028ef5db9eSArvid Norlander return rval;
31038ef5db9eSArvid Norlander
31048ef5db9eSArvid Norlander if (value < 1 || value > 100)
31058ef5db9eSArvid Norlander return -EINVAL;
31068ef5db9eSArvid Norlander rval = toshiba_battery_charge_mode_set(toshiba_acpi,
31078ef5db9eSArvid Norlander (value < 90) ? 1 : 0);
31088ef5db9eSArvid Norlander if (rval < 0)
31098ef5db9eSArvid Norlander return rval;
31108ef5db9eSArvid Norlander else
31118ef5db9eSArvid Norlander return count;
31128ef5db9eSArvid Norlander }
31138ef5db9eSArvid Norlander
31148ef5db9eSArvid Norlander static DEVICE_ATTR_RW(charge_control_end_threshold);
31158ef5db9eSArvid Norlander
31168ef5db9eSArvid Norlander static struct attribute *toshiba_acpi_battery_attrs[] = {
31178ef5db9eSArvid Norlander &dev_attr_charge_control_end_threshold.attr,
31188ef5db9eSArvid Norlander NULL,
31198ef5db9eSArvid Norlander };
31208ef5db9eSArvid Norlander
31218ef5db9eSArvid Norlander ATTRIBUTE_GROUPS(toshiba_acpi_battery);
31228ef5db9eSArvid Norlander
toshiba_acpi_battery_add(struct power_supply * battery,struct acpi_battery_hook * hook)3123878a82c2SArmin Wolf static int toshiba_acpi_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook)
31248ef5db9eSArvid Norlander {
31258ef5db9eSArvid Norlander if (toshiba_acpi == NULL) {
31268ef5db9eSArvid Norlander pr_err("Init order issue\n");
31278ef5db9eSArvid Norlander return -ENODEV;
31288ef5db9eSArvid Norlander }
31298ef5db9eSArvid Norlander if (!toshiba_acpi->battery_charge_mode_supported)
31308ef5db9eSArvid Norlander return -ENODEV;
31318ef5db9eSArvid Norlander if (device_add_groups(&battery->dev, toshiba_acpi_battery_groups))
31328ef5db9eSArvid Norlander return -ENODEV;
31338ef5db9eSArvid Norlander return 0;
31348ef5db9eSArvid Norlander }
31358ef5db9eSArvid Norlander
toshiba_acpi_battery_remove(struct power_supply * battery,struct acpi_battery_hook * hook)3136878a82c2SArmin Wolf static int toshiba_acpi_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook)
31378ef5db9eSArvid Norlander {
31388ef5db9eSArvid Norlander device_remove_groups(&battery->dev, toshiba_acpi_battery_groups);
31398ef5db9eSArvid Norlander return 0;
31408ef5db9eSArvid Norlander }
31418ef5db9eSArvid Norlander
31428ef5db9eSArvid Norlander static struct acpi_battery_hook battery_hook = {
31438ef5db9eSArvid Norlander .add_battery = toshiba_acpi_battery_add,
31448ef5db9eSArvid Norlander .remove_battery = toshiba_acpi_battery_remove,
31458ef5db9eSArvid Norlander .name = "Toshiba Battery Extension",
31468ef5db9eSArvid Norlander };
31478ef5db9eSArvid Norlander
print_supported_features(struct toshiba_acpi_dev * dev)31480409cbceSAzael Avalos static void print_supported_features(struct toshiba_acpi_dev *dev)
31490409cbceSAzael Avalos {
31500409cbceSAzael Avalos pr_info("Supported laptop features:");
31510409cbceSAzael Avalos
31520409cbceSAzael Avalos if (dev->hotkey_dev)
31530409cbceSAzael Avalos pr_cont(" hotkeys");
31540409cbceSAzael Avalos if (dev->backlight_dev)
31550409cbceSAzael Avalos pr_cont(" backlight");
31560409cbceSAzael Avalos if (dev->video_supported)
31570409cbceSAzael Avalos pr_cont(" video-out");
31580409cbceSAzael Avalos if (dev->fan_supported)
31590409cbceSAzael Avalos pr_cont(" fan");
3160dd193dcdSArvid Norlander if (dev->fan_rpm_supported)
3161dd193dcdSArvid Norlander pr_cont(" fan-rpm");
31620409cbceSAzael Avalos if (dev->tr_backlight_supported)
31630409cbceSAzael Avalos pr_cont(" transflective-backlight");
31640409cbceSAzael Avalos if (dev->illumination_supported)
31650409cbceSAzael Avalos pr_cont(" illumination");
31660409cbceSAzael Avalos if (dev->kbd_illum_supported)
31670409cbceSAzael Avalos pr_cont(" keyboard-backlight");
31680409cbceSAzael Avalos if (dev->touchpad_supported)
31690409cbceSAzael Avalos pr_cont(" touchpad");
31700409cbceSAzael Avalos if (dev->eco_supported)
31710409cbceSAzael Avalos pr_cont(" eco-led");
31720409cbceSAzael Avalos if (dev->accelerometer_supported)
31730409cbceSAzael Avalos pr_cont(" accelerometer-axes");
31740409cbceSAzael Avalos if (dev->usb_sleep_charge_supported)
31750409cbceSAzael Avalos pr_cont(" usb-sleep-charge");
31760409cbceSAzael Avalos if (dev->usb_rapid_charge_supported)
31770409cbceSAzael Avalos pr_cont(" usb-rapid-charge");
31780409cbceSAzael Avalos if (dev->usb_sleep_music_supported)
31790409cbceSAzael Avalos pr_cont(" usb-sleep-music");
31800409cbceSAzael Avalos if (dev->kbd_function_keys_supported)
31810409cbceSAzael Avalos pr_cont(" special-function-keys");
31820409cbceSAzael Avalos if (dev->panel_power_on_supported)
31830409cbceSAzael Avalos pr_cont(" panel-power-on");
31840409cbceSAzael Avalos if (dev->usb_three_supported)
31850409cbceSAzael Avalos pr_cont(" usb3");
31866873f46aSAzael Avalos if (dev->wwan_supported)
31876873f46aSAzael Avalos pr_cont(" wwan");
3188763ff32fSAzael Avalos if (dev->cooling_method_supported)
3189763ff32fSAzael Avalos pr_cont(" cooling-method");
319089655fbbSArvid Norlander if (dev->battery_charge_mode_supported)
319189655fbbSArvid Norlander pr_cont(" battery-charge-mode");
31920409cbceSAzael Avalos
31930409cbceSAzael Avalos pr_cont("\n");
31940409cbceSAzael Avalos }
31950409cbceSAzael Avalos
toshiba_acpi_remove(struct acpi_device * acpi_dev)31966c0eb5baSDawei Li static void toshiba_acpi_remove(struct acpi_device *acpi_dev)
3197135740deSSeth Forshee {
3198135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
3199135740deSSeth Forshee
3200fc5462f8SAzael Avalos misc_deregister(&dev->miscdev);
3201fc5462f8SAzael Avalos
320236d03f93SSeth Forshee remove_toshiba_proc_entries(dev);
3203135740deSSeth Forshee
3204c727ba4cSArvid Norlander #if IS_ENABLED(CONFIG_HWMON)
3205c727ba4cSArvid Norlander if (dev->hwmon_device)
3206c727ba4cSArvid Norlander hwmon_device_unregister(dev->hwmon_device);
3207c727ba4cSArvid Norlander #endif
3208c727ba4cSArvid Norlander
320998010f1eSAzael Avalos if (dev->accelerometer_supported && dev->indio_dev) {
321098010f1eSAzael Avalos iio_device_unregister(dev->indio_dev);
321198010f1eSAzael Avalos iio_device_free(dev->indio_dev);
321298010f1eSAzael Avalos }
321398010f1eSAzael Avalos
3214360f0f39SAzael Avalos if (dev->sysfs_created)
3215360f0f39SAzael Avalos sysfs_remove_group(&dev->acpi_dev->dev.kobj,
3216360f0f39SAzael Avalos &toshiba_attr_group);
3217360f0f39SAzael Avalos
321829cd293fSSeth Forshee if (dev->ntfy_supported) {
321929cd293fSSeth Forshee i8042_remove_filter(toshiba_acpi_i8042_filter);
322029cd293fSSeth Forshee cancel_work_sync(&dev->hotkey_work);
322129cd293fSSeth Forshee }
322229cd293fSSeth Forshee
3223db8f95d0SMichał Kępień if (dev->hotkey_dev)
3224135740deSSeth Forshee input_unregister_device(dev->hotkey_dev);
3225135740deSSeth Forshee
3226135740deSSeth Forshee backlight_device_unregister(dev->backlight_dev);
3227135740deSSeth Forshee
3228135740deSSeth Forshee led_classdev_unregister(&dev->led_dev);
3229360f0f39SAzael Avalos led_classdev_unregister(&dev->kbd_led);
3230def6c4e2SAzael Avalos led_classdev_unregister(&dev->eco_led);
3231def6c4e2SAzael Avalos
32322fdde834SAzael Avalos if (dev->wwan_rfk) {
32332fdde834SAzael Avalos rfkill_unregister(dev->wwan_rfk);
32342fdde834SAzael Avalos rfkill_destroy(dev->wwan_rfk);
32352fdde834SAzael Avalos }
32362fdde834SAzael Avalos
32378ef5db9eSArvid Norlander if (dev->battery_charge_mode_supported)
32388ef5db9eSArvid Norlander battery_hook_unregister(&battery_hook);
32398ef5db9eSArvid Norlander
324029cd293fSSeth Forshee if (toshiba_acpi)
324129cd293fSSeth Forshee toshiba_acpi = NULL;
324229cd293fSSeth Forshee
3243135740deSSeth Forshee kfree(dev);
3244135740deSSeth Forshee }
3245135740deSSeth Forshee
find_hci_method(acpi_handle handle)3246b859f159SGreg Kroah-Hartman static const char *find_hci_method(acpi_handle handle)
3247a540d6b5SSeth Forshee {
3248e2e19606SZhang Rui if (acpi_has_method(handle, "GHCI"))
3249a540d6b5SSeth Forshee return "GHCI";
3250a540d6b5SSeth Forshee
3251e2e19606SZhang Rui if (acpi_has_method(handle, "SPFC"))
3252a540d6b5SSeth Forshee return "SPFC";
3253a540d6b5SSeth Forshee
3254a540d6b5SSeth Forshee return NULL;
3255a540d6b5SSeth Forshee }
3256a540d6b5SSeth Forshee
32573cb1f40dSHans de Goede /*
32583cb1f40dSHans de Goede * Some Toshibas have a broken acpi-video interface for brightness control,
32593cb1f40dSHans de Goede * these are quirked in drivers/acpi/video_detect.c to use the GPU native
32603cb1f40dSHans de Goede * (/sys/class/backlight/intel_backlight) instead.
32613cb1f40dSHans de Goede * But these need a HCI_SET call to actually turn the panel back on at resume,
32623cb1f40dSHans de Goede * without this call the screen stays black at resume.
32633cb1f40dSHans de Goede * Either HCI_LCD_BRIGHTNESS (used by acpi_video's _BCM) or HCI_PANEL_POWER_ON
32643cb1f40dSHans de Goede * works. toshiba_acpi_resume() uses HCI_PANEL_POWER_ON to avoid changing
32653cb1f40dSHans de Goede * the configured brightness level.
32663cb1f40dSHans de Goede */
326723f1d8b4SArvid Norlander #define QUIRK_TURN_ON_PANEL_ON_RESUME BIT(0)
326823f1d8b4SArvid Norlander /*
326923f1d8b4SArvid Norlander * Some Toshibas use "quickstart" keys. On these, HCI_HOTKEY_EVENT must use
327023f1d8b4SArvid Norlander * the value HCI_HOTKEY_ENABLE_QUICKSTART.
327123f1d8b4SArvid Norlander */
327223f1d8b4SArvid Norlander #define QUIRK_HCI_HOTKEY_QUICKSTART BIT(1)
327323f1d8b4SArvid Norlander
3274e527a612SArmin Wolf static const struct dmi_system_id toshiba_dmi_quirks[] __initconst = {
32753cb1f40dSHans de Goede {
32763cb1f40dSHans de Goede /* Toshiba Portégé R700 */
32773cb1f40dSHans de Goede /* https://bugzilla.kernel.org/show_bug.cgi?id=21012 */
32783cb1f40dSHans de Goede .matches = {
32793cb1f40dSHans de Goede DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
32803cb1f40dSHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R700"),
32813cb1f40dSHans de Goede },
328223f1d8b4SArvid Norlander .driver_data = (void *)QUIRK_TURN_ON_PANEL_ON_RESUME,
32833cb1f40dSHans de Goede },
32843cb1f40dSHans de Goede {
32853cb1f40dSHans de Goede /* Toshiba Satellite/Portégé R830 */
32863cb1f40dSHans de Goede /* Portégé: https://bugs.freedesktop.org/show_bug.cgi?id=82634 */
32873cb1f40dSHans de Goede /* Satellite: https://bugzilla.kernel.org/show_bug.cgi?id=21012 */
32883cb1f40dSHans de Goede .matches = {
32893cb1f40dSHans de Goede DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
32903cb1f40dSHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "R830"),
32913cb1f40dSHans de Goede },
329223f1d8b4SArvid Norlander .driver_data = (void *)QUIRK_TURN_ON_PANEL_ON_RESUME,
32933cb1f40dSHans de Goede },
32943cb1f40dSHans de Goede {
32953cb1f40dSHans de Goede /* Toshiba Satellite/Portégé Z830 */
32963cb1f40dSHans de Goede .matches = {
32973cb1f40dSHans de Goede DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
32983cb1f40dSHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "Z830"),
32993cb1f40dSHans de Goede },
330023f1d8b4SArvid Norlander .driver_data = (void *)(QUIRK_TURN_ON_PANEL_ON_RESUME | QUIRK_HCI_HOTKEY_QUICKSTART),
33013cb1f40dSHans de Goede },
3302*b6e02c6bSArmin Wolf { }
33033cb1f40dSHans de Goede };
33043cb1f40dSHans de Goede
toshiba_acpi_add(struct acpi_device * acpi_dev)3305b859f159SGreg Kroah-Hartman static int toshiba_acpi_add(struct acpi_device *acpi_dev)
3306135740deSSeth Forshee {
3307135740deSSeth Forshee struct toshiba_acpi_dev *dev;
3308a540d6b5SSeth Forshee const char *hci_method;
330936d03f93SSeth Forshee u32 dummy;
3310135740deSSeth Forshee int ret = 0;
3311135740deSSeth Forshee
331229cd293fSSeth Forshee if (toshiba_acpi)
331329cd293fSSeth Forshee return -EBUSY;
331429cd293fSSeth Forshee
3315135740deSSeth Forshee pr_info("Toshiba Laptop ACPI Extras version %s\n",
3316135740deSSeth Forshee TOSHIBA_ACPI_VERSION);
3317135740deSSeth Forshee
3318a540d6b5SSeth Forshee hci_method = find_hci_method(acpi_dev->handle);
3319a540d6b5SSeth Forshee if (!hci_method) {
3320a540d6b5SSeth Forshee pr_err("HCI interface not found\n");
33216e02cc7eSSeth Forshee return -ENODEV;
3322a540d6b5SSeth Forshee }
33236e02cc7eSSeth Forshee
3324135740deSSeth Forshee dev = kzalloc(sizeof(*dev), GFP_KERNEL);
3325135740deSSeth Forshee if (!dev)
3326135740deSSeth Forshee return -ENOMEM;
3327135740deSSeth Forshee dev->acpi_dev = acpi_dev;
3328a540d6b5SSeth Forshee dev->method_hci = hci_method;
3329fc5462f8SAzael Avalos dev->miscdev.minor = MISC_DYNAMIC_MINOR;
3330fc5462f8SAzael Avalos dev->miscdev.name = "toshiba_acpi";
3331fc5462f8SAzael Avalos dev->miscdev.fops = &toshiba_acpi_fops;
3332fc5462f8SAzael Avalos
3333fc5462f8SAzael Avalos ret = misc_register(&dev->miscdev);
3334fc5462f8SAzael Avalos if (ret) {
3335fc5462f8SAzael Avalos pr_err("Failed to register miscdevice\n");
3336fc5462f8SAzael Avalos kfree(dev);
3337fc5462f8SAzael Avalos return ret;
3338fc5462f8SAzael Avalos }
3339fc5462f8SAzael Avalos
3340135740deSSeth Forshee acpi_dev->driver_data = dev;
3341360f0f39SAzael Avalos dev_set_drvdata(&acpi_dev->dev, dev);
3342135740deSSeth Forshee
3343a2b3471bSAzael Avalos /* Query the BIOS for supported features */
3344a2b3471bSAzael Avalos
3345a2b3471bSAzael Avalos /*
3346a2b3471bSAzael Avalos * The "Special Functions" are always supported by the laptops
3347a2b3471bSAzael Avalos * with the new keyboard layout, query for its presence to help
3348a2b3471bSAzael Avalos * determine the keymap layout to use.
3349a2b3471bSAzael Avalos */
3350b116fd00SAzael Avalos ret = toshiba_function_keys_get(dev, &dev->special_functions);
3351a2b3471bSAzael Avalos dev->kbd_function_keys_supported = !ret;
3352a2b3471bSAzael Avalos
3353d2f20619SAzael Avalos dev->hotkey_event_type = 0;
33546e02cc7eSSeth Forshee if (toshiba_acpi_setup_keyboard(dev))
3355135740deSSeth Forshee pr_info("Unable to activate hotkeys\n");
3356135740deSSeth Forshee
3357695f6060SAzael Avalos /* Determine whether or not BIOS supports transflective backlight */
3358695f6060SAzael Avalos ret = get_tr_backlight_status(dev, &dummy);
3359695f6060SAzael Avalos dev->tr_backlight_supported = !ret;
3360695f6060SAzael Avalos
336162cce752SSeth Forshee ret = toshiba_acpi_setup_backlight(dev);
336262cce752SSeth Forshee if (ret)
3363135740deSSeth Forshee goto error;
3364135740deSSeth Forshee
3365ea215a3fSAzael Avalos toshiba_illumination_available(dev);
3366ea215a3fSAzael Avalos if (dev->illumination_supported) {
3367135740deSSeth Forshee dev->led_dev.name = "toshiba::illumination";
3368135740deSSeth Forshee dev->led_dev.max_brightness = 1;
3369135740deSSeth Forshee dev->led_dev.brightness_set = toshiba_illumination_set;
3370135740deSSeth Forshee dev->led_dev.brightness_get = toshiba_illumination_get;
3371409f3aedSAndy Shevchenko led_classdev_register(&acpi_dev->dev, &dev->led_dev);
3372135740deSSeth Forshee }
3373135740deSSeth Forshee
3374ea215a3fSAzael Avalos toshiba_eco_mode_available(dev);
3375ea215a3fSAzael Avalos if (dev->eco_supported) {
3376def6c4e2SAzael Avalos dev->eco_led.name = "toshiba::eco_mode";
3377def6c4e2SAzael Avalos dev->eco_led.max_brightness = 1;
3378def6c4e2SAzael Avalos dev->eco_led.brightness_set = toshiba_eco_mode_set_status;
3379def6c4e2SAzael Avalos dev->eco_led.brightness_get = toshiba_eco_mode_get_status;
3380409f3aedSAndy Shevchenko led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led);
3381def6c4e2SAzael Avalos }
3382def6c4e2SAzael Avalos
3383ea215a3fSAzael Avalos toshiba_kbd_illum_available(dev);
3384360f0f39SAzael Avalos /*
3385360f0f39SAzael Avalos * Only register the LED if KBD illumination is supported
3386360f0f39SAzael Avalos * and the keyboard backlight operation mode is set to FN-Z
3387147288e6SAzael Avalos * or we detect a second gen keyboard backlight
3388360f0f39SAzael Avalos */
3389147288e6SAzael Avalos if (dev->kbd_illum_supported &&
3390147288e6SAzael Avalos (dev->kbd_mode == SCI_KBD_MODE_FNZ || dev->kbd_type == 2)) {
3391360f0f39SAzael Avalos dev->kbd_led.name = "toshiba::kbd_backlight";
3392147288e6SAzael Avalos dev->kbd_led.flags = LED_BRIGHT_HW_CHANGED;
3393360f0f39SAzael Avalos dev->kbd_led.max_brightness = 1;
3394360f0f39SAzael Avalos dev->kbd_led.brightness_set = toshiba_kbd_backlight_set;
3395360f0f39SAzael Avalos dev->kbd_led.brightness_get = toshiba_kbd_backlight_get;
3396409f3aedSAndy Shevchenko led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led);
3397360f0f39SAzael Avalos }
3398360f0f39SAzael Avalos
33999d8658acSAzael Avalos ret = toshiba_touchpad_get(dev, &dummy);
34009d8658acSAzael Avalos dev->touchpad_supported = !ret;
34019d8658acSAzael Avalos
3402ea215a3fSAzael Avalos toshiba_accelerometer_available(dev);
340398010f1eSAzael Avalos if (dev->accelerometer_supported) {
340478289b4aSAlexandru Ardelean dev->indio_dev = iio_device_alloc(&acpi_dev->dev, sizeof(*dev));
340598010f1eSAzael Avalos if (!dev->indio_dev) {
340698010f1eSAzael Avalos pr_err("Unable to allocate iio device\n");
340798010f1eSAzael Avalos goto iio_error;
340898010f1eSAzael Avalos }
340998010f1eSAzael Avalos
341098010f1eSAzael Avalos pr_info("Registering Toshiba accelerometer iio device\n");
341198010f1eSAzael Avalos
341298010f1eSAzael Avalos dev->indio_dev->info = &toshiba_iio_accel_info;
341398010f1eSAzael Avalos dev->indio_dev->name = "Toshiba accelerometer";
341498010f1eSAzael Avalos dev->indio_dev->modes = INDIO_DIRECT_MODE;
341598010f1eSAzael Avalos dev->indio_dev->channels = toshiba_iio_accel_channels;
341698010f1eSAzael Avalos dev->indio_dev->num_channels =
341798010f1eSAzael Avalos ARRAY_SIZE(toshiba_iio_accel_channels);
341898010f1eSAzael Avalos
341998010f1eSAzael Avalos ret = iio_device_register(dev->indio_dev);
342098010f1eSAzael Avalos if (ret < 0) {
342198010f1eSAzael Avalos pr_err("Unable to register iio device\n");
342298010f1eSAzael Avalos iio_device_free(dev->indio_dev);
342398010f1eSAzael Avalos }
342498010f1eSAzael Avalos }
342598010f1eSAzael Avalos iio_error:
34265a2813e9SAzael Avalos
3427c8c91842SAzael Avalos toshiba_usb_sleep_charge_available(dev);
3428e26ffe51SAzael Avalos
3429bb3fe01fSAzael Avalos ret = toshiba_usb_rapid_charge_get(dev, &dummy);
3430bb3fe01fSAzael Avalos dev->usb_rapid_charge_supported = !ret;
3431bb3fe01fSAzael Avalos
3432172ce0a9SAzael Avalos ret = toshiba_usb_sleep_music_get(dev, &dummy);
3433172ce0a9SAzael Avalos dev->usb_sleep_music_supported = !ret;
3434172ce0a9SAzael Avalos
343535d53ceaSAzael Avalos ret = toshiba_panel_power_on_get(dev, &dummy);
343635d53ceaSAzael Avalos dev->panel_power_on_supported = !ret;
343735d53ceaSAzael Avalos
343817fe4b3dSAzael Avalos ret = toshiba_usb_three_get(dev, &dummy);
343917fe4b3dSAzael Avalos dev->usb_three_supported = !ret;
344017fe4b3dSAzael Avalos
344136d03f93SSeth Forshee ret = get_video_status(dev, &dummy);
344236d03f93SSeth Forshee dev->video_supported = !ret;
344336d03f93SSeth Forshee
344436d03f93SSeth Forshee ret = get_fan_status(dev, &dummy);
344536d03f93SSeth Forshee dev->fan_supported = !ret;
344636d03f93SSeth Forshee
3447dd193dcdSArvid Norlander ret = get_fan_rpm(dev, &dummy);
3448dd193dcdSArvid Norlander dev->fan_rpm_supported = !ret;
3449dd193dcdSArvid Norlander
3450c727ba4cSArvid Norlander #if IS_ENABLED(CONFIG_HWMON)
3451c727ba4cSArvid Norlander if (dev->fan_rpm_supported) {
3452c727ba4cSArvid Norlander dev->hwmon_device = hwmon_device_register_with_info(
3453c727ba4cSArvid Norlander &dev->acpi_dev->dev, "toshiba_acpi_sensors", NULL,
3454c727ba4cSArvid Norlander &toshiba_acpi_hwmon_chip_info, NULL);
3455c727ba4cSArvid Norlander if (IS_ERR(dev->hwmon_device)) {
3456c727ba4cSArvid Norlander dev->hwmon_device = NULL;
3457c727ba4cSArvid Norlander pr_warn("unable to register hwmon device, skipping\n");
3458c727ba4cSArvid Norlander }
3459c727ba4cSArvid Norlander }
3460c727ba4cSArvid Norlander #endif
3461c727ba4cSArvid Norlander
34626873f46aSAzael Avalos toshiba_wwan_available(dev);
34632fdde834SAzael Avalos if (dev->wwan_supported)
34642fdde834SAzael Avalos toshiba_acpi_setup_wwan_rfkill(dev);
34656873f46aSAzael Avalos
3466763ff32fSAzael Avalos toshiba_cooling_method_available(dev);
3467763ff32fSAzael Avalos
346889655fbbSArvid Norlander toshiba_battery_charge_mode_available(dev);
346989655fbbSArvid Norlander
34700409cbceSAzael Avalos print_supported_features(dev);
34710409cbceSAzael Avalos
3472360f0f39SAzael Avalos ret = sysfs_create_group(&dev->acpi_dev->dev.kobj,
3473360f0f39SAzael Avalos &toshiba_attr_group);
3474360f0f39SAzael Avalos if (ret) {
3475360f0f39SAzael Avalos dev->sysfs_created = 0;
3476360f0f39SAzael Avalos goto error;
3477360f0f39SAzael Avalos }
3478360f0f39SAzael Avalos dev->sysfs_created = !ret;
3479360f0f39SAzael Avalos
348036d03f93SSeth Forshee create_toshiba_proc_entries(dev);
348136d03f93SSeth Forshee
348229cd293fSSeth Forshee toshiba_acpi = dev;
348329cd293fSSeth Forshee
34848ef5db9eSArvid Norlander /*
34858ef5db9eSArvid Norlander * As the battery hook relies on the static variable toshiba_acpi being
34868ef5db9eSArvid Norlander * set, this must be done after toshiba_acpi is assigned.
34878ef5db9eSArvid Norlander */
34888ef5db9eSArvid Norlander if (dev->battery_charge_mode_supported)
34898ef5db9eSArvid Norlander battery_hook_register(&battery_hook);
34908ef5db9eSArvid Norlander
3491135740deSSeth Forshee return 0;
3492135740deSSeth Forshee
3493135740deSSeth Forshee error:
349451fac838SRafael J. Wysocki toshiba_acpi_remove(acpi_dev);
3495135740deSSeth Forshee return ret;
3496135740deSSeth Forshee }
3497135740deSSeth Forshee
toshiba_acpi_notify(struct acpi_device * acpi_dev,u32 event)3498135740deSSeth Forshee static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
3499135740deSSeth Forshee {
3500135740deSSeth Forshee struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
35016335e4d5SMatthew Garrett
350271454d78SAzael Avalos switch (event) {
350371454d78SAzael Avalos case 0x80: /* Hotkeys and some system events */
3504a88bc06eSAzael Avalos /*
3505a88bc06eSAzael Avalos * Machines with this WMI GUID aren't supported due to bugs in
3506a88bc06eSAzael Avalos * their AML.
3507a88bc06eSAzael Avalos *
3508a88bc06eSAzael Avalos * Return silently to avoid triggering a netlink event.
3509a88bc06eSAzael Avalos */
3510a88bc06eSAzael Avalos if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
3511a88bc06eSAzael Avalos return;
351271454d78SAzael Avalos toshiba_acpi_process_hotkeys(dev);
351311948b93SSeth Forshee break;
3514bab09e23SAzael Avalos case 0x81: /* Dock events */
3515bab09e23SAzael Avalos case 0x82:
3516bab09e23SAzael Avalos case 0x83:
3517bab09e23SAzael Avalos pr_info("Dock event received %x\n", event);
3518bab09e23SAzael Avalos break;
3519bab09e23SAzael Avalos case 0x88: /* Thermal events */
3520bab09e23SAzael Avalos pr_info("Thermal event received\n");
3521bab09e23SAzael Avalos break;
3522bab09e23SAzael Avalos case 0x8f: /* LID closed */
3523bab09e23SAzael Avalos case 0x90: /* LID is closed and Dock has been ejected */
3524bab09e23SAzael Avalos break;
3525bab09e23SAzael Avalos case 0x8c: /* SATA power events */
3526bab09e23SAzael Avalos case 0x8b:
3527bab09e23SAzael Avalos pr_info("SATA power event received %x\n", event);
3528bab09e23SAzael Avalos break;
352980546905SAzael Avalos case 0x92: /* Keyboard backlight mode changed */
3530147288e6SAzael Avalos dev->kbd_event_generated = true;
353180546905SAzael Avalos /* Update sysfs entries */
353265e3cf9cSAzael Avalos if (sysfs_update_group(&acpi_dev->dev.kobj,
353365e3cf9cSAzael Avalos &toshiba_attr_group))
353480546905SAzael Avalos pr_err("Unable to update sysfs entries\n");
3535147288e6SAzael Avalos /* Notify LED subsystem about keyboard backlight change */
3536147288e6SAzael Avalos if (dev->kbd_type == 2 && dev->kbd_mode != SCI_KBD_MODE_AUTO)
3537147288e6SAzael Avalos led_classdev_notify_brightness_hw_changed(&dev->kbd_led,
3538147288e6SAzael Avalos (dev->kbd_mode == SCI_KBD_MODE_ON) ?
3539147288e6SAzael Avalos LED_FULL : LED_OFF);
354080546905SAzael Avalos break;
35410dd50b3eSHans de Goede case 0x8e: /* Power button pressed */
35420dd50b3eSHans de Goede break;
3543bab09e23SAzael Avalos case 0x85: /* Unknown */
3544bab09e23SAzael Avalos case 0x8d: /* Unknown */
3545bab09e23SAzael Avalos case 0x94: /* Unknown */
3546bab09e23SAzael Avalos case 0x95: /* Unknown */
354711948b93SSeth Forshee default:
354871454d78SAzael Avalos pr_info("Unknown event received %x\n", event);
354911948b93SSeth Forshee break;
35506335e4d5SMatthew Garrett }
3551bab09e23SAzael Avalos
3552bab09e23SAzael Avalos acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class,
3553bab09e23SAzael Avalos dev_name(&acpi_dev->dev),
355413ae84f9SAzael Avalos event, (event == 0x80) ?
355513ae84f9SAzael Avalos dev->last_key_event : 0);
355629cd293fSSeth Forshee }
35576335e4d5SMatthew Garrett
35583567a4e2SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP
toshiba_acpi_suspend(struct device * device)355943d2fd3bSRafael J. Wysocki static int toshiba_acpi_suspend(struct device *device)
356029cd293fSSeth Forshee {
356143d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
35621e574dbfSAzael Avalos
35631e574dbfSAzael Avalos if (dev->hotkey_dev) {
356429cd293fSSeth Forshee u32 result;
356529cd293fSSeth Forshee
3566d37782bdSAzael Avalos result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE);
35671e574dbfSAzael Avalos if (result != TOS_SUCCESS)
35681e574dbfSAzael Avalos pr_info("Unable to disable hotkeys\n");
35691e574dbfSAzael Avalos }
357029cd293fSSeth Forshee
357129cd293fSSeth Forshee return 0;
357229cd293fSSeth Forshee }
357329cd293fSSeth Forshee
toshiba_acpi_resume(struct device * device)357443d2fd3bSRafael J. Wysocki static int toshiba_acpi_resume(struct device *device)
357529cd293fSSeth Forshee {
357643d2fd3bSRafael J. Wysocki struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
357729cd293fSSeth Forshee
3578e7fdb762SBenjamin Tissoires if (dev->hotkey_dev) {
35792fdde834SAzael Avalos if (toshiba_acpi_enable_hotkeys(dev))
3580e7fdb762SBenjamin Tissoires pr_info("Unable to re-enable hotkeys\n");
3581e7fdb762SBenjamin Tissoires }
358229cd293fSSeth Forshee
35832fdde834SAzael Avalos if (dev->wwan_rfk) {
35842fdde834SAzael Avalos if (!toshiba_wireless_status(dev))
35852fdde834SAzael Avalos rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch);
35862fdde834SAzael Avalos }
35872fdde834SAzael Avalos
35883cb1f40dSHans de Goede if (turn_on_panel_on_resume)
35893cb1f40dSHans de Goede hci_write(dev, HCI_PANEL_POWER_ON, 1);
35903cb1f40dSHans de Goede
359129cd293fSSeth Forshee return 0;
359229cd293fSSeth Forshee }
35933567a4e2SRafael J. Wysocki #endif
35946335e4d5SMatthew Garrett
359543d2fd3bSRafael J. Wysocki static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm,
359643d2fd3bSRafael J. Wysocki toshiba_acpi_suspend, toshiba_acpi_resume);
359743d2fd3bSRafael J. Wysocki
3598135740deSSeth Forshee static struct acpi_driver toshiba_acpi_driver = {
3599135740deSSeth Forshee .name = "Toshiba ACPI driver",
3600135740deSSeth Forshee .ids = toshiba_device_ids,
3601135740deSSeth Forshee .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
3602135740deSSeth Forshee .ops = {
3603135740deSSeth Forshee .add = toshiba_acpi_add,
3604135740deSSeth Forshee .remove = toshiba_acpi_remove,
3605135740deSSeth Forshee .notify = toshiba_acpi_notify,
3606135740deSSeth Forshee },
360743d2fd3bSRafael J. Wysocki .drv.pm = &toshiba_acpi_pm,
3608135740deSSeth Forshee };
3609b4f9fe12SLen Brown
toshiba_dmi_init(void)3610e527a612SArmin Wolf static void __init toshiba_dmi_init(void)
3611e527a612SArmin Wolf {
3612e527a612SArmin Wolf const struct dmi_system_id *dmi_id;
3613e527a612SArmin Wolf long quirks = 0;
3614e527a612SArmin Wolf
3615e527a612SArmin Wolf dmi_id = dmi_first_match(toshiba_dmi_quirks);
3616e527a612SArmin Wolf if (dmi_id)
3617e527a612SArmin Wolf quirks = (long)dmi_id->driver_data;
3618e527a612SArmin Wolf
3619e527a612SArmin Wolf if (turn_on_panel_on_resume == -1)
3620e527a612SArmin Wolf turn_on_panel_on_resume = !!(quirks & QUIRK_TURN_ON_PANEL_ON_RESUME);
3621e527a612SArmin Wolf
3622e527a612SArmin Wolf if (hci_hotkey_quickstart == -1)
3623e527a612SArmin Wolf hci_hotkey_quickstart = !!(quirks & QUIRK_HCI_HOTKEY_QUICKSTART);
3624e527a612SArmin Wolf }
3625e527a612SArmin Wolf
toshiba_acpi_init(void)3626b4f9fe12SLen Brown static int __init toshiba_acpi_init(void)
3627b4f9fe12SLen Brown {
3628135740deSSeth Forshee int ret;
3629b4f9fe12SLen Brown
3630e527a612SArmin Wolf toshiba_dmi_init();
3631b4f9fe12SLen Brown toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
3632b4f9fe12SLen Brown if (!toshiba_proc_dir) {
3633135740deSSeth Forshee pr_err("Unable to create proc dir " PROC_TOSHIBA "\n");
3634b4f9fe12SLen Brown return -ENODEV;
3635b4f9fe12SLen Brown }
3636b4f9fe12SLen Brown
3637135740deSSeth Forshee ret = acpi_bus_register_driver(&toshiba_acpi_driver);
3638b4f9fe12SLen Brown if (ret) {
3639135740deSSeth Forshee pr_err("Failed to register ACPI driver: %d\n", ret);
3640135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
3641135740deSSeth Forshee }
3642135740deSSeth Forshee
3643b4f9fe12SLen Brown return ret;
3644b4f9fe12SLen Brown }
3645b4f9fe12SLen Brown
toshiba_acpi_exit(void)3646135740deSSeth Forshee static void __exit toshiba_acpi_exit(void)
3647135740deSSeth Forshee {
3648135740deSSeth Forshee acpi_bus_unregister_driver(&toshiba_acpi_driver);
3649135740deSSeth Forshee if (toshiba_proc_dir)
3650135740deSSeth Forshee remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
3651b4f9fe12SLen Brown }
3652b4f9fe12SLen Brown
3653b4f9fe12SLen Brown module_init(toshiba_acpi_init);
3654b4f9fe12SLen Brown module_exit(toshiba_acpi_exit);
3655