xref: /linux/drivers/platform/x86/toshiba_acpi.c (revision 98fc4ec64a211a9d301172dec2aed08f47964295)
1b4f9fe12SLen Brown /*
2b4f9fe12SLen Brown  *  toshiba_acpi.c - Toshiba Laptop ACPI Extras
3b4f9fe12SLen Brown  *
4b4f9fe12SLen Brown  *
5b4f9fe12SLen Brown  *  Copyright (C) 2002-2004 John Belmonte
6b4f9fe12SLen Brown  *  Copyright (C) 2008 Philip Langdale
76c3f6e6cSPierre Ducroquet  *  Copyright (C) 2010 Pierre Ducroquet
8548c4306SAzael Avalos  *  Copyright (C) 2014 Azael Avalos
9b4f9fe12SLen Brown  *
10b4f9fe12SLen Brown  *  This program is free software; you can redistribute it and/or modify
11b4f9fe12SLen Brown  *  it under the terms of the GNU General Public License as published by
12b4f9fe12SLen Brown  *  the Free Software Foundation; either version 2 of the License, or
13b4f9fe12SLen Brown  *  (at your option) any later version.
14b4f9fe12SLen Brown  *
15b4f9fe12SLen Brown  *  This program is distributed in the hope that it will be useful,
16b4f9fe12SLen Brown  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17b4f9fe12SLen Brown  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18b4f9fe12SLen Brown  *  GNU General Public License for more details.
19b4f9fe12SLen Brown  *
20b4f9fe12SLen Brown  *  You should have received a copy of the GNU General Public License
21b4f9fe12SLen Brown  *  along with this program; if not, write to the Free Software
22b4f9fe12SLen Brown  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23b4f9fe12SLen Brown  *
24b4f9fe12SLen Brown  *
25b4f9fe12SLen Brown  *  The devolpment page for this driver is located at
26b4f9fe12SLen Brown  *  http://memebeam.org/toys/ToshibaAcpiDriver.
27b4f9fe12SLen Brown  *
28b4f9fe12SLen Brown  *  Credits:
29b4f9fe12SLen Brown  *	Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse
30b4f9fe12SLen Brown  *		engineering the Windows drivers
31b4f9fe12SLen Brown  *	Yasushi Nagato - changes for linux kernel 2.4 -> 2.5
32b4f9fe12SLen Brown  *	Rob Miller - TV out and hotkeys help
33b4f9fe12SLen Brown  *
34b4f9fe12SLen Brown  *
35b4f9fe12SLen Brown  *  TODO
36b4f9fe12SLen Brown  *
37b4f9fe12SLen Brown  */
38b4f9fe12SLen Brown 
397e33460dSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
407e33460dSJoe Perches 
41548c4306SAzael Avalos #define TOSHIBA_ACPI_VERSION	"0.20"
42b4f9fe12SLen Brown #define PROC_INTERFACE_VERSION	1
43b4f9fe12SLen Brown 
44b4f9fe12SLen Brown #include <linux/kernel.h>
45b4f9fe12SLen Brown #include <linux/module.h>
46b4f9fe12SLen Brown #include <linux/init.h>
47b4f9fe12SLen Brown #include <linux/types.h>
48b4f9fe12SLen Brown #include <linux/proc_fs.h>
49936c8bcdSAlexey Dobriyan #include <linux/seq_file.h>
50b4f9fe12SLen Brown #include <linux/backlight.h>
51b4f9fe12SLen Brown #include <linux/rfkill.h>
526335e4d5SMatthew Garrett #include <linux/input.h>
53384a7cd9SDmitry Torokhov #include <linux/input/sparse-keymap.h>
546c3f6e6cSPierre Ducroquet #include <linux/leds.h>
555a0e3ad6STejun Heo #include <linux/slab.h>
5629cd293fSSeth Forshee #include <linux/workqueue.h>
5729cd293fSSeth Forshee #include <linux/i8042.h>
588b48463fSLv Zheng #include <linux/acpi.h>
59fe808bfbSTakashi Iwai #include <linux/dmi.h>
60b4f9fe12SLen Brown #include <asm/uaccess.h>
61b4f9fe12SLen Brown 
62b4f9fe12SLen Brown MODULE_AUTHOR("John Belmonte");
63b4f9fe12SLen Brown MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
64b4f9fe12SLen Brown MODULE_LICENSE("GPL");
65b4f9fe12SLen Brown 
66f11f999eSSeth Forshee #define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100"
67f11f999eSSeth Forshee 
6829cd293fSSeth Forshee /* Scan code for Fn key on TOS1900 models */
6929cd293fSSeth Forshee #define TOS1900_FN_SCAN		0x6e
7029cd293fSSeth Forshee 
71b4f9fe12SLen Brown /* Toshiba ACPI method paths */
72b4f9fe12SLen Brown #define METHOD_VIDEO_OUT	"\\_SB_.VALX.DSSX"
73b4f9fe12SLen Brown 
74258c5903SAzael Avalos /* The Toshiba configuration interface is composed of the HCI and the SCI,
75258c5903SAzael Avalos  * which are defined as follows:
76b4f9fe12SLen Brown  *
77b4f9fe12SLen Brown  * HCI is Toshiba's "Hardware Control Interface" which is supposed to
78b4f9fe12SLen Brown  * be uniform across all their models.  Ideally we would just call
79b4f9fe12SLen Brown  * dedicated ACPI methods instead of using this primitive interface.
80b4f9fe12SLen Brown  * However the ACPI methods seem to be incomplete in some areas (for
81b4f9fe12SLen Brown  * example they allow setting, but not reading, the LCD brightness value),
82b4f9fe12SLen Brown  * so this is still useful.
8384a6273fSAzael Avalos  *
8484a6273fSAzael Avalos  * SCI stands for "System Configuration Interface" which aim is to
8584a6273fSAzael Avalos  * conceal differences in hardware between different models.
86b4f9fe12SLen Brown  */
87b4f9fe12SLen Brown 
88258c5903SAzael Avalos #define TCI_WORDS			6
89b4f9fe12SLen Brown 
90b4f9fe12SLen Brown /* operations */
91b4f9fe12SLen Brown #define HCI_SET				0xff00
92b4f9fe12SLen Brown #define HCI_GET				0xfe00
9384a6273fSAzael Avalos #define SCI_OPEN			0xf100
9484a6273fSAzael Avalos #define SCI_CLOSE			0xf200
9584a6273fSAzael Avalos #define SCI_GET				0xf300
9684a6273fSAzael Avalos #define SCI_SET				0xf400
97b4f9fe12SLen Brown 
98b4f9fe12SLen Brown /* return codes */
991864bbc2SAzael Avalos #define TOS_SUCCESS			0x0000
1001864bbc2SAzael Avalos #define TOS_OPEN_CLOSE_OK		0x0044
1011864bbc2SAzael Avalos #define TOS_FAILURE			0x1000
1021864bbc2SAzael Avalos #define TOS_NOT_SUPPORTED		0x8000
1031864bbc2SAzael Avalos #define TOS_ALREADY_OPEN		0x8100
1041864bbc2SAzael Avalos #define TOS_NOT_OPENED			0x8200
1051864bbc2SAzael Avalos #define TOS_INPUT_DATA_ERROR		0x8300
1061864bbc2SAzael Avalos #define TOS_WRITE_PROTECTED		0x8400
1071864bbc2SAzael Avalos #define TOS_NOT_PRESENT			0x8600
1081864bbc2SAzael Avalos #define TOS_FIFO_EMPTY			0x8c00
1091864bbc2SAzael Avalos #define TOS_DATA_NOT_AVAILABLE		0x8d20
1101864bbc2SAzael Avalos #define TOS_NOT_INITIALIZED		0x8d50
111*98fc4ec6SAzael Avalos #define TOS_NOT_INSTALLED		0x8e00
112b4f9fe12SLen Brown 
113b4f9fe12SLen Brown /* registers */
114b4f9fe12SLen Brown #define HCI_FAN				0x0004
115121b7b0dSAkio Idehara #define HCI_TR_BACKLIGHT		0x0005
116b4f9fe12SLen Brown #define HCI_SYSTEM_EVENT		0x0016
117b4f9fe12SLen Brown #define HCI_VIDEO_OUT			0x001c
118b4f9fe12SLen Brown #define HCI_HOTKEY_EVENT		0x001e
119b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS		0x002a
120b4f9fe12SLen Brown #define HCI_WIRELESS			0x0056
1215a2813e9SAzael Avalos #define HCI_ACCELEROMETER		0x006d
122360f0f39SAzael Avalos #define HCI_KBD_ILLUMINATION		0x0095
123def6c4e2SAzael Avalos #define HCI_ECO_MODE			0x0097
1245a2813e9SAzael Avalos #define HCI_ACCELEROMETER2		0x00a6
125fdb79081SAzael Avalos #define SCI_ILLUMINATION		0x014e
126e26ffe51SAzael Avalos #define SCI_USB_SLEEP_CHARGE		0x0150
127360f0f39SAzael Avalos #define SCI_KBD_ILLUM_STATUS		0x015c
128172ce0a9SAzael Avalos #define SCI_USB_SLEEP_MUSIC		0x015e
1299d8658acSAzael Avalos #define SCI_TOUCHPAD			0x050e
130b4f9fe12SLen Brown 
131b4f9fe12SLen Brown /* field definitions */
1325a2813e9SAzael Avalos #define HCI_ACCEL_MASK			0x7fff
13329cd293fSSeth Forshee #define HCI_HOTKEY_DISABLE		0x0b
13429cd293fSSeth Forshee #define HCI_HOTKEY_ENABLE		0x09
135b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_BITS		3
136b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_SHIFT	(16-HCI_LCD_BRIGHTNESS_BITS)
137b4f9fe12SLen Brown #define HCI_LCD_BRIGHTNESS_LEVELS	(1 << HCI_LCD_BRIGHTNESS_BITS)
138360f0f39SAzael Avalos #define HCI_MISC_SHIFT			0x10
139b4f9fe12SLen Brown #define HCI_VIDEO_OUT_LCD		0x1
140b4f9fe12SLen Brown #define HCI_VIDEO_OUT_CRT		0x2
141b4f9fe12SLen Brown #define HCI_VIDEO_OUT_TV		0x4
142b4f9fe12SLen Brown #define HCI_WIRELESS_KILL_SWITCH	0x01
143b4f9fe12SLen Brown #define HCI_WIRELESS_BT_PRESENT		0x0f
144b4f9fe12SLen Brown #define HCI_WIRELESS_BT_ATTACH		0x40
145b4f9fe12SLen Brown #define HCI_WIRELESS_BT_POWER		0x80
14693f8c16dSAzael Avalos #define SCI_KBD_MODE_MASK		0x1f
147360f0f39SAzael Avalos #define SCI_KBD_MODE_FNZ		0x1
148360f0f39SAzael Avalos #define SCI_KBD_MODE_AUTO		0x2
14993f8c16dSAzael Avalos #define SCI_KBD_MODE_ON			0x8
15093f8c16dSAzael Avalos #define SCI_KBD_MODE_OFF		0x10
15193f8c16dSAzael Avalos #define SCI_KBD_TIME_MAX		0x3c001a
152e26ffe51SAzael Avalos #define SCI_USB_CHARGE_MODE_MASK	0xff
153e26ffe51SAzael Avalos #define SCI_USB_CHARGE_DISABLED		0x30000
154e26ffe51SAzael Avalos #define SCI_USB_CHARGE_ALTERNATE	0x30009
155e26ffe51SAzael Avalos #define SCI_USB_CHARGE_AUTO		0x30021
156182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_MASK		0x7
157182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_OFF	0x1
158182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL_ON	0x4
159182bcaa5SAzael Avalos #define SCI_USB_CHARGE_BAT_LVL		0x0200
160bb3fe01fSAzael Avalos #define SCI_USB_CHARGE_RAPID_DSP	0x0300
161b4f9fe12SLen Brown 
162135740deSSeth Forshee struct toshiba_acpi_dev {
163135740deSSeth Forshee 	struct acpi_device *acpi_dev;
164135740deSSeth Forshee 	const char *method_hci;
165135740deSSeth Forshee 	struct rfkill *bt_rfk;
166135740deSSeth Forshee 	struct input_dev *hotkey_dev;
16729cd293fSSeth Forshee 	struct work_struct hotkey_work;
168135740deSSeth Forshee 	struct backlight_device *backlight_dev;
169135740deSSeth Forshee 	struct led_classdev led_dev;
170360f0f39SAzael Avalos 	struct led_classdev kbd_led;
171def6c4e2SAzael Avalos 	struct led_classdev eco_led;
17236d03f93SSeth Forshee 
173135740deSSeth Forshee 	int force_fan;
174135740deSSeth Forshee 	int last_key_event;
175135740deSSeth Forshee 	int key_event_valid;
17693f8c16dSAzael Avalos 	int kbd_type;
177360f0f39SAzael Avalos 	int kbd_mode;
178360f0f39SAzael Avalos 	int kbd_time;
179182bcaa5SAzael Avalos 	int usbsc_bat_level;
180135740deSSeth Forshee 
181592b746cSDan Carpenter 	unsigned int illumination_supported:1;
182592b746cSDan Carpenter 	unsigned int video_supported:1;
183592b746cSDan Carpenter 	unsigned int fan_supported:1;
184592b746cSDan Carpenter 	unsigned int system_event_supported:1;
18529cd293fSSeth Forshee 	unsigned int ntfy_supported:1;
18629cd293fSSeth Forshee 	unsigned int info_supported:1;
187121b7b0dSAkio Idehara 	unsigned int tr_backlight_supported:1;
188360f0f39SAzael Avalos 	unsigned int kbd_illum_supported:1;
189360f0f39SAzael Avalos 	unsigned int kbd_led_registered:1;
1909d8658acSAzael Avalos 	unsigned int touchpad_supported:1;
191def6c4e2SAzael Avalos 	unsigned int eco_supported:1;
1925a2813e9SAzael Avalos 	unsigned int accelerometer_supported:1;
193e26ffe51SAzael Avalos 	unsigned int usb_sleep_charge_supported:1;
194bb3fe01fSAzael Avalos 	unsigned int usb_rapid_charge_supported:1;
195172ce0a9SAzael Avalos 	unsigned int usb_sleep_music_supported:1;
196360f0f39SAzael Avalos 	unsigned int sysfs_created:1;
19736d03f93SSeth Forshee 
198135740deSSeth Forshee 	struct mutex mutex;
199135740deSSeth Forshee };
200135740deSSeth Forshee 
20129cd293fSSeth Forshee static struct toshiba_acpi_dev *toshiba_acpi;
20229cd293fSSeth Forshee 
203b4f9fe12SLen Brown static const struct acpi_device_id toshiba_device_ids[] = {
204b4f9fe12SLen Brown 	{"TOS6200", 0},
20563a9e016SOndrej Zary 	{"TOS6207", 0},
206b4f9fe12SLen Brown 	{"TOS6208", 0},
207b4f9fe12SLen Brown 	{"TOS1900", 0},
208b4f9fe12SLen Brown 	{"", 0},
209b4f9fe12SLen Brown };
210b4f9fe12SLen Brown MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
211b4f9fe12SLen Brown 
212b859f159SGreg Kroah-Hartman static const struct key_entry toshiba_acpi_keymap[] = {
213fec278a1SUnai Uribarri 	{ KE_KEY, 0x9e, { KEY_RFKILL } },
214384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x101, { KEY_MUTE } },
215384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x102, { KEY_ZOOMOUT } },
216384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x103, { KEY_ZOOMIN } },
217408a5d13SAzael Avalos 	{ KE_KEY, 0x10f, { KEY_TAB } },
218af502837SAzael Avalos 	{ KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
219af502837SAzael Avalos 	{ KE_KEY, 0x139, { KEY_ZOOMRESET } },
220384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x13b, { KEY_COFFEE } },
221384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x13c, { KEY_BATTERY } },
222384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x13d, { KEY_SLEEP } },
223384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x13e, { KEY_SUSPEND } },
224384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } },
225384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } },
226384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x141, { KEY_BRIGHTNESSUP } },
227384a7cd9SDmitry Torokhov 	{ KE_KEY, 0x142, { KEY_WLAN } },
228af502837SAzael Avalos 	{ KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } },
229a49010f5SJon Dowland 	{ KE_KEY, 0x17f, { KEY_FN } },
230384a7cd9SDmitry Torokhov 	{ KE_KEY, 0xb05, { KEY_PROG2 } },
231384a7cd9SDmitry Torokhov 	{ KE_KEY, 0xb06, { KEY_WWW } },
232384a7cd9SDmitry Torokhov 	{ KE_KEY, 0xb07, { KEY_MAIL } },
233384a7cd9SDmitry Torokhov 	{ KE_KEY, 0xb30, { KEY_STOP } },
234384a7cd9SDmitry Torokhov 	{ KE_KEY, 0xb31, { KEY_PREVIOUSSONG } },
235384a7cd9SDmitry Torokhov 	{ KE_KEY, 0xb32, { KEY_NEXTSONG } },
236384a7cd9SDmitry Torokhov 	{ KE_KEY, 0xb33, { KEY_PLAYPAUSE } },
237384a7cd9SDmitry Torokhov 	{ KE_KEY, 0xb5a, { KEY_MEDIA } },
238408a5d13SAzael Avalos 	{ KE_IGNORE, 0x1430, { KEY_RESERVED } }, /* Wake from sleep */
239408a5d13SAzael Avalos 	{ KE_IGNORE, 0x1501, { KEY_RESERVED } }, /* Output changed */
240408a5d13SAzael Avalos 	{ KE_IGNORE, 0x1502, { KEY_RESERVED } }, /* HDMI plugged/unplugged */
241408a5d13SAzael Avalos 	{ KE_IGNORE, 0x1ABE, { KEY_RESERVED } }, /* Protection level set */
242408a5d13SAzael Avalos 	{ KE_IGNORE, 0x1ABF, { KEY_RESERVED } }, /* Protection level off */
243384a7cd9SDmitry Torokhov 	{ KE_END, 0 },
2446335e4d5SMatthew Garrett };
2456335e4d5SMatthew Garrett 
246fe808bfbSTakashi Iwai /* alternative keymap */
247fe808bfbSTakashi Iwai static const struct dmi_system_id toshiba_alt_keymap_dmi[] = {
248fe808bfbSTakashi Iwai 	{
249fe808bfbSTakashi Iwai 		.matches = {
250fe808bfbSTakashi Iwai 			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
251fe808bfbSTakashi Iwai 			DMI_MATCH(DMI_PRODUCT_NAME, "Satellite M840"),
252fe808bfbSTakashi Iwai 		},
253fe808bfbSTakashi Iwai 	},
254e6efad7fSAzael Avalos 	{
255e6efad7fSAzael Avalos 		.matches = {
256e6efad7fSAzael Avalos 			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
257e6efad7fSAzael Avalos 			DMI_MATCH(DMI_PRODUCT_NAME, "Qosmio X75-A"),
258e6efad7fSAzael Avalos 		},
259e6efad7fSAzael Avalos 	},
260b1bde689SAaron Lu 	{
261b1bde689SAaron Lu 		.matches = {
262b1bde689SAaron Lu 			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
263b1bde689SAaron Lu 			DMI_MATCH(DMI_PRODUCT_NAME, "TECRA A50-A"),
264b1bde689SAaron Lu 		},
265b1bde689SAaron Lu 	},
266fe808bfbSTakashi Iwai 	{}
267fe808bfbSTakashi Iwai };
268fe808bfbSTakashi Iwai 
269fe808bfbSTakashi Iwai static const struct key_entry toshiba_acpi_alt_keymap[] = {
270fe808bfbSTakashi Iwai 	{ KE_KEY, 0x157, { KEY_MUTE } },
271fe808bfbSTakashi Iwai 	{ KE_KEY, 0x102, { KEY_ZOOMOUT } },
272fe808bfbSTakashi Iwai 	{ KE_KEY, 0x103, { KEY_ZOOMIN } },
273e6efad7fSAzael Avalos 	{ KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
274fe808bfbSTakashi Iwai 	{ KE_KEY, 0x139, { KEY_ZOOMRESET } },
275fe808bfbSTakashi Iwai 	{ KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } },
276fe808bfbSTakashi Iwai 	{ KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } },
277fe808bfbSTakashi Iwai 	{ KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } },
278fe808bfbSTakashi Iwai 	{ KE_KEY, 0x158, { KEY_WLAN } },
279fe808bfbSTakashi Iwai 	{ KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } },
280fe808bfbSTakashi Iwai 	{ KE_END, 0 },
281fe808bfbSTakashi Iwai };
282fe808bfbSTakashi Iwai 
283b4f9fe12SLen Brown /* utility
284b4f9fe12SLen Brown  */
285b4f9fe12SLen Brown 
286b4f9fe12SLen Brown static __inline__ void _set_bit(u32 * word, u32 mask, int value)
287b4f9fe12SLen Brown {
288b4f9fe12SLen Brown 	*word = (*word & ~mask) | (mask * value);
289b4f9fe12SLen Brown }
290b4f9fe12SLen Brown 
291b4f9fe12SLen Brown /* acpi interface wrappers
292b4f9fe12SLen Brown  */
293b4f9fe12SLen Brown 
294b4f9fe12SLen Brown static int write_acpi_int(const char *methodName, int val)
295b4f9fe12SLen Brown {
296b4f9fe12SLen Brown 	acpi_status status;
297b4f9fe12SLen Brown 
298619400daSZhang Rui 	status = acpi_execute_simple_method(NULL, (char *)methodName, val);
29932bcd5cbSSeth Forshee 	return (status == AE_OK) ? 0 : -EIO;
300b4f9fe12SLen Brown }
301b4f9fe12SLen Brown 
302258c5903SAzael Avalos /* Perform a raw configuration call.  Here we don't care about input or output
303258c5903SAzael Avalos  * buffer format.
304b4f9fe12SLen Brown  */
305258c5903SAzael Avalos static acpi_status tci_raw(struct toshiba_acpi_dev *dev,
306258c5903SAzael Avalos 			   const u32 in[TCI_WORDS], u32 out[TCI_WORDS])
307b4f9fe12SLen Brown {
308b4f9fe12SLen Brown 	struct acpi_object_list params;
309258c5903SAzael Avalos 	union acpi_object in_objs[TCI_WORDS];
310b4f9fe12SLen Brown 	struct acpi_buffer results;
311258c5903SAzael Avalos 	union acpi_object out_objs[TCI_WORDS + 1];
312b4f9fe12SLen Brown 	acpi_status status;
313b4f9fe12SLen Brown 	int i;
314b4f9fe12SLen Brown 
315258c5903SAzael Avalos 	params.count = TCI_WORDS;
316b4f9fe12SLen Brown 	params.pointer = in_objs;
317258c5903SAzael Avalos 	for (i = 0; i < TCI_WORDS; ++i) {
318b4f9fe12SLen Brown 		in_objs[i].type = ACPI_TYPE_INTEGER;
319b4f9fe12SLen Brown 		in_objs[i].integer.value = in[i];
320b4f9fe12SLen Brown 	}
321b4f9fe12SLen Brown 
322b4f9fe12SLen Brown 	results.length = sizeof(out_objs);
323b4f9fe12SLen Brown 	results.pointer = out_objs;
324b4f9fe12SLen Brown 
3256e02cc7eSSeth Forshee 	status = acpi_evaluate_object(dev->acpi_dev->handle,
3266e02cc7eSSeth Forshee 				      (char *)dev->method_hci, &params,
327b4f9fe12SLen Brown 				      &results);
328258c5903SAzael Avalos 	if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) {
329b4f9fe12SLen Brown 		for (i = 0; i < out_objs->package.count; ++i) {
330b4f9fe12SLen Brown 			out[i] = out_objs->package.elements[i].integer.value;
331b4f9fe12SLen Brown 		}
332b4f9fe12SLen Brown 	}
333b4f9fe12SLen Brown 
334b4f9fe12SLen Brown 	return status;
335b4f9fe12SLen Brown }
336b4f9fe12SLen Brown 
337b4f9fe12SLen Brown /* common hci tasks (get or set one or two value)
338b4f9fe12SLen Brown  *
339b4f9fe12SLen Brown  * In addition to the ACPI status, the HCI system returns a result which
340b4f9fe12SLen Brown  * may be useful (such as "not supported").
341b4f9fe12SLen Brown  */
342b4f9fe12SLen Brown 
343893f3f62SAzael Avalos static u32 hci_write1(struct toshiba_acpi_dev *dev, u32 reg, u32 in1)
344b4f9fe12SLen Brown {
345258c5903SAzael Avalos 	u32 in[TCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 };
346258c5903SAzael Avalos 	u32 out[TCI_WORDS];
347258c5903SAzael Avalos 	acpi_status status = tci_raw(dev, in, out);
348893f3f62SAzael Avalos 
349893f3f62SAzael Avalos 	return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE;
350b4f9fe12SLen Brown }
351b4f9fe12SLen Brown 
352893f3f62SAzael Avalos static u32 hci_read1(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1)
353b4f9fe12SLen Brown {
354258c5903SAzael Avalos 	u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 };
355258c5903SAzael Avalos 	u32 out[TCI_WORDS];
356258c5903SAzael Avalos 	acpi_status status = tci_raw(dev, in, out);
357893f3f62SAzael Avalos 	if (ACPI_FAILURE(status))
358893f3f62SAzael Avalos 		return TOS_FAILURE;
359893f3f62SAzael Avalos 
360b4f9fe12SLen Brown 	*out1 = out[2];
361893f3f62SAzael Avalos 
362893f3f62SAzael Avalos 	return out[0];
363b4f9fe12SLen Brown }
364b4f9fe12SLen Brown 
365893f3f62SAzael Avalos static u32 hci_write2(struct toshiba_acpi_dev *dev, u32 reg, u32 in1, u32 in2)
366b4f9fe12SLen Brown {
367258c5903SAzael Avalos 	u32 in[TCI_WORDS] = { HCI_SET, reg, in1, in2, 0, 0 };
368258c5903SAzael Avalos 	u32 out[TCI_WORDS];
369258c5903SAzael Avalos 	acpi_status status = tci_raw(dev, in, out);
370893f3f62SAzael Avalos 
371893f3f62SAzael Avalos 	return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE;
372b4f9fe12SLen Brown }
373b4f9fe12SLen Brown 
374893f3f62SAzael Avalos static u32 hci_read2(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1, u32 *out2)
375b4f9fe12SLen Brown {
376258c5903SAzael Avalos 	u32 in[TCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 };
377258c5903SAzael Avalos 	u32 out[TCI_WORDS];
378258c5903SAzael Avalos 	acpi_status status = tci_raw(dev, in, out);
379893f3f62SAzael Avalos 	if (ACPI_FAILURE(status))
380893f3f62SAzael Avalos 		return TOS_FAILURE;
381893f3f62SAzael Avalos 
382b4f9fe12SLen Brown 	*out1 = out[2];
383b4f9fe12SLen Brown 	*out2 = out[3];
384893f3f62SAzael Avalos 
385893f3f62SAzael Avalos 	return out[0];
386b4f9fe12SLen Brown }
387b4f9fe12SLen Brown 
38884a6273fSAzael Avalos /* common sci tasks
38984a6273fSAzael Avalos  */
39084a6273fSAzael Avalos 
39184a6273fSAzael Avalos static int sci_open(struct toshiba_acpi_dev *dev)
39284a6273fSAzael Avalos {
393258c5903SAzael Avalos 	u32 in[TCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 };
394258c5903SAzael Avalos 	u32 out[TCI_WORDS];
39584a6273fSAzael Avalos 	acpi_status status;
39684a6273fSAzael Avalos 
397258c5903SAzael Avalos 	status = tci_raw(dev, in, out);
3981864bbc2SAzael Avalos 	if  (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
39984a6273fSAzael Avalos 		pr_err("ACPI call to open SCI failed\n");
40084a6273fSAzael Avalos 		return 0;
40184a6273fSAzael Avalos 	}
40284a6273fSAzael Avalos 
4031864bbc2SAzael Avalos 	if (out[0] == TOS_OPEN_CLOSE_OK) {
40484a6273fSAzael Avalos 		return 1;
4051864bbc2SAzael Avalos 	} else if (out[0] == TOS_ALREADY_OPEN) {
40684a6273fSAzael Avalos 		pr_info("Toshiba SCI already opened\n");
40784a6273fSAzael Avalos 		return 1;
408fa465739SAzael Avalos 	} else if (out[0] == TOS_NOT_SUPPORTED) {
409fa465739SAzael Avalos 		/* Some BIOSes do not have the SCI open/close functions
410fa465739SAzael Avalos 		 * implemented and return 0x8000 (Not Supported), failing to
411fa465739SAzael Avalos 		 * register some supported features.
412fa465739SAzael Avalos 		 *
413fa465739SAzael Avalos 		 * Simply return 1 if we hit those affected laptops to make the
414fa465739SAzael Avalos 		 * supported features work.
415fa465739SAzael Avalos 		 *
416fa465739SAzael Avalos 		 * In the case that some laptops really do not support the SCI,
417fa465739SAzael Avalos 		 * all the SCI dependent functions check for TOS_NOT_SUPPORTED,
418fa465739SAzael Avalos 		 * and thus, not registering support for the queried feature.
419fa465739SAzael Avalos 		 */
420fa465739SAzael Avalos 		return 1;
4211864bbc2SAzael Avalos 	} else if (out[0] == TOS_NOT_PRESENT) {
42284a6273fSAzael Avalos 		pr_info("Toshiba SCI is not present\n");
42384a6273fSAzael Avalos 	}
42484a6273fSAzael Avalos 
42584a6273fSAzael Avalos 	return 0;
42684a6273fSAzael Avalos }
42784a6273fSAzael Avalos 
42884a6273fSAzael Avalos static void sci_close(struct toshiba_acpi_dev *dev)
42984a6273fSAzael Avalos {
430258c5903SAzael Avalos 	u32 in[TCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 };
431258c5903SAzael Avalos 	u32 out[TCI_WORDS];
43284a6273fSAzael Avalos 	acpi_status status;
43384a6273fSAzael Avalos 
434258c5903SAzael Avalos 	status = tci_raw(dev, in, out);
4351864bbc2SAzael Avalos 	if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
43684a6273fSAzael Avalos 		pr_err("ACPI call to close SCI failed\n");
43784a6273fSAzael Avalos 		return;
43884a6273fSAzael Avalos 	}
43984a6273fSAzael Avalos 
4401864bbc2SAzael Avalos 	if (out[0] == TOS_OPEN_CLOSE_OK)
44184a6273fSAzael Avalos 		return;
4421864bbc2SAzael Avalos 	else if (out[0] == TOS_NOT_OPENED)
44384a6273fSAzael Avalos 		pr_info("Toshiba SCI not opened\n");
4441864bbc2SAzael Avalos 	else if (out[0] == TOS_NOT_PRESENT)
44584a6273fSAzael Avalos 		pr_info("Toshiba SCI is not present\n");
44684a6273fSAzael Avalos }
44784a6273fSAzael Avalos 
448893f3f62SAzael Avalos static u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1)
44984a6273fSAzael Avalos {
450258c5903SAzael Avalos 	u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 };
451258c5903SAzael Avalos 	u32 out[TCI_WORDS];
452258c5903SAzael Avalos 	acpi_status status = tci_raw(dev, in, out);
453893f3f62SAzael Avalos 	if (ACPI_FAILURE(status))
454893f3f62SAzael Avalos 		return TOS_FAILURE;
455893f3f62SAzael Avalos 
45684a6273fSAzael Avalos 	*out1 = out[2];
457893f3f62SAzael Avalos 
458893f3f62SAzael Avalos 	return out[0];
45984a6273fSAzael Avalos }
46084a6273fSAzael Avalos 
461893f3f62SAzael Avalos static u32 sci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1)
46284a6273fSAzael Avalos {
463258c5903SAzael Avalos 	u32 in[TCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 };
464258c5903SAzael Avalos 	u32 out[TCI_WORDS];
465258c5903SAzael Avalos 	acpi_status status = tci_raw(dev, in, out);
466893f3f62SAzael Avalos 
467893f3f62SAzael Avalos 	return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE;
46884a6273fSAzael Avalos }
46984a6273fSAzael Avalos 
4706c3f6e6cSPierre Ducroquet /* Illumination support */
471135740deSSeth Forshee static int toshiba_illumination_available(struct toshiba_acpi_dev *dev)
4726c3f6e6cSPierre Ducroquet {
473258c5903SAzael Avalos 	u32 in[TCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 };
474258c5903SAzael Avalos 	u32 out[TCI_WORDS];
4756c3f6e6cSPierre Ducroquet 	acpi_status status;
4766c3f6e6cSPierre Ducroquet 
477fdb79081SAzael Avalos 	if (!sci_open(dev))
478fdb79081SAzael Avalos 		return 0;
479fdb79081SAzael Avalos 
480258c5903SAzael Avalos 	status = tci_raw(dev, in, out);
481fdb79081SAzael Avalos 	sci_close(dev);
4821864bbc2SAzael Avalos 	if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
483fdb79081SAzael Avalos 		pr_err("ACPI call to query Illumination support failed\n");
484fdb79081SAzael Avalos 		return 0;
4851864bbc2SAzael Avalos 	} else if (out[0] == TOS_NOT_SUPPORTED) {
4867e33460dSJoe Perches 		pr_info("Illumination device not available\n");
4876c3f6e6cSPierre Ducroquet 		return 0;
4886c3f6e6cSPierre Ducroquet 	}
489fdb79081SAzael Avalos 
4906c3f6e6cSPierre Ducroquet 	return 1;
4916c3f6e6cSPierre Ducroquet }
4926c3f6e6cSPierre Ducroquet 
4936c3f6e6cSPierre Ducroquet static void toshiba_illumination_set(struct led_classdev *cdev,
4946c3f6e6cSPierre Ducroquet 				     enum led_brightness brightness)
4956c3f6e6cSPierre Ducroquet {
496135740deSSeth Forshee 	struct toshiba_acpi_dev *dev = container_of(cdev,
497135740deSSeth Forshee 			struct toshiba_acpi_dev, led_dev);
498fdb79081SAzael Avalos 	u32 state, result;
4996c3f6e6cSPierre Ducroquet 
5006c3f6e6cSPierre Ducroquet 	/* First request : initialize communication. */
501fdb79081SAzael Avalos 	if (!sci_open(dev))
5026c3f6e6cSPierre Ducroquet 		return;
5036c3f6e6cSPierre Ducroquet 
504fdb79081SAzael Avalos 	/* Switch the illumination on/off */
505fdb79081SAzael Avalos 	state = brightness ? 1 : 0;
506893f3f62SAzael Avalos 	result = sci_write(dev, SCI_ILLUMINATION, state);
507fdb79081SAzael Avalos 	sci_close(dev);
508893f3f62SAzael Avalos 	if (result == TOS_FAILURE) {
509fdb79081SAzael Avalos 		pr_err("ACPI call for illumination failed\n");
510fdb79081SAzael Avalos 		return;
5111864bbc2SAzael Avalos 	} else if (result == TOS_NOT_SUPPORTED) {
512fdb79081SAzael Avalos 		pr_info("Illumination not supported\n");
5136c3f6e6cSPierre Ducroquet 		return;
5146c3f6e6cSPierre Ducroquet 	}
5156c3f6e6cSPierre Ducroquet }
5166c3f6e6cSPierre Ducroquet 
5176c3f6e6cSPierre Ducroquet static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
5186c3f6e6cSPierre Ducroquet {
519135740deSSeth Forshee 	struct toshiba_acpi_dev *dev = container_of(cdev,
520135740deSSeth Forshee 			struct toshiba_acpi_dev, led_dev);
521fdb79081SAzael Avalos 	u32 state, result;
5226c3f6e6cSPierre Ducroquet 
5236c3f6e6cSPierre Ducroquet 	/* First request : initialize communication. */
524fdb79081SAzael Avalos 	if (!sci_open(dev))
5256c3f6e6cSPierre Ducroquet 		return LED_OFF;
5266c3f6e6cSPierre Ducroquet 
5276c3f6e6cSPierre Ducroquet 	/* Check the illumination */
528893f3f62SAzael Avalos 	result = sci_read(dev, SCI_ILLUMINATION, &state);
529fdb79081SAzael Avalos 	sci_close(dev);
530893f3f62SAzael Avalos 	if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
531fdb79081SAzael Avalos 		pr_err("ACPI call for illumination failed\n");
532fdb79081SAzael Avalos 		return LED_OFF;
5331864bbc2SAzael Avalos 	} else if (result == TOS_NOT_SUPPORTED) {
534fdb79081SAzael Avalos 		pr_info("Illumination not supported\n");
5356c3f6e6cSPierre Ducroquet 		return LED_OFF;
5366c3f6e6cSPierre Ducroquet 	}
5376c3f6e6cSPierre Ducroquet 
538fdb79081SAzael Avalos 	return state ? LED_FULL : LED_OFF;
5396c3f6e6cSPierre Ducroquet }
5406c3f6e6cSPierre Ducroquet 
541360f0f39SAzael Avalos /* KBD Illumination */
54293f8c16dSAzael Avalos static int toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev)
54393f8c16dSAzael Avalos {
544258c5903SAzael Avalos 	u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 };
545258c5903SAzael Avalos 	u32 out[TCI_WORDS];
54693f8c16dSAzael Avalos 	acpi_status status;
54793f8c16dSAzael Avalos 
54893f8c16dSAzael Avalos 	if (!sci_open(dev))
54993f8c16dSAzael Avalos 		return 0;
55093f8c16dSAzael Avalos 
551258c5903SAzael Avalos 	status = tci_raw(dev, in, out);
55293f8c16dSAzael Avalos 	sci_close(dev);
5531864bbc2SAzael Avalos 	if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
55493f8c16dSAzael Avalos 		pr_err("ACPI call to query kbd illumination support failed\n");
55593f8c16dSAzael Avalos 		return 0;
5561864bbc2SAzael Avalos 	} else if (out[0] == TOS_NOT_SUPPORTED) {
55793f8c16dSAzael Avalos 		pr_info("Keyboard illumination not available\n");
55893f8c16dSAzael Avalos 		return 0;
55993f8c16dSAzael Avalos 	}
56093f8c16dSAzael Avalos 
56193f8c16dSAzael Avalos 	/* Check for keyboard backlight timeout max value,
56293f8c16dSAzael Avalos 	 * previous kbd backlight implementation set this to
56393f8c16dSAzael Avalos 	 * 0x3c0003, and now the new implementation set this
56493f8c16dSAzael Avalos 	 * to 0x3c001a, use this to distinguish between them
56593f8c16dSAzael Avalos 	 */
56693f8c16dSAzael Avalos 	if (out[3] == SCI_KBD_TIME_MAX)
56793f8c16dSAzael Avalos 		dev->kbd_type = 2;
56893f8c16dSAzael Avalos 	else
56993f8c16dSAzael Avalos 		dev->kbd_type = 1;
57093f8c16dSAzael Avalos 	/* Get the current keyboard backlight mode */
57193f8c16dSAzael Avalos 	dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK;
57293f8c16dSAzael Avalos 	/* Get the current time (1-60 seconds) */
57393f8c16dSAzael Avalos 	dev->kbd_time = out[2] >> HCI_MISC_SHIFT;
57493f8c16dSAzael Avalos 
57593f8c16dSAzael Avalos 	return 1;
57693f8c16dSAzael Avalos }
57793f8c16dSAzael Avalos 
578360f0f39SAzael Avalos static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time)
579360f0f39SAzael Avalos {
580360f0f39SAzael Avalos 	u32 result;
581360f0f39SAzael Avalos 
582360f0f39SAzael Avalos 	if (!sci_open(dev))
583360f0f39SAzael Avalos 		return -EIO;
584360f0f39SAzael Avalos 
585893f3f62SAzael Avalos 	result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time);
586360f0f39SAzael Avalos 	sci_close(dev);
587893f3f62SAzael Avalos 	if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
588360f0f39SAzael Avalos 		pr_err("ACPI call to set KBD backlight status failed\n");
589360f0f39SAzael Avalos 		return -EIO;
5901864bbc2SAzael Avalos 	} else if (result == TOS_NOT_SUPPORTED) {
591360f0f39SAzael Avalos 		pr_info("Keyboard backlight status not supported\n");
592360f0f39SAzael Avalos 		return -ENODEV;
593360f0f39SAzael Avalos 	}
594360f0f39SAzael Avalos 
595360f0f39SAzael Avalos 	return 0;
596360f0f39SAzael Avalos }
597360f0f39SAzael Avalos 
598360f0f39SAzael Avalos static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time)
599360f0f39SAzael Avalos {
600360f0f39SAzael Avalos 	u32 result;
601360f0f39SAzael Avalos 
602360f0f39SAzael Avalos 	if (!sci_open(dev))
603360f0f39SAzael Avalos 		return -EIO;
604360f0f39SAzael Avalos 
605893f3f62SAzael Avalos 	result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time);
606360f0f39SAzael Avalos 	sci_close(dev);
607893f3f62SAzael Avalos 	if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
608360f0f39SAzael Avalos 		pr_err("ACPI call to get KBD backlight status failed\n");
609360f0f39SAzael Avalos 		return -EIO;
6101864bbc2SAzael Avalos 	} else if (result == TOS_NOT_SUPPORTED) {
611360f0f39SAzael Avalos 		pr_info("Keyboard backlight status not supported\n");
612360f0f39SAzael Avalos 		return -ENODEV;
613360f0f39SAzael Avalos 	}
614360f0f39SAzael Avalos 
615360f0f39SAzael Avalos 	return 0;
616360f0f39SAzael Avalos }
617360f0f39SAzael Avalos 
618360f0f39SAzael Avalos static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev)
619360f0f39SAzael Avalos {
620360f0f39SAzael Avalos 	struct toshiba_acpi_dev *dev = container_of(cdev,
621360f0f39SAzael Avalos 			struct toshiba_acpi_dev, kbd_led);
622360f0f39SAzael Avalos 	u32 state, result;
623360f0f39SAzael Avalos 
624360f0f39SAzael Avalos 	/* Check the keyboard backlight state */
625893f3f62SAzael Avalos 	result = hci_read1(dev, HCI_KBD_ILLUMINATION, &state);
626893f3f62SAzael Avalos 	if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
627360f0f39SAzael Avalos 		pr_err("ACPI call to get the keyboard backlight failed\n");
628360f0f39SAzael Avalos 		return LED_OFF;
6291864bbc2SAzael Avalos 	} else if (result == TOS_NOT_SUPPORTED) {
630360f0f39SAzael Avalos 		pr_info("Keyboard backlight not supported\n");
631360f0f39SAzael Avalos 		return LED_OFF;
632360f0f39SAzael Avalos 	}
633360f0f39SAzael Avalos 
634360f0f39SAzael Avalos 	return state ? LED_FULL : LED_OFF;
635360f0f39SAzael Avalos }
636360f0f39SAzael Avalos 
637360f0f39SAzael Avalos static void toshiba_kbd_backlight_set(struct led_classdev *cdev,
638360f0f39SAzael Avalos 				     enum led_brightness brightness)
639360f0f39SAzael Avalos {
640360f0f39SAzael Avalos 	struct toshiba_acpi_dev *dev = container_of(cdev,
641360f0f39SAzael Avalos 			struct toshiba_acpi_dev, kbd_led);
642360f0f39SAzael Avalos 	u32 state, result;
643360f0f39SAzael Avalos 
644360f0f39SAzael Avalos 	/* Set the keyboard backlight state */
645360f0f39SAzael Avalos 	state = brightness ? 1 : 0;
646893f3f62SAzael Avalos 	result = hci_write1(dev, HCI_KBD_ILLUMINATION, state);
647893f3f62SAzael Avalos 	if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
648360f0f39SAzael Avalos 		pr_err("ACPI call to set KBD Illumination mode failed\n");
649360f0f39SAzael Avalos 		return;
6501864bbc2SAzael Avalos 	} else if (result == TOS_NOT_SUPPORTED) {
651360f0f39SAzael Avalos 		pr_info("Keyboard backlight not supported\n");
652360f0f39SAzael Avalos 		return;
653360f0f39SAzael Avalos 	}
654360f0f39SAzael Avalos }
655360f0f39SAzael Avalos 
6569d8658acSAzael Avalos /* TouchPad support */
6579d8658acSAzael Avalos static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state)
6589d8658acSAzael Avalos {
6599d8658acSAzael Avalos 	u32 result;
6609d8658acSAzael Avalos 
6619d8658acSAzael Avalos 	if (!sci_open(dev))
6629d8658acSAzael Avalos 		return -EIO;
6639d8658acSAzael Avalos 
664893f3f62SAzael Avalos 	result = sci_write(dev, SCI_TOUCHPAD, state);
6659d8658acSAzael Avalos 	sci_close(dev);
666893f3f62SAzael Avalos 	if (result == TOS_FAILURE) {
6679d8658acSAzael Avalos 		pr_err("ACPI call to set the touchpad failed\n");
6689d8658acSAzael Avalos 		return -EIO;
6691864bbc2SAzael Avalos 	} else if (result == TOS_NOT_SUPPORTED) {
6709d8658acSAzael Avalos 		return -ENODEV;
6719d8658acSAzael Avalos 	}
6729d8658acSAzael Avalos 
6739d8658acSAzael Avalos 	return 0;
6749d8658acSAzael Avalos }
6759d8658acSAzael Avalos 
6769d8658acSAzael Avalos static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state)
6779d8658acSAzael Avalos {
6789d8658acSAzael Avalos 	u32 result;
6799d8658acSAzael Avalos 
6809d8658acSAzael Avalos 	if (!sci_open(dev))
6819d8658acSAzael Avalos 		return -EIO;
6829d8658acSAzael Avalos 
683893f3f62SAzael Avalos 	result = sci_read(dev, SCI_TOUCHPAD, state);
6849d8658acSAzael Avalos 	sci_close(dev);
685893f3f62SAzael Avalos 	if (result == TOS_FAILURE) {
6869d8658acSAzael Avalos 		pr_err("ACPI call to query the touchpad failed\n");
6879d8658acSAzael Avalos 		return -EIO;
6881864bbc2SAzael Avalos 	} else if (result == TOS_NOT_SUPPORTED) {
6899d8658acSAzael Avalos 		return -ENODEV;
6909d8658acSAzael Avalos 	}
6919d8658acSAzael Avalos 
6929d8658acSAzael Avalos 	return 0;
6939d8658acSAzael Avalos }
6949d8658acSAzael Avalos 
695def6c4e2SAzael Avalos /* Eco Mode support */
696def6c4e2SAzael Avalos static int toshiba_eco_mode_available(struct toshiba_acpi_dev *dev)
697def6c4e2SAzael Avalos {
698def6c4e2SAzael Avalos 	acpi_status status;
699*98fc4ec6SAzael Avalos 	u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 };
700258c5903SAzael Avalos 	u32 out[TCI_WORDS];
701def6c4e2SAzael Avalos 
702258c5903SAzael Avalos 	status = tci_raw(dev, in, out);
703*98fc4ec6SAzael Avalos 	if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
704*98fc4ec6SAzael Avalos 		pr_err("ACPI call to get ECO led failed\n");
705*98fc4ec6SAzael Avalos 	} else if (out[0] == TOS_NOT_INSTALLED) {
706*98fc4ec6SAzael Avalos 		pr_info("ECO led not installed");
707*98fc4ec6SAzael Avalos 	} else if (out[0] == TOS_INPUT_DATA_ERROR) {
708*98fc4ec6SAzael Avalos 		/* If we receive 0x8300 (Input Data Error), it means that the
709*98fc4ec6SAzael Avalos 		 * LED device is present, but that we just screwed the input
710*98fc4ec6SAzael Avalos 		 * parameters.
711*98fc4ec6SAzael Avalos 		 *
712*98fc4ec6SAzael Avalos 		 * Let's query the status of the LED to see if we really have a
713*98fc4ec6SAzael Avalos 		 * success response, indicating the actual presense of the LED,
714*98fc4ec6SAzael Avalos 		 * bail out otherwise.
715*98fc4ec6SAzael Avalos 		 */
716*98fc4ec6SAzael Avalos 		in[3] = 1;
717*98fc4ec6SAzael Avalos 		status = tci_raw(dev, in, out);
718*98fc4ec6SAzael Avalos 		if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE)
719*98fc4ec6SAzael Avalos 			pr_err("ACPI call to get ECO led failed\n");
720*98fc4ec6SAzael Avalos 		else if (out[0] == TOS_SUCCESS)
721*98fc4ec6SAzael Avalos 			return 1;
722def6c4e2SAzael Avalos 	}
723def6c4e2SAzael Avalos 
724*98fc4ec6SAzael Avalos 	return 0;
725def6c4e2SAzael Avalos }
726def6c4e2SAzael Avalos 
727def6c4e2SAzael Avalos static enum led_brightness toshiba_eco_mode_get_status(struct led_classdev *cdev)
728def6c4e2SAzael Avalos {
729def6c4e2SAzael Avalos 	struct toshiba_acpi_dev *dev = container_of(cdev,
730def6c4e2SAzael Avalos 			struct toshiba_acpi_dev, eco_led);
731258c5903SAzael Avalos 	u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 };
732258c5903SAzael Avalos 	u32 out[TCI_WORDS];
733def6c4e2SAzael Avalos 	acpi_status status;
734def6c4e2SAzael Avalos 
735258c5903SAzael Avalos 	status = tci_raw(dev, in, out);
7361864bbc2SAzael Avalos 	if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
737def6c4e2SAzael Avalos 		pr_err("ACPI call to get ECO led failed\n");
738def6c4e2SAzael Avalos 		return LED_OFF;
739def6c4e2SAzael Avalos 	}
740def6c4e2SAzael Avalos 
741def6c4e2SAzael Avalos 	return out[2] ? LED_FULL : LED_OFF;
742def6c4e2SAzael Avalos }
743def6c4e2SAzael Avalos 
744def6c4e2SAzael Avalos static void toshiba_eco_mode_set_status(struct led_classdev *cdev,
745def6c4e2SAzael Avalos 				     enum led_brightness brightness)
746def6c4e2SAzael Avalos {
747def6c4e2SAzael Avalos 	struct toshiba_acpi_dev *dev = container_of(cdev,
748def6c4e2SAzael Avalos 			struct toshiba_acpi_dev, eco_led);
749258c5903SAzael Avalos 	u32 in[TCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 };
750258c5903SAzael Avalos 	u32 out[TCI_WORDS];
751def6c4e2SAzael Avalos 	acpi_status status;
752def6c4e2SAzael Avalos 
753def6c4e2SAzael Avalos 	/* Switch the Eco Mode led on/off */
754def6c4e2SAzael Avalos 	in[2] = (brightness) ? 1 : 0;
755258c5903SAzael Avalos 	status = tci_raw(dev, in, out);
7561864bbc2SAzael Avalos 	if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
757def6c4e2SAzael Avalos 		pr_err("ACPI call to set ECO led failed\n");
758def6c4e2SAzael Avalos 		return;
759def6c4e2SAzael Avalos 	}
760def6c4e2SAzael Avalos }
761def6c4e2SAzael Avalos 
7625a2813e9SAzael Avalos /* Accelerometer support */
7635a2813e9SAzael Avalos static int toshiba_accelerometer_supported(struct toshiba_acpi_dev *dev)
7645a2813e9SAzael Avalos {
765258c5903SAzael Avalos 	u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 };
766258c5903SAzael Avalos 	u32 out[TCI_WORDS];
7675a2813e9SAzael Avalos 	acpi_status status;
7685a2813e9SAzael Avalos 
7695a2813e9SAzael Avalos 	/* Check if the accelerometer call exists,
7705a2813e9SAzael Avalos 	 * this call also serves as initialization
7715a2813e9SAzael Avalos 	 */
772258c5903SAzael Avalos 	status = tci_raw(dev, in, out);
7731864bbc2SAzael Avalos 	if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
7745a2813e9SAzael Avalos 		pr_err("ACPI call to query the accelerometer failed\n");
7755a2813e9SAzael Avalos 		return -EIO;
7761864bbc2SAzael Avalos 	} else if (out[0] == TOS_DATA_NOT_AVAILABLE ||
7771864bbc2SAzael Avalos 		   out[0] == TOS_NOT_INITIALIZED) {
7785a2813e9SAzael Avalos 		pr_err("Accelerometer not initialized\n");
7795a2813e9SAzael Avalos 		return -EIO;
7801864bbc2SAzael Avalos 	} else if (out[0] == TOS_NOT_SUPPORTED) {
7815a2813e9SAzael Avalos 		pr_info("Accelerometer not supported\n");
7825a2813e9SAzael Avalos 		return -ENODEV;
7835a2813e9SAzael Avalos 	}
7845a2813e9SAzael Avalos 
7855a2813e9SAzael Avalos 	return 0;
7865a2813e9SAzael Avalos }
7875a2813e9SAzael Avalos 
7885a2813e9SAzael Avalos static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev,
7895a2813e9SAzael Avalos 				      u32 *xy, u32 *z)
7905a2813e9SAzael Avalos {
791258c5903SAzael Avalos 	u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 };
792258c5903SAzael Avalos 	u32 out[TCI_WORDS];
7935a2813e9SAzael Avalos 	acpi_status status;
7945a2813e9SAzael Avalos 
7955a2813e9SAzael Avalos 	/* Check the Accelerometer status */
796258c5903SAzael Avalos 	status = tci_raw(dev, in, out);
7971864bbc2SAzael Avalos 	if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
7985a2813e9SAzael Avalos 		pr_err("ACPI call to query the accelerometer failed\n");
7995a2813e9SAzael Avalos 		return -EIO;
8005a2813e9SAzael Avalos 	}
8015a2813e9SAzael Avalos 
8025a2813e9SAzael Avalos 	*xy = out[2];
8035a2813e9SAzael Avalos 	*z = out[4];
8045a2813e9SAzael Avalos 
8055a2813e9SAzael Avalos 	return 0;
8065a2813e9SAzael Avalos }
8075a2813e9SAzael Avalos 
808e26ffe51SAzael Avalos /* Sleep (Charge and Music) utilities support */
809e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev,
810e26ffe51SAzael Avalos 					u32 *mode)
811e26ffe51SAzael Avalos {
812e26ffe51SAzael Avalos 	u32 result;
813e26ffe51SAzael Avalos 
814e26ffe51SAzael Avalos 	if (!sci_open(dev))
815e26ffe51SAzael Avalos 		return -EIO;
816e26ffe51SAzael Avalos 
817e26ffe51SAzael Avalos 	result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode);
818e26ffe51SAzael Avalos 	sci_close(dev);
819e26ffe51SAzael Avalos 	if (result == TOS_FAILURE) {
820e26ffe51SAzael Avalos 		pr_err("ACPI call to set USB S&C mode failed\n");
821e26ffe51SAzael Avalos 		return -EIO;
822e26ffe51SAzael Avalos 	} else if (result == TOS_NOT_SUPPORTED) {
823e26ffe51SAzael Avalos 		pr_info("USB Sleep and Charge not supported\n");
824e26ffe51SAzael Avalos 		return -ENODEV;
825e26ffe51SAzael Avalos 	} else if (result == TOS_INPUT_DATA_ERROR) {
826e26ffe51SAzael Avalos 		return -EIO;
827e26ffe51SAzael Avalos 	}
828e26ffe51SAzael Avalos 
829e26ffe51SAzael Avalos 	return 0;
830e26ffe51SAzael Avalos }
831e26ffe51SAzael Avalos 
832e26ffe51SAzael Avalos static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev,
833e26ffe51SAzael Avalos 					u32 mode)
834e26ffe51SAzael Avalos {
835e26ffe51SAzael Avalos 	u32 result;
836e26ffe51SAzael Avalos 
837e26ffe51SAzael Avalos 	if (!sci_open(dev))
838e26ffe51SAzael Avalos 		return -EIO;
839e26ffe51SAzael Avalos 
840e26ffe51SAzael Avalos 	result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode);
841e26ffe51SAzael Avalos 	sci_close(dev);
842e26ffe51SAzael Avalos 	if (result == TOS_FAILURE) {
843e26ffe51SAzael Avalos 		pr_err("ACPI call to set USB S&C mode failed\n");
844e26ffe51SAzael Avalos 		return -EIO;
845e26ffe51SAzael Avalos 	} else if (result == TOS_NOT_SUPPORTED) {
846e26ffe51SAzael Avalos 		pr_info("USB Sleep and Charge not supported\n");
847e26ffe51SAzael Avalos 		return -ENODEV;
848e26ffe51SAzael Avalos 	} else if (result == TOS_INPUT_DATA_ERROR) {
849e26ffe51SAzael Avalos 		return -EIO;
850e26ffe51SAzael Avalos 	}
851e26ffe51SAzael Avalos 
852e26ffe51SAzael Avalos 	return 0;
853e26ffe51SAzael Avalos }
854e26ffe51SAzael Avalos 
855182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev,
856182bcaa5SAzael Avalos 					      u32 *mode)
857182bcaa5SAzael Avalos {
858182bcaa5SAzael Avalos 	u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
859182bcaa5SAzael Avalos 	u32 out[TCI_WORDS];
860182bcaa5SAzael Avalos 	acpi_status status;
861182bcaa5SAzael Avalos 
862182bcaa5SAzael Avalos 	if (!sci_open(dev))
863182bcaa5SAzael Avalos 		return -EIO;
864182bcaa5SAzael Avalos 
865182bcaa5SAzael Avalos 	in[5] = SCI_USB_CHARGE_BAT_LVL;
866182bcaa5SAzael Avalos 	status = tci_raw(dev, in, out);
867182bcaa5SAzael Avalos 	sci_close(dev);
868182bcaa5SAzael Avalos 	if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
869182bcaa5SAzael Avalos 		pr_err("ACPI call to get USB S&C battery level failed\n");
870182bcaa5SAzael Avalos 		return -EIO;
871182bcaa5SAzael Avalos 	} else if (out[0] == TOS_NOT_SUPPORTED) {
872182bcaa5SAzael Avalos 		pr_info("USB Sleep and Charge not supported\n");
873182bcaa5SAzael Avalos 		return -ENODEV;
874182bcaa5SAzael Avalos 	} else if (out[0] == TOS_INPUT_DATA_ERROR) {
875182bcaa5SAzael Avalos 		return -EIO;
876182bcaa5SAzael Avalos 	}
877182bcaa5SAzael Avalos 
878182bcaa5SAzael Avalos 	*mode = out[2];
879182bcaa5SAzael Avalos 
880182bcaa5SAzael Avalos 	return 0;
881182bcaa5SAzael Avalos }
882182bcaa5SAzael Avalos 
883182bcaa5SAzael Avalos static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev,
884182bcaa5SAzael Avalos 					      u32 mode)
885182bcaa5SAzael Avalos {
886182bcaa5SAzael Avalos 	u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
887182bcaa5SAzael Avalos 	u32 out[TCI_WORDS];
888182bcaa5SAzael Avalos 	acpi_status status;
889182bcaa5SAzael Avalos 
890182bcaa5SAzael Avalos 	if (!sci_open(dev))
891182bcaa5SAzael Avalos 		return -EIO;
892182bcaa5SAzael Avalos 
893182bcaa5SAzael Avalos 	in[2] = mode;
894182bcaa5SAzael Avalos 	in[5] = SCI_USB_CHARGE_BAT_LVL;
895182bcaa5SAzael Avalos 	status = tci_raw(dev, in, out);
896182bcaa5SAzael Avalos 	sci_close(dev);
897182bcaa5SAzael Avalos 	if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
898182bcaa5SAzael Avalos 		pr_err("ACPI call to set USB S&C battery level failed\n");
899182bcaa5SAzael Avalos 		return -EIO;
900182bcaa5SAzael Avalos 	} else if (out[0] == TOS_NOT_SUPPORTED) {
901182bcaa5SAzael Avalos 		pr_info("USB Sleep and Charge not supported\n");
902182bcaa5SAzael Avalos 		return -ENODEV;
903182bcaa5SAzael Avalos 	} else if (out[0] == TOS_INPUT_DATA_ERROR) {
904182bcaa5SAzael Avalos 		return -EIO;
905182bcaa5SAzael Avalos 	}
906182bcaa5SAzael Avalos 
907182bcaa5SAzael Avalos 	return 0;
908182bcaa5SAzael Avalos }
909182bcaa5SAzael Avalos 
910bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev,
911bb3fe01fSAzael Avalos 					u32 *state)
912bb3fe01fSAzael Avalos {
913bb3fe01fSAzael Avalos 	u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
914bb3fe01fSAzael Avalos 	u32 out[TCI_WORDS];
915bb3fe01fSAzael Avalos 	acpi_status status;
916bb3fe01fSAzael Avalos 
917bb3fe01fSAzael Avalos 	if (!sci_open(dev))
918bb3fe01fSAzael Avalos 		return -EIO;
919bb3fe01fSAzael Avalos 
920bb3fe01fSAzael Avalos 	in[5] = SCI_USB_CHARGE_RAPID_DSP;
921bb3fe01fSAzael Avalos 	status = tci_raw(dev, in, out);
922bb3fe01fSAzael Avalos 	sci_close(dev);
923bb3fe01fSAzael Avalos 	if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
924bb3fe01fSAzael Avalos 		pr_err("ACPI call to get USB S&C battery level failed\n");
925bb3fe01fSAzael Avalos 		return -EIO;
926bb3fe01fSAzael Avalos 	} else if (out[0] == TOS_NOT_SUPPORTED ||
927bb3fe01fSAzael Avalos 		   out[0] == TOS_INPUT_DATA_ERROR) {
928bb3fe01fSAzael Avalos 		pr_info("USB Sleep and Charge not supported\n");
929bb3fe01fSAzael Avalos 		return -ENODEV;
930bb3fe01fSAzael Avalos 	}
931bb3fe01fSAzael Avalos 
932bb3fe01fSAzael Avalos 	*state = out[2];
933bb3fe01fSAzael Avalos 
934bb3fe01fSAzael Avalos 	return 0;
935bb3fe01fSAzael Avalos }
936bb3fe01fSAzael Avalos 
937bb3fe01fSAzael Avalos static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev,
938bb3fe01fSAzael Avalos 					u32 state)
939bb3fe01fSAzael Avalos {
940bb3fe01fSAzael Avalos 	u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
941bb3fe01fSAzael Avalos 	u32 out[TCI_WORDS];
942bb3fe01fSAzael Avalos 	acpi_status status;
943bb3fe01fSAzael Avalos 
944bb3fe01fSAzael Avalos 	if (!sci_open(dev))
945bb3fe01fSAzael Avalos 		return -EIO;
946bb3fe01fSAzael Avalos 
947bb3fe01fSAzael Avalos 	in[2] = state;
948bb3fe01fSAzael Avalos 	in[5] = SCI_USB_CHARGE_RAPID_DSP;
949bb3fe01fSAzael Avalos 	status = tci_raw(dev, in, out);
950bb3fe01fSAzael Avalos 	sci_close(dev);
951bb3fe01fSAzael Avalos 	if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
952bb3fe01fSAzael Avalos 		pr_err("ACPI call to set USB S&C battery level failed\n");
953bb3fe01fSAzael Avalos 		return -EIO;
954bb3fe01fSAzael Avalos 	} else if (out[0] == TOS_NOT_SUPPORTED) {
955bb3fe01fSAzael Avalos 		pr_info("USB Sleep and Charge not supported\n");
956bb3fe01fSAzael Avalos 		return -ENODEV;
957bb3fe01fSAzael Avalos 	} else if (out[0] == TOS_INPUT_DATA_ERROR) {
958bb3fe01fSAzael Avalos 		return -EIO;
959bb3fe01fSAzael Avalos 	}
960bb3fe01fSAzael Avalos 
961bb3fe01fSAzael Avalos 	return 0;
962bb3fe01fSAzael Avalos }
963bb3fe01fSAzael Avalos 
964172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state)
965172ce0a9SAzael Avalos {
966172ce0a9SAzael Avalos 	u32 result;
967172ce0a9SAzael Avalos 
968172ce0a9SAzael Avalos 	if (!sci_open(dev))
969172ce0a9SAzael Avalos 		return -EIO;
970172ce0a9SAzael Avalos 
971172ce0a9SAzael Avalos 	result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state);
972172ce0a9SAzael Avalos 	sci_close(dev);
973172ce0a9SAzael Avalos 	if (result == TOS_FAILURE) {
974172ce0a9SAzael Avalos 		pr_err("ACPI call to set USB S&C mode failed\n");
975172ce0a9SAzael Avalos 		return -EIO;
976172ce0a9SAzael Avalos 	} else if (result == TOS_NOT_SUPPORTED) {
977172ce0a9SAzael Avalos 		pr_info("USB Sleep and Charge not supported\n");
978172ce0a9SAzael Avalos 		return -ENODEV;
979172ce0a9SAzael Avalos 	} else if (result == TOS_INPUT_DATA_ERROR) {
980172ce0a9SAzael Avalos 		return -EIO;
981172ce0a9SAzael Avalos 	}
982172ce0a9SAzael Avalos 
983172ce0a9SAzael Avalos 	return 0;
984172ce0a9SAzael Avalos }
985172ce0a9SAzael Avalos 
986172ce0a9SAzael Avalos static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state)
987172ce0a9SAzael Avalos {
988172ce0a9SAzael Avalos 	u32 result;
989172ce0a9SAzael Avalos 
990172ce0a9SAzael Avalos 	if (!sci_open(dev))
991172ce0a9SAzael Avalos 		return -EIO;
992172ce0a9SAzael Avalos 
993172ce0a9SAzael Avalos 	result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state);
994172ce0a9SAzael Avalos 	sci_close(dev);
995172ce0a9SAzael Avalos 	if (result == TOS_FAILURE) {
996172ce0a9SAzael Avalos 		pr_err("ACPI call to set USB S&C mode failed\n");
997172ce0a9SAzael Avalos 		return -EIO;
998172ce0a9SAzael Avalos 	} else if (result == TOS_NOT_SUPPORTED) {
999172ce0a9SAzael Avalos 		pr_info("USB Sleep and Charge not supported\n");
1000172ce0a9SAzael Avalos 		return -ENODEV;
1001172ce0a9SAzael Avalos 	} else if (result == TOS_INPUT_DATA_ERROR) {
1002172ce0a9SAzael Avalos 		return -EIO;
1003172ce0a9SAzael Avalos 	}
1004172ce0a9SAzael Avalos 
1005172ce0a9SAzael Avalos 	return 0;
1006172ce0a9SAzael Avalos }
1007172ce0a9SAzael Avalos 
1008b4f9fe12SLen Brown /* Bluetooth rfkill handlers */
1009b4f9fe12SLen Brown 
1010135740deSSeth Forshee static u32 hci_get_bt_present(struct toshiba_acpi_dev *dev, bool *present)
1011b4f9fe12SLen Brown {
1012b4f9fe12SLen Brown 	u32 hci_result;
1013b4f9fe12SLen Brown 	u32 value, value2;
1014b4f9fe12SLen Brown 
1015b4f9fe12SLen Brown 	value = 0;
1016b4f9fe12SLen Brown 	value2 = 0;
1017893f3f62SAzael Avalos 	hci_result = hci_read2(dev, HCI_WIRELESS, &value, &value2);
10181864bbc2SAzael Avalos 	if (hci_result == TOS_SUCCESS)
1019b4f9fe12SLen Brown 		*present = (value & HCI_WIRELESS_BT_PRESENT) ? true : false;
1020b4f9fe12SLen Brown 
1021b4f9fe12SLen Brown 	return hci_result;
1022b4f9fe12SLen Brown }
1023b4f9fe12SLen Brown 
1024135740deSSeth Forshee static u32 hci_get_radio_state(struct toshiba_acpi_dev *dev, bool *radio_state)
1025b4f9fe12SLen Brown {
1026b4f9fe12SLen Brown 	u32 hci_result;
1027b4f9fe12SLen Brown 	u32 value, value2;
1028b4f9fe12SLen Brown 
1029b4f9fe12SLen Brown 	value = 0;
1030b4f9fe12SLen Brown 	value2 = 0x0001;
1031893f3f62SAzael Avalos 	hci_result = hci_read2(dev, HCI_WIRELESS, &value, &value2);
1032b4f9fe12SLen Brown 
1033b4f9fe12SLen Brown 	*radio_state = value & HCI_WIRELESS_KILL_SWITCH;
1034b4f9fe12SLen Brown 	return hci_result;
1035b4f9fe12SLen Brown }
1036b4f9fe12SLen Brown 
103719d337dfSJohannes Berg static int bt_rfkill_set_block(void *data, bool blocked)
1038b4f9fe12SLen Brown {
103919d337dfSJohannes Berg 	struct toshiba_acpi_dev *dev = data;
1040b4f9fe12SLen Brown 	u32 result1, result2;
1041b4f9fe12SLen Brown 	u32 value;
104219d337dfSJohannes Berg 	int err;
1043b4f9fe12SLen Brown 	bool radio_state;
1044b4f9fe12SLen Brown 
104519d337dfSJohannes Berg 	value = (blocked == false);
1046b4f9fe12SLen Brown 
1047b4f9fe12SLen Brown 	mutex_lock(&dev->mutex);
10481864bbc2SAzael Avalos 	if (hci_get_radio_state(dev, &radio_state) != TOS_SUCCESS) {
104932bcd5cbSSeth Forshee 		err = -EIO;
105019d337dfSJohannes Berg 		goto out;
1051b4f9fe12SLen Brown 	}
1052b4f9fe12SLen Brown 
105319d337dfSJohannes Berg 	if (!radio_state) {
105419d337dfSJohannes Berg 		err = 0;
105519d337dfSJohannes Berg 		goto out;
105619d337dfSJohannes Berg 	}
105719d337dfSJohannes Berg 
1058893f3f62SAzael Avalos 	result1 = hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER);
1059893f3f62SAzael Avalos 	result2 = hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH);
106019d337dfSJohannes Berg 
10611864bbc2SAzael Avalos 	if (result1 != TOS_SUCCESS || result2 != TOS_SUCCESS)
106232bcd5cbSSeth Forshee 		err = -EIO;
106319d337dfSJohannes Berg 	else
106419d337dfSJohannes Berg 		err = 0;
106519d337dfSJohannes Berg  out:
106619d337dfSJohannes Berg 	mutex_unlock(&dev->mutex);
106719d337dfSJohannes Berg 	return err;
106819d337dfSJohannes Berg }
106919d337dfSJohannes Berg 
107019d337dfSJohannes Berg static void bt_rfkill_poll(struct rfkill *rfkill, void *data)
1071b4f9fe12SLen Brown {
1072b4f9fe12SLen Brown 	bool new_rfk_state;
1073b4f9fe12SLen Brown 	bool value;
1074b4f9fe12SLen Brown 	u32 hci_result;
107519d337dfSJohannes Berg 	struct toshiba_acpi_dev *dev = data;
107619d337dfSJohannes Berg 
107719d337dfSJohannes Berg 	mutex_lock(&dev->mutex);
1078b4f9fe12SLen Brown 
1079135740deSSeth Forshee 	hci_result = hci_get_radio_state(dev, &value);
10801864bbc2SAzael Avalos 	if (hci_result != TOS_SUCCESS) {
108119d337dfSJohannes Berg 		/* Can't do anything useful */
108219d337dfSJohannes Berg 		mutex_unlock(&dev->mutex);
108382e7784fSJiri Slaby 		return;
108419d337dfSJohannes Berg 	}
1085b4f9fe12SLen Brown 
1086b4f9fe12SLen Brown 	new_rfk_state = value;
1087b4f9fe12SLen Brown 
1088b4f9fe12SLen Brown 	mutex_unlock(&dev->mutex);
1089b4f9fe12SLen Brown 
109019d337dfSJohannes Berg 	if (rfkill_set_hw_state(rfkill, !new_rfk_state))
109119d337dfSJohannes Berg 		bt_rfkill_set_block(data, true);
1092b4f9fe12SLen Brown }
109319d337dfSJohannes Berg 
109419d337dfSJohannes Berg static const struct rfkill_ops toshiba_rfk_ops = {
109519d337dfSJohannes Berg 	.set_block = bt_rfkill_set_block,
109619d337dfSJohannes Berg 	.poll = bt_rfkill_poll,
109719d337dfSJohannes Berg };
1098b4f9fe12SLen Brown 
1099121b7b0dSAkio Idehara static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled)
1100121b7b0dSAkio Idehara {
1101121b7b0dSAkio Idehara 	u32 hci_result;
1102121b7b0dSAkio Idehara 	u32 status;
1103121b7b0dSAkio Idehara 
1104893f3f62SAzael Avalos 	hci_result = hci_read1(dev, HCI_TR_BACKLIGHT, &status);
1105121b7b0dSAkio Idehara 	*enabled = !status;
11061864bbc2SAzael Avalos 	return hci_result == TOS_SUCCESS ? 0 : -EIO;
1107121b7b0dSAkio Idehara }
1108121b7b0dSAkio Idehara 
1109121b7b0dSAkio Idehara static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable)
1110121b7b0dSAkio Idehara {
1111121b7b0dSAkio Idehara 	u32 hci_result;
1112121b7b0dSAkio Idehara 	u32 value = !enable;
1113121b7b0dSAkio Idehara 
1114893f3f62SAzael Avalos 	hci_result = hci_write1(dev, HCI_TR_BACKLIGHT, value);
11151864bbc2SAzael Avalos 	return hci_result == TOS_SUCCESS ? 0 : -EIO;
1116121b7b0dSAkio Idehara }
1117121b7b0dSAkio Idehara 
1118b4f9fe12SLen Brown static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
1119b4f9fe12SLen Brown 
112062cce752SSeth Forshee static int __get_lcd_brightness(struct toshiba_acpi_dev *dev)
1121b4f9fe12SLen Brown {
1122b4f9fe12SLen Brown 	u32 hci_result;
1123b4f9fe12SLen Brown 	u32 value;
1124121b7b0dSAkio Idehara 	int brightness = 0;
1125121b7b0dSAkio Idehara 
1126121b7b0dSAkio Idehara 	if (dev->tr_backlight_supported) {
1127121b7b0dSAkio Idehara 		bool enabled;
1128121b7b0dSAkio Idehara 		int ret = get_tr_backlight_status(dev, &enabled);
1129121b7b0dSAkio Idehara 		if (ret)
1130121b7b0dSAkio Idehara 			return ret;
1131121b7b0dSAkio Idehara 		if (enabled)
1132121b7b0dSAkio Idehara 			return 0;
1133121b7b0dSAkio Idehara 		brightness++;
1134121b7b0dSAkio Idehara 	}
1135b4f9fe12SLen Brown 
1136893f3f62SAzael Avalos 	hci_result = hci_read1(dev, HCI_LCD_BRIGHTNESS, &value);
11371864bbc2SAzael Avalos 	if (hci_result == TOS_SUCCESS)
1138121b7b0dSAkio Idehara 		return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT);
113932bcd5cbSSeth Forshee 
114032bcd5cbSSeth Forshee 	return -EIO;
1141b4f9fe12SLen Brown }
1142b4f9fe12SLen Brown 
114362cce752SSeth Forshee static int get_lcd_brightness(struct backlight_device *bd)
114462cce752SSeth Forshee {
114562cce752SSeth Forshee 	struct toshiba_acpi_dev *dev = bl_get_data(bd);
114662cce752SSeth Forshee 	return __get_lcd_brightness(dev);
114762cce752SSeth Forshee }
114862cce752SSeth Forshee 
1149936c8bcdSAlexey Dobriyan static int lcd_proc_show(struct seq_file *m, void *v)
1150b4f9fe12SLen Brown {
1151135740deSSeth Forshee 	struct toshiba_acpi_dev *dev = m->private;
1152135740deSSeth Forshee 	int value;
1153121b7b0dSAkio Idehara 	int levels;
1154b4f9fe12SLen Brown 
1155135740deSSeth Forshee 	if (!dev->backlight_dev)
1156135740deSSeth Forshee 		return -ENODEV;
1157135740deSSeth Forshee 
1158121b7b0dSAkio Idehara 	levels = dev->backlight_dev->props.max_brightness + 1;
115962cce752SSeth Forshee 	value = get_lcd_brightness(dev->backlight_dev);
1160b4f9fe12SLen Brown 	if (value >= 0) {
1161936c8bcdSAlexey Dobriyan 		seq_printf(m, "brightness:              %d\n", value);
1162121b7b0dSAkio Idehara 		seq_printf(m, "brightness_levels:       %d\n", levels);
116332bcd5cbSSeth Forshee 		return 0;
1164b4f9fe12SLen Brown 	}
1165b4f9fe12SLen Brown 
116632bcd5cbSSeth Forshee 	pr_err("Error reading LCD brightness\n");
116732bcd5cbSSeth Forshee 	return -EIO;
1168936c8bcdSAlexey Dobriyan }
1169936c8bcdSAlexey Dobriyan 
1170936c8bcdSAlexey Dobriyan static int lcd_proc_open(struct inode *inode, struct file *file)
1171936c8bcdSAlexey Dobriyan {
1172d9dda78bSAl Viro 	return single_open(file, lcd_proc_show, PDE_DATA(inode));
1173b4f9fe12SLen Brown }
1174b4f9fe12SLen Brown 
117562cce752SSeth Forshee static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
1176b4f9fe12SLen Brown {
1177a39f46dfSAzael Avalos 	u32 hci_result;
1178b4f9fe12SLen Brown 
1179121b7b0dSAkio Idehara 	if (dev->tr_backlight_supported) {
1180121b7b0dSAkio Idehara 		bool enable = !value;
1181121b7b0dSAkio Idehara 		int ret = set_tr_backlight_status(dev, enable);
1182121b7b0dSAkio Idehara 		if (ret)
1183121b7b0dSAkio Idehara 			return ret;
1184121b7b0dSAkio Idehara 		if (value)
1185121b7b0dSAkio Idehara 			value--;
1186121b7b0dSAkio Idehara 	}
1187121b7b0dSAkio Idehara 
1188a39f46dfSAzael Avalos 	value = value << HCI_LCD_BRIGHTNESS_SHIFT;
1189a39f46dfSAzael Avalos 	hci_result = hci_write1(dev, HCI_LCD_BRIGHTNESS, value);
1190a39f46dfSAzael Avalos 	return hci_result == TOS_SUCCESS ? 0 : -EIO;
1191b4f9fe12SLen Brown }
1192b4f9fe12SLen Brown 
1193b4f9fe12SLen Brown static int set_lcd_status(struct backlight_device *bd)
1194b4f9fe12SLen Brown {
1195135740deSSeth Forshee 	struct toshiba_acpi_dev *dev = bl_get_data(bd);
119662cce752SSeth Forshee 	return set_lcd_brightness(dev, bd->props.brightness);
1197b4f9fe12SLen Brown }
1198b4f9fe12SLen Brown 
1199936c8bcdSAlexey Dobriyan static ssize_t lcd_proc_write(struct file *file, const char __user *buf,
1200936c8bcdSAlexey Dobriyan 			      size_t count, loff_t *pos)
1201b4f9fe12SLen Brown {
1202d9dda78bSAl Viro 	struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
1203936c8bcdSAlexey Dobriyan 	char cmd[42];
1204936c8bcdSAlexey Dobriyan 	size_t len;
1205b4f9fe12SLen Brown 	int value;
1206b4f9fe12SLen Brown 	int ret;
1207121b7b0dSAkio Idehara 	int levels = dev->backlight_dev->props.max_brightness + 1;
1208b4f9fe12SLen Brown 
1209936c8bcdSAlexey Dobriyan 	len = min(count, sizeof(cmd) - 1);
1210936c8bcdSAlexey Dobriyan 	if (copy_from_user(cmd, buf, len))
1211936c8bcdSAlexey Dobriyan 		return -EFAULT;
1212936c8bcdSAlexey Dobriyan 	cmd[len] = '\0';
1213936c8bcdSAlexey Dobriyan 
1214936c8bcdSAlexey Dobriyan 	if (sscanf(cmd, " brightness : %i", &value) == 1 &&
1215121b7b0dSAkio Idehara 	    value >= 0 && value < levels) {
121662cce752SSeth Forshee 		ret = set_lcd_brightness(dev, value);
1217b4f9fe12SLen Brown 		if (ret == 0)
1218b4f9fe12SLen Brown 			ret = count;
1219b4f9fe12SLen Brown 	} else {
1220b4f9fe12SLen Brown 		ret = -EINVAL;
1221b4f9fe12SLen Brown 	}
1222b4f9fe12SLen Brown 	return ret;
1223b4f9fe12SLen Brown }
1224b4f9fe12SLen Brown 
1225936c8bcdSAlexey Dobriyan static const struct file_operations lcd_proc_fops = {
1226936c8bcdSAlexey Dobriyan 	.owner		= THIS_MODULE,
1227936c8bcdSAlexey Dobriyan 	.open		= lcd_proc_open,
1228936c8bcdSAlexey Dobriyan 	.read		= seq_read,
1229936c8bcdSAlexey Dobriyan 	.llseek		= seq_lseek,
1230936c8bcdSAlexey Dobriyan 	.release	= single_release,
1231936c8bcdSAlexey Dobriyan 	.write		= lcd_proc_write,
1232936c8bcdSAlexey Dobriyan };
1233936c8bcdSAlexey Dobriyan 
123436d03f93SSeth Forshee static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status)
123536d03f93SSeth Forshee {
123636d03f93SSeth Forshee 	u32 hci_result;
123736d03f93SSeth Forshee 
1238893f3f62SAzael Avalos 	hci_result = hci_read1(dev, HCI_VIDEO_OUT, status);
12391864bbc2SAzael Avalos 	return hci_result == TOS_SUCCESS ? 0 : -EIO;
124036d03f93SSeth Forshee }
124136d03f93SSeth Forshee 
1242936c8bcdSAlexey Dobriyan static int video_proc_show(struct seq_file *m, void *v)
1243b4f9fe12SLen Brown {
1244135740deSSeth Forshee 	struct toshiba_acpi_dev *dev = m->private;
1245b4f9fe12SLen Brown 	u32 value;
124636d03f93SSeth Forshee 	int ret;
1247b4f9fe12SLen Brown 
124836d03f93SSeth Forshee 	ret = get_video_status(dev, &value);
124936d03f93SSeth Forshee 	if (!ret) {
1250b4f9fe12SLen Brown 		int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0;
1251b4f9fe12SLen Brown 		int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0;
1252b4f9fe12SLen Brown 		int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0;
1253936c8bcdSAlexey Dobriyan 		seq_printf(m, "lcd_out:                 %d\n", is_lcd);
1254936c8bcdSAlexey Dobriyan 		seq_printf(m, "crt_out:                 %d\n", is_crt);
1255936c8bcdSAlexey Dobriyan 		seq_printf(m, "tv_out:                  %d\n", is_tv);
1256b4f9fe12SLen Brown 	}
1257b4f9fe12SLen Brown 
125836d03f93SSeth Forshee 	return ret;
1259b4f9fe12SLen Brown }
1260b4f9fe12SLen Brown 
1261936c8bcdSAlexey Dobriyan static int video_proc_open(struct inode *inode, struct file *file)
1262b4f9fe12SLen Brown {
1263d9dda78bSAl Viro 	return single_open(file, video_proc_show, PDE_DATA(inode));
1264936c8bcdSAlexey Dobriyan }
1265936c8bcdSAlexey Dobriyan 
1266936c8bcdSAlexey Dobriyan static ssize_t video_proc_write(struct file *file, const char __user *buf,
1267936c8bcdSAlexey Dobriyan 				size_t count, loff_t *pos)
1268936c8bcdSAlexey Dobriyan {
1269d9dda78bSAl Viro 	struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
1270936c8bcdSAlexey Dobriyan 	char *cmd, *buffer;
127136d03f93SSeth Forshee 	int ret;
1272b4f9fe12SLen Brown 	int value;
1273b4f9fe12SLen Brown 	int remain = count;
1274b4f9fe12SLen Brown 	int lcd_out = -1;
1275b4f9fe12SLen Brown 	int crt_out = -1;
1276b4f9fe12SLen Brown 	int tv_out = -1;
1277b4f9fe12SLen Brown 	u32 video_out;
1278b4f9fe12SLen Brown 
1279936c8bcdSAlexey Dobriyan 	cmd = kmalloc(count + 1, GFP_KERNEL);
1280936c8bcdSAlexey Dobriyan 	if (!cmd)
1281936c8bcdSAlexey Dobriyan 		return -ENOMEM;
1282936c8bcdSAlexey Dobriyan 	if (copy_from_user(cmd, buf, count)) {
1283936c8bcdSAlexey Dobriyan 		kfree(cmd);
1284936c8bcdSAlexey Dobriyan 		return -EFAULT;
1285936c8bcdSAlexey Dobriyan 	}
1286936c8bcdSAlexey Dobriyan 	cmd[count] = '\0';
1287936c8bcdSAlexey Dobriyan 
1288936c8bcdSAlexey Dobriyan 	buffer = cmd;
1289936c8bcdSAlexey Dobriyan 
1290b4f9fe12SLen Brown 	/* scan expression.  Multiple expressions may be delimited with ;
1291b4f9fe12SLen Brown 	 *
1292b4f9fe12SLen Brown 	 *  NOTE: to keep scanning simple, invalid fields are ignored
1293b4f9fe12SLen Brown 	 */
1294b4f9fe12SLen Brown 	while (remain) {
1295b4f9fe12SLen Brown 		if (sscanf(buffer, " lcd_out : %i", &value) == 1)
1296b4f9fe12SLen Brown 			lcd_out = value & 1;
1297b4f9fe12SLen Brown 		else if (sscanf(buffer, " crt_out : %i", &value) == 1)
1298b4f9fe12SLen Brown 			crt_out = value & 1;
1299b4f9fe12SLen Brown 		else if (sscanf(buffer, " tv_out : %i", &value) == 1)
1300b4f9fe12SLen Brown 			tv_out = value & 1;
1301b4f9fe12SLen Brown 		/* advance to one character past the next ; */
1302b4f9fe12SLen Brown 		do {
1303b4f9fe12SLen Brown 			++buffer;
1304b4f9fe12SLen Brown 			--remain;
1305b4f9fe12SLen Brown 		}
1306b4f9fe12SLen Brown 		while (remain && *(buffer - 1) != ';');
1307b4f9fe12SLen Brown 	}
1308b4f9fe12SLen Brown 
1309936c8bcdSAlexey Dobriyan 	kfree(cmd);
1310936c8bcdSAlexey Dobriyan 
131136d03f93SSeth Forshee 	ret = get_video_status(dev, &video_out);
131236d03f93SSeth Forshee 	if (!ret) {
1313b4f9fe12SLen Brown 		unsigned int new_video_out = video_out;
1314b4f9fe12SLen Brown 		if (lcd_out != -1)
1315b4f9fe12SLen Brown 			_set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out);
1316b4f9fe12SLen Brown 		if (crt_out != -1)
1317b4f9fe12SLen Brown 			_set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out);
1318b4f9fe12SLen Brown 		if (tv_out != -1)
1319b4f9fe12SLen Brown 			_set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out);
1320b4f9fe12SLen Brown 		/* To avoid unnecessary video disruption, only write the new
1321b4f9fe12SLen Brown 		 * video setting if something changed. */
1322b4f9fe12SLen Brown 		if (new_video_out != video_out)
132332bcd5cbSSeth Forshee 			ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out);
1324b4f9fe12SLen Brown 	}
1325b4f9fe12SLen Brown 
132632bcd5cbSSeth Forshee 	return ret ? ret : count;
1327b4f9fe12SLen Brown }
1328b4f9fe12SLen Brown 
1329936c8bcdSAlexey Dobriyan static const struct file_operations video_proc_fops = {
1330936c8bcdSAlexey Dobriyan 	.owner		= THIS_MODULE,
1331936c8bcdSAlexey Dobriyan 	.open		= video_proc_open,
1332936c8bcdSAlexey Dobriyan 	.read		= seq_read,
1333936c8bcdSAlexey Dobriyan 	.llseek		= seq_lseek,
1334936c8bcdSAlexey Dobriyan 	.release	= single_release,
1335936c8bcdSAlexey Dobriyan 	.write		= video_proc_write,
1336936c8bcdSAlexey Dobriyan };
1337936c8bcdSAlexey Dobriyan 
133836d03f93SSeth Forshee static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status)
133936d03f93SSeth Forshee {
134036d03f93SSeth Forshee 	u32 hci_result;
134136d03f93SSeth Forshee 
1342893f3f62SAzael Avalos 	hci_result = hci_read1(dev, HCI_FAN, status);
13431864bbc2SAzael Avalos 	return hci_result == TOS_SUCCESS ? 0 : -EIO;
134436d03f93SSeth Forshee }
134536d03f93SSeth Forshee 
1346936c8bcdSAlexey Dobriyan static int fan_proc_show(struct seq_file *m, void *v)
1347b4f9fe12SLen Brown {
1348135740deSSeth Forshee 	struct toshiba_acpi_dev *dev = m->private;
134936d03f93SSeth Forshee 	int ret;
1350b4f9fe12SLen Brown 	u32 value;
1351b4f9fe12SLen Brown 
135236d03f93SSeth Forshee 	ret = get_fan_status(dev, &value);
135336d03f93SSeth Forshee 	if (!ret) {
1354936c8bcdSAlexey Dobriyan 		seq_printf(m, "running:                 %d\n", (value > 0));
1355135740deSSeth Forshee 		seq_printf(m, "force_on:                %d\n", dev->force_fan);
1356b4f9fe12SLen Brown 	}
1357b4f9fe12SLen Brown 
135836d03f93SSeth Forshee 	return ret;
1359b4f9fe12SLen Brown }
1360b4f9fe12SLen Brown 
1361936c8bcdSAlexey Dobriyan static int fan_proc_open(struct inode *inode, struct file *file)
1362b4f9fe12SLen Brown {
1363d9dda78bSAl Viro 	return single_open(file, fan_proc_show, PDE_DATA(inode));
1364936c8bcdSAlexey Dobriyan }
1365936c8bcdSAlexey Dobriyan 
1366936c8bcdSAlexey Dobriyan static ssize_t fan_proc_write(struct file *file, const char __user *buf,
1367936c8bcdSAlexey Dobriyan 			      size_t count, loff_t *pos)
1368936c8bcdSAlexey Dobriyan {
1369d9dda78bSAl Viro 	struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
1370936c8bcdSAlexey Dobriyan 	char cmd[42];
1371936c8bcdSAlexey Dobriyan 	size_t len;
1372b4f9fe12SLen Brown 	int value;
1373b4f9fe12SLen Brown 	u32 hci_result;
1374b4f9fe12SLen Brown 
1375936c8bcdSAlexey Dobriyan 	len = min(count, sizeof(cmd) - 1);
1376936c8bcdSAlexey Dobriyan 	if (copy_from_user(cmd, buf, len))
1377936c8bcdSAlexey Dobriyan 		return -EFAULT;
1378936c8bcdSAlexey Dobriyan 	cmd[len] = '\0';
1379936c8bcdSAlexey Dobriyan 
1380936c8bcdSAlexey Dobriyan 	if (sscanf(cmd, " force_on : %i", &value) == 1 &&
1381b4f9fe12SLen Brown 	    value >= 0 && value <= 1) {
1382893f3f62SAzael Avalos 		hci_result = hci_write1(dev, HCI_FAN, value);
13831864bbc2SAzael Avalos 		if (hci_result != TOS_SUCCESS)
138432bcd5cbSSeth Forshee 			return -EIO;
1385b4f9fe12SLen Brown 		else
1386135740deSSeth Forshee 			dev->force_fan = value;
1387b4f9fe12SLen Brown 	} else {
1388b4f9fe12SLen Brown 		return -EINVAL;
1389b4f9fe12SLen Brown 	}
1390b4f9fe12SLen Brown 
1391b4f9fe12SLen Brown 	return count;
1392b4f9fe12SLen Brown }
1393b4f9fe12SLen Brown 
1394936c8bcdSAlexey Dobriyan static const struct file_operations fan_proc_fops = {
1395936c8bcdSAlexey Dobriyan 	.owner		= THIS_MODULE,
1396936c8bcdSAlexey Dobriyan 	.open		= fan_proc_open,
1397936c8bcdSAlexey Dobriyan 	.read		= seq_read,
1398936c8bcdSAlexey Dobriyan 	.llseek		= seq_lseek,
1399936c8bcdSAlexey Dobriyan 	.release	= single_release,
1400936c8bcdSAlexey Dobriyan 	.write		= fan_proc_write,
1401936c8bcdSAlexey Dobriyan };
1402936c8bcdSAlexey Dobriyan 
1403936c8bcdSAlexey Dobriyan static int keys_proc_show(struct seq_file *m, void *v)
1404b4f9fe12SLen Brown {
1405135740deSSeth Forshee 	struct toshiba_acpi_dev *dev = m->private;
1406b4f9fe12SLen Brown 	u32 hci_result;
1407b4f9fe12SLen Brown 	u32 value;
1408b4f9fe12SLen Brown 
140911948b93SSeth Forshee 	if (!dev->key_event_valid && dev->system_event_supported) {
1410893f3f62SAzael Avalos 		hci_result = hci_read1(dev, HCI_SYSTEM_EVENT, &value);
14111864bbc2SAzael Avalos 		if (hci_result == TOS_SUCCESS) {
1412135740deSSeth Forshee 			dev->key_event_valid = 1;
1413135740deSSeth Forshee 			dev->last_key_event = value;
14141864bbc2SAzael Avalos 		} else if (hci_result == TOS_FIFO_EMPTY) {
1415b4f9fe12SLen Brown 			/* better luck next time */
14161864bbc2SAzael Avalos 		} else if (hci_result == TOS_NOT_SUPPORTED) {
1417b4f9fe12SLen Brown 			/* This is a workaround for an unresolved issue on
1418b4f9fe12SLen Brown 			 * some machines where system events sporadically
1419b4f9fe12SLen Brown 			 * become disabled. */
1420893f3f62SAzael Avalos 			hci_result = hci_write1(dev, HCI_SYSTEM_EVENT, 1);
14217e33460dSJoe Perches 			pr_notice("Re-enabled hotkeys\n");
1422b4f9fe12SLen Brown 		} else {
14237e33460dSJoe Perches 			pr_err("Error reading hotkey status\n");
142432bcd5cbSSeth Forshee 			return -EIO;
1425b4f9fe12SLen Brown 		}
1426b4f9fe12SLen Brown 	}
1427b4f9fe12SLen Brown 
1428135740deSSeth Forshee 	seq_printf(m, "hotkey_ready:            %d\n", dev->key_event_valid);
1429135740deSSeth Forshee 	seq_printf(m, "hotkey:                  0x%04x\n", dev->last_key_event);
1430936c8bcdSAlexey Dobriyan 	return 0;
1431b4f9fe12SLen Brown }
1432b4f9fe12SLen Brown 
1433936c8bcdSAlexey Dobriyan static int keys_proc_open(struct inode *inode, struct file *file)
1434b4f9fe12SLen Brown {
1435d9dda78bSAl Viro 	return single_open(file, keys_proc_show, PDE_DATA(inode));
1436936c8bcdSAlexey Dobriyan }
1437936c8bcdSAlexey Dobriyan 
1438936c8bcdSAlexey Dobriyan static ssize_t keys_proc_write(struct file *file, const char __user *buf,
1439936c8bcdSAlexey Dobriyan 			       size_t count, loff_t *pos)
1440936c8bcdSAlexey Dobriyan {
1441d9dda78bSAl Viro 	struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
1442936c8bcdSAlexey Dobriyan 	char cmd[42];
1443936c8bcdSAlexey Dobriyan 	size_t len;
1444b4f9fe12SLen Brown 	int value;
1445b4f9fe12SLen Brown 
1446936c8bcdSAlexey Dobriyan 	len = min(count, sizeof(cmd) - 1);
1447936c8bcdSAlexey Dobriyan 	if (copy_from_user(cmd, buf, len))
1448936c8bcdSAlexey Dobriyan 		return -EFAULT;
1449936c8bcdSAlexey Dobriyan 	cmd[len] = '\0';
1450936c8bcdSAlexey Dobriyan 
1451936c8bcdSAlexey Dobriyan 	if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) {
1452135740deSSeth Forshee 		dev->key_event_valid = 0;
1453b4f9fe12SLen Brown 	} else {
1454b4f9fe12SLen Brown 		return -EINVAL;
1455b4f9fe12SLen Brown 	}
1456b4f9fe12SLen Brown 
1457b4f9fe12SLen Brown 	return count;
1458b4f9fe12SLen Brown }
1459b4f9fe12SLen Brown 
1460936c8bcdSAlexey Dobriyan static const struct file_operations keys_proc_fops = {
1461936c8bcdSAlexey Dobriyan 	.owner		= THIS_MODULE,
1462936c8bcdSAlexey Dobriyan 	.open		= keys_proc_open,
1463936c8bcdSAlexey Dobriyan 	.read		= seq_read,
1464936c8bcdSAlexey Dobriyan 	.llseek		= seq_lseek,
1465936c8bcdSAlexey Dobriyan 	.release	= single_release,
1466936c8bcdSAlexey Dobriyan 	.write		= keys_proc_write,
1467936c8bcdSAlexey Dobriyan };
1468936c8bcdSAlexey Dobriyan 
1469936c8bcdSAlexey Dobriyan static int version_proc_show(struct seq_file *m, void *v)
1470b4f9fe12SLen Brown {
1471936c8bcdSAlexey Dobriyan 	seq_printf(m, "driver:                  %s\n", TOSHIBA_ACPI_VERSION);
1472936c8bcdSAlexey Dobriyan 	seq_printf(m, "proc_interface:          %d\n", PROC_INTERFACE_VERSION);
1473936c8bcdSAlexey Dobriyan 	return 0;
1474b4f9fe12SLen Brown }
1475b4f9fe12SLen Brown 
1476936c8bcdSAlexey Dobriyan static int version_proc_open(struct inode *inode, struct file *file)
1477936c8bcdSAlexey Dobriyan {
1478d9dda78bSAl Viro 	return single_open(file, version_proc_show, PDE_DATA(inode));
1479936c8bcdSAlexey Dobriyan }
1480936c8bcdSAlexey Dobriyan 
1481936c8bcdSAlexey Dobriyan static const struct file_operations version_proc_fops = {
1482936c8bcdSAlexey Dobriyan 	.owner		= THIS_MODULE,
1483936c8bcdSAlexey Dobriyan 	.open		= version_proc_open,
1484936c8bcdSAlexey Dobriyan 	.read		= seq_read,
1485936c8bcdSAlexey Dobriyan 	.llseek		= seq_lseek,
1486936c8bcdSAlexey Dobriyan 	.release	= single_release,
1487936c8bcdSAlexey Dobriyan };
1488936c8bcdSAlexey Dobriyan 
1489b4f9fe12SLen Brown /* proc and module init
1490b4f9fe12SLen Brown  */
1491b4f9fe12SLen Brown 
1492b4f9fe12SLen Brown #define PROC_TOSHIBA		"toshiba"
1493b4f9fe12SLen Brown 
1494b859f159SGreg Kroah-Hartman static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
1495b4f9fe12SLen Brown {
149636d03f93SSeth Forshee 	if (dev->backlight_dev)
1497135740deSSeth Forshee 		proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1498135740deSSeth Forshee 				 &lcd_proc_fops, dev);
149936d03f93SSeth Forshee 	if (dev->video_supported)
1500135740deSSeth Forshee 		proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1501135740deSSeth Forshee 				 &video_proc_fops, dev);
150236d03f93SSeth Forshee 	if (dev->fan_supported)
1503135740deSSeth Forshee 		proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1504135740deSSeth Forshee 				 &fan_proc_fops, dev);
150536d03f93SSeth Forshee 	if (dev->hotkey_dev)
1506135740deSSeth Forshee 		proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1507135740deSSeth Forshee 				 &keys_proc_fops, dev);
1508135740deSSeth Forshee 	proc_create_data("version", S_IRUGO, toshiba_proc_dir,
1509135740deSSeth Forshee 			 &version_proc_fops, dev);
1510b4f9fe12SLen Brown }
1511b4f9fe12SLen Brown 
151236d03f93SSeth Forshee static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
1513b4f9fe12SLen Brown {
151436d03f93SSeth Forshee 	if (dev->backlight_dev)
1515936c8bcdSAlexey Dobriyan 		remove_proc_entry("lcd", toshiba_proc_dir);
151636d03f93SSeth Forshee 	if (dev->video_supported)
1517936c8bcdSAlexey Dobriyan 		remove_proc_entry("video", toshiba_proc_dir);
151836d03f93SSeth Forshee 	if (dev->fan_supported)
1519936c8bcdSAlexey Dobriyan 		remove_proc_entry("fan", toshiba_proc_dir);
152036d03f93SSeth Forshee 	if (dev->hotkey_dev)
1521936c8bcdSAlexey Dobriyan 		remove_proc_entry("keys", toshiba_proc_dir);
1522936c8bcdSAlexey Dobriyan 	remove_proc_entry("version", toshiba_proc_dir);
1523b4f9fe12SLen Brown }
1524b4f9fe12SLen Brown 
1525acc2472eSLionel Debroux static const struct backlight_ops toshiba_backlight_data = {
1526121b7b0dSAkio Idehara 	.options = BL_CORE_SUSPENDRESUME,
152762cce752SSeth Forshee 	.get_brightness = get_lcd_brightness,
1528b4f9fe12SLen Brown 	.update_status  = set_lcd_status,
1529b4f9fe12SLen Brown };
1530b4f9fe12SLen Brown 
1531360f0f39SAzael Avalos /*
1532360f0f39SAzael Avalos  * Sysfs files
1533360f0f39SAzael Avalos  */
153493f8c16dSAzael Avalos static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
153593f8c16dSAzael Avalos 					 struct device_attribute *attr,
153693f8c16dSAzael Avalos 					 const char *buf, size_t count);
153793f8c16dSAzael Avalos static ssize_t toshiba_kbd_bl_mode_show(struct device *dev,
153893f8c16dSAzael Avalos 					struct device_attribute *attr,
153993f8c16dSAzael Avalos 					char *buf);
154093f8c16dSAzael Avalos static ssize_t toshiba_kbd_type_show(struct device *dev,
154193f8c16dSAzael Avalos 				     struct device_attribute *attr,
154293f8c16dSAzael Avalos 				     char *buf);
154393f8c16dSAzael Avalos static ssize_t toshiba_available_kbd_modes_show(struct device *dev,
154493f8c16dSAzael Avalos 					struct device_attribute *attr,
154593f8c16dSAzael Avalos 					char *buf);
154693f8c16dSAzael Avalos static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev,
154793f8c16dSAzael Avalos 					    struct device_attribute *attr,
154893f8c16dSAzael Avalos 					    const char *buf, size_t count);
154993f8c16dSAzael Avalos static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev,
155093f8c16dSAzael Avalos 					   struct device_attribute *attr,
155193f8c16dSAzael Avalos 					   char *buf);
155293f8c16dSAzael Avalos static ssize_t toshiba_touchpad_store(struct device *dev,
155393f8c16dSAzael Avalos 				      struct device_attribute *attr,
155493f8c16dSAzael Avalos 				      const char *buf, size_t count);
155593f8c16dSAzael Avalos static ssize_t toshiba_touchpad_show(struct device *dev,
155693f8c16dSAzael Avalos 				     struct device_attribute *attr,
155793f8c16dSAzael Avalos 				     char *buf);
155893f8c16dSAzael Avalos static ssize_t toshiba_position_show(struct device *dev,
155993f8c16dSAzael Avalos 				     struct device_attribute *attr,
156093f8c16dSAzael Avalos 				     char *buf);
1561e26ffe51SAzael Avalos static ssize_t toshiba_usb_sleep_charge_show(struct device *dev,
1562e26ffe51SAzael Avalos 					     struct device_attribute *attr,
1563e26ffe51SAzael Avalos 					     char *buf);
1564e26ffe51SAzael Avalos static ssize_t toshiba_usb_sleep_charge_store(struct device *dev,
1565e26ffe51SAzael Avalos 					      struct device_attribute *attr,
1566e26ffe51SAzael Avalos 					      const char *buf, size_t count);
1567182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_show(struct device *dev,
1568182bcaa5SAzael Avalos 					       struct device_attribute *attr,
1569182bcaa5SAzael Avalos 					       char *buf);
1570182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_store(struct device *dev,
1571182bcaa5SAzael Avalos 						struct device_attribute *attr,
1572182bcaa5SAzael Avalos 						const char *buf, size_t count);
1573bb3fe01fSAzael Avalos static ssize_t toshiba_usb_rapid_charge_show(struct device *dev,
1574bb3fe01fSAzael Avalos 					     struct device_attribute *attr,
1575bb3fe01fSAzael Avalos 					     char *buf);
1576bb3fe01fSAzael Avalos static ssize_t toshiba_usb_rapid_charge_store(struct device *dev,
1577bb3fe01fSAzael Avalos 					      struct device_attribute *attr,
1578bb3fe01fSAzael Avalos 					      const char *buf, size_t count);
1579172ce0a9SAzael Avalos static ssize_t toshiba_usb_sleep_music_show(struct device *dev,
1580172ce0a9SAzael Avalos 					    struct device_attribute *attr,
1581172ce0a9SAzael Avalos 					    char *buf);
1582172ce0a9SAzael Avalos static ssize_t toshiba_usb_sleep_music_store(struct device *dev,
1583172ce0a9SAzael Avalos 					     struct device_attribute *attr,
1584172ce0a9SAzael Avalos 					     const char *buf, size_t count);
158593f8c16dSAzael Avalos 
158693f8c16dSAzael Avalos static DEVICE_ATTR(kbd_backlight_mode, S_IRUGO | S_IWUSR,
158793f8c16dSAzael Avalos 		   toshiba_kbd_bl_mode_show, toshiba_kbd_bl_mode_store);
158893f8c16dSAzael Avalos static DEVICE_ATTR(kbd_type, S_IRUGO, toshiba_kbd_type_show, NULL);
158993f8c16dSAzael Avalos static DEVICE_ATTR(available_kbd_modes, S_IRUGO,
159093f8c16dSAzael Avalos 		   toshiba_available_kbd_modes_show, NULL);
159193f8c16dSAzael Avalos static DEVICE_ATTR(kbd_backlight_timeout, S_IRUGO | S_IWUSR,
159293f8c16dSAzael Avalos 		   toshiba_kbd_bl_timeout_show, toshiba_kbd_bl_timeout_store);
159393f8c16dSAzael Avalos static DEVICE_ATTR(touchpad, S_IRUGO | S_IWUSR,
159493f8c16dSAzael Avalos 		   toshiba_touchpad_show, toshiba_touchpad_store);
159593f8c16dSAzael Avalos static DEVICE_ATTR(position, S_IRUGO, toshiba_position_show, NULL);
1596e26ffe51SAzael Avalos static DEVICE_ATTR(usb_sleep_charge, S_IRUGO | S_IWUSR,
1597e26ffe51SAzael Avalos 		   toshiba_usb_sleep_charge_show,
1598e26ffe51SAzael Avalos 		   toshiba_usb_sleep_charge_store);
1599182bcaa5SAzael Avalos static DEVICE_ATTR(sleep_functions_on_battery, S_IRUGO | S_IWUSR,
1600182bcaa5SAzael Avalos 		   sleep_functions_on_battery_show,
1601182bcaa5SAzael Avalos 		   sleep_functions_on_battery_store);
1602bb3fe01fSAzael Avalos static DEVICE_ATTR(usb_rapid_charge, S_IRUGO | S_IWUSR,
1603bb3fe01fSAzael Avalos 		   toshiba_usb_rapid_charge_show,
1604bb3fe01fSAzael Avalos 		   toshiba_usb_rapid_charge_store);
1605172ce0a9SAzael Avalos static DEVICE_ATTR(usb_sleep_music, S_IRUGO | S_IWUSR,
1606172ce0a9SAzael Avalos 		   toshiba_usb_sleep_music_show,
1607172ce0a9SAzael Avalos 		   toshiba_usb_sleep_music_store);
160893f8c16dSAzael Avalos 
160993f8c16dSAzael Avalos static struct attribute *toshiba_attributes[] = {
161093f8c16dSAzael Avalos 	&dev_attr_kbd_backlight_mode.attr,
161193f8c16dSAzael Avalos 	&dev_attr_kbd_type.attr,
161293f8c16dSAzael Avalos 	&dev_attr_available_kbd_modes.attr,
161393f8c16dSAzael Avalos 	&dev_attr_kbd_backlight_timeout.attr,
161493f8c16dSAzael Avalos 	&dev_attr_touchpad.attr,
161593f8c16dSAzael Avalos 	&dev_attr_position.attr,
1616e26ffe51SAzael Avalos 	&dev_attr_usb_sleep_charge.attr,
1617182bcaa5SAzael Avalos 	&dev_attr_sleep_functions_on_battery.attr,
1618bb3fe01fSAzael Avalos 	&dev_attr_usb_rapid_charge.attr,
1619172ce0a9SAzael Avalos 	&dev_attr_usb_sleep_music.attr,
162093f8c16dSAzael Avalos 	NULL,
162193f8c16dSAzael Avalos };
162293f8c16dSAzael Avalos 
162393f8c16dSAzael Avalos static umode_t toshiba_sysfs_is_visible(struct kobject *,
162493f8c16dSAzael Avalos 					struct attribute *, int);
162593f8c16dSAzael Avalos 
162693f8c16dSAzael Avalos static struct attribute_group toshiba_attr_group = {
162793f8c16dSAzael Avalos 	.is_visible = toshiba_sysfs_is_visible,
162893f8c16dSAzael Avalos 	.attrs = toshiba_attributes,
162993f8c16dSAzael Avalos };
1630360f0f39SAzael Avalos 
1631360f0f39SAzael Avalos static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
1632360f0f39SAzael Avalos 					 struct device_attribute *attr,
1633360f0f39SAzael Avalos 					 const char *buf, size_t count)
1634360f0f39SAzael Avalos {
1635360f0f39SAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1636aeaac098SDan Carpenter 	int mode;
1637aeaac098SDan Carpenter 	int time;
1638aeaac098SDan Carpenter 	int ret;
1639360f0f39SAzael Avalos 
1640aeaac098SDan Carpenter 
1641aeaac098SDan Carpenter 	ret = kstrtoint(buf, 0, &mode);
1642aeaac098SDan Carpenter 	if (ret)
1643aeaac098SDan Carpenter 		return ret;
164493f8c16dSAzael Avalos 
164593f8c16dSAzael Avalos 	/* Check for supported modes depending on keyboard backlight type */
164693f8c16dSAzael Avalos 	if (toshiba->kbd_type == 1) {
164793f8c16dSAzael Avalos 		/* Type 1 supports SCI_KBD_MODE_FNZ and SCI_KBD_MODE_AUTO */
1648aeaac098SDan Carpenter 		if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO)
1649360f0f39SAzael Avalos 			return -EINVAL;
165093f8c16dSAzael Avalos 	} else if (toshiba->kbd_type == 2) {
165193f8c16dSAzael Avalos 		/* Type 2 doesn't support SCI_KBD_MODE_FNZ */
165293f8c16dSAzael Avalos 		if (mode != SCI_KBD_MODE_AUTO && mode != SCI_KBD_MODE_ON &&
165393f8c16dSAzael Avalos 		    mode != SCI_KBD_MODE_OFF)
165493f8c16dSAzael Avalos 			return -EINVAL;
165593f8c16dSAzael Avalos 	}
1656360f0f39SAzael Avalos 
1657360f0f39SAzael Avalos 	/* Set the Keyboard Backlight Mode where:
1658360f0f39SAzael Avalos 	 *	Auto - KBD backlight turns off automatically in given time
1659360f0f39SAzael Avalos 	 *	FN-Z - KBD backlight "toggles" when hotkey pressed
166093f8c16dSAzael Avalos 	 *	ON   - KBD backlight is always on
166193f8c16dSAzael Avalos 	 *	OFF  - KBD backlight is always off
1662360f0f39SAzael Avalos 	 */
166393f8c16dSAzael Avalos 
166493f8c16dSAzael Avalos 	/* Only make a change if the actual mode has changed */
1665aeaac098SDan Carpenter 	if (toshiba->kbd_mode != mode) {
166693f8c16dSAzael Avalos 		/* Shift the time to "base time" (0x3c0000 == 60 seconds) */
1667360f0f39SAzael Avalos 		time = toshiba->kbd_time << HCI_MISC_SHIFT;
166893f8c16dSAzael Avalos 
166993f8c16dSAzael Avalos 		/* OR the "base time" to the actual method format */
167093f8c16dSAzael Avalos 		if (toshiba->kbd_type == 1) {
167193f8c16dSAzael Avalos 			/* Type 1 requires the current mode */
167293f8c16dSAzael Avalos 			time |= toshiba->kbd_mode;
167393f8c16dSAzael Avalos 		} else if (toshiba->kbd_type == 2) {
167493f8c16dSAzael Avalos 			/* Type 2 requires the desired mode */
167593f8c16dSAzael Avalos 			time |= mode;
167693f8c16dSAzael Avalos 		}
167793f8c16dSAzael Avalos 
1678aeaac098SDan Carpenter 		ret = toshiba_kbd_illum_status_set(toshiba, time);
1679aeaac098SDan Carpenter 		if (ret)
1680aeaac098SDan Carpenter 			return ret;
168193f8c16dSAzael Avalos 
1682360f0f39SAzael Avalos 		toshiba->kbd_mode = mode;
1683360f0f39SAzael Avalos 	}
1684360f0f39SAzael Avalos 
1685360f0f39SAzael Avalos 	return count;
1686360f0f39SAzael Avalos }
1687360f0f39SAzael Avalos 
1688360f0f39SAzael Avalos static ssize_t toshiba_kbd_bl_mode_show(struct device *dev,
1689360f0f39SAzael Avalos 					struct device_attribute *attr,
1690360f0f39SAzael Avalos 					char *buf)
1691360f0f39SAzael Avalos {
1692360f0f39SAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1693360f0f39SAzael Avalos 	u32 time;
1694360f0f39SAzael Avalos 
1695360f0f39SAzael Avalos 	if (toshiba_kbd_illum_status_get(toshiba, &time) < 0)
1696360f0f39SAzael Avalos 		return -EIO;
1697360f0f39SAzael Avalos 
169893f8c16dSAzael Avalos 	return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK);
169993f8c16dSAzael Avalos }
170093f8c16dSAzael Avalos 
170193f8c16dSAzael Avalos static ssize_t toshiba_kbd_type_show(struct device *dev,
170293f8c16dSAzael Avalos 				     struct device_attribute *attr,
170393f8c16dSAzael Avalos 				     char *buf)
170493f8c16dSAzael Avalos {
170593f8c16dSAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
170693f8c16dSAzael Avalos 
170793f8c16dSAzael Avalos 	return sprintf(buf, "%d\n", toshiba->kbd_type);
170893f8c16dSAzael Avalos }
170993f8c16dSAzael Avalos 
171093f8c16dSAzael Avalos static ssize_t toshiba_available_kbd_modes_show(struct device *dev,
171193f8c16dSAzael Avalos 						struct device_attribute *attr,
171293f8c16dSAzael Avalos 						char *buf)
171393f8c16dSAzael Avalos {
171493f8c16dSAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
171593f8c16dSAzael Avalos 
171693f8c16dSAzael Avalos 	if (toshiba->kbd_type == 1)
171793f8c16dSAzael Avalos 		return sprintf(buf, "%x %x\n",
171893f8c16dSAzael Avalos 			       SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO);
171993f8c16dSAzael Avalos 
172093f8c16dSAzael Avalos 	return sprintf(buf, "%x %x %x\n",
172193f8c16dSAzael Avalos 		       SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF);
1722360f0f39SAzael Avalos }
1723360f0f39SAzael Avalos 
1724360f0f39SAzael Avalos static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev,
1725360f0f39SAzael Avalos 					    struct device_attribute *attr,
1726360f0f39SAzael Avalos 					    const char *buf, size_t count)
1727360f0f39SAzael Avalos {
1728360f0f39SAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1729eabde0faSAzael Avalos 	int time;
1730eabde0faSAzael Avalos 	int ret;
1731360f0f39SAzael Avalos 
1732eabde0faSAzael Avalos 	ret = kstrtoint(buf, 0, &time);
1733eabde0faSAzael Avalos 	if (ret)
1734eabde0faSAzael Avalos 		return ret;
1735eabde0faSAzael Avalos 
1736eabde0faSAzael Avalos 	/* Check for supported values depending on kbd_type */
1737eabde0faSAzael Avalos 	if (toshiba->kbd_type == 1) {
1738eabde0faSAzael Avalos 		if (time < 0 || time > 60)
1739360f0f39SAzael Avalos 			return -EINVAL;
1740eabde0faSAzael Avalos 	} else if (toshiba->kbd_type == 2) {
1741eabde0faSAzael Avalos 		if (time < 1 || time > 60)
1742eabde0faSAzael Avalos 			return -EINVAL;
1743eabde0faSAzael Avalos 	}
1744360f0f39SAzael Avalos 
1745eabde0faSAzael Avalos 	/* Set the Keyboard Backlight Timeout */
1746eabde0faSAzael Avalos 
1747eabde0faSAzael Avalos 	/* Only make a change if the actual timeout has changed */
1748eabde0faSAzael Avalos 	if (toshiba->kbd_time != time) {
1749eabde0faSAzael Avalos 		/* Shift the time to "base time" (0x3c0000 == 60 seconds) */
1750360f0f39SAzael Avalos 		time = time << HCI_MISC_SHIFT;
1751eabde0faSAzael Avalos 		/* OR the "base time" to the actual method format */
1752eabde0faSAzael Avalos 		if (toshiba->kbd_type == 1)
1753eabde0faSAzael Avalos 			time |= SCI_KBD_MODE_FNZ;
1754eabde0faSAzael Avalos 		else if (toshiba->kbd_type == 2)
1755eabde0faSAzael Avalos 			time |= SCI_KBD_MODE_AUTO;
1756eabde0faSAzael Avalos 
1757eabde0faSAzael Avalos 		ret = toshiba_kbd_illum_status_set(toshiba, time);
1758eabde0faSAzael Avalos 		if (ret)
1759eabde0faSAzael Avalos 			return ret;
1760eabde0faSAzael Avalos 
1761360f0f39SAzael Avalos 		toshiba->kbd_time = time >> HCI_MISC_SHIFT;
1762360f0f39SAzael Avalos 	}
1763360f0f39SAzael Avalos 
1764360f0f39SAzael Avalos 	return count;
1765360f0f39SAzael Avalos }
1766360f0f39SAzael Avalos 
1767360f0f39SAzael Avalos static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev,
1768360f0f39SAzael Avalos 					   struct device_attribute *attr,
1769360f0f39SAzael Avalos 					   char *buf)
1770360f0f39SAzael Avalos {
1771360f0f39SAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1772360f0f39SAzael Avalos 	u32 time;
1773360f0f39SAzael Avalos 
1774360f0f39SAzael Avalos 	if (toshiba_kbd_illum_status_get(toshiba, &time) < 0)
1775360f0f39SAzael Avalos 		return -EIO;
1776360f0f39SAzael Avalos 
1777360f0f39SAzael Avalos 	return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT);
1778360f0f39SAzael Avalos }
1779360f0f39SAzael Avalos 
17809d8658acSAzael Avalos static ssize_t toshiba_touchpad_store(struct device *dev,
17819d8658acSAzael Avalos 				      struct device_attribute *attr,
17829d8658acSAzael Avalos 				      const char *buf, size_t count)
17839d8658acSAzael Avalos {
17849d8658acSAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
17859d8658acSAzael Avalos 	int state;
1786c8a41669SAzael Avalos 	int ret;
17879d8658acSAzael Avalos 
17889d8658acSAzael Avalos 	/* Set the TouchPad on/off, 0 - Disable | 1 - Enable */
1789c8a41669SAzael Avalos 	ret = kstrtoint(buf, 0, &state);
1790c8a41669SAzael Avalos 	if (ret)
1791c8a41669SAzael Avalos 		return ret;
1792c8a41669SAzael Avalos 	if (state != 0 && state != 1)
1793c8a41669SAzael Avalos 		return -EINVAL;
1794c8a41669SAzael Avalos 
1795c8a41669SAzael Avalos 	ret = toshiba_touchpad_set(toshiba, state);
1796c8a41669SAzael Avalos 	if (ret)
1797c8a41669SAzael Avalos 		return ret;
17989d8658acSAzael Avalos 
17999d8658acSAzael Avalos 	return count;
18009d8658acSAzael Avalos }
18019d8658acSAzael Avalos 
18029d8658acSAzael Avalos static ssize_t toshiba_touchpad_show(struct device *dev,
18039d8658acSAzael Avalos 				     struct device_attribute *attr, char *buf)
18049d8658acSAzael Avalos {
18059d8658acSAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
18069d8658acSAzael Avalos 	u32 state;
18079d8658acSAzael Avalos 	int ret;
18089d8658acSAzael Avalos 
18099d8658acSAzael Avalos 	ret = toshiba_touchpad_get(toshiba, &state);
18109d8658acSAzael Avalos 	if (ret < 0)
18119d8658acSAzael Avalos 		return ret;
18129d8658acSAzael Avalos 
18139d8658acSAzael Avalos 	return sprintf(buf, "%i\n", state);
18149d8658acSAzael Avalos }
18159d8658acSAzael Avalos 
18165a2813e9SAzael Avalos static ssize_t toshiba_position_show(struct device *dev,
18175a2813e9SAzael Avalos 				     struct device_attribute *attr, char *buf)
18185a2813e9SAzael Avalos {
18195a2813e9SAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
18205a2813e9SAzael Avalos 	u32 xyval, zval, tmp;
18215a2813e9SAzael Avalos 	u16 x, y, z;
18225a2813e9SAzael Avalos 	int ret;
18235a2813e9SAzael Avalos 
18245a2813e9SAzael Avalos 	xyval = zval = 0;
18255a2813e9SAzael Avalos 	ret = toshiba_accelerometer_get(toshiba, &xyval, &zval);
18265a2813e9SAzael Avalos 	if (ret < 0)
18275a2813e9SAzael Avalos 		return ret;
18285a2813e9SAzael Avalos 
18295a2813e9SAzael Avalos 	x = xyval & HCI_ACCEL_MASK;
18305a2813e9SAzael Avalos 	tmp = xyval >> HCI_MISC_SHIFT;
18315a2813e9SAzael Avalos 	y = tmp & HCI_ACCEL_MASK;
18325a2813e9SAzael Avalos 	z = zval & HCI_ACCEL_MASK;
18335a2813e9SAzael Avalos 
18345a2813e9SAzael Avalos 	return sprintf(buf, "%d %d %d\n", x, y, z);
18355a2813e9SAzael Avalos }
18365a2813e9SAzael Avalos 
1837e26ffe51SAzael Avalos static ssize_t toshiba_usb_sleep_charge_show(struct device *dev,
1838e26ffe51SAzael Avalos 					     struct device_attribute *attr,
1839e26ffe51SAzael Avalos 					     char *buf)
1840e26ffe51SAzael Avalos {
1841e26ffe51SAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1842e26ffe51SAzael Avalos 	u32 mode;
1843e26ffe51SAzael Avalos 	int ret;
1844e26ffe51SAzael Avalos 
1845e26ffe51SAzael Avalos 	ret = toshiba_usb_sleep_charge_get(toshiba, &mode);
1846e26ffe51SAzael Avalos 	if (ret < 0)
1847e26ffe51SAzael Avalos 		return ret;
1848e26ffe51SAzael Avalos 
1849e26ffe51SAzael Avalos 	return sprintf(buf, "%x\n", mode & SCI_USB_CHARGE_MODE_MASK);
1850e26ffe51SAzael Avalos }
1851e26ffe51SAzael Avalos 
1852e26ffe51SAzael Avalos static ssize_t toshiba_usb_sleep_charge_store(struct device *dev,
1853e26ffe51SAzael Avalos 					      struct device_attribute *attr,
1854e26ffe51SAzael Avalos 					      const char *buf, size_t count)
1855e26ffe51SAzael Avalos {
1856e26ffe51SAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1857e26ffe51SAzael Avalos 	u32 mode;
1858e26ffe51SAzael Avalos 	int state;
1859e26ffe51SAzael Avalos 	int ret;
1860e26ffe51SAzael Avalos 
1861e26ffe51SAzael Avalos 	ret = kstrtoint(buf, 0, &state);
1862e26ffe51SAzael Avalos 	if (ret)
1863e26ffe51SAzael Avalos 		return ret;
1864e26ffe51SAzael Avalos 	/* Check for supported values, where:
1865e26ffe51SAzael Avalos 	 * 0 - Disabled
1866e26ffe51SAzael Avalos 	 * 1 - Alternate (Non USB conformant devices that require more power)
1867e26ffe51SAzael Avalos 	 * 2 - Auto (USB conformant devices)
1868e26ffe51SAzael Avalos 	 */
1869e26ffe51SAzael Avalos 	if (state != 0 && state != 1 && state != 2)
1870e26ffe51SAzael Avalos 		return -EINVAL;
1871e26ffe51SAzael Avalos 
1872e26ffe51SAzael Avalos 	/* Set the USB charging mode to internal value */
1873e26ffe51SAzael Avalos 	if (state == 0)
1874e26ffe51SAzael Avalos 		mode = SCI_USB_CHARGE_DISABLED;
1875e26ffe51SAzael Avalos 	else if (state == 1)
1876e26ffe51SAzael Avalos 		mode = SCI_USB_CHARGE_ALTERNATE;
1877e26ffe51SAzael Avalos 	else if (state == 2)
1878e26ffe51SAzael Avalos 		mode = SCI_USB_CHARGE_AUTO;
1879e26ffe51SAzael Avalos 
1880e26ffe51SAzael Avalos 	ret = toshiba_usb_sleep_charge_set(toshiba, mode);
1881e26ffe51SAzael Avalos 	if (ret)
1882e26ffe51SAzael Avalos 		return ret;
1883e26ffe51SAzael Avalos 
1884e26ffe51SAzael Avalos 	return count;
1885e26ffe51SAzael Avalos }
1886e26ffe51SAzael Avalos 
1887182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_show(struct device *dev,
1888182bcaa5SAzael Avalos 					       struct device_attribute *attr,
1889182bcaa5SAzael Avalos 					       char *buf)
1890182bcaa5SAzael Avalos {
1891182bcaa5SAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1892182bcaa5SAzael Avalos 	u32 state;
1893182bcaa5SAzael Avalos 	int bat_lvl;
1894182bcaa5SAzael Avalos 	int status;
1895182bcaa5SAzael Avalos 	int ret;
1896182bcaa5SAzael Avalos 	int tmp;
1897182bcaa5SAzael Avalos 
1898182bcaa5SAzael Avalos 	ret = toshiba_sleep_functions_status_get(toshiba, &state);
1899182bcaa5SAzael Avalos 	if (ret < 0)
1900182bcaa5SAzael Avalos 		return ret;
1901182bcaa5SAzael Avalos 
1902182bcaa5SAzael Avalos 	/* Determine the status: 0x4 - Enabled | 0x1 - Disabled */
1903182bcaa5SAzael Avalos 	tmp = state & SCI_USB_CHARGE_BAT_MASK;
1904182bcaa5SAzael Avalos 	status = (tmp == 0x4) ? 1 : 0;
1905182bcaa5SAzael Avalos 	/* Determine the battery level set */
1906182bcaa5SAzael Avalos 	bat_lvl = state >> HCI_MISC_SHIFT;
1907182bcaa5SAzael Avalos 
1908182bcaa5SAzael Avalos 	return sprintf(buf, "%d %d\n", status, bat_lvl);
1909182bcaa5SAzael Avalos }
1910182bcaa5SAzael Avalos 
1911182bcaa5SAzael Avalos static ssize_t sleep_functions_on_battery_store(struct device *dev,
1912182bcaa5SAzael Avalos 						struct device_attribute *attr,
1913182bcaa5SAzael Avalos 						const char *buf, size_t count)
1914182bcaa5SAzael Avalos {
1915182bcaa5SAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1916182bcaa5SAzael Avalos 	u32 status;
1917182bcaa5SAzael Avalos 	int value;
1918182bcaa5SAzael Avalos 	int ret;
1919182bcaa5SAzael Avalos 	int tmp;
1920182bcaa5SAzael Avalos 
1921182bcaa5SAzael Avalos 	ret = kstrtoint(buf, 0, &value);
1922182bcaa5SAzael Avalos 	if (ret)
1923182bcaa5SAzael Avalos 		return ret;
1924182bcaa5SAzael Avalos 
1925182bcaa5SAzael Avalos 	/* Set the status of the function:
1926182bcaa5SAzael Avalos 	 * 0 - Disabled
1927182bcaa5SAzael Avalos 	 * 1-100 - Enabled
1928182bcaa5SAzael Avalos 	 */
1929182bcaa5SAzael Avalos 	if (value < 0 || value > 100)
1930182bcaa5SAzael Avalos 		return -EINVAL;
1931182bcaa5SAzael Avalos 
1932182bcaa5SAzael Avalos 	if (value == 0) {
1933182bcaa5SAzael Avalos 		tmp = toshiba->usbsc_bat_level << HCI_MISC_SHIFT;
1934182bcaa5SAzael Avalos 		status = tmp | SCI_USB_CHARGE_BAT_LVL_OFF;
1935182bcaa5SAzael Avalos 	} else {
1936182bcaa5SAzael Avalos 		tmp = value << HCI_MISC_SHIFT;
1937182bcaa5SAzael Avalos 		status = tmp | SCI_USB_CHARGE_BAT_LVL_ON;
1938182bcaa5SAzael Avalos 	}
1939182bcaa5SAzael Avalos 	ret = toshiba_sleep_functions_status_set(toshiba, status);
1940182bcaa5SAzael Avalos 	if (ret < 0)
1941182bcaa5SAzael Avalos 		return ret;
1942182bcaa5SAzael Avalos 
1943182bcaa5SAzael Avalos 	toshiba->usbsc_bat_level = status >> HCI_MISC_SHIFT;
1944182bcaa5SAzael Avalos 
1945182bcaa5SAzael Avalos 	return count;
1946182bcaa5SAzael Avalos }
1947182bcaa5SAzael Avalos 
1948bb3fe01fSAzael Avalos static ssize_t toshiba_usb_rapid_charge_show(struct device *dev,
1949bb3fe01fSAzael Avalos 					     struct device_attribute *attr,
1950bb3fe01fSAzael Avalos 					     char *buf)
1951bb3fe01fSAzael Avalos {
1952bb3fe01fSAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1953bb3fe01fSAzael Avalos 	u32 state;
1954bb3fe01fSAzael Avalos 	int ret;
1955bb3fe01fSAzael Avalos 
1956bb3fe01fSAzael Avalos 	ret = toshiba_usb_rapid_charge_get(toshiba, &state);
1957bb3fe01fSAzael Avalos 	if (ret < 0)
1958bb3fe01fSAzael Avalos 		return ret;
1959bb3fe01fSAzael Avalos 
1960bb3fe01fSAzael Avalos 	return sprintf(buf, "%d\n", state);
1961bb3fe01fSAzael Avalos }
1962bb3fe01fSAzael Avalos 
1963bb3fe01fSAzael Avalos static ssize_t toshiba_usb_rapid_charge_store(struct device *dev,
1964bb3fe01fSAzael Avalos 					      struct device_attribute *attr,
1965bb3fe01fSAzael Avalos 					      const char *buf, size_t count)
1966bb3fe01fSAzael Avalos {
1967bb3fe01fSAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1968bb3fe01fSAzael Avalos 	int state;
1969bb3fe01fSAzael Avalos 	int ret;
1970bb3fe01fSAzael Avalos 
1971bb3fe01fSAzael Avalos 	ret = kstrtoint(buf, 0, &state);
1972bb3fe01fSAzael Avalos 	if (ret)
1973bb3fe01fSAzael Avalos 		return ret;
1974bb3fe01fSAzael Avalos 	if (state != 0 && state != 1)
1975bb3fe01fSAzael Avalos 		return -EINVAL;
1976bb3fe01fSAzael Avalos 
1977bb3fe01fSAzael Avalos 	ret = toshiba_usb_rapid_charge_set(toshiba, state);
1978bb3fe01fSAzael Avalos 	if (ret)
1979bb3fe01fSAzael Avalos 		return ret;
1980bb3fe01fSAzael Avalos 
1981bb3fe01fSAzael Avalos 	return count;
1982bb3fe01fSAzael Avalos }
1983bb3fe01fSAzael Avalos 
1984172ce0a9SAzael Avalos static ssize_t toshiba_usb_sleep_music_show(struct device *dev,
1985172ce0a9SAzael Avalos 					    struct device_attribute *attr,
1986172ce0a9SAzael Avalos 					    char *buf)
1987172ce0a9SAzael Avalos {
1988172ce0a9SAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1989172ce0a9SAzael Avalos 	u32 state;
1990172ce0a9SAzael Avalos 	int ret;
1991172ce0a9SAzael Avalos 
1992172ce0a9SAzael Avalos 	ret = toshiba_usb_sleep_music_get(toshiba, &state);
1993172ce0a9SAzael Avalos 	if (ret < 0)
1994172ce0a9SAzael Avalos 		return ret;
1995172ce0a9SAzael Avalos 
1996172ce0a9SAzael Avalos 	return sprintf(buf, "%d\n", state);
1997172ce0a9SAzael Avalos }
1998172ce0a9SAzael Avalos 
1999172ce0a9SAzael Avalos static ssize_t toshiba_usb_sleep_music_store(struct device *dev,
2000172ce0a9SAzael Avalos 					     struct device_attribute *attr,
2001172ce0a9SAzael Avalos 					     const char *buf, size_t count)
2002172ce0a9SAzael Avalos {
2003172ce0a9SAzael Avalos 	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2004172ce0a9SAzael Avalos 	int state;
2005172ce0a9SAzael Avalos 	int ret;
2006172ce0a9SAzael Avalos 
2007172ce0a9SAzael Avalos 	ret = kstrtoint(buf, 0, &state);
2008172ce0a9SAzael Avalos 	if (ret)
2009172ce0a9SAzael Avalos 		return ret;
2010172ce0a9SAzael Avalos 	if (state != 0 && state != 1)
2011172ce0a9SAzael Avalos 		return -EINVAL;
2012172ce0a9SAzael Avalos 
2013172ce0a9SAzael Avalos 	ret = toshiba_usb_sleep_music_set(toshiba, state);
2014172ce0a9SAzael Avalos 	if (ret)
2015172ce0a9SAzael Avalos 		return ret;
2016172ce0a9SAzael Avalos 
2017172ce0a9SAzael Avalos 	return count;
2018172ce0a9SAzael Avalos }
2019172ce0a9SAzael Avalos 
2020360f0f39SAzael Avalos static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
2021360f0f39SAzael Avalos 					struct attribute *attr, int idx)
2022360f0f39SAzael Avalos {
2023360f0f39SAzael Avalos 	struct device *dev = container_of(kobj, struct device, kobj);
2024360f0f39SAzael Avalos 	struct toshiba_acpi_dev *drv = dev_get_drvdata(dev);
2025360f0f39SAzael Avalos 	bool exists = true;
2026360f0f39SAzael Avalos 
2027360f0f39SAzael Avalos 	if (attr == &dev_attr_kbd_backlight_mode.attr)
2028360f0f39SAzael Avalos 		exists = (drv->kbd_illum_supported) ? true : false;
2029360f0f39SAzael Avalos 	else if (attr == &dev_attr_kbd_backlight_timeout.attr)
2030360f0f39SAzael Avalos 		exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false;
20319d8658acSAzael Avalos 	else if (attr == &dev_attr_touchpad.attr)
20329d8658acSAzael Avalos 		exists = (drv->touchpad_supported) ? true : false;
20335a2813e9SAzael Avalos 	else if (attr == &dev_attr_position.attr)
20345a2813e9SAzael Avalos 		exists = (drv->accelerometer_supported) ? true : false;
2035e26ffe51SAzael Avalos 	else if (attr == &dev_attr_usb_sleep_charge.attr)
2036e26ffe51SAzael Avalos 		exists = (drv->usb_sleep_charge_supported) ? true : false;
2037182bcaa5SAzael Avalos 	else if (attr == &dev_attr_sleep_functions_on_battery.attr)
2038182bcaa5SAzael Avalos 		exists = (drv->usb_sleep_charge_supported) ? true : false;
2039bb3fe01fSAzael Avalos 	else if (attr == &dev_attr_usb_rapid_charge.attr)
2040bb3fe01fSAzael Avalos 		exists = (drv->usb_rapid_charge_supported) ? true : false;
2041172ce0a9SAzael Avalos 	else if (attr == &dev_attr_usb_sleep_music.attr)
2042172ce0a9SAzael Avalos 		exists = (drv->usb_sleep_music_supported) ? true : false;
2043360f0f39SAzael Avalos 
2044360f0f39SAzael Avalos 	return exists ? attr->mode : 0;
2045360f0f39SAzael Avalos }
2046360f0f39SAzael Avalos 
20471f28f290SAzael Avalos /*
20481f28f290SAzael Avalos  * Hotkeys
20491f28f290SAzael Avalos  */
20501f28f290SAzael Avalos static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev)
20511f28f290SAzael Avalos {
20521f28f290SAzael Avalos 	acpi_status status;
20531f28f290SAzael Avalos 	u32 result;
20541f28f290SAzael Avalos 
20551f28f290SAzael Avalos 	status = acpi_evaluate_object(dev->acpi_dev->handle,
20561f28f290SAzael Avalos 				      "ENAB", NULL, NULL);
20571f28f290SAzael Avalos 	if (ACPI_FAILURE(status))
20581f28f290SAzael Avalos 		return -ENODEV;
20591f28f290SAzael Avalos 
20601f28f290SAzael Avalos 	result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE);
20611f28f290SAzael Avalos 	if (result == TOS_FAILURE)
20621f28f290SAzael Avalos 		return -EIO;
20631f28f290SAzael Avalos 	else if (result == TOS_NOT_SUPPORTED)
20641f28f290SAzael Avalos 		return -ENODEV;
20651f28f290SAzael Avalos 
20661f28f290SAzael Avalos 	return 0;
20671f28f290SAzael Avalos }
20681f28f290SAzael Avalos 
206929cd293fSSeth Forshee static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
207029cd293fSSeth Forshee 				      struct serio *port)
207129cd293fSSeth Forshee {
207298280374SGiedrius Statkevičius 	if (str & I8042_STR_AUXDATA)
207329cd293fSSeth Forshee 		return false;
207429cd293fSSeth Forshee 
207529cd293fSSeth Forshee 	if (unlikely(data == 0xe0))
207629cd293fSSeth Forshee 		return false;
207729cd293fSSeth Forshee 
207829cd293fSSeth Forshee 	if ((data & 0x7f) == TOS1900_FN_SCAN) {
207929cd293fSSeth Forshee 		schedule_work(&toshiba_acpi->hotkey_work);
208029cd293fSSeth Forshee 		return true;
208129cd293fSSeth Forshee 	}
208229cd293fSSeth Forshee 
208329cd293fSSeth Forshee 	return false;
208429cd293fSSeth Forshee }
208529cd293fSSeth Forshee 
208629cd293fSSeth Forshee static void toshiba_acpi_hotkey_work(struct work_struct *work)
208729cd293fSSeth Forshee {
208829cd293fSSeth Forshee 	acpi_handle ec_handle = ec_get_handle();
208929cd293fSSeth Forshee 	acpi_status status;
209029cd293fSSeth Forshee 
209129cd293fSSeth Forshee 	if (!ec_handle)
209229cd293fSSeth Forshee 		return;
209329cd293fSSeth Forshee 
209429cd293fSSeth Forshee 	status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL);
209529cd293fSSeth Forshee 	if (ACPI_FAILURE(status))
209629cd293fSSeth Forshee 		pr_err("ACPI NTFY method execution failed\n");
209729cd293fSSeth Forshee }
209829cd293fSSeth Forshee 
209929cd293fSSeth Forshee /*
210029cd293fSSeth Forshee  * Returns hotkey scancode, or < 0 on failure.
210129cd293fSSeth Forshee  */
210229cd293fSSeth Forshee static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev)
210329cd293fSSeth Forshee {
210474facaf7SZhang Rui 	unsigned long long value;
210529cd293fSSeth Forshee 	acpi_status status;
210629cd293fSSeth Forshee 
210774facaf7SZhang Rui 	status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO",
210874facaf7SZhang Rui 				      NULL, &value);
210974facaf7SZhang Rui 	if (ACPI_FAILURE(status)) {
211029cd293fSSeth Forshee 		pr_err("ACPI INFO method execution failed\n");
211129cd293fSSeth Forshee 		return -EIO;
211229cd293fSSeth Forshee 	}
211329cd293fSSeth Forshee 
211474facaf7SZhang Rui 	return value;
211529cd293fSSeth Forshee }
211629cd293fSSeth Forshee 
211729cd293fSSeth Forshee static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev,
211829cd293fSSeth Forshee 				       int scancode)
211929cd293fSSeth Forshee {
212029cd293fSSeth Forshee 	if (scancode == 0x100)
212129cd293fSSeth Forshee 		return;
212229cd293fSSeth Forshee 
212329cd293fSSeth Forshee 	/* act on key press; ignore key release */
212429cd293fSSeth Forshee 	if (scancode & 0x80)
212529cd293fSSeth Forshee 		return;
212629cd293fSSeth Forshee 
212729cd293fSSeth Forshee 	if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true))
212829cd293fSSeth Forshee 		pr_info("Unknown key %x\n", scancode);
212929cd293fSSeth Forshee }
213029cd293fSSeth Forshee 
213171454d78SAzael Avalos static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev)
213271454d78SAzael Avalos {
213371454d78SAzael Avalos 	u32 hci_result, value;
213471454d78SAzael Avalos 	int retries = 3;
213571454d78SAzael Avalos 	int scancode;
213671454d78SAzael Avalos 
213771454d78SAzael Avalos 	if (dev->info_supported) {
213871454d78SAzael Avalos 		scancode = toshiba_acpi_query_hotkey(dev);
213971454d78SAzael Avalos 		if (scancode < 0)
214071454d78SAzael Avalos 			pr_err("Failed to query hotkey event\n");
214171454d78SAzael Avalos 		else if (scancode != 0)
214271454d78SAzael Avalos 			toshiba_acpi_report_hotkey(dev, scancode);
214371454d78SAzael Avalos 	} else if (dev->system_event_supported) {
214471454d78SAzael Avalos 		do {
214571454d78SAzael Avalos 			hci_result = hci_read1(dev, HCI_SYSTEM_EVENT, &value);
214671454d78SAzael Avalos 			switch (hci_result) {
214771454d78SAzael Avalos 			case TOS_SUCCESS:
214871454d78SAzael Avalos 				toshiba_acpi_report_hotkey(dev, (int)value);
214971454d78SAzael Avalos 				break;
215071454d78SAzael Avalos 			case TOS_NOT_SUPPORTED:
215171454d78SAzael Avalos 				/*
215271454d78SAzael Avalos 				 * This is a workaround for an unresolved
215371454d78SAzael Avalos 				 * issue on some machines where system events
215471454d78SAzael Avalos 				 * sporadically become disabled.
215571454d78SAzael Avalos 				 */
215671454d78SAzael Avalos 				hci_result =
215771454d78SAzael Avalos 					hci_write1(dev, HCI_SYSTEM_EVENT, 1);
215871454d78SAzael Avalos 				pr_notice("Re-enabled hotkeys\n");
215971454d78SAzael Avalos 				/* fall through */
216071454d78SAzael Avalos 			default:
216171454d78SAzael Avalos 				retries--;
216271454d78SAzael Avalos 				break;
216371454d78SAzael Avalos 			}
216471454d78SAzael Avalos 		} while (retries && hci_result != TOS_FIFO_EMPTY);
216571454d78SAzael Avalos 	}
216671454d78SAzael Avalos }
216771454d78SAzael Avalos 
2168b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
21696335e4d5SMatthew Garrett {
2170e2e19606SZhang Rui 	acpi_handle ec_handle;
2171135740deSSeth Forshee 	int error;
217229cd293fSSeth Forshee 	u32 hci_result;
2173fe808bfbSTakashi Iwai 	const struct key_entry *keymap = toshiba_acpi_keymap;
2174135740deSSeth Forshee 
2175135740deSSeth Forshee 	dev->hotkey_dev = input_allocate_device();
2176b222cca6SJoe Perches 	if (!dev->hotkey_dev)
2177135740deSSeth Forshee 		return -ENOMEM;
2178135740deSSeth Forshee 
2179135740deSSeth Forshee 	dev->hotkey_dev->name = "Toshiba input device";
21806e02cc7eSSeth Forshee 	dev->hotkey_dev->phys = "toshiba_acpi/input0";
2181135740deSSeth Forshee 	dev->hotkey_dev->id.bustype = BUS_HOST;
2182135740deSSeth Forshee 
2183fe808bfbSTakashi Iwai 	if (dmi_check_system(toshiba_alt_keymap_dmi))
2184fe808bfbSTakashi Iwai 		keymap = toshiba_acpi_alt_keymap;
2185fe808bfbSTakashi Iwai 	error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL);
2186135740deSSeth Forshee 	if (error)
2187135740deSSeth Forshee 		goto err_free_dev;
2188135740deSSeth Forshee 
218929cd293fSSeth Forshee 	/*
219029cd293fSSeth Forshee 	 * For some machines the SCI responsible for providing hotkey
219129cd293fSSeth Forshee 	 * notification doesn't fire. We can trigger the notification
219229cd293fSSeth Forshee 	 * whenever the Fn key is pressed using the NTFY method, if
219329cd293fSSeth Forshee 	 * supported, so if it's present set up an i8042 key filter
219429cd293fSSeth Forshee 	 * for this purpose.
219529cd293fSSeth Forshee 	 */
219629cd293fSSeth Forshee 	ec_handle = ec_get_handle();
2197e2e19606SZhang Rui 	if (ec_handle && acpi_has_method(ec_handle, "NTFY")) {
219829cd293fSSeth Forshee 		INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work);
219929cd293fSSeth Forshee 
220029cd293fSSeth Forshee 		error = i8042_install_filter(toshiba_acpi_i8042_filter);
220129cd293fSSeth Forshee 		if (error) {
220229cd293fSSeth Forshee 			pr_err("Error installing key filter\n");
220329cd293fSSeth Forshee 			goto err_free_keymap;
220429cd293fSSeth Forshee 		}
220529cd293fSSeth Forshee 
220629cd293fSSeth Forshee 		dev->ntfy_supported = 1;
220729cd293fSSeth Forshee 	}
220829cd293fSSeth Forshee 
220929cd293fSSeth Forshee 	/*
221029cd293fSSeth Forshee 	 * Determine hotkey query interface. Prefer using the INFO
221129cd293fSSeth Forshee 	 * method when it is available.
221229cd293fSSeth Forshee 	 */
2213e2e19606SZhang Rui 	if (acpi_has_method(dev->acpi_dev->handle, "INFO"))
221429cd293fSSeth Forshee 		dev->info_supported = 1;
2215e2e19606SZhang Rui 	else {
2216893f3f62SAzael Avalos 		hci_result = hci_write1(dev, HCI_SYSTEM_EVENT, 1);
22171864bbc2SAzael Avalos 		if (hci_result == TOS_SUCCESS)
221829cd293fSSeth Forshee 			dev->system_event_supported = 1;
221929cd293fSSeth Forshee 	}
222029cd293fSSeth Forshee 
222129cd293fSSeth Forshee 	if (!dev->info_supported && !dev->system_event_supported) {
222229cd293fSSeth Forshee 		pr_warn("No hotkey query interface found\n");
222329cd293fSSeth Forshee 		goto err_remove_filter;
222429cd293fSSeth Forshee 	}
222529cd293fSSeth Forshee 
22261f28f290SAzael Avalos 	error = toshiba_acpi_enable_hotkeys(dev);
22271f28f290SAzael Avalos 	if (error) {
2228135740deSSeth Forshee 		pr_info("Unable to enable hotkeys\n");
222929cd293fSSeth Forshee 		goto err_remove_filter;
2230135740deSSeth Forshee 	}
2231135740deSSeth Forshee 
2232135740deSSeth Forshee 	error = input_register_device(dev->hotkey_dev);
2233135740deSSeth Forshee 	if (error) {
2234135740deSSeth Forshee 		pr_info("Unable to register input device\n");
223529cd293fSSeth Forshee 		goto err_remove_filter;
2236135740deSSeth Forshee 	}
2237135740deSSeth Forshee 
2238135740deSSeth Forshee 	return 0;
2239135740deSSeth Forshee 
224029cd293fSSeth Forshee  err_remove_filter:
224129cd293fSSeth Forshee 	if (dev->ntfy_supported)
224229cd293fSSeth Forshee 		i8042_remove_filter(toshiba_acpi_i8042_filter);
2243135740deSSeth Forshee  err_free_keymap:
2244135740deSSeth Forshee 	sparse_keymap_free(dev->hotkey_dev);
2245135740deSSeth Forshee  err_free_dev:
2246135740deSSeth Forshee 	input_free_device(dev->hotkey_dev);
2247135740deSSeth Forshee 	dev->hotkey_dev = NULL;
2248135740deSSeth Forshee 	return error;
2249135740deSSeth Forshee }
2250135740deSSeth Forshee 
2251b859f159SGreg Kroah-Hartman static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
225262cce752SSeth Forshee {
225362cce752SSeth Forshee 	struct backlight_properties props;
225462cce752SSeth Forshee 	int brightness;
225562cce752SSeth Forshee 	int ret;
2256121b7b0dSAkio Idehara 	bool enabled;
225762cce752SSeth Forshee 
225862cce752SSeth Forshee 	/*
225962cce752SSeth Forshee 	 * Some machines don't support the backlight methods at all, and
226062cce752SSeth Forshee 	 * others support it read-only. Either of these is pretty useless,
226162cce752SSeth Forshee 	 * so only register the backlight device if the backlight method
226262cce752SSeth Forshee 	 * supports both reads and writes.
226362cce752SSeth Forshee 	 */
226462cce752SSeth Forshee 	brightness = __get_lcd_brightness(dev);
226562cce752SSeth Forshee 	if (brightness < 0)
226662cce752SSeth Forshee 		return 0;
226762cce752SSeth Forshee 	ret = set_lcd_brightness(dev, brightness);
226862cce752SSeth Forshee 	if (ret) {
226962cce752SSeth Forshee 		pr_debug("Backlight method is read-only, disabling backlight support\n");
227062cce752SSeth Forshee 		return 0;
227162cce752SSeth Forshee 	}
227262cce752SSeth Forshee 
2273121b7b0dSAkio Idehara 	/* Determine whether or not BIOS supports transflective backlight */
2274121b7b0dSAkio Idehara 	ret = get_tr_backlight_status(dev, &enabled);
2275121b7b0dSAkio Idehara 	dev->tr_backlight_supported = !ret;
2276121b7b0dSAkio Idehara 
227753039f22SMatthew Garrett 	memset(&props, 0, sizeof(props));
227862cce752SSeth Forshee 	props.type = BACKLIGHT_PLATFORM;
227962cce752SSeth Forshee 	props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
228062cce752SSeth Forshee 
2281121b7b0dSAkio Idehara 	/* adding an extra level and having 0 change to transflective mode */
2282121b7b0dSAkio Idehara 	if (dev->tr_backlight_supported)
2283121b7b0dSAkio Idehara 		props.max_brightness++;
2284121b7b0dSAkio Idehara 
228562cce752SSeth Forshee 	dev->backlight_dev = backlight_device_register("toshiba",
228662cce752SSeth Forshee 						       &dev->acpi_dev->dev,
228762cce752SSeth Forshee 						       dev,
228862cce752SSeth Forshee 						       &toshiba_backlight_data,
228962cce752SSeth Forshee 						       &props);
229062cce752SSeth Forshee 	if (IS_ERR(dev->backlight_dev)) {
229162cce752SSeth Forshee 		ret = PTR_ERR(dev->backlight_dev);
229262cce752SSeth Forshee 		pr_err("Could not register toshiba backlight device\n");
229362cce752SSeth Forshee 		dev->backlight_dev = NULL;
229462cce752SSeth Forshee 		return ret;
229562cce752SSeth Forshee 	}
229662cce752SSeth Forshee 
229762cce752SSeth Forshee 	dev->backlight_dev->props.brightness = brightness;
229862cce752SSeth Forshee 	return 0;
229962cce752SSeth Forshee }
230062cce752SSeth Forshee 
230151fac838SRafael J. Wysocki static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
2302135740deSSeth Forshee {
2303135740deSSeth Forshee 	struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
2304135740deSSeth Forshee 
230536d03f93SSeth Forshee 	remove_toshiba_proc_entries(dev);
2306135740deSSeth Forshee 
2307360f0f39SAzael Avalos 	if (dev->sysfs_created)
2308360f0f39SAzael Avalos 		sysfs_remove_group(&dev->acpi_dev->dev.kobj,
2309360f0f39SAzael Avalos 				   &toshiba_attr_group);
2310360f0f39SAzael Avalos 
231129cd293fSSeth Forshee 	if (dev->ntfy_supported) {
231229cd293fSSeth Forshee 		i8042_remove_filter(toshiba_acpi_i8042_filter);
231329cd293fSSeth Forshee 		cancel_work_sync(&dev->hotkey_work);
231429cd293fSSeth Forshee 	}
231529cd293fSSeth Forshee 
2316135740deSSeth Forshee 	if (dev->hotkey_dev) {
2317135740deSSeth Forshee 		input_unregister_device(dev->hotkey_dev);
2318135740deSSeth Forshee 		sparse_keymap_free(dev->hotkey_dev);
2319135740deSSeth Forshee 	}
2320135740deSSeth Forshee 
2321135740deSSeth Forshee 	if (dev->bt_rfk) {
2322135740deSSeth Forshee 		rfkill_unregister(dev->bt_rfk);
2323135740deSSeth Forshee 		rfkill_destroy(dev->bt_rfk);
2324135740deSSeth Forshee 	}
2325135740deSSeth Forshee 
2326135740deSSeth Forshee 	backlight_device_unregister(dev->backlight_dev);
2327135740deSSeth Forshee 
232836d03f93SSeth Forshee 	if (dev->illumination_supported)
2329135740deSSeth Forshee 		led_classdev_unregister(&dev->led_dev);
2330135740deSSeth Forshee 
2331360f0f39SAzael Avalos 	if (dev->kbd_led_registered)
2332360f0f39SAzael Avalos 		led_classdev_unregister(&dev->kbd_led);
2333360f0f39SAzael Avalos 
2334def6c4e2SAzael Avalos 	if (dev->eco_supported)
2335def6c4e2SAzael Avalos 		led_classdev_unregister(&dev->eco_led);
2336def6c4e2SAzael Avalos 
233729cd293fSSeth Forshee 	if (toshiba_acpi)
233829cd293fSSeth Forshee 		toshiba_acpi = NULL;
233929cd293fSSeth Forshee 
2340135740deSSeth Forshee 	kfree(dev);
2341135740deSSeth Forshee 
2342135740deSSeth Forshee 	return 0;
2343135740deSSeth Forshee }
2344135740deSSeth Forshee 
2345b859f159SGreg Kroah-Hartman static const char *find_hci_method(acpi_handle handle)
2346a540d6b5SSeth Forshee {
2347e2e19606SZhang Rui 	if (acpi_has_method(handle, "GHCI"))
2348a540d6b5SSeth Forshee 		return "GHCI";
2349a540d6b5SSeth Forshee 
2350e2e19606SZhang Rui 	if (acpi_has_method(handle, "SPFC"))
2351a540d6b5SSeth Forshee 		return "SPFC";
2352a540d6b5SSeth Forshee 
2353a540d6b5SSeth Forshee 	return NULL;
2354a540d6b5SSeth Forshee }
2355a540d6b5SSeth Forshee 
2356b859f159SGreg Kroah-Hartman static int toshiba_acpi_add(struct acpi_device *acpi_dev)
2357135740deSSeth Forshee {
2358135740deSSeth Forshee 	struct toshiba_acpi_dev *dev;
2359a540d6b5SSeth Forshee 	const char *hci_method;
236036d03f93SSeth Forshee 	u32 dummy;
2361135740deSSeth Forshee 	bool bt_present;
2362135740deSSeth Forshee 	int ret = 0;
2363135740deSSeth Forshee 
236429cd293fSSeth Forshee 	if (toshiba_acpi)
236529cd293fSSeth Forshee 		return -EBUSY;
236629cd293fSSeth Forshee 
2367135740deSSeth Forshee 	pr_info("Toshiba Laptop ACPI Extras version %s\n",
2368135740deSSeth Forshee 	       TOSHIBA_ACPI_VERSION);
2369135740deSSeth Forshee 
2370a540d6b5SSeth Forshee 	hci_method = find_hci_method(acpi_dev->handle);
2371a540d6b5SSeth Forshee 	if (!hci_method) {
2372a540d6b5SSeth Forshee 		pr_err("HCI interface not found\n");
23736e02cc7eSSeth Forshee 		return -ENODEV;
2374a540d6b5SSeth Forshee 	}
23756e02cc7eSSeth Forshee 
2376135740deSSeth Forshee 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
2377135740deSSeth Forshee 	if (!dev)
2378135740deSSeth Forshee 		return -ENOMEM;
2379135740deSSeth Forshee 	dev->acpi_dev = acpi_dev;
2380a540d6b5SSeth Forshee 	dev->method_hci = hci_method;
2381135740deSSeth Forshee 	acpi_dev->driver_data = dev;
2382360f0f39SAzael Avalos 	dev_set_drvdata(&acpi_dev->dev, dev);
2383135740deSSeth Forshee 
23846e02cc7eSSeth Forshee 	if (toshiba_acpi_setup_keyboard(dev))
2385135740deSSeth Forshee 		pr_info("Unable to activate hotkeys\n");
2386135740deSSeth Forshee 
2387135740deSSeth Forshee 	mutex_init(&dev->mutex);
2388135740deSSeth Forshee 
238962cce752SSeth Forshee 	ret = toshiba_acpi_setup_backlight(dev);
239062cce752SSeth Forshee 	if (ret)
2391135740deSSeth Forshee 		goto error;
2392135740deSSeth Forshee 
2393135740deSSeth Forshee 	/* Register rfkill switch for Bluetooth */
23941864bbc2SAzael Avalos 	if (hci_get_bt_present(dev, &bt_present) == TOS_SUCCESS && bt_present) {
2395135740deSSeth Forshee 		dev->bt_rfk = rfkill_alloc("Toshiba Bluetooth",
2396135740deSSeth Forshee 					   &acpi_dev->dev,
2397135740deSSeth Forshee 					   RFKILL_TYPE_BLUETOOTH,
2398135740deSSeth Forshee 					   &toshiba_rfk_ops,
2399135740deSSeth Forshee 					   dev);
2400135740deSSeth Forshee 		if (!dev->bt_rfk) {
2401135740deSSeth Forshee 			pr_err("unable to allocate rfkill device\n");
2402135740deSSeth Forshee 			ret = -ENOMEM;
2403135740deSSeth Forshee 			goto error;
2404135740deSSeth Forshee 		}
2405135740deSSeth Forshee 
2406135740deSSeth Forshee 		ret = rfkill_register(dev->bt_rfk);
2407135740deSSeth Forshee 		if (ret) {
2408135740deSSeth Forshee 			pr_err("unable to register rfkill device\n");
2409135740deSSeth Forshee 			rfkill_destroy(dev->bt_rfk);
2410135740deSSeth Forshee 			goto error;
2411135740deSSeth Forshee 		}
2412135740deSSeth Forshee 	}
2413135740deSSeth Forshee 
2414135740deSSeth Forshee 	if (toshiba_illumination_available(dev)) {
2415135740deSSeth Forshee 		dev->led_dev.name = "toshiba::illumination";
2416135740deSSeth Forshee 		dev->led_dev.max_brightness = 1;
2417135740deSSeth Forshee 		dev->led_dev.brightness_set = toshiba_illumination_set;
2418135740deSSeth Forshee 		dev->led_dev.brightness_get = toshiba_illumination_get;
2419135740deSSeth Forshee 		if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev))
242036d03f93SSeth Forshee 			dev->illumination_supported = 1;
2421135740deSSeth Forshee 	}
2422135740deSSeth Forshee 
2423def6c4e2SAzael Avalos 	if (toshiba_eco_mode_available(dev)) {
2424def6c4e2SAzael Avalos 		dev->eco_led.name = "toshiba::eco_mode";
2425def6c4e2SAzael Avalos 		dev->eco_led.max_brightness = 1;
2426def6c4e2SAzael Avalos 		dev->eco_led.brightness_set = toshiba_eco_mode_set_status;
2427def6c4e2SAzael Avalos 		dev->eco_led.brightness_get = toshiba_eco_mode_get_status;
2428def6c4e2SAzael Avalos 		if (!led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led))
2429def6c4e2SAzael Avalos 			dev->eco_supported = 1;
2430def6c4e2SAzael Avalos 	}
2431def6c4e2SAzael Avalos 
243293f8c16dSAzael Avalos 	dev->kbd_illum_supported = toshiba_kbd_illum_available(dev);
2433360f0f39SAzael Avalos 	/*
2434360f0f39SAzael Avalos 	 * Only register the LED if KBD illumination is supported
2435360f0f39SAzael Avalos 	 * and the keyboard backlight operation mode is set to FN-Z
2436360f0f39SAzael Avalos 	 */
2437360f0f39SAzael Avalos 	if (dev->kbd_illum_supported && dev->kbd_mode == SCI_KBD_MODE_FNZ) {
2438360f0f39SAzael Avalos 		dev->kbd_led.name = "toshiba::kbd_backlight";
2439360f0f39SAzael Avalos 		dev->kbd_led.max_brightness = 1;
2440360f0f39SAzael Avalos 		dev->kbd_led.brightness_set = toshiba_kbd_backlight_set;
2441360f0f39SAzael Avalos 		dev->kbd_led.brightness_get = toshiba_kbd_backlight_get;
2442360f0f39SAzael Avalos 		if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led))
2443360f0f39SAzael Avalos 			dev->kbd_led_registered = 1;
2444360f0f39SAzael Avalos 	}
2445360f0f39SAzael Avalos 
24469d8658acSAzael Avalos 	ret = toshiba_touchpad_get(dev, &dummy);
24479d8658acSAzael Avalos 	dev->touchpad_supported = !ret;
24489d8658acSAzael Avalos 
24495a2813e9SAzael Avalos 	ret = toshiba_accelerometer_supported(dev);
24505a2813e9SAzael Avalos 	dev->accelerometer_supported = !ret;
24515a2813e9SAzael Avalos 
2452e26ffe51SAzael Avalos 	ret = toshiba_usb_sleep_charge_get(dev, &dummy);
2453e26ffe51SAzael Avalos 	dev->usb_sleep_charge_supported = !ret;
2454e26ffe51SAzael Avalos 
2455bb3fe01fSAzael Avalos 	ret = toshiba_usb_rapid_charge_get(dev, &dummy);
2456bb3fe01fSAzael Avalos 	dev->usb_rapid_charge_supported = !ret;
2457bb3fe01fSAzael Avalos 
2458172ce0a9SAzael Avalos 	ret = toshiba_usb_sleep_music_get(dev, &dummy);
2459172ce0a9SAzael Avalos 	dev->usb_sleep_music_supported = !ret;
2460172ce0a9SAzael Avalos 
246136d03f93SSeth Forshee 	/* Determine whether or not BIOS supports fan and video interfaces */
246236d03f93SSeth Forshee 
246336d03f93SSeth Forshee 	ret = get_video_status(dev, &dummy);
246436d03f93SSeth Forshee 	dev->video_supported = !ret;
246536d03f93SSeth Forshee 
246636d03f93SSeth Forshee 	ret = get_fan_status(dev, &dummy);
246736d03f93SSeth Forshee 	dev->fan_supported = !ret;
246836d03f93SSeth Forshee 
2469360f0f39SAzael Avalos 	ret = sysfs_create_group(&dev->acpi_dev->dev.kobj,
2470360f0f39SAzael Avalos 				 &toshiba_attr_group);
2471360f0f39SAzael Avalos 	if (ret) {
2472360f0f39SAzael Avalos 		dev->sysfs_created = 0;
2473360f0f39SAzael Avalos 		goto error;
2474360f0f39SAzael Avalos 	}
2475360f0f39SAzael Avalos 	dev->sysfs_created = !ret;
2476360f0f39SAzael Avalos 
247736d03f93SSeth Forshee 	create_toshiba_proc_entries(dev);
247836d03f93SSeth Forshee 
247929cd293fSSeth Forshee 	toshiba_acpi = dev;
248029cd293fSSeth Forshee 
2481135740deSSeth Forshee 	return 0;
2482135740deSSeth Forshee 
2483135740deSSeth Forshee error:
248451fac838SRafael J. Wysocki 	toshiba_acpi_remove(acpi_dev);
2485135740deSSeth Forshee 	return ret;
2486135740deSSeth Forshee }
2487135740deSSeth Forshee 
2488135740deSSeth Forshee static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
2489135740deSSeth Forshee {
2490135740deSSeth Forshee 	struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
249180546905SAzael Avalos 	int ret;
24926335e4d5SMatthew Garrett 
249371454d78SAzael Avalos 	switch (event) {
249471454d78SAzael Avalos 	case 0x80: /* Hotkeys and some system events */
249571454d78SAzael Avalos 		toshiba_acpi_process_hotkeys(dev);
249611948b93SSeth Forshee 		break;
249780546905SAzael Avalos 	case 0x92: /* Keyboard backlight mode changed */
249880546905SAzael Avalos 		/* Update sysfs entries */
249980546905SAzael Avalos 		ret = sysfs_update_group(&acpi_dev->dev.kobj,
250080546905SAzael Avalos 					 &toshiba_attr_group);
250180546905SAzael Avalos 		if (ret)
250280546905SAzael Avalos 			pr_err("Unable to update sysfs entries\n");
250380546905SAzael Avalos 		break;
250471454d78SAzael Avalos 	case 0x81: /* Unknown */
250571454d78SAzael Avalos 	case 0x82: /* Unknown */
250671454d78SAzael Avalos 	case 0x83: /* Unknown */
250771454d78SAzael Avalos 	case 0x8c: /* Unknown */
250871454d78SAzael Avalos 	case 0x8e: /* Unknown */
250971454d78SAzael Avalos 	case 0x8f: /* Unknown */
251071454d78SAzael Avalos 	case 0x90: /* Unknown */
251111948b93SSeth Forshee 	default:
251271454d78SAzael Avalos 		pr_info("Unknown event received %x\n", event);
251311948b93SSeth Forshee 		break;
25146335e4d5SMatthew Garrett 	}
251529cd293fSSeth Forshee }
25166335e4d5SMatthew Garrett 
25173567a4e2SRafael J. Wysocki #ifdef CONFIG_PM_SLEEP
251843d2fd3bSRafael J. Wysocki static int toshiba_acpi_suspend(struct device *device)
251929cd293fSSeth Forshee {
252043d2fd3bSRafael J. Wysocki 	struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
252129cd293fSSeth Forshee 	u32 result;
252229cd293fSSeth Forshee 
252329cd293fSSeth Forshee 	if (dev->hotkey_dev)
2524893f3f62SAzael Avalos 		result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE);
252529cd293fSSeth Forshee 
252629cd293fSSeth Forshee 	return 0;
252729cd293fSSeth Forshee }
252829cd293fSSeth Forshee 
252943d2fd3bSRafael J. Wysocki static int toshiba_acpi_resume(struct device *device)
253029cd293fSSeth Forshee {
253143d2fd3bSRafael J. Wysocki 	struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
25321f28f290SAzael Avalos 	int error;
253329cd293fSSeth Forshee 
2534e7fdb762SBenjamin Tissoires 	if (dev->hotkey_dev) {
25351f28f290SAzael Avalos 		error = toshiba_acpi_enable_hotkeys(dev);
25361f28f290SAzael Avalos 		if (error)
2537e7fdb762SBenjamin Tissoires 			pr_info("Unable to re-enable hotkeys\n");
2538e7fdb762SBenjamin Tissoires 	}
253929cd293fSSeth Forshee 
254029cd293fSSeth Forshee 	return 0;
254129cd293fSSeth Forshee }
25423567a4e2SRafael J. Wysocki #endif
25436335e4d5SMatthew Garrett 
254443d2fd3bSRafael J. Wysocki static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm,
254543d2fd3bSRafael J. Wysocki 			 toshiba_acpi_suspend, toshiba_acpi_resume);
254643d2fd3bSRafael J. Wysocki 
2547135740deSSeth Forshee static struct acpi_driver toshiba_acpi_driver = {
2548135740deSSeth Forshee 	.name	= "Toshiba ACPI driver",
2549135740deSSeth Forshee 	.owner	= THIS_MODULE,
2550135740deSSeth Forshee 	.ids	= toshiba_device_ids,
2551135740deSSeth Forshee 	.flags	= ACPI_DRIVER_ALL_NOTIFY_EVENTS,
2552135740deSSeth Forshee 	.ops	= {
2553135740deSSeth Forshee 		.add		= toshiba_acpi_add,
2554135740deSSeth Forshee 		.remove		= toshiba_acpi_remove,
2555135740deSSeth Forshee 		.notify		= toshiba_acpi_notify,
2556135740deSSeth Forshee 	},
255743d2fd3bSRafael J. Wysocki 	.drv.pm	= &toshiba_acpi_pm,
2558135740deSSeth Forshee };
2559b4f9fe12SLen Brown 
2560b4f9fe12SLen Brown static int __init toshiba_acpi_init(void)
2561b4f9fe12SLen Brown {
2562135740deSSeth Forshee 	int ret;
2563b4f9fe12SLen Brown 
2564f11f999eSSeth Forshee 	/*
2565f11f999eSSeth Forshee 	 * Machines with this WMI guid aren't supported due to bugs in
2566f11f999eSSeth Forshee 	 * their AML. This check relies on wmi initializing before
2567f11f999eSSeth Forshee 	 * toshiba_acpi to guarantee guids have been identified.
2568f11f999eSSeth Forshee 	 */
2569f11f999eSSeth Forshee 	if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
2570f11f999eSSeth Forshee 		return -ENODEV;
2571f11f999eSSeth Forshee 
2572b4f9fe12SLen Brown 	toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
2573b4f9fe12SLen Brown 	if (!toshiba_proc_dir) {
2574135740deSSeth Forshee 		pr_err("Unable to create proc dir " PROC_TOSHIBA "\n");
2575b4f9fe12SLen Brown 		return -ENODEV;
2576b4f9fe12SLen Brown 	}
2577b4f9fe12SLen Brown 
2578135740deSSeth Forshee 	ret = acpi_bus_register_driver(&toshiba_acpi_driver);
2579b4f9fe12SLen Brown 	if (ret) {
2580135740deSSeth Forshee 		pr_err("Failed to register ACPI driver: %d\n", ret);
2581135740deSSeth Forshee 		remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
2582135740deSSeth Forshee 	}
2583135740deSSeth Forshee 
2584b4f9fe12SLen Brown 	return ret;
2585b4f9fe12SLen Brown }
2586b4f9fe12SLen Brown 
2587135740deSSeth Forshee static void __exit toshiba_acpi_exit(void)
2588135740deSSeth Forshee {
2589135740deSSeth Forshee 	acpi_bus_unregister_driver(&toshiba_acpi_driver);
2590135740deSSeth Forshee 	if (toshiba_proc_dir)
2591135740deSSeth Forshee 		remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
2592b4f9fe12SLen Brown }
2593b4f9fe12SLen Brown 
2594b4f9fe12SLen Brown module_init(toshiba_acpi_init);
2595b4f9fe12SLen Brown module_exit(toshiba_acpi_exit);
2596