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