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