blob: 3884bdd1e9fef1e0a2184d95563ac9d1b124266b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * toshiba_acpi.c - Toshiba Laptop ACPI Extras
3 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * Copyright (C) 2002-2004 John Belmonte
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04005 * Copyright (C) 2008 Philip Langdale
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +02006 * Copyright (C) 2010 Pierre Ducroquet
Azael Avalos7216d702015-02-10 21:09:21 -07007 * Copyright (C) 2014-2015 Azael Avalos
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
Darren Hartc57c0fa2015-02-11 21:25:22 -080019 * The full GNU General Public License is included in this distribution in
20 * the file called "COPYING".
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 *
22 * The devolpment page for this driver is located at
23 * http://memebeam.org/toys/ToshibaAcpiDriver.
24 *
25 * Credits:
26 * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse
27 * engineering the Windows drivers
28 * Yasushi Nagato - changes for linux kernel 2.4 -> 2.5
29 * Rob Miller - TV out and hotkeys help
Linus Torvalds1da177e2005-04-16 15:20:36 -070030 */
31
Joe Perches7e334602011-03-29 15:21:52 -070032#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
33
Azael Avalos495078f2015-07-31 21:58:16 -060034#define TOSHIBA_ACPI_VERSION "0.23"
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#define PROC_INTERFACE_VERSION 1
36
37#include <linux/kernel.h>
38#include <linux/module.h>
39#include <linux/init.h>
40#include <linux/types.h>
41#include <linux/proc_fs.h>
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -080042#include <linux/seq_file.h>
Holger Machtc9263552006-10-20 14:30:29 -070043#include <linux/backlight.h>
Matthew Garrett6335e4d2010-02-25 15:20:54 -050044#include <linux/input.h>
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -070045#include <linux/input/sparse-keymap.h>
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +020046#include <linux/leds.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090047#include <linux/slab.h>
Seth Forshee29cd2932012-01-18 13:44:09 -060048#include <linux/workqueue.h>
49#include <linux/i8042.h>
Lv Zheng8b484632013-12-03 08:49:16 +080050#include <linux/acpi.h>
Hans de Goede358d6a22015-04-21 12:01:32 +020051#include <linux/dmi.h>
Azael Avalosb5163992015-02-10 23:43:56 -070052#include <linux/uaccess.h>
Azael Avalosfc5462f2015-07-22 18:09:11 -060053#include <linux/miscdevice.h>
54#include <linux/toshiba.h>
Hans de Goede358d6a22015-04-21 12:01:32 +020055#include <acpi/video.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Linus Torvalds1da177e2005-04-16 15:20:36 -070057MODULE_AUTHOR("John Belmonte");
58MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
59MODULE_LICENSE("GPL");
60
Seth Forsheef11f9992012-01-18 13:44:11 -060061#define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100"
62
Seth Forshee29cd2932012-01-18 13:44:09 -060063/* Scan code for Fn key on TOS1900 models */
64#define TOS1900_FN_SCAN 0x6e
65
Linus Torvalds1da177e2005-04-16 15:20:36 -070066/* Toshiba ACPI method paths */
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX"
68
Darren Harte0769fe2015-02-11 20:50:08 -080069/*
70 * The Toshiba configuration interface is composed of the HCI and the SCI,
Azael Avalos258c5902014-09-29 20:40:07 -060071 * which are defined as follows:
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 *
73 * HCI is Toshiba's "Hardware Control Interface" which is supposed to
74 * be uniform across all their models. Ideally we would just call
75 * dedicated ACPI methods instead of using this primitive interface.
76 * However the ACPI methods seem to be incomplete in some areas (for
77 * example they allow setting, but not reading, the LCD brightness value),
78 * so this is still useful.
Matthew Garrettea6b31f2014-04-04 14:22:34 -040079 *
Azael Avalos84a62732014-03-25 20:38:29 -060080 * SCI stands for "System Configuration Interface" which aim is to
81 * conceal differences in hardware between different models.
Linus Torvalds1da177e2005-04-16 15:20:36 -070082 */
83
Azael Avalos258c5902014-09-29 20:40:07 -060084#define TCI_WORDS 6
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
Azael Avalos3f75bbe2015-05-06 09:35:11 -060086/* Operations */
Linus Torvalds1da177e2005-04-16 15:20:36 -070087#define HCI_SET 0xff00
88#define HCI_GET 0xfe00
Azael Avalos84a62732014-03-25 20:38:29 -060089#define SCI_OPEN 0xf100
90#define SCI_CLOSE 0xf200
91#define SCI_GET 0xf300
92#define SCI_SET 0xf400
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
Azael Avalos3f75bbe2015-05-06 09:35:11 -060094/* Return codes */
Azael Avalos1864bbc2014-09-29 20:40:08 -060095#define TOS_SUCCESS 0x0000
Azael Avalose1a949c2015-07-31 21:58:14 -060096#define TOS_SUCCESS2 0x0001
Azael Avalos1864bbc2014-09-29 20:40:08 -060097#define TOS_OPEN_CLOSE_OK 0x0044
98#define TOS_FAILURE 0x1000
99#define TOS_NOT_SUPPORTED 0x8000
100#define TOS_ALREADY_OPEN 0x8100
101#define TOS_NOT_OPENED 0x8200
102#define TOS_INPUT_DATA_ERROR 0x8300
103#define TOS_WRITE_PROTECTED 0x8400
104#define TOS_NOT_PRESENT 0x8600
105#define TOS_FIFO_EMPTY 0x8c00
106#define TOS_DATA_NOT_AVAILABLE 0x8d20
107#define TOS_NOT_INITIALIZED 0x8d50
Azael Avalos98fc4ec2015-02-09 20:55:02 -0700108#define TOS_NOT_INSTALLED 0x8e00
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
Azael Avalos3f75bbe2015-05-06 09:35:11 -0600110/* Registers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111#define HCI_FAN 0x0004
Akio Idehara121b7b02012-04-06 01:46:43 +0900112#define HCI_TR_BACKLIGHT 0x0005
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113#define HCI_SYSTEM_EVENT 0x0016
114#define HCI_VIDEO_OUT 0x001c
115#define HCI_HOTKEY_EVENT 0x001e
116#define HCI_LCD_BRIGHTNESS 0x002a
Azael Avalos6873f462015-11-23 10:49:10 -0700117#define HCI_WIRELESS 0x0056
Azael Avalos5a2813e2014-03-25 20:38:34 -0600118#define HCI_ACCELEROMETER 0x006d
Azael Avalos360f0f32014-03-25 20:38:31 -0600119#define HCI_KBD_ILLUMINATION 0x0095
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600120#define HCI_ECO_MODE 0x0097
Azael Avalos5a2813e2014-03-25 20:38:34 -0600121#define HCI_ACCELEROMETER2 0x00a6
Azael Avalos56e6b352015-03-20 16:55:16 -0600122#define HCI_SYSTEM_INFO 0xc000
Azael Avalos35d53ce2015-02-10 21:09:19 -0700123#define SCI_PANEL_POWER_ON 0x010d
Azael Avalosfdb79082014-03-25 20:38:30 -0600124#define SCI_ILLUMINATION 0x014e
Azael Avalose26ffe52015-01-18 18:30:22 -0700125#define SCI_USB_SLEEP_CHARGE 0x0150
Azael Avalos360f0f32014-03-25 20:38:31 -0600126#define SCI_KBD_ILLUM_STATUS 0x015c
Azael Avalos172ce0a2015-01-18 18:30:25 -0700127#define SCI_USB_SLEEP_MUSIC 0x015e
Azael Avalos17fe4b32015-02-10 21:09:20 -0700128#define SCI_USB_THREE 0x0169
Azael Avalos9d8658a2014-03-25 20:38:32 -0600129#define SCI_TOUCHPAD 0x050e
Azael Avalosbae84192015-02-10 21:09:18 -0700130#define SCI_KBD_FUNCTION_KEYS 0x0522
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
Azael Avalos3f75bbe2015-05-06 09:35:11 -0600132/* Field definitions */
Azael Avalos5a2813e2014-03-25 20:38:34 -0600133#define HCI_ACCEL_MASK 0x7fff
Seth Forshee29cd2932012-01-18 13:44:09 -0600134#define HCI_HOTKEY_DISABLE 0x0b
Azael Avalos52cbae02015-09-09 11:28:20 -0600135#define HCI_HOTKEY_ENABLE 0x01
Azael Avalosfb42d1f2015-03-20 16:55:18 -0600136#define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137#define HCI_LCD_BRIGHTNESS_BITS 3
138#define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS)
139#define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS)
Azael Avalos360f0f32014-03-25 20:38:31 -0600140#define HCI_MISC_SHIFT 0x10
Azael Avalos56e6b352015-03-20 16:55:16 -0600141#define HCI_SYSTEM_TYPE1 0x10
142#define HCI_SYSTEM_TYPE2 0x11
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143#define HCI_VIDEO_OUT_LCD 0x1
144#define HCI_VIDEO_OUT_CRT 0x2
145#define HCI_VIDEO_OUT_TV 0x4
Azael Avalos93f8c162014-09-12 18:50:36 -0600146#define SCI_KBD_MODE_MASK 0x1f
Azael Avalos360f0f32014-03-25 20:38:31 -0600147#define SCI_KBD_MODE_FNZ 0x1
148#define SCI_KBD_MODE_AUTO 0x2
Azael Avalos93f8c162014-09-12 18:50:36 -0600149#define SCI_KBD_MODE_ON 0x8
150#define SCI_KBD_MODE_OFF 0x10
151#define SCI_KBD_TIME_MAX 0x3c001a
Azael Avalos6873f462015-11-23 10:49:10 -0700152#define HCI_WIRELESS_STATUS 0x1
153#define HCI_WIRELESS_WWAN 0x3
154#define HCI_WIRELESS_WWAN_STATUS 0x2000
155#define HCI_WIRELESS_WWAN_POWER 0x4000
Azael Avalose26ffe52015-01-18 18:30:22 -0700156#define SCI_USB_CHARGE_MODE_MASK 0xff
Azael Avalosc8c91842015-04-02 19:26:20 -0600157#define SCI_USB_CHARGE_DISABLED 0x00
158#define SCI_USB_CHARGE_ALTERNATE 0x09
159#define SCI_USB_CHARGE_TYPICAL 0x11
160#define SCI_USB_CHARGE_AUTO 0x21
Azael Avalos182bcaa2015-01-18 18:30:23 -0700161#define SCI_USB_CHARGE_BAT_MASK 0x7
162#define SCI_USB_CHARGE_BAT_LVL_OFF 0x1
163#define SCI_USB_CHARGE_BAT_LVL_ON 0x4
164#define SCI_USB_CHARGE_BAT_LVL 0x0200
Azael Avalosbb3fe012015-01-18 18:30:24 -0700165#define SCI_USB_CHARGE_RAPID_DSP 0x0300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
Seth Forshee135740d2011-09-20 16:55:49 -0500167struct toshiba_acpi_dev {
168 struct acpi_device *acpi_dev;
169 const char *method_hci;
Seth Forshee135740d2011-09-20 16:55:49 -0500170 struct input_dev *hotkey_dev;
Seth Forshee29cd2932012-01-18 13:44:09 -0600171 struct work_struct hotkey_work;
Seth Forshee135740d2011-09-20 16:55:49 -0500172 struct backlight_device *backlight_dev;
173 struct led_classdev led_dev;
Azael Avalos360f0f32014-03-25 20:38:31 -0600174 struct led_classdev kbd_led;
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600175 struct led_classdev eco_led;
Azael Avalosfc5462f2015-07-22 18:09:11 -0600176 struct miscdevice miscdev;
Seth Forshee36d03f92011-09-20 16:55:53 -0500177
Seth Forshee135740d2011-09-20 16:55:49 -0500178 int force_fan;
179 int last_key_event;
180 int key_event_valid;
Azael Avalos93f8c162014-09-12 18:50:36 -0600181 int kbd_type;
Azael Avalos360f0f32014-03-25 20:38:31 -0600182 int kbd_mode;
183 int kbd_time;
Azael Avalos182bcaa2015-01-18 18:30:23 -0700184 int usbsc_bat_level;
Azael Avalosc8c91842015-04-02 19:26:20 -0600185 int usbsc_mode_base;
Azael Avalosa2b34712015-03-20 16:55:17 -0600186 int hotkey_event_type;
Seth Forshee135740d2011-09-20 16:55:49 -0500187
Dan Carpenter592b7462012-01-15 14:28:20 +0300188 unsigned int illumination_supported:1;
189 unsigned int video_supported:1;
190 unsigned int fan_supported:1;
191 unsigned int system_event_supported:1;
Seth Forshee29cd2932012-01-18 13:44:09 -0600192 unsigned int ntfy_supported:1;
193 unsigned int info_supported:1;
Akio Idehara121b7b02012-04-06 01:46:43 +0900194 unsigned int tr_backlight_supported:1;
Azael Avalos360f0f32014-03-25 20:38:31 -0600195 unsigned int kbd_illum_supported:1;
Azael Avalos9d8658a2014-03-25 20:38:32 -0600196 unsigned int touchpad_supported:1;
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600197 unsigned int eco_supported:1;
Azael Avalos5a2813e2014-03-25 20:38:34 -0600198 unsigned int accelerometer_supported:1;
Azael Avalose26ffe52015-01-18 18:30:22 -0700199 unsigned int usb_sleep_charge_supported:1;
Azael Avalosbb3fe012015-01-18 18:30:24 -0700200 unsigned int usb_rapid_charge_supported:1;
Azael Avalos172ce0a2015-01-18 18:30:25 -0700201 unsigned int usb_sleep_music_supported:1;
Azael Avalosbae84192015-02-10 21:09:18 -0700202 unsigned int kbd_function_keys_supported:1;
Azael Avalos35d53ce2015-02-10 21:09:19 -0700203 unsigned int panel_power_on_supported:1;
Azael Avalos17fe4b32015-02-10 21:09:20 -0700204 unsigned int usb_three_supported:1;
Azael Avalos6873f462015-11-23 10:49:10 -0700205 unsigned int wwan_supported:1;
Azael Avalos360f0f32014-03-25 20:38:31 -0600206 unsigned int sysfs_created:1;
Azael Avalosb116fd002015-09-09 11:28:19 -0600207 unsigned int special_functions;
Azael Avalosea215a3f2015-07-31 21:58:12 -0600208
209 bool kbd_led_registered;
210 bool illumination_led_registered;
211 bool eco_led_registered;
Azael Avalos6873f462015-11-23 10:49:10 -0700212 bool killswitch;
Seth Forshee135740d2011-09-20 16:55:49 -0500213};
214
Seth Forshee29cd2932012-01-18 13:44:09 -0600215static struct toshiba_acpi_dev *toshiba_acpi;
216
arvidjaar@mail.ru4db42c52008-03-04 15:06:34 -0800217static const struct acpi_device_id toshiba_device_ids[] = {
218 {"TOS6200", 0},
Ondrej Zary63a9e012014-11-10 00:11:54 +0100219 {"TOS6207", 0},
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400220 {"TOS6208", 0},
arvidjaar@mail.ru4db42c52008-03-04 15:06:34 -0800221 {"TOS1900", 0},
222 {"", 0},
223};
224MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
225
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -0800226static const struct key_entry toshiba_acpi_keymap[] = {
Unai Uribarrifec278a2014-01-14 11:06:47 +0100227 { KE_KEY, 0x9e, { KEY_RFKILL } },
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -0700228 { KE_KEY, 0x101, { KEY_MUTE } },
229 { KE_KEY, 0x102, { KEY_ZOOMOUT } },
230 { KE_KEY, 0x103, { KEY_ZOOMIN } },
Azael Avalos408a5d12014-09-05 11:14:03 -0600231 { KE_KEY, 0x10f, { KEY_TAB } },
Azael Avalosaf502832012-01-18 13:44:10 -0600232 { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
233 { KE_KEY, 0x139, { KEY_ZOOMRESET } },
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -0700234 { KE_KEY, 0x13b, { KEY_COFFEE } },
235 { KE_KEY, 0x13c, { KEY_BATTERY } },
236 { KE_KEY, 0x13d, { KEY_SLEEP } },
237 { KE_KEY, 0x13e, { KEY_SUSPEND } },
238 { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } },
239 { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } },
240 { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } },
241 { KE_KEY, 0x142, { KEY_WLAN } },
Azael Avalosaf502832012-01-18 13:44:10 -0600242 { KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } },
Jon Dowlanda49010f2010-10-27 00:24:59 +0100243 { KE_KEY, 0x17f, { KEY_FN } },
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -0700244 { KE_KEY, 0xb05, { KEY_PROG2 } },
245 { KE_KEY, 0xb06, { KEY_WWW } },
246 { KE_KEY, 0xb07, { KEY_MAIL } },
247 { KE_KEY, 0xb30, { KEY_STOP } },
248 { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } },
249 { KE_KEY, 0xb32, { KEY_NEXTSONG } },
250 { KE_KEY, 0xb33, { KEY_PLAYPAUSE } },
251 { KE_KEY, 0xb5a, { KEY_MEDIA } },
Azael Avalos408a5d12014-09-05 11:14:03 -0600252 { KE_IGNORE, 0x1430, { KEY_RESERVED } }, /* Wake from sleep */
253 { KE_IGNORE, 0x1501, { KEY_RESERVED } }, /* Output changed */
254 { KE_IGNORE, 0x1502, { KEY_RESERVED } }, /* HDMI plugged/unplugged */
255 { KE_IGNORE, 0x1ABE, { KEY_RESERVED } }, /* Protection level set */
256 { KE_IGNORE, 0x1ABF, { KEY_RESERVED } }, /* Protection level off */
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -0700257 { KE_END, 0 },
Matthew Garrett6335e4d2010-02-25 15:20:54 -0500258};
259
Takashi Iwaife808bfb2014-04-29 15:15:38 +0200260static const struct key_entry toshiba_acpi_alt_keymap[] = {
Takashi Iwaife808bfb2014-04-29 15:15:38 +0200261 { KE_KEY, 0x102, { KEY_ZOOMOUT } },
262 { KE_KEY, 0x103, { KEY_ZOOMIN } },
Azael Avalose6efad72014-08-04 09:21:02 -0600263 { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
Takashi Iwaife808bfb2014-04-29 15:15:38 +0200264 { KE_KEY, 0x139, { KEY_ZOOMRESET } },
Takashi Iwaife808bfb2014-04-29 15:15:38 +0200265 { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } },
266 { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } },
Azael Avalosd50c9002015-07-22 19:37:46 -0600267 { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } },
Takashi Iwaife808bfb2014-04-29 15:15:38 +0200268 { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } },
Azael Avalosd50c9002015-07-22 19:37:46 -0600269 { KE_KEY, 0x157, { KEY_MUTE } },
270 { KE_KEY, 0x158, { KEY_WLAN } },
Takashi Iwaife808bfb2014-04-29 15:15:38 +0200271 { KE_END, 0 },
272};
273
Darren Harte0769fe2015-02-11 20:50:08 -0800274/*
Hans de Goede358d6a22015-04-21 12:01:32 +0200275 * List of models which have a broken acpi-video backlight interface and thus
276 * need to use the toshiba (vendor) interface instead.
277 */
278static const struct dmi_system_id toshiba_vendor_backlight_dmi[] = {
279 {}
280};
281
282/*
Darren Harte0769fe2015-02-11 20:50:08 -0800283 * Utility
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 */
285
Azael Avalosb5163992015-02-10 23:43:56 -0700286static inline void _set_bit(u32 *word, u32 mask, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287{
288 *word = (*word & ~mask) | (mask * value);
289}
290
Darren Harte0769fe2015-02-11 20:50:08 -0800291/*
292 * ACPI interface wrappers
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 */
294
Len Brown4be44fc2005-08-05 00:44:28 -0400295static int write_acpi_int(const char *methodName, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 acpi_status status;
298
Zhang Rui619400d2013-09-03 08:31:56 +0800299 status = acpi_execute_simple_method(NULL, (char *)methodName, val);
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500300 return (status == AE_OK) ? 0 : -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301}
302
Darren Harte0769fe2015-02-11 20:50:08 -0800303/*
304 * Perform a raw configuration call. Here we don't care about input or output
Azael Avalos258c5902014-09-29 20:40:07 -0600305 * buffer format.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 */
Azael Avalos258c5902014-09-29 20:40:07 -0600307static acpi_status tci_raw(struct toshiba_acpi_dev *dev,
308 const u32 in[TCI_WORDS], u32 out[TCI_WORDS])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309{
310 struct acpi_object_list params;
Azael Avalos258c5902014-09-29 20:40:07 -0600311 union acpi_object in_objs[TCI_WORDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 struct acpi_buffer results;
Azael Avalos258c5902014-09-29 20:40:07 -0600313 union acpi_object out_objs[TCI_WORDS + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 acpi_status status;
315 int i;
316
Azael Avalos258c5902014-09-29 20:40:07 -0600317 params.count = TCI_WORDS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 params.pointer = in_objs;
Azael Avalos258c5902014-09-29 20:40:07 -0600319 for (i = 0; i < TCI_WORDS; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 in_objs[i].type = ACPI_TYPE_INTEGER;
321 in_objs[i].integer.value = in[i];
322 }
323
324 results.length = sizeof(out_objs);
325 results.pointer = out_objs;
326
Seth Forshee6e02cc72011-09-20 16:55:51 -0500327 status = acpi_evaluate_object(dev->acpi_dev->handle,
328 (char *)dev->method_hci, &params,
Len Brown4be44fc2005-08-05 00:44:28 -0400329 &results);
Azael Avalos258c5902014-09-29 20:40:07 -0600330 if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) {
Azael Avalosb5163992015-02-10 23:43:56 -0700331 for (i = 0; i < out_objs->package.count; ++i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 out[i] = out_objs->package.elements[i].integer.value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 }
334
335 return status;
336}
337
Darren Harte0769fe2015-02-11 20:50:08 -0800338/*
Azael Avalosd37782b2015-05-06 09:35:10 -0600339 * Common hci tasks
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 *
341 * In addition to the ACPI status, the HCI system returns a result which
342 * may be useful (such as "not supported").
343 */
344
Azael Avalosd37782b2015-05-06 09:35:10 -0600345static u32 hci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346{
Azael Avalos258c5902014-09-29 20:40:07 -0600347 u32 in[TCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 };
348 u32 out[TCI_WORDS];
349 acpi_status status = tci_raw(dev, in, out);
Azael Avalos893f3f62014-09-29 20:40:09 -0600350
351 return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352}
353
Azael Avalosd37782b2015-05-06 09:35:10 -0600354static u32 hci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355{
Azael Avalos258c5902014-09-29 20:40:07 -0600356 u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 };
357 u32 out[TCI_WORDS];
358 acpi_status status = tci_raw(dev, in, out);
Azael Avalosb5163992015-02-10 23:43:56 -0700359
Azael Avalos893f3f62014-09-29 20:40:09 -0600360 if (ACPI_FAILURE(status))
361 return TOS_FAILURE;
362
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 *out1 = out[2];
Azael Avalos893f3f62014-09-29 20:40:09 -0600364
365 return out[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366}
367
Darren Harte0769fe2015-02-11 20:50:08 -0800368/*
369 * Common sci tasks
Azael Avalos84a62732014-03-25 20:38:29 -0600370 */
371
372static int sci_open(struct toshiba_acpi_dev *dev)
373{
Azael Avalos258c5902014-09-29 20:40:07 -0600374 u32 in[TCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 };
375 u32 out[TCI_WORDS];
Azael Avalos84a62732014-03-25 20:38:29 -0600376 acpi_status status;
377
Azael Avalos258c5902014-09-29 20:40:07 -0600378 status = tci_raw(dev, in, out);
Azael Avalos8baec452015-05-06 09:35:12 -0600379 if (ACPI_FAILURE(status)) {
Azael Avalos84a62732014-03-25 20:38:29 -0600380 pr_err("ACPI call to open SCI failed\n");
381 return 0;
382 }
383
Azael Avalos1864bbc2014-09-29 20:40:08 -0600384 if (out[0] == TOS_OPEN_CLOSE_OK) {
Azael Avalos84a62732014-03-25 20:38:29 -0600385 return 1;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600386 } else if (out[0] == TOS_ALREADY_OPEN) {
Azael Avalos84a62732014-03-25 20:38:29 -0600387 pr_info("Toshiba SCI already opened\n");
388 return 1;
Azael Avalosfa465732015-01-18 19:17:12 -0700389 } else if (out[0] == TOS_NOT_SUPPORTED) {
Darren Harte0769fe2015-02-11 20:50:08 -0800390 /*
391 * Some BIOSes do not have the SCI open/close functions
Azael Avalosfa465732015-01-18 19:17:12 -0700392 * implemented and return 0x8000 (Not Supported), failing to
393 * register some supported features.
394 *
395 * Simply return 1 if we hit those affected laptops to make the
396 * supported features work.
397 *
398 * In the case that some laptops really do not support the SCI,
399 * all the SCI dependent functions check for TOS_NOT_SUPPORTED,
400 * and thus, not registering support for the queried feature.
401 */
402 return 1;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600403 } else if (out[0] == TOS_NOT_PRESENT) {
Azael Avalos84a62732014-03-25 20:38:29 -0600404 pr_info("Toshiba SCI is not present\n");
405 }
406
407 return 0;
408}
409
410static void sci_close(struct toshiba_acpi_dev *dev)
411{
Azael Avalos258c5902014-09-29 20:40:07 -0600412 u32 in[TCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 };
413 u32 out[TCI_WORDS];
Azael Avalos84a62732014-03-25 20:38:29 -0600414 acpi_status status;
415
Azael Avalos258c5902014-09-29 20:40:07 -0600416 status = tci_raw(dev, in, out);
Azael Avalos8baec452015-05-06 09:35:12 -0600417 if (ACPI_FAILURE(status)) {
Azael Avalos84a62732014-03-25 20:38:29 -0600418 pr_err("ACPI call to close SCI failed\n");
419 return;
420 }
421
Azael Avalos1864bbc2014-09-29 20:40:08 -0600422 if (out[0] == TOS_OPEN_CLOSE_OK)
Azael Avalos84a62732014-03-25 20:38:29 -0600423 return;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600424 else if (out[0] == TOS_NOT_OPENED)
Azael Avalos84a62732014-03-25 20:38:29 -0600425 pr_info("Toshiba SCI not opened\n");
Azael Avalos1864bbc2014-09-29 20:40:08 -0600426 else if (out[0] == TOS_NOT_PRESENT)
Azael Avalos84a62732014-03-25 20:38:29 -0600427 pr_info("Toshiba SCI is not present\n");
428}
429
Azael Avalos893f3f62014-09-29 20:40:09 -0600430static u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1)
Azael Avalos84a62732014-03-25 20:38:29 -0600431{
Azael Avalos258c5902014-09-29 20:40:07 -0600432 u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 };
433 u32 out[TCI_WORDS];
434 acpi_status status = tci_raw(dev, in, out);
Azael Avalosb5163992015-02-10 23:43:56 -0700435
Azael Avalos893f3f62014-09-29 20:40:09 -0600436 if (ACPI_FAILURE(status))
437 return TOS_FAILURE;
438
Azael Avalos84a62732014-03-25 20:38:29 -0600439 *out1 = out[2];
Azael Avalos893f3f62014-09-29 20:40:09 -0600440
441 return out[0];
Azael Avalos84a62732014-03-25 20:38:29 -0600442}
443
Azael Avalos893f3f62014-09-29 20:40:09 -0600444static u32 sci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1)
Azael Avalos84a62732014-03-25 20:38:29 -0600445{
Azael Avalos258c5902014-09-29 20:40:07 -0600446 u32 in[TCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 };
447 u32 out[TCI_WORDS];
448 acpi_status status = tci_raw(dev, in, out);
Azael Avalos893f3f62014-09-29 20:40:09 -0600449
450 return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE;
Azael Avalos84a62732014-03-25 20:38:29 -0600451}
452
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200453/* Illumination support */
Azael Avalosea215a3f2015-07-31 21:58:12 -0600454static void toshiba_illumination_available(struct toshiba_acpi_dev *dev)
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200455{
Azael Avalos258c5902014-09-29 20:40:07 -0600456 u32 in[TCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 };
457 u32 out[TCI_WORDS];
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200458 acpi_status status;
459
Azael Avalosea215a3f2015-07-31 21:58:12 -0600460 dev->illumination_supported = 0;
461 dev->illumination_led_registered = false;
462
Azael Avalosfdb79082014-03-25 20:38:30 -0600463 if (!sci_open(dev))
Azael Avalosea215a3f2015-07-31 21:58:12 -0600464 return;
Azael Avalosfdb79082014-03-25 20:38:30 -0600465
Azael Avalos258c5902014-09-29 20:40:07 -0600466 status = tci_raw(dev, in, out);
Azael Avalosfdb79082014-03-25 20:38:30 -0600467 sci_close(dev);
Azael Avalosea215a3f2015-07-31 21:58:12 -0600468 if (ACPI_FAILURE(status))
Azael Avalosfdb79082014-03-25 20:38:30 -0600469 pr_err("ACPI call to query Illumination support failed\n");
Azael Avalosea215a3f2015-07-31 21:58:12 -0600470 else if (out[0] == TOS_SUCCESS)
471 dev->illumination_supported = 1;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200472}
473
474static void toshiba_illumination_set(struct led_classdev *cdev,
475 enum led_brightness brightness)
476{
Seth Forshee135740d2011-09-20 16:55:49 -0500477 struct toshiba_acpi_dev *dev = container_of(cdev,
478 struct toshiba_acpi_dev, led_dev);
Azael Avalose1a949c2015-07-31 21:58:14 -0600479 u32 result;
480 u32 state;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200481
482 /* First request : initialize communication. */
Azael Avalosfdb79082014-03-25 20:38:30 -0600483 if (!sci_open(dev))
484 return;
485
486 /* Switch the illumination on/off */
487 state = brightness ? 1 : 0;
Azael Avalos893f3f62014-09-29 20:40:09 -0600488 result = sci_write(dev, SCI_ILLUMINATION, state);
Azael Avalosfdb79082014-03-25 20:38:30 -0600489 sci_close(dev);
Azael Avalosa6b53542015-07-31 21:58:15 -0600490 if (result == TOS_FAILURE)
Azael Avalosfdb79082014-03-25 20:38:30 -0600491 pr_err("ACPI call for illumination failed\n");
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200492}
493
494static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
495{
Seth Forshee135740d2011-09-20 16:55:49 -0500496 struct toshiba_acpi_dev *dev = container_of(cdev,
497 struct toshiba_acpi_dev, led_dev);
Azael Avalosfdb79082014-03-25 20:38:30 -0600498 u32 state, result;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200499
Azael Avalos3f75bbe2015-05-06 09:35:11 -0600500 /* First request : initialize communication. */
Azael Avalosfdb79082014-03-25 20:38:30 -0600501 if (!sci_open(dev))
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200502 return LED_OFF;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200503
504 /* Check the illumination */
Azael Avalos893f3f62014-09-29 20:40:09 -0600505 result = sci_read(dev, SCI_ILLUMINATION, &state);
Azael Avalosfdb79082014-03-25 20:38:30 -0600506 sci_close(dev);
Azael Avalosa6b53542015-07-31 21:58:15 -0600507 if (result == TOS_FAILURE) {
Azael Avalosfdb79082014-03-25 20:38:30 -0600508 pr_err("ACPI call for illumination failed\n");
509 return LED_OFF;
Azael Avalose1a949c2015-07-31 21:58:14 -0600510 } else if (result != TOS_SUCCESS) {
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200511 return LED_OFF;
512 }
513
Azael Avalosfdb79082014-03-25 20:38:30 -0600514 return state ? LED_FULL : LED_OFF;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200515}
Matthew Garrettea6b31f2014-04-04 14:22:34 -0400516
Azael Avalos360f0f32014-03-25 20:38:31 -0600517/* KBD Illumination */
Azael Avalosea215a3f2015-07-31 21:58:12 -0600518static void toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev)
Azael Avalos93f8c162014-09-12 18:50:36 -0600519{
Azael Avalos258c5902014-09-29 20:40:07 -0600520 u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 };
521 u32 out[TCI_WORDS];
Azael Avalos93f8c162014-09-12 18:50:36 -0600522 acpi_status status;
523
Azael Avalosea215a3f2015-07-31 21:58:12 -0600524 dev->kbd_illum_supported = 0;
525 dev->kbd_led_registered = false;
526
Azael Avalos93f8c162014-09-12 18:50:36 -0600527 if (!sci_open(dev))
Azael Avalosea215a3f2015-07-31 21:58:12 -0600528 return;
Azael Avalos93f8c162014-09-12 18:50:36 -0600529
Azael Avalos258c5902014-09-29 20:40:07 -0600530 status = tci_raw(dev, in, out);
Azael Avalos93f8c162014-09-12 18:50:36 -0600531 sci_close(dev);
Azael Avalosa6b53542015-07-31 21:58:15 -0600532 if (ACPI_FAILURE(status)) {
Azael Avalos93f8c162014-09-12 18:50:36 -0600533 pr_err("ACPI call to query kbd illumination support failed\n");
Azael Avalosea215a3f2015-07-31 21:58:12 -0600534 } else if (out[0] == TOS_SUCCESS) {
535 /*
536 * Check for keyboard backlight timeout max value,
537 * previous kbd backlight implementation set this to
538 * 0x3c0003, and now the new implementation set this
539 * to 0x3c001a, use this to distinguish between them.
540 */
541 if (out[3] == SCI_KBD_TIME_MAX)
542 dev->kbd_type = 2;
543 else
544 dev->kbd_type = 1;
545 /* Get the current keyboard backlight mode */
546 dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK;
547 /* Get the current time (1-60 seconds) */
548 dev->kbd_time = out[2] >> HCI_MISC_SHIFT;
549 /* Flag as supported */
550 dev->kbd_illum_supported = 1;
Azael Avalos93f8c162014-09-12 18:50:36 -0600551 }
Azael Avalos93f8c162014-09-12 18:50:36 -0600552}
553
Azael Avalos360f0f32014-03-25 20:38:31 -0600554static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time)
555{
556 u32 result;
Azael Avalos360f0f32014-03-25 20:38:31 -0600557
558 if (!sci_open(dev))
559 return -EIO;
560
Azael Avalos893f3f62014-09-29 20:40:09 -0600561 result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time);
Azael Avalos360f0f32014-03-25 20:38:31 -0600562 sci_close(dev);
Azael Avalosa6b53542015-07-31 21:58:15 -0600563 if (result == TOS_FAILURE)
Azael Avalos360f0f32014-03-25 20:38:31 -0600564 pr_err("ACPI call to set KBD backlight status failed\n");
Azael Avalosa6b53542015-07-31 21:58:15 -0600565 else if (result == TOS_NOT_SUPPORTED)
Azael Avalos360f0f32014-03-25 20:38:31 -0600566 return -ENODEV;
Azael Avalos360f0f32014-03-25 20:38:31 -0600567
Azael Avalose1a949c2015-07-31 21:58:14 -0600568 return result == TOS_SUCCESS ? 0 : -EIO;
Azael Avalos360f0f32014-03-25 20:38:31 -0600569}
570
571static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time)
572{
573 u32 result;
Azael Avalos360f0f32014-03-25 20:38:31 -0600574
575 if (!sci_open(dev))
576 return -EIO;
577
Azael Avalos893f3f62014-09-29 20:40:09 -0600578 result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time);
Azael Avalos360f0f32014-03-25 20:38:31 -0600579 sci_close(dev);
Azael Avalosa6b53542015-07-31 21:58:15 -0600580 if (result == TOS_FAILURE)
Azael Avalos360f0f32014-03-25 20:38:31 -0600581 pr_err("ACPI call to get KBD backlight status failed\n");
Azael Avalosa6b53542015-07-31 21:58:15 -0600582 else if (result == TOS_NOT_SUPPORTED)
Azael Avalos360f0f32014-03-25 20:38:31 -0600583 return -ENODEV;
Azael Avalos360f0f32014-03-25 20:38:31 -0600584
Azael Avalose1a949c2015-07-31 21:58:14 -0600585 return result == TOS_SUCCESS ? 0 : -EIO;
Azael Avalos360f0f32014-03-25 20:38:31 -0600586}
587
588static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev)
589{
590 struct toshiba_acpi_dev *dev = container_of(cdev,
591 struct toshiba_acpi_dev, kbd_led);
Azael Avalose1a949c2015-07-31 21:58:14 -0600592 u32 result;
593 u32 state;
Azael Avalos360f0f32014-03-25 20:38:31 -0600594
595 /* Check the keyboard backlight state */
Azael Avalosd37782b2015-05-06 09:35:10 -0600596 result = hci_read(dev, HCI_KBD_ILLUMINATION, &state);
Azael Avalosa6b53542015-07-31 21:58:15 -0600597 if (result == TOS_FAILURE) {
Azael Avalos360f0f32014-03-25 20:38:31 -0600598 pr_err("ACPI call to get the keyboard backlight failed\n");
599 return LED_OFF;
Azael Avalose1a949c2015-07-31 21:58:14 -0600600 } else if (result != TOS_SUCCESS) {
Azael Avalos360f0f32014-03-25 20:38:31 -0600601 return LED_OFF;
602 }
603
604 return state ? LED_FULL : LED_OFF;
605}
606
607static void toshiba_kbd_backlight_set(struct led_classdev *cdev,
608 enum led_brightness brightness)
609{
610 struct toshiba_acpi_dev *dev = container_of(cdev,
611 struct toshiba_acpi_dev, kbd_led);
Azael Avalose1a949c2015-07-31 21:58:14 -0600612 u32 result;
613 u32 state;
Azael Avalos360f0f32014-03-25 20:38:31 -0600614
615 /* Set the keyboard backlight state */
616 state = brightness ? 1 : 0;
Azael Avalosd37782b2015-05-06 09:35:10 -0600617 result = hci_write(dev, HCI_KBD_ILLUMINATION, state);
Azael Avalosa6b53542015-07-31 21:58:15 -0600618 if (result == TOS_FAILURE)
Azael Avalos360f0f32014-03-25 20:38:31 -0600619 pr_err("ACPI call to set KBD Illumination mode failed\n");
Azael Avalos360f0f32014-03-25 20:38:31 -0600620}
Matthew Garrettea6b31f2014-04-04 14:22:34 -0400621
Azael Avalos9d8658a2014-03-25 20:38:32 -0600622/* TouchPad support */
623static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state)
624{
625 u32 result;
Azael Avalos9d8658a2014-03-25 20:38:32 -0600626
627 if (!sci_open(dev))
628 return -EIO;
629
Azael Avalos893f3f62014-09-29 20:40:09 -0600630 result = sci_write(dev, SCI_TOUCHPAD, state);
Azael Avalos9d8658a2014-03-25 20:38:32 -0600631 sci_close(dev);
Azael Avalosa6b53542015-07-31 21:58:15 -0600632 if (result == TOS_FAILURE)
Azael Avalos9d8658a2014-03-25 20:38:32 -0600633 pr_err("ACPI call to set the touchpad failed\n");
Azael Avalosa6b53542015-07-31 21:58:15 -0600634 else if (result == TOS_NOT_SUPPORTED)
Azael Avalos9d8658a2014-03-25 20:38:32 -0600635 return -ENODEV;
Azael Avalos9d8658a2014-03-25 20:38:32 -0600636
Azael Avalose1a949c2015-07-31 21:58:14 -0600637 return result == TOS_SUCCESS ? 0 : -EIO;
Azael Avalos9d8658a2014-03-25 20:38:32 -0600638}
639
640static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state)
641{
642 u32 result;
Azael Avalos9d8658a2014-03-25 20:38:32 -0600643
644 if (!sci_open(dev))
645 return -EIO;
646
Azael Avalos893f3f62014-09-29 20:40:09 -0600647 result = sci_read(dev, SCI_TOUCHPAD, state);
Azael Avalos9d8658a2014-03-25 20:38:32 -0600648 sci_close(dev);
Azael Avalosa6b53542015-07-31 21:58:15 -0600649 if (result == TOS_FAILURE)
Azael Avalos9d8658a2014-03-25 20:38:32 -0600650 pr_err("ACPI call to query the touchpad failed\n");
Azael Avalosa6b53542015-07-31 21:58:15 -0600651 else if (result == TOS_NOT_SUPPORTED)
Azael Avalos9d8658a2014-03-25 20:38:32 -0600652 return -ENODEV;
Azael Avalos9d8658a2014-03-25 20:38:32 -0600653
Azael Avalose1a949c2015-07-31 21:58:14 -0600654 return result == TOS_SUCCESS ? 0 : -EIO;
Azael Avalos9d8658a2014-03-25 20:38:32 -0600655}
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200656
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600657/* Eco Mode support */
Azael Avalosea215a3f2015-07-31 21:58:12 -0600658static void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev)
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600659{
660 acpi_status status;
Azael Avalos98fc4ec2015-02-09 20:55:02 -0700661 u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 };
Azael Avalos258c5902014-09-29 20:40:07 -0600662 u32 out[TCI_WORDS];
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600663
Azael Avalosea215a3f2015-07-31 21:58:12 -0600664 dev->eco_supported = 0;
665 dev->eco_led_registered = false;
666
Azael Avalos258c5902014-09-29 20:40:07 -0600667 status = tci_raw(dev, in, out);
Azael Avalos8baec452015-05-06 09:35:12 -0600668 if (ACPI_FAILURE(status)) {
Azael Avalos98fc4ec2015-02-09 20:55:02 -0700669 pr_err("ACPI call to get ECO led failed\n");
Azael Avalos98fc4ec2015-02-09 20:55:02 -0700670 } else if (out[0] == TOS_INPUT_DATA_ERROR) {
Darren Harte0769fe2015-02-11 20:50:08 -0800671 /*
672 * If we receive 0x8300 (Input Data Error), it means that the
Azael Avalos98fc4ec2015-02-09 20:55:02 -0700673 * LED device is present, but that we just screwed the input
674 * parameters.
675 *
676 * Let's query the status of the LED to see if we really have a
677 * success response, indicating the actual presense of the LED,
678 * bail out otherwise.
679 */
680 in[3] = 1;
681 status = tci_raw(dev, in, out);
Azael Avalosa6b53542015-07-31 21:58:15 -0600682 if (ACPI_FAILURE(status))
Azael Avalos98fc4ec2015-02-09 20:55:02 -0700683 pr_err("ACPI call to get ECO led failed\n");
684 else if (out[0] == TOS_SUCCESS)
Azael Avalosea215a3f2015-07-31 21:58:12 -0600685 dev->eco_supported = 1;
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600686 }
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600687}
688
Azael Avalosb5163992015-02-10 23:43:56 -0700689static enum led_brightness
690toshiba_eco_mode_get_status(struct led_classdev *cdev)
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600691{
692 struct toshiba_acpi_dev *dev = container_of(cdev,
693 struct toshiba_acpi_dev, eco_led);
Azael Avalos258c5902014-09-29 20:40:07 -0600694 u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 };
695 u32 out[TCI_WORDS];
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600696 acpi_status status;
697
Azael Avalos258c5902014-09-29 20:40:07 -0600698 status = tci_raw(dev, in, out);
Azael Avalosa6b53542015-07-31 21:58:15 -0600699 if (ACPI_FAILURE(status)) {
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600700 pr_err("ACPI call to get ECO led failed\n");
701 return LED_OFF;
Azael Avalose1a949c2015-07-31 21:58:14 -0600702 } else if (out[0] != TOS_SUCCESS) {
703 return LED_OFF;
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600704 }
705
706 return out[2] ? LED_FULL : LED_OFF;
707}
708
709static void toshiba_eco_mode_set_status(struct led_classdev *cdev,
710 enum led_brightness brightness)
711{
712 struct toshiba_acpi_dev *dev = container_of(cdev,
713 struct toshiba_acpi_dev, eco_led);
Azael Avalos258c5902014-09-29 20:40:07 -0600714 u32 in[TCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 };
715 u32 out[TCI_WORDS];
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600716 acpi_status status;
717
718 /* Switch the Eco Mode led on/off */
719 in[2] = (brightness) ? 1 : 0;
Azael Avalos258c5902014-09-29 20:40:07 -0600720 status = tci_raw(dev, in, out);
Azael Avalosa6b53542015-07-31 21:58:15 -0600721 if (ACPI_FAILURE(status))
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600722 pr_err("ACPI call to set ECO led failed\n");
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600723}
Matthew Garrettea6b31f2014-04-04 14:22:34 -0400724
Azael Avalos5a2813e2014-03-25 20:38:34 -0600725/* Accelerometer support */
Azael Avalosea215a3f2015-07-31 21:58:12 -0600726static void toshiba_accelerometer_available(struct toshiba_acpi_dev *dev)
Azael Avalos5a2813e2014-03-25 20:38:34 -0600727{
Azael Avalos258c5902014-09-29 20:40:07 -0600728 u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 };
729 u32 out[TCI_WORDS];
Azael Avalos5a2813e2014-03-25 20:38:34 -0600730 acpi_status status;
731
Azael Avalosea215a3f2015-07-31 21:58:12 -0600732 dev->accelerometer_supported = 0;
733
Darren Harte0769fe2015-02-11 20:50:08 -0800734 /*
735 * Check if the accelerometer call exists,
Azael Avalos5a2813e2014-03-25 20:38:34 -0600736 * this call also serves as initialization
737 */
Azael Avalos258c5902014-09-29 20:40:07 -0600738 status = tci_raw(dev, in, out);
Azael Avalosa6b53542015-07-31 21:58:15 -0600739 if (ACPI_FAILURE(status))
Azael Avalos5a2813e2014-03-25 20:38:34 -0600740 pr_err("ACPI call to query the accelerometer failed\n");
Azael Avalosea215a3f2015-07-31 21:58:12 -0600741 else if (out[0] == TOS_SUCCESS)
742 dev->accelerometer_supported = 1;
Azael Avalos5a2813e2014-03-25 20:38:34 -0600743}
744
745static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev,
Azael Avalosa6b53542015-07-31 21:58:15 -0600746 u32 *xy, u32 *z)
Azael Avalos5a2813e2014-03-25 20:38:34 -0600747{
Azael Avalos258c5902014-09-29 20:40:07 -0600748 u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 };
749 u32 out[TCI_WORDS];
Azael Avalos5a2813e2014-03-25 20:38:34 -0600750 acpi_status status;
751
752 /* Check the Accelerometer status */
Azael Avalos258c5902014-09-29 20:40:07 -0600753 status = tci_raw(dev, in, out);
Azael Avalosa6b53542015-07-31 21:58:15 -0600754 if (ACPI_FAILURE(status)) {
Azael Avalos5a2813e2014-03-25 20:38:34 -0600755 pr_err("ACPI call to query the accelerometer failed\n");
756 return -EIO;
Azael Avalose1a949c2015-07-31 21:58:14 -0600757 } else if (out[0] == TOS_NOT_SUPPORTED) {
758 return -ENODEV;
759 } else if (out[0] == TOS_SUCCESS) {
760 *xy = out[2];
761 *z = out[4];
762 return 0;
Azael Avalos5a2813e2014-03-25 20:38:34 -0600763 }
764
Azael Avalose1a949c2015-07-31 21:58:14 -0600765 return -EIO;
Azael Avalos5a2813e2014-03-25 20:38:34 -0600766}
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600767
Azael Avalose26ffe52015-01-18 18:30:22 -0700768/* Sleep (Charge and Music) utilities support */
Azael Avalosc8c91842015-04-02 19:26:20 -0600769static void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev)
770{
771 u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
772 u32 out[TCI_WORDS];
773 acpi_status status;
774
Azael Avalosc8c91842015-04-02 19:26:20 -0600775 dev->usb_sleep_charge_supported = 0;
776
777 if (!sci_open(dev))
778 return;
779
780 status = tci_raw(dev, in, out);
Azael Avalos8baec452015-05-06 09:35:12 -0600781 if (ACPI_FAILURE(status)) {
Azael Avalosc8c91842015-04-02 19:26:20 -0600782 pr_err("ACPI call to get USB Sleep and Charge mode failed\n");
783 sci_close(dev);
784 return;
785 } else if (out[0] == TOS_NOT_SUPPORTED) {
Azael Avalosc8c91842015-04-02 19:26:20 -0600786 sci_close(dev);
787 return;
788 } else if (out[0] == TOS_SUCCESS) {
789 dev->usbsc_mode_base = out[4];
790 }
791
792 in[5] = SCI_USB_CHARGE_BAT_LVL;
793 status = tci_raw(dev, in, out);
Azael Avalosea215a3f2015-07-31 21:58:12 -0600794 sci_close(dev);
Azael Avalos8baec452015-05-06 09:35:12 -0600795 if (ACPI_FAILURE(status)) {
Azael Avalosc8c91842015-04-02 19:26:20 -0600796 pr_err("ACPI call to get USB Sleep and Charge mode failed\n");
Azael Avalosc8c91842015-04-02 19:26:20 -0600797 } else if (out[0] == TOS_SUCCESS) {
798 dev->usbsc_bat_level = out[2];
Azael Avalosea215a3f2015-07-31 21:58:12 -0600799 /* Flag as supported */
Azael Avalosc8c91842015-04-02 19:26:20 -0600800 dev->usb_sleep_charge_supported = 1;
801 }
802
Azael Avalosc8c91842015-04-02 19:26:20 -0600803}
804
Azael Avalose26ffe52015-01-18 18:30:22 -0700805static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev,
806 u32 *mode)
807{
808 u32 result;
809
810 if (!sci_open(dev))
811 return -EIO;
812
813 result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode);
814 sci_close(dev);
Azael Avalosa6b53542015-07-31 21:58:15 -0600815 if (result == TOS_FAILURE)
Azael Avalose26ffe52015-01-18 18:30:22 -0700816 pr_err("ACPI call to set USB S&C mode failed\n");
Azael Avalosa6b53542015-07-31 21:58:15 -0600817 else if (result == TOS_NOT_SUPPORTED)
Azael Avalose26ffe52015-01-18 18:30:22 -0700818 return -ENODEV;
Azael Avalose26ffe52015-01-18 18:30:22 -0700819
Azael Avalose1a949c2015-07-31 21:58:14 -0600820 return result == TOS_SUCCESS ? 0 : -EIO;
Azael Avalose26ffe52015-01-18 18:30:22 -0700821}
822
823static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev,
824 u32 mode)
825{
826 u32 result;
827
828 if (!sci_open(dev))
829 return -EIO;
830
831 result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode);
832 sci_close(dev);
Azael Avalosa6b53542015-07-31 21:58:15 -0600833 if (result == TOS_FAILURE)
Azael Avalose26ffe52015-01-18 18:30:22 -0700834 pr_err("ACPI call to set USB S&C mode failed\n");
Azael Avalosa6b53542015-07-31 21:58:15 -0600835 else if (result == TOS_NOT_SUPPORTED)
Azael Avalose26ffe52015-01-18 18:30:22 -0700836 return -ENODEV;
Azael Avalose26ffe52015-01-18 18:30:22 -0700837
Azael Avalose1a949c2015-07-31 21:58:14 -0600838 return result == TOS_SUCCESS ? 0 : -EIO;
Azael Avalose26ffe52015-01-18 18:30:22 -0700839}
840
Azael Avalos182bcaa2015-01-18 18:30:23 -0700841static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev,
842 u32 *mode)
843{
844 u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
845 u32 out[TCI_WORDS];
846 acpi_status status;
847
848 if (!sci_open(dev))
849 return -EIO;
850
851 in[5] = SCI_USB_CHARGE_BAT_LVL;
852 status = tci_raw(dev, in, out);
853 sci_close(dev);
Azael Avalos8baec452015-05-06 09:35:12 -0600854 if (ACPI_FAILURE(status)) {
Azael Avalos182bcaa2015-01-18 18:30:23 -0700855 pr_err("ACPI call to get USB S&C battery level failed\n");
Azael Avalos182bcaa2015-01-18 18:30:23 -0700856 } else if (out[0] == TOS_NOT_SUPPORTED) {
Azael Avalos182bcaa2015-01-18 18:30:23 -0700857 return -ENODEV;
Azael Avalose1a949c2015-07-31 21:58:14 -0600858 } else if (out[0] == TOS_SUCCESS) {
859 *mode = out[2];
860 return 0;
Azael Avalos182bcaa2015-01-18 18:30:23 -0700861 }
862
Azael Avalose1a949c2015-07-31 21:58:14 -0600863 return -EIO;
Azael Avalos182bcaa2015-01-18 18:30:23 -0700864}
865
866static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev,
867 u32 mode)
868{
869 u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
870 u32 out[TCI_WORDS];
871 acpi_status status;
872
873 if (!sci_open(dev))
874 return -EIO;
875
876 in[2] = mode;
877 in[5] = SCI_USB_CHARGE_BAT_LVL;
878 status = tci_raw(dev, in, out);
879 sci_close(dev);
Azael Avalosa6b53542015-07-31 21:58:15 -0600880 if (ACPI_FAILURE(status))
Azael Avalos182bcaa2015-01-18 18:30:23 -0700881 pr_err("ACPI call to set USB S&C battery level failed\n");
Azael Avalosa6b53542015-07-31 21:58:15 -0600882 else if (out[0] == TOS_NOT_SUPPORTED)
Azael Avalos182bcaa2015-01-18 18:30:23 -0700883 return -ENODEV;
Azael Avalos182bcaa2015-01-18 18:30:23 -0700884
Azael Avalose1a949c2015-07-31 21:58:14 -0600885 return out[0] == TOS_SUCCESS ? 0 : -EIO;
Azael Avalos182bcaa2015-01-18 18:30:23 -0700886}
887
Azael Avalosbb3fe012015-01-18 18:30:24 -0700888static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev,
889 u32 *state)
890{
891 u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
892 u32 out[TCI_WORDS];
893 acpi_status status;
894
895 if (!sci_open(dev))
896 return -EIO;
897
898 in[5] = SCI_USB_CHARGE_RAPID_DSP;
899 status = tci_raw(dev, in, out);
900 sci_close(dev);
Azael Avalos8baec452015-05-06 09:35:12 -0600901 if (ACPI_FAILURE(status)) {
Azael Avalosbb26f182015-04-02 19:26:21 -0600902 pr_err("ACPI call to get USB Rapid Charge failed\n");
Azael Avalosa6b53542015-07-31 21:58:15 -0600903 } else if (out[0] == TOS_NOT_SUPPORTED) {
Azael Avalosbb3fe012015-01-18 18:30:24 -0700904 return -ENODEV;
Azael Avalose1a949c2015-07-31 21:58:14 -0600905 } else if (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) {
906 *state = out[2];
907 return 0;
Azael Avalosbb3fe012015-01-18 18:30:24 -0700908 }
909
Azael Avalose1a949c2015-07-31 21:58:14 -0600910 return -EIO;
Azael Avalosbb3fe012015-01-18 18:30:24 -0700911}
912
913static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev,
914 u32 state)
915{
916 u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
917 u32 out[TCI_WORDS];
918 acpi_status status;
919
920 if (!sci_open(dev))
921 return -EIO;
922
923 in[2] = state;
924 in[5] = SCI_USB_CHARGE_RAPID_DSP;
925 status = tci_raw(dev, in, out);
926 sci_close(dev);
Azael Avalosa6b53542015-07-31 21:58:15 -0600927 if (ACPI_FAILURE(status))
Azael Avalosbb26f182015-04-02 19:26:21 -0600928 pr_err("ACPI call to set USB Rapid Charge failed\n");
Azael Avalosa6b53542015-07-31 21:58:15 -0600929 else if (out[0] == TOS_NOT_SUPPORTED)
Azael Avalosbb3fe012015-01-18 18:30:24 -0700930 return -ENODEV;
Azael Avalosbb3fe012015-01-18 18:30:24 -0700931
Azael Avalose1a949c2015-07-31 21:58:14 -0600932 return (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) ? 0 : -EIO;
Azael Avalosbb3fe012015-01-18 18:30:24 -0700933}
934
Azael Avalos172ce0a2015-01-18 18:30:25 -0700935static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state)
936{
937 u32 result;
938
939 if (!sci_open(dev))
940 return -EIO;
941
942 result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state);
943 sci_close(dev);
Azael Avalosa6b53542015-07-31 21:58:15 -0600944 if (result == TOS_FAILURE)
Azael Avalosbb26f182015-04-02 19:26:21 -0600945 pr_err("ACPI call to get Sleep and Music failed\n");
Azael Avalosa6b53542015-07-31 21:58:15 -0600946 else if (result == TOS_NOT_SUPPORTED)
Azael Avalos172ce0a2015-01-18 18:30:25 -0700947 return -ENODEV;
Azael Avalos172ce0a2015-01-18 18:30:25 -0700948
Azael Avaloscf680ea2015-09-09 11:25:44 -0600949 return result == TOS_SUCCESS ? 0 : -EIO;
Azael Avalos172ce0a2015-01-18 18:30:25 -0700950}
951
952static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state)
953{
954 u32 result;
955
956 if (!sci_open(dev))
957 return -EIO;
958
959 result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state);
960 sci_close(dev);
Azael Avalosa6b53542015-07-31 21:58:15 -0600961 if (result == TOS_FAILURE)
Azael Avalosbb26f182015-04-02 19:26:21 -0600962 pr_err("ACPI call to set Sleep and Music failed\n");
Azael Avalosa6b53542015-07-31 21:58:15 -0600963 else if (result == TOS_NOT_SUPPORTED)
Azael Avalos172ce0a2015-01-18 18:30:25 -0700964 return -ENODEV;
Azael Avalos172ce0a2015-01-18 18:30:25 -0700965
Azael Avalose1a949c2015-07-31 21:58:14 -0600966 return result == TOS_SUCCESS ? 0 : -EIO;
Azael Avalos172ce0a2015-01-18 18:30:25 -0700967}
968
Azael Avalosbae84192015-02-10 21:09:18 -0700969/* Keyboard function keys */
970static int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode)
971{
972 u32 result;
973
974 if (!sci_open(dev))
975 return -EIO;
976
977 result = sci_read(dev, SCI_KBD_FUNCTION_KEYS, mode);
978 sci_close(dev);
Azael Avalosa6b53542015-07-31 21:58:15 -0600979 if (result == TOS_FAILURE)
Azael Avalosbae84192015-02-10 21:09:18 -0700980 pr_err("ACPI call to get KBD function keys failed\n");
Azael Avalosa6b53542015-07-31 21:58:15 -0600981 else if (result == TOS_NOT_SUPPORTED)
Azael Avalosbae84192015-02-10 21:09:18 -0700982 return -ENODEV;
Azael Avalosbae84192015-02-10 21:09:18 -0700983
Azael Avalose1a949c2015-07-31 21:58:14 -0600984 return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
Azael Avalosbae84192015-02-10 21:09:18 -0700985}
986
987static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode)
988{
989 u32 result;
990
991 if (!sci_open(dev))
992 return -EIO;
993
994 result = sci_write(dev, SCI_KBD_FUNCTION_KEYS, mode);
995 sci_close(dev);
Azael Avalosa6b53542015-07-31 21:58:15 -0600996 if (result == TOS_FAILURE)
Azael Avalosbae84192015-02-10 21:09:18 -0700997 pr_err("ACPI call to set KBD function keys failed\n");
Azael Avalosa6b53542015-07-31 21:58:15 -0600998 else if (result == TOS_NOT_SUPPORTED)
Azael Avalosbae84192015-02-10 21:09:18 -0700999 return -ENODEV;
Azael Avalosbae84192015-02-10 21:09:18 -07001000
Azael Avalose1a949c2015-07-31 21:58:14 -06001001 return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
Azael Avalosbae84192015-02-10 21:09:18 -07001002}
1003
Azael Avalos35d53ce2015-02-10 21:09:19 -07001004/* Panel Power ON */
1005static int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state)
1006{
1007 u32 result;
1008
1009 if (!sci_open(dev))
1010 return -EIO;
1011
1012 result = sci_read(dev, SCI_PANEL_POWER_ON, state);
1013 sci_close(dev);
Azael Avalosa6b53542015-07-31 21:58:15 -06001014 if (result == TOS_FAILURE)
Azael Avalos35d53ce2015-02-10 21:09:19 -07001015 pr_err("ACPI call to get Panel Power ON failed\n");
Azael Avalosa6b53542015-07-31 21:58:15 -06001016 else if (result == TOS_NOT_SUPPORTED)
Azael Avalos35d53ce2015-02-10 21:09:19 -07001017 return -ENODEV;
Azael Avalos35d53ce2015-02-10 21:09:19 -07001018
Azael Avalose1a949c2015-07-31 21:58:14 -06001019 return result == TOS_SUCCESS ? 0 : -EIO;
Azael Avalos35d53ce2015-02-10 21:09:19 -07001020}
1021
1022static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state)
1023{
1024 u32 result;
1025
1026 if (!sci_open(dev))
1027 return -EIO;
1028
1029 result = sci_write(dev, SCI_PANEL_POWER_ON, state);
1030 sci_close(dev);
Azael Avalosa6b53542015-07-31 21:58:15 -06001031 if (result == TOS_FAILURE)
Azael Avalos35d53ce2015-02-10 21:09:19 -07001032 pr_err("ACPI call to set Panel Power ON failed\n");
Azael Avalosa6b53542015-07-31 21:58:15 -06001033 else if (result == TOS_NOT_SUPPORTED)
Azael Avalos35d53ce2015-02-10 21:09:19 -07001034 return -ENODEV;
Azael Avalos35d53ce2015-02-10 21:09:19 -07001035
Azael Avalose1a949c2015-07-31 21:58:14 -06001036 return result == TOS_SUCCESS ? 0 : -EIO;
Azael Avalos35d53ce2015-02-10 21:09:19 -07001037}
1038
Azael Avalos17fe4b32015-02-10 21:09:20 -07001039/* USB Three */
1040static int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state)
1041{
1042 u32 result;
1043
1044 if (!sci_open(dev))
1045 return -EIO;
1046
1047 result = sci_read(dev, SCI_USB_THREE, state);
1048 sci_close(dev);
Azael Avalosa6b53542015-07-31 21:58:15 -06001049 if (result == TOS_FAILURE)
Azael Avalos17fe4b32015-02-10 21:09:20 -07001050 pr_err("ACPI call to get USB 3 failed\n");
Azael Avalosa6b53542015-07-31 21:58:15 -06001051 else if (result == TOS_NOT_SUPPORTED)
Azael Avalos17fe4b32015-02-10 21:09:20 -07001052 return -ENODEV;
Azael Avalos17fe4b32015-02-10 21:09:20 -07001053
Azael Avalose1a949c2015-07-31 21:58:14 -06001054 return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
Azael Avalos17fe4b32015-02-10 21:09:20 -07001055}
1056
1057static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state)
1058{
1059 u32 result;
1060
1061 if (!sci_open(dev))
1062 return -EIO;
1063
1064 result = sci_write(dev, SCI_USB_THREE, state);
1065 sci_close(dev);
Azael Avalosa6b53542015-07-31 21:58:15 -06001066 if (result == TOS_FAILURE)
Azael Avalos17fe4b32015-02-10 21:09:20 -07001067 pr_err("ACPI call to set USB 3 failed\n");
Azael Avalosa6b53542015-07-31 21:58:15 -06001068 else if (result == TOS_NOT_SUPPORTED)
Azael Avalos17fe4b32015-02-10 21:09:20 -07001069 return -ENODEV;
Azael Avalos17fe4b32015-02-10 21:09:20 -07001070
Azael Avalose1a949c2015-07-31 21:58:14 -06001071 return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
Azael Avalos17fe4b32015-02-10 21:09:20 -07001072}
1073
Azael Avalos56e6b352015-03-20 16:55:16 -06001074/* Hotkey Event type */
1075static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev,
1076 u32 *type)
1077{
Azael Avalos3b876002015-05-06 09:35:09 -06001078 u32 in[TCI_WORDS] = { HCI_GET, HCI_SYSTEM_INFO, 0x03, 0, 0, 0 };
1079 u32 out[TCI_WORDS];
1080 acpi_status status;
Azael Avalos56e6b352015-03-20 16:55:16 -06001081
Azael Avalos3b876002015-05-06 09:35:09 -06001082 status = tci_raw(dev, in, out);
1083 if (ACPI_FAILURE(status)) {
Azael Avalos56e6b352015-03-20 16:55:16 -06001084 pr_err("ACPI call to get System type failed\n");
Azael Avalos3b876002015-05-06 09:35:09 -06001085 } else if (out[0] == TOS_NOT_SUPPORTED) {
Azael Avalos56e6b352015-03-20 16:55:16 -06001086 return -ENODEV;
Azael Avalose1a949c2015-07-31 21:58:14 -06001087 } else if (out[0] == TOS_SUCCESS) {
1088 *type = out[3];
1089 return 0;
Azael Avalos56e6b352015-03-20 16:55:16 -06001090 }
1091
Azael Avalose1a949c2015-07-31 21:58:14 -06001092 return -EIO;
Azael Avalos56e6b352015-03-20 16:55:16 -06001093}
1094
Azael Avalos6873f462015-11-23 10:49:10 -07001095/* Wireless status (RFKill, WLAN, BT, WWAN) */
1096static int toshiba_wireless_status(struct toshiba_acpi_dev *dev)
1097{
1098 u32 in[TCI_WORDS] = { HCI_GET, HCI_WIRELESS, 0, 0, 0, 0 };
1099 u32 out[TCI_WORDS];
1100 acpi_status status;
1101
1102 in[3] = HCI_WIRELESS_STATUS;
1103 status = tci_raw(dev, in, out);
1104
1105 if (ACPI_FAILURE(status)) {
1106 pr_err("ACPI call to get Wireless status failed\n");
1107 return -EIO;
1108 }
1109
1110 if (out[0] == TOS_NOT_SUPPORTED)
1111 return -ENODEV;
1112
1113 if (out[0] != TOS_SUCCESS)
1114 return -EIO;
1115
1116 dev->killswitch = !!(out[2] & HCI_WIRELESS_STATUS);
1117
1118 return 0;
1119}
1120
1121/* WWAN */
1122static void toshiba_wwan_available(struct toshiba_acpi_dev *dev)
1123{
1124 u32 in[TCI_WORDS] = { HCI_GET, HCI_WIRELESS, 0, 0, 0, 0 };
1125 u32 out[TCI_WORDS];
1126 acpi_status status;
1127
1128 dev->wwan_supported = 0;
1129
1130 /*
1131 * WWAN support can be queried by setting the in[3] value to
1132 * HCI_WIRELESS_WWAN (0x03).
1133 *
1134 * If supported, out[0] contains TOS_SUCCESS and out[2] contains
1135 * HCI_WIRELESS_WWAN_STATUS (0x2000).
1136 *
1137 * If not supported, out[0] contains TOS_INPUT_DATA_ERROR (0x8300)
1138 * or TOS_NOT_SUPPORTED (0x8000).
1139 */
1140 in[3] = HCI_WIRELESS_WWAN;
1141 status = tci_raw(dev, in, out);
1142
1143 if (ACPI_FAILURE(status)) {
1144 pr_err("ACPI call to get WWAN status failed\n");
1145 return;
1146 }
1147
1148 if (out[0] != TOS_SUCCESS)
1149 return;
1150
1151 dev->wwan_supported = (out[2] == HCI_WIRELESS_WWAN_STATUS);
1152}
1153
1154static int toshiba_wwan_set(struct toshiba_acpi_dev *dev, u32 state)
1155{
1156 u32 in[TCI_WORDS] = { HCI_SET, HCI_WIRELESS, state, 0, 0, 0 };
1157 u32 out[TCI_WORDS];
1158 acpi_status status;
1159
1160 in[3] = HCI_WIRELESS_WWAN_STATUS;
1161 status = tci_raw(dev, in, out);
1162
1163 if (ACPI_FAILURE(status)) {
1164 pr_err("ACPI call to set WWAN status failed\n");
1165 return -EIO;
1166 }
1167
1168 if (out[0] == TOS_NOT_SUPPORTED)
1169 return -ENODEV;
1170
1171 if (out[0] != TOS_SUCCESS)
1172 return -EIO;
1173
1174 /*
1175 * Some devices only need to call HCI_WIRELESS_WWAN_STATUS to
1176 * (de)activate the device, but some others need the
1177 * HCI_WIRELESS_WWAN_POWER call as well.
1178 */
1179 in[3] = HCI_WIRELESS_WWAN_POWER;
1180 status = tci_raw(dev, in, out);
1181
1182 if (ACPI_FAILURE(status)) {
1183 pr_err("ACPI call to set WWAN power failed\n");
1184 return -EIO;
1185 }
1186
1187 if (out[0] == TOS_NOT_SUPPORTED)
1188 return -ENODEV;
1189
1190 return out[0] == TOS_SUCCESS ? 0 : -EIO;
1191}
1192
Azael Avalos3f75bbe2015-05-06 09:35:11 -06001193/* Transflective Backlight */
Azael Avalos695f6062015-07-22 18:09:13 -06001194static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status)
Akio Idehara121b7b02012-04-06 01:46:43 +09001195{
Azael Avalose1a949c2015-07-31 21:58:14 -06001196 u32 result = hci_read(dev, HCI_TR_BACKLIGHT, status);
Akio Idehara121b7b02012-04-06 01:46:43 +09001197
Azael Avalose1a949c2015-07-31 21:58:14 -06001198 if (result == TOS_FAILURE)
1199 pr_err("ACPI call to get Transflective Backlight failed\n");
1200 else if (result == TOS_NOT_SUPPORTED)
1201 return -ENODEV;
1202
1203 return result == TOS_SUCCESS ? 0 : -EIO;
Akio Idehara121b7b02012-04-06 01:46:43 +09001204}
1205
Azael Avalos695f6062015-07-22 18:09:13 -06001206static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 status)
Akio Idehara121b7b02012-04-06 01:46:43 +09001207{
Azael Avalose1a949c2015-07-31 21:58:14 -06001208 u32 result = hci_write(dev, HCI_TR_BACKLIGHT, !status);
Akio Idehara121b7b02012-04-06 01:46:43 +09001209
Azael Avalose1a949c2015-07-31 21:58:14 -06001210 if (result == TOS_FAILURE)
1211 pr_err("ACPI call to set Transflective Backlight failed\n");
1212 else if (result == TOS_NOT_SUPPORTED)
1213 return -ENODEV;
1214
1215 return result == TOS_SUCCESS ? 0 : -EIO;
Akio Idehara121b7b02012-04-06 01:46:43 +09001216}
1217
Azael Avalos3f75bbe2015-05-06 09:35:11 -06001218static struct proc_dir_entry *toshiba_proc_dir;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219
Azael Avalos3f75bbe2015-05-06 09:35:11 -06001220/* LCD Brightness */
Seth Forshee62cce752012-04-19 11:23:50 -05001221static int __get_lcd_brightness(struct toshiba_acpi_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222{
Azael Avalose1a949c2015-07-31 21:58:14 -06001223 u32 result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 u32 value;
Akio Idehara121b7b02012-04-06 01:46:43 +09001225 int brightness = 0;
1226
1227 if (dev->tr_backlight_supported) {
Azael Avalos695f6062015-07-22 18:09:13 -06001228 int ret = get_tr_backlight_status(dev, &value);
Azael Avalosb5163992015-02-10 23:43:56 -07001229
Akio Idehara121b7b02012-04-06 01:46:43 +09001230 if (ret)
1231 return ret;
Azael Avalos695f6062015-07-22 18:09:13 -06001232 if (value)
Akio Idehara121b7b02012-04-06 01:46:43 +09001233 return 0;
1234 brightness++;
1235 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
Azael Avalose1a949c2015-07-31 21:58:14 -06001237 result = hci_read(dev, HCI_LCD_BRIGHTNESS, &value);
1238 if (result == TOS_FAILURE)
1239 pr_err("ACPI call to get LCD Brightness failed\n");
1240 else if (result == TOS_NOT_SUPPORTED)
1241 return -ENODEV;
1242 if (result == TOS_SUCCESS)
Akio Idehara121b7b02012-04-06 01:46:43 +09001243 return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT);
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001244
1245 return -EIO;
Holger Machtc9263552006-10-20 14:30:29 -07001246}
1247
Seth Forshee62cce752012-04-19 11:23:50 -05001248static int get_lcd_brightness(struct backlight_device *bd)
1249{
1250 struct toshiba_acpi_dev *dev = bl_get_data(bd);
Azael Avalosb5163992015-02-10 23:43:56 -07001251
Seth Forshee62cce752012-04-19 11:23:50 -05001252 return __get_lcd_brightness(dev);
1253}
1254
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001255static int lcd_proc_show(struct seq_file *m, void *v)
Holger Machtc9263552006-10-20 14:30:29 -07001256{
Seth Forshee135740d2011-09-20 16:55:49 -05001257 struct toshiba_acpi_dev *dev = m->private;
Akio Idehara121b7b02012-04-06 01:46:43 +09001258 int levels;
Azael Avalose1a949c2015-07-31 21:58:14 -06001259 int value;
Holger Machtc9263552006-10-20 14:30:29 -07001260
Seth Forshee135740d2011-09-20 16:55:49 -05001261 if (!dev->backlight_dev)
1262 return -ENODEV;
1263
Akio Idehara121b7b02012-04-06 01:46:43 +09001264 levels = dev->backlight_dev->props.max_brightness + 1;
Seth Forshee62cce752012-04-19 11:23:50 -05001265 value = get_lcd_brightness(dev->backlight_dev);
Holger Machtc9263552006-10-20 14:30:29 -07001266 if (value >= 0) {
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001267 seq_printf(m, "brightness: %d\n", value);
Akio Idehara121b7b02012-04-06 01:46:43 +09001268 seq_printf(m, "brightness_levels: %d\n", levels);
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001269 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 }
1271
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001272 pr_err("Error reading LCD brightness\n");
Azael Avalose1a949c2015-07-31 21:58:14 -06001273
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001274 return -EIO;
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001275}
1276
1277static int lcd_proc_open(struct inode *inode, struct file *file)
1278{
Al Virod9dda782013-03-31 18:16:14 -04001279 return single_open(file, lcd_proc_show, PDE_DATA(inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280}
1281
Seth Forshee62cce752012-04-19 11:23:50 -05001282static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
Holger Machtc9263552006-10-20 14:30:29 -07001283{
Azael Avalose1a949c2015-07-31 21:58:14 -06001284 u32 result;
Holger Machtc9263552006-10-20 14:30:29 -07001285
Akio Idehara121b7b02012-04-06 01:46:43 +09001286 if (dev->tr_backlight_supported) {
Azael Avalos695f6062015-07-22 18:09:13 -06001287 int ret = set_tr_backlight_status(dev, !value);
Azael Avalosb5163992015-02-10 23:43:56 -07001288
Akio Idehara121b7b02012-04-06 01:46:43 +09001289 if (ret)
1290 return ret;
1291 if (value)
1292 value--;
1293 }
1294
Azael Avalosa39f46d2014-11-24 19:29:36 -07001295 value = value << HCI_LCD_BRIGHTNESS_SHIFT;
Azael Avalose1a949c2015-07-31 21:58:14 -06001296 result = hci_write(dev, HCI_LCD_BRIGHTNESS, value);
1297 if (result == TOS_FAILURE)
1298 pr_err("ACPI call to set LCD Brightness failed\n");
1299 else if (result == TOS_NOT_SUPPORTED)
1300 return -ENODEV;
1301
1302 return result == TOS_SUCCESS ? 0 : -EIO;
Holger Machtc9263552006-10-20 14:30:29 -07001303}
1304
1305static int set_lcd_status(struct backlight_device *bd)
1306{
Seth Forshee135740d2011-09-20 16:55:49 -05001307 struct toshiba_acpi_dev *dev = bl_get_data(bd);
Azael Avalosb5163992015-02-10 23:43:56 -07001308
Seth Forshee62cce752012-04-19 11:23:50 -05001309 return set_lcd_brightness(dev, bd->props.brightness);
Holger Machtc9263552006-10-20 14:30:29 -07001310}
1311
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001312static ssize_t lcd_proc_write(struct file *file, const char __user *buf,
1313 size_t count, loff_t *pos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314{
Al Virod9dda782013-03-31 18:16:14 -04001315 struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001316 char cmd[42];
1317 size_t len;
Akio Idehara121b7b02012-04-06 01:46:43 +09001318 int levels = dev->backlight_dev->props.max_brightness + 1;
Azael Avalose1a949c2015-07-31 21:58:14 -06001319 int value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001321 len = min(count, sizeof(cmd) - 1);
1322 if (copy_from_user(cmd, buf, len))
1323 return -EFAULT;
1324 cmd[len] = '\0';
1325
Azael Avalose1a949c2015-07-31 21:58:14 -06001326 if (sscanf(cmd, " brightness : %i", &value) != 1 &&
1327 value < 0 && value > levels)
1328 return -EINVAL;
1329
1330 if (set_lcd_brightness(dev, value))
1331 return -EIO;
1332
1333 return count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334}
1335
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001336static const struct file_operations lcd_proc_fops = {
1337 .owner = THIS_MODULE,
1338 .open = lcd_proc_open,
1339 .read = seq_read,
1340 .llseek = seq_lseek,
1341 .release = single_release,
1342 .write = lcd_proc_write,
1343};
1344
Azael Avalose1a949c2015-07-31 21:58:14 -06001345/* Video-Out */
Seth Forshee36d03f92011-09-20 16:55:53 -05001346static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status)
1347{
Azael Avalose1a949c2015-07-31 21:58:14 -06001348 u32 result = hci_read(dev, HCI_VIDEO_OUT, status);
Seth Forshee36d03f92011-09-20 16:55:53 -05001349
Azael Avalose1a949c2015-07-31 21:58:14 -06001350 if (result == TOS_FAILURE)
1351 pr_err("ACPI call to get Video-Out failed\n");
1352 else if (result == TOS_NOT_SUPPORTED)
1353 return -ENODEV;
1354
1355 return result == TOS_SUCCESS ? 0 : -EIO;
Seth Forshee36d03f92011-09-20 16:55:53 -05001356}
1357
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001358static int video_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359{
Seth Forshee135740d2011-09-20 16:55:49 -05001360 struct toshiba_acpi_dev *dev = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 u32 value;
1362
Azael Avalose1a949c2015-07-31 21:58:14 -06001363 if (!get_video_status(dev, &value)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0;
1365 int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0;
Len Brown4be44fc2005-08-05 00:44:28 -04001366 int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0;
Azael Avalosb5163992015-02-10 23:43:56 -07001367
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001368 seq_printf(m, "lcd_out: %d\n", is_lcd);
1369 seq_printf(m, "crt_out: %d\n", is_crt);
1370 seq_printf(m, "tv_out: %d\n", is_tv);
Azael Avalose1a949c2015-07-31 21:58:14 -06001371 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 }
1373
Azael Avalose1a949c2015-07-31 21:58:14 -06001374 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375}
1376
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001377static int video_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378{
Al Virod9dda782013-03-31 18:16:14 -04001379 return single_open(file, video_proc_show, PDE_DATA(inode));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001380}
1381
1382static ssize_t video_proc_write(struct file *file, const char __user *buf,
1383 size_t count, loff_t *pos)
1384{
Al Virod9dda782013-03-31 18:16:14 -04001385 struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
Azael Avalose1a949c2015-07-31 21:58:14 -06001386 char *buffer;
1387 char *cmd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 int remain = count;
1389 int lcd_out = -1;
1390 int crt_out = -1;
1391 int tv_out = -1;
Azael Avalose1a949c2015-07-31 21:58:14 -06001392 int value;
1393 int ret;
Al Virob4482a42007-10-14 19:35:40 +01001394 u32 video_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001396 cmd = kmalloc(count + 1, GFP_KERNEL);
1397 if (!cmd)
1398 return -ENOMEM;
1399 if (copy_from_user(cmd, buf, count)) {
1400 kfree(cmd);
1401 return -EFAULT;
1402 }
1403 cmd[count] = '\0';
1404
1405 buffer = cmd;
1406
Darren Harte0769fe2015-02-11 20:50:08 -08001407 /*
1408 * Scan expression. Multiple expressions may be delimited with ;
1409 * NOTE: To keep scanning simple, invalid fields are ignored.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 */
1411 while (remain) {
1412 if (sscanf(buffer, " lcd_out : %i", &value) == 1)
1413 lcd_out = value & 1;
1414 else if (sscanf(buffer, " crt_out : %i", &value) == 1)
1415 crt_out = value & 1;
1416 else if (sscanf(buffer, " tv_out : %i", &value) == 1)
1417 tv_out = value & 1;
Darren Harte0769fe2015-02-11 20:50:08 -08001418 /* Advance to one character past the next ; */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419 do {
1420 ++buffer;
1421 --remain;
Azael Avalosb5163992015-02-10 23:43:56 -07001422 } while (remain && *(buffer - 1) != ';');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 }
1424
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001425 kfree(cmd);
1426
Seth Forshee36d03f92011-09-20 16:55:53 -05001427 ret = get_video_status(dev, &video_out);
1428 if (!ret) {
Harvey Harrison9e113e02008-09-22 14:37:29 -07001429 unsigned int new_video_out = video_out;
Azael Avalosb5163992015-02-10 23:43:56 -07001430
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 if (lcd_out != -1)
1432 _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out);
1433 if (crt_out != -1)
1434 _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out);
1435 if (tv_out != -1)
1436 _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out);
Darren Harte0769fe2015-02-11 20:50:08 -08001437 /*
1438 * To avoid unnecessary video disruption, only write the new
Azael Avalos3f75bbe2015-05-06 09:35:11 -06001439 * video setting if something changed.
1440 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 if (new_video_out != video_out)
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001442 ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 }
1444
Azael Avalose1a949c2015-07-31 21:58:14 -06001445 return ret ? -EIO : count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446}
1447
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001448static const struct file_operations video_proc_fops = {
1449 .owner = THIS_MODULE,
1450 .open = video_proc_open,
1451 .read = seq_read,
1452 .llseek = seq_lseek,
1453 .release = single_release,
1454 .write = video_proc_write,
1455};
1456
Azael Avalos3e07e5b2015-07-27 19:22:23 -06001457/* Fan status */
Seth Forshee36d03f92011-09-20 16:55:53 -05001458static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status)
1459{
Azael Avalos3e07e5b2015-07-27 19:22:23 -06001460 u32 result = hci_read(dev, HCI_FAN, status);
Seth Forshee36d03f92011-09-20 16:55:53 -05001461
Azael Avalos3e07e5b2015-07-27 19:22:23 -06001462 if (result == TOS_FAILURE)
1463 pr_err("ACPI call to get Fan status failed\n");
1464 else if (result == TOS_NOT_SUPPORTED)
1465 return -ENODEV;
Azael Avalos3e07e5b2015-07-27 19:22:23 -06001466
Azael Avalose1a949c2015-07-31 21:58:14 -06001467 return result == TOS_SUCCESS ? 0 : -EIO;
Azael Avalos3e07e5b2015-07-27 19:22:23 -06001468}
1469
1470static int set_fan_status(struct toshiba_acpi_dev *dev, u32 status)
1471{
1472 u32 result = hci_write(dev, HCI_FAN, status);
1473
1474 if (result == TOS_FAILURE)
1475 pr_err("ACPI call to set Fan status failed\n");
1476 else if (result == TOS_NOT_SUPPORTED)
1477 return -ENODEV;
Azael Avalos3e07e5b2015-07-27 19:22:23 -06001478
Azael Avalose1a949c2015-07-31 21:58:14 -06001479 return result == TOS_SUCCESS ? 0 : -EIO;
Seth Forshee36d03f92011-09-20 16:55:53 -05001480}
1481
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001482static int fan_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483{
Seth Forshee135740d2011-09-20 16:55:49 -05001484 struct toshiba_acpi_dev *dev = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 u32 value;
1486
Azael Avalos3e07e5b2015-07-27 19:22:23 -06001487 if (get_fan_status(dev, &value))
1488 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489
Azael Avalos3e07e5b2015-07-27 19:22:23 -06001490 seq_printf(m, "running: %d\n", (value > 0));
1491 seq_printf(m, "force_on: %d\n", dev->force_fan);
1492
1493 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494}
1495
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001496static int fan_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497{
Al Virod9dda782013-03-31 18:16:14 -04001498 return single_open(file, fan_proc_show, PDE_DATA(inode));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001499}
1500
1501static ssize_t fan_proc_write(struct file *file, const char __user *buf,
1502 size_t count, loff_t *pos)
1503{
Al Virod9dda782013-03-31 18:16:14 -04001504 struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001505 char cmd[42];
1506 size_t len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 int value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001509 len = min(count, sizeof(cmd) - 1);
1510 if (copy_from_user(cmd, buf, len))
1511 return -EFAULT;
1512 cmd[len] = '\0';
1513
Azael Avalos3e07e5b2015-07-27 19:22:23 -06001514 if (sscanf(cmd, " force_on : %i", &value) != 1 &&
1515 value != 0 && value != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 return -EINVAL;
Azael Avalos3e07e5b2015-07-27 19:22:23 -06001517
1518 if (set_fan_status(dev, value))
1519 return -EIO;
1520
1521 dev->force_fan = value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522
1523 return count;
1524}
1525
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001526static const struct file_operations fan_proc_fops = {
1527 .owner = THIS_MODULE,
1528 .open = fan_proc_open,
1529 .read = seq_read,
1530 .llseek = seq_lseek,
1531 .release = single_release,
1532 .write = fan_proc_write,
1533};
1534
1535static int keys_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536{
Seth Forshee135740d2011-09-20 16:55:49 -05001537 struct toshiba_acpi_dev *dev = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538
Seth Forshee135740d2011-09-20 16:55:49 -05001539 seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid);
1540 seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event);
Azael Avalos7deef552015-07-22 18:09:10 -06001541
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001542 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543}
1544
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001545static int keys_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546{
Al Virod9dda782013-03-31 18:16:14 -04001547 return single_open(file, keys_proc_show, PDE_DATA(inode));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001548}
1549
1550static ssize_t keys_proc_write(struct file *file, const char __user *buf,
1551 size_t count, loff_t *pos)
1552{
Al Virod9dda782013-03-31 18:16:14 -04001553 struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001554 char cmd[42];
1555 size_t len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 int value;
1557
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001558 len = min(count, sizeof(cmd) - 1);
1559 if (copy_from_user(cmd, buf, len))
1560 return -EFAULT;
1561 cmd[len] = '\0';
1562
Azael Avalosb5163992015-02-10 23:43:56 -07001563 if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0)
Seth Forshee135740d2011-09-20 16:55:49 -05001564 dev->key_event_valid = 0;
Azael Avalosb5163992015-02-10 23:43:56 -07001565 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567
1568 return count;
1569}
1570
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001571static const struct file_operations keys_proc_fops = {
1572 .owner = THIS_MODULE,
1573 .open = keys_proc_open,
1574 .read = seq_read,
1575 .llseek = seq_lseek,
1576 .release = single_release,
1577 .write = keys_proc_write,
1578};
1579
1580static int version_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581{
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001582 seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION);
1583 seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION);
1584 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585}
1586
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001587static int version_proc_open(struct inode *inode, struct file *file)
1588{
Al Virod9dda782013-03-31 18:16:14 -04001589 return single_open(file, version_proc_show, PDE_DATA(inode));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001590}
1591
1592static const struct file_operations version_proc_fops = {
1593 .owner = THIS_MODULE,
1594 .open = version_proc_open,
1595 .read = seq_read,
1596 .llseek = seq_lseek,
1597 .release = single_release,
1598};
1599
Darren Harte0769fe2015-02-11 20:50:08 -08001600/*
1601 * Proc and module init
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 */
1603
1604#define PROC_TOSHIBA "toshiba"
1605
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08001606static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607{
Seth Forshee36d03f92011-09-20 16:55:53 -05001608 if (dev->backlight_dev)
1609 proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1610 &lcd_proc_fops, dev);
1611 if (dev->video_supported)
1612 proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1613 &video_proc_fops, dev);
1614 if (dev->fan_supported)
1615 proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1616 &fan_proc_fops, dev);
1617 if (dev->hotkey_dev)
1618 proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1619 &keys_proc_fops, dev);
Seth Forshee135740d2011-09-20 16:55:49 -05001620 proc_create_data("version", S_IRUGO, toshiba_proc_dir,
1621 &version_proc_fops, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622}
1623
Seth Forshee36d03f92011-09-20 16:55:53 -05001624static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625{
Seth Forshee36d03f92011-09-20 16:55:53 -05001626 if (dev->backlight_dev)
1627 remove_proc_entry("lcd", toshiba_proc_dir);
1628 if (dev->video_supported)
1629 remove_proc_entry("video", toshiba_proc_dir);
1630 if (dev->fan_supported)
1631 remove_proc_entry("fan", toshiba_proc_dir);
1632 if (dev->hotkey_dev)
1633 remove_proc_entry("keys", toshiba_proc_dir);
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001634 remove_proc_entry("version", toshiba_proc_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635}
1636
Lionel Debrouxacc24722010-11-16 14:14:02 +01001637static const struct backlight_ops toshiba_backlight_data = {
Akio Idehara121b7b02012-04-06 01:46:43 +09001638 .options = BL_CORE_SUSPENDRESUME,
Seth Forshee62cce752012-04-19 11:23:50 -05001639 .get_brightness = get_lcd_brightness,
1640 .update_status = set_lcd_status,
Holger Machtc9263552006-10-20 14:30:29 -07001641};
Matthew Garrettea6b31f2014-04-04 14:22:34 -04001642
Azael Avalos360f0f32014-03-25 20:38:31 -06001643/*
1644 * Sysfs files
1645 */
Azael Avalos9d309842015-02-10 23:43:59 -07001646static ssize_t version_show(struct device *dev,
1647 struct device_attribute *attr, char *buf)
Azael Avalosc6c68ff2015-02-10 21:09:16 -07001648{
1649 return sprintf(buf, "%s\n", TOSHIBA_ACPI_VERSION);
1650}
Azael Avalos0c3c0f12015-02-10 23:44:00 -07001651static DEVICE_ATTR_RO(version);
Azael Avalosc6c68ff2015-02-10 21:09:16 -07001652
Azael Avalos9d309842015-02-10 23:43:59 -07001653static ssize_t fan_store(struct device *dev,
1654 struct device_attribute *attr,
1655 const char *buf, size_t count)
Azael Avalos94477d42015-02-10 21:09:17 -07001656{
1657 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
Azael Avalos94477d42015-02-10 21:09:17 -07001658 int state;
1659 int ret;
1660
1661 ret = kstrtoint(buf, 0, &state);
1662 if (ret)
1663 return ret;
1664
1665 if (state != 0 && state != 1)
1666 return -EINVAL;
1667
Azael Avalos3e07e5b2015-07-27 19:22:23 -06001668 ret = set_fan_status(toshiba, state);
1669 if (ret)
1670 return ret;
Azael Avalos94477d42015-02-10 21:09:17 -07001671
1672 return count;
1673}
1674
Azael Avalos9d309842015-02-10 23:43:59 -07001675static ssize_t fan_show(struct device *dev,
1676 struct device_attribute *attr, char *buf)
Azael Avalos94477d42015-02-10 21:09:17 -07001677{
1678 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1679 u32 value;
1680 int ret;
1681
1682 ret = get_fan_status(toshiba, &value);
1683 if (ret)
1684 return ret;
1685
1686 return sprintf(buf, "%d\n", value);
1687}
Azael Avalos0c3c0f12015-02-10 23:44:00 -07001688static DEVICE_ATTR_RW(fan);
Azael Avalos94477d42015-02-10 21:09:17 -07001689
Azael Avalos9d309842015-02-10 23:43:59 -07001690static ssize_t kbd_backlight_mode_store(struct device *dev,
1691 struct device_attribute *attr,
1692 const char *buf, size_t count)
Azael Avalos360f0f32014-03-25 20:38:31 -06001693{
1694 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
Dan Carpenteraeaac092014-09-03 14:44:37 +03001695 int mode;
Dan Carpenteraeaac092014-09-03 14:44:37 +03001696 int ret;
Azael Avalos360f0f32014-03-25 20:38:31 -06001697
Dan Carpenteraeaac092014-09-03 14:44:37 +03001698
1699 ret = kstrtoint(buf, 0, &mode);
1700 if (ret)
1701 return ret;
Azael Avalos93f8c162014-09-12 18:50:36 -06001702
1703 /* Check for supported modes depending on keyboard backlight type */
1704 if (toshiba->kbd_type == 1) {
1705 /* Type 1 supports SCI_KBD_MODE_FNZ and SCI_KBD_MODE_AUTO */
1706 if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO)
1707 return -EINVAL;
1708 } else if (toshiba->kbd_type == 2) {
1709 /* Type 2 doesn't support SCI_KBD_MODE_FNZ */
1710 if (mode != SCI_KBD_MODE_AUTO && mode != SCI_KBD_MODE_ON &&
1711 mode != SCI_KBD_MODE_OFF)
1712 return -EINVAL;
1713 }
Azael Avalos360f0f32014-03-25 20:38:31 -06001714
Darren Harte0769fe2015-02-11 20:50:08 -08001715 /*
1716 * Set the Keyboard Backlight Mode where:
Azael Avalos360f0f32014-03-25 20:38:31 -06001717 * Auto - KBD backlight turns off automatically in given time
1718 * FN-Z - KBD backlight "toggles" when hotkey pressed
Azael Avalos93f8c162014-09-12 18:50:36 -06001719 * ON - KBD backlight is always on
1720 * OFF - KBD backlight is always off
Azael Avalos360f0f32014-03-25 20:38:31 -06001721 */
Azael Avalos93f8c162014-09-12 18:50:36 -06001722
1723 /* Only make a change if the actual mode has changed */
Dan Carpenteraeaac092014-09-03 14:44:37 +03001724 if (toshiba->kbd_mode != mode) {
Azael Avalos93f8c162014-09-12 18:50:36 -06001725 /* Shift the time to "base time" (0x3c0000 == 60 seconds) */
Azael Avalos1e574db2015-07-22 19:37:49 -06001726 int time = toshiba->kbd_time << HCI_MISC_SHIFT;
Azael Avalos93f8c162014-09-12 18:50:36 -06001727
1728 /* OR the "base time" to the actual method format */
1729 if (toshiba->kbd_type == 1) {
1730 /* Type 1 requires the current mode */
1731 time |= toshiba->kbd_mode;
1732 } else if (toshiba->kbd_type == 2) {
1733 /* Type 2 requires the desired mode */
1734 time |= mode;
1735 }
1736
Dan Carpenteraeaac092014-09-03 14:44:37 +03001737 ret = toshiba_kbd_illum_status_set(toshiba, time);
1738 if (ret)
1739 return ret;
Azael Avalos93f8c162014-09-12 18:50:36 -06001740
Azael Avalos360f0f32014-03-25 20:38:31 -06001741 toshiba->kbd_mode = mode;
1742 }
1743
1744 return count;
1745}
1746
Azael Avalos9d309842015-02-10 23:43:59 -07001747static ssize_t kbd_backlight_mode_show(struct device *dev,
1748 struct device_attribute *attr,
1749 char *buf)
Azael Avalos360f0f32014-03-25 20:38:31 -06001750{
1751 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1752 u32 time;
1753
1754 if (toshiba_kbd_illum_status_get(toshiba, &time) < 0)
1755 return -EIO;
1756
Azael Avalos93f8c162014-09-12 18:50:36 -06001757 return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK);
1758}
Azael Avalos0c3c0f12015-02-10 23:44:00 -07001759static DEVICE_ATTR_RW(kbd_backlight_mode);
Azael Avalos93f8c162014-09-12 18:50:36 -06001760
Azael Avalos9d309842015-02-10 23:43:59 -07001761static ssize_t kbd_type_show(struct device *dev,
1762 struct device_attribute *attr, char *buf)
Azael Avalos93f8c162014-09-12 18:50:36 -06001763{
1764 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1765
1766 return sprintf(buf, "%d\n", toshiba->kbd_type);
1767}
Azael Avalos0c3c0f12015-02-10 23:44:00 -07001768static DEVICE_ATTR_RO(kbd_type);
Azael Avalos93f8c162014-09-12 18:50:36 -06001769
Azael Avalos9d309842015-02-10 23:43:59 -07001770static ssize_t available_kbd_modes_show(struct device *dev,
1771 struct device_attribute *attr,
1772 char *buf)
Azael Avalos93f8c162014-09-12 18:50:36 -06001773{
1774 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1775
1776 if (toshiba->kbd_type == 1)
Azael Avalos0b498202015-09-09 11:30:09 -06001777 return sprintf(buf, "0x%x 0x%x\n",
Azael Avalos93f8c162014-09-12 18:50:36 -06001778 SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO);
1779
Azael Avalos0b498202015-09-09 11:30:09 -06001780 return sprintf(buf, "0x%x 0x%x 0x%x\n",
Azael Avalos93f8c162014-09-12 18:50:36 -06001781 SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF);
Azael Avalos360f0f32014-03-25 20:38:31 -06001782}
Azael Avalos0c3c0f12015-02-10 23:44:00 -07001783static DEVICE_ATTR_RO(available_kbd_modes);
Azael Avalos360f0f32014-03-25 20:38:31 -06001784
Azael Avalos9d309842015-02-10 23:43:59 -07001785static ssize_t kbd_backlight_timeout_store(struct device *dev,
1786 struct device_attribute *attr,
1787 const char *buf, size_t count)
Azael Avalos360f0f32014-03-25 20:38:31 -06001788{
1789 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
Azael Avaloseabde0f2014-10-04 12:02:21 -06001790 int time;
1791 int ret;
Azael Avalos360f0f32014-03-25 20:38:31 -06001792
Azael Avaloseabde0f2014-10-04 12:02:21 -06001793 ret = kstrtoint(buf, 0, &time);
1794 if (ret)
1795 return ret;
Azael Avalos360f0f32014-03-25 20:38:31 -06001796
Azael Avaloseabde0f2014-10-04 12:02:21 -06001797 /* Check for supported values depending on kbd_type */
1798 if (toshiba->kbd_type == 1) {
1799 if (time < 0 || time > 60)
1800 return -EINVAL;
1801 } else if (toshiba->kbd_type == 2) {
1802 if (time < 1 || time > 60)
1803 return -EINVAL;
1804 }
1805
1806 /* Set the Keyboard Backlight Timeout */
1807
1808 /* Only make a change if the actual timeout has changed */
1809 if (toshiba->kbd_time != time) {
1810 /* Shift the time to "base time" (0x3c0000 == 60 seconds) */
Azael Avalos360f0f32014-03-25 20:38:31 -06001811 time = time << HCI_MISC_SHIFT;
Azael Avaloseabde0f2014-10-04 12:02:21 -06001812 /* OR the "base time" to the actual method format */
1813 if (toshiba->kbd_type == 1)
1814 time |= SCI_KBD_MODE_FNZ;
1815 else if (toshiba->kbd_type == 2)
1816 time |= SCI_KBD_MODE_AUTO;
1817
1818 ret = toshiba_kbd_illum_status_set(toshiba, time);
1819 if (ret)
1820 return ret;
1821
Azael Avalos360f0f32014-03-25 20:38:31 -06001822 toshiba->kbd_time = time >> HCI_MISC_SHIFT;
1823 }
1824
1825 return count;
1826}
1827
Azael Avalos9d309842015-02-10 23:43:59 -07001828static ssize_t kbd_backlight_timeout_show(struct device *dev,
1829 struct device_attribute *attr,
1830 char *buf)
Azael Avalos360f0f32014-03-25 20:38:31 -06001831{
1832 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1833 u32 time;
1834
1835 if (toshiba_kbd_illum_status_get(toshiba, &time) < 0)
1836 return -EIO;
1837
1838 return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT);
1839}
Azael Avalos0c3c0f12015-02-10 23:44:00 -07001840static DEVICE_ATTR_RW(kbd_backlight_timeout);
Matthew Garrettea6b31f2014-04-04 14:22:34 -04001841
Azael Avalos9d309842015-02-10 23:43:59 -07001842static ssize_t touchpad_store(struct device *dev,
1843 struct device_attribute *attr,
1844 const char *buf, size_t count)
Azael Avalos9d8658a2014-03-25 20:38:32 -06001845{
1846 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1847 int state;
Azael Avalosc8a41662014-09-10 21:01:57 -06001848 int ret;
Azael Avalos9d8658a2014-03-25 20:38:32 -06001849
1850 /* Set the TouchPad on/off, 0 - Disable | 1 - Enable */
Azael Avalosc8a41662014-09-10 21:01:57 -06001851 ret = kstrtoint(buf, 0, &state);
1852 if (ret)
1853 return ret;
1854 if (state != 0 && state != 1)
1855 return -EINVAL;
1856
1857 ret = toshiba_touchpad_set(toshiba, state);
1858 if (ret)
1859 return ret;
Azael Avalos9d8658a2014-03-25 20:38:32 -06001860
1861 return count;
1862}
1863
Azael Avalos9d309842015-02-10 23:43:59 -07001864static ssize_t touchpad_show(struct device *dev,
1865 struct device_attribute *attr, char *buf)
Azael Avalos9d8658a2014-03-25 20:38:32 -06001866{
1867 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1868 u32 state;
1869 int ret;
1870
1871 ret = toshiba_touchpad_get(toshiba, &state);
1872 if (ret < 0)
1873 return ret;
1874
1875 return sprintf(buf, "%i\n", state);
1876}
Azael Avalos0c3c0f12015-02-10 23:44:00 -07001877static DEVICE_ATTR_RW(touchpad);
Matthew Garrettea6b31f2014-04-04 14:22:34 -04001878
Azael Avalos9d309842015-02-10 23:43:59 -07001879static ssize_t position_show(struct device *dev,
1880 struct device_attribute *attr, char *buf)
Azael Avalos5a2813e2014-03-25 20:38:34 -06001881{
1882 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1883 u32 xyval, zval, tmp;
1884 u16 x, y, z;
1885 int ret;
1886
1887 xyval = zval = 0;
1888 ret = toshiba_accelerometer_get(toshiba, &xyval, &zval);
1889 if (ret < 0)
1890 return ret;
1891
1892 x = xyval & HCI_ACCEL_MASK;
1893 tmp = xyval >> HCI_MISC_SHIFT;
1894 y = tmp & HCI_ACCEL_MASK;
1895 z = zval & HCI_ACCEL_MASK;
1896
1897 return sprintf(buf, "%d %d %d\n", x, y, z);
1898}
Azael Avalos0c3c0f12015-02-10 23:44:00 -07001899static DEVICE_ATTR_RO(position);
Azael Avalos360f0f32014-03-25 20:38:31 -06001900
Azael Avalos9d309842015-02-10 23:43:59 -07001901static ssize_t usb_sleep_charge_show(struct device *dev,
1902 struct device_attribute *attr, char *buf)
Azael Avalose26ffe52015-01-18 18:30:22 -07001903{
1904 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1905 u32 mode;
1906 int ret;
1907
1908 ret = toshiba_usb_sleep_charge_get(toshiba, &mode);
1909 if (ret < 0)
1910 return ret;
1911
1912 return sprintf(buf, "%x\n", mode & SCI_USB_CHARGE_MODE_MASK);
1913}
1914
Azael Avalos9d309842015-02-10 23:43:59 -07001915static ssize_t usb_sleep_charge_store(struct device *dev,
1916 struct device_attribute *attr,
1917 const char *buf, size_t count)
Azael Avalose26ffe52015-01-18 18:30:22 -07001918{
1919 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1920 u32 mode;
1921 int state;
1922 int ret;
1923
1924 ret = kstrtoint(buf, 0, &state);
1925 if (ret)
1926 return ret;
Darren Harte0769fe2015-02-11 20:50:08 -08001927 /*
1928 * Check for supported values, where:
Azael Avalose26ffe52015-01-18 18:30:22 -07001929 * 0 - Disabled
1930 * 1 - Alternate (Non USB conformant devices that require more power)
1931 * 2 - Auto (USB conformant devices)
Azael Avalosc8c91842015-04-02 19:26:20 -06001932 * 3 - Typical
Azael Avalose26ffe52015-01-18 18:30:22 -07001933 */
Azael Avalosc8c91842015-04-02 19:26:20 -06001934 if (state != 0 && state != 1 && state != 2 && state != 3)
Azael Avalose26ffe52015-01-18 18:30:22 -07001935 return -EINVAL;
1936
1937 /* Set the USB charging mode to internal value */
Azael Avalosc8c91842015-04-02 19:26:20 -06001938 mode = toshiba->usbsc_mode_base;
Azael Avalose26ffe52015-01-18 18:30:22 -07001939 if (state == 0)
Azael Avalosc8c91842015-04-02 19:26:20 -06001940 mode |= SCI_USB_CHARGE_DISABLED;
Azael Avalose26ffe52015-01-18 18:30:22 -07001941 else if (state == 1)
Azael Avalosc8c91842015-04-02 19:26:20 -06001942 mode |= SCI_USB_CHARGE_ALTERNATE;
Azael Avalose26ffe52015-01-18 18:30:22 -07001943 else if (state == 2)
Azael Avalosc8c91842015-04-02 19:26:20 -06001944 mode |= SCI_USB_CHARGE_AUTO;
1945 else if (state == 3)
1946 mode |= SCI_USB_CHARGE_TYPICAL;
Azael Avalose26ffe52015-01-18 18:30:22 -07001947
1948 ret = toshiba_usb_sleep_charge_set(toshiba, mode);
1949 if (ret)
1950 return ret;
1951
1952 return count;
1953}
Azael Avalos0c3c0f12015-02-10 23:44:00 -07001954static DEVICE_ATTR_RW(usb_sleep_charge);
Azael Avalose26ffe52015-01-18 18:30:22 -07001955
Azael Avalos182bcaa2015-01-18 18:30:23 -07001956static ssize_t sleep_functions_on_battery_show(struct device *dev,
1957 struct device_attribute *attr,
1958 char *buf)
1959{
1960 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1961 u32 state;
1962 int bat_lvl;
1963 int status;
1964 int ret;
1965 int tmp;
1966
1967 ret = toshiba_sleep_functions_status_get(toshiba, &state);
1968 if (ret < 0)
1969 return ret;
1970
1971 /* Determine the status: 0x4 - Enabled | 0x1 - Disabled */
1972 tmp = state & SCI_USB_CHARGE_BAT_MASK;
1973 status = (tmp == 0x4) ? 1 : 0;
1974 /* Determine the battery level set */
1975 bat_lvl = state >> HCI_MISC_SHIFT;
1976
1977 return sprintf(buf, "%d %d\n", status, bat_lvl);
1978}
1979
1980static ssize_t sleep_functions_on_battery_store(struct device *dev,
1981 struct device_attribute *attr,
1982 const char *buf, size_t count)
1983{
1984 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1985 u32 status;
1986 int value;
1987 int ret;
1988 int tmp;
1989
1990 ret = kstrtoint(buf, 0, &value);
1991 if (ret)
1992 return ret;
1993
Darren Harte0769fe2015-02-11 20:50:08 -08001994 /*
1995 * Set the status of the function:
Azael Avalos182bcaa2015-01-18 18:30:23 -07001996 * 0 - Disabled
1997 * 1-100 - Enabled
1998 */
1999 if (value < 0 || value > 100)
2000 return -EINVAL;
2001
2002 if (value == 0) {
2003 tmp = toshiba->usbsc_bat_level << HCI_MISC_SHIFT;
2004 status = tmp | SCI_USB_CHARGE_BAT_LVL_OFF;
2005 } else {
2006 tmp = value << HCI_MISC_SHIFT;
2007 status = tmp | SCI_USB_CHARGE_BAT_LVL_ON;
2008 }
2009 ret = toshiba_sleep_functions_status_set(toshiba, status);
2010 if (ret < 0)
2011 return ret;
2012
2013 toshiba->usbsc_bat_level = status >> HCI_MISC_SHIFT;
2014
2015 return count;
2016}
Azael Avalos0c3c0f12015-02-10 23:44:00 -07002017static DEVICE_ATTR_RW(sleep_functions_on_battery);
Azael Avalos182bcaa2015-01-18 18:30:23 -07002018
Azael Avalos9d309842015-02-10 23:43:59 -07002019static ssize_t usb_rapid_charge_show(struct device *dev,
2020 struct device_attribute *attr, char *buf)
Azael Avalosbb3fe012015-01-18 18:30:24 -07002021{
2022 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2023 u32 state;
2024 int ret;
2025
2026 ret = toshiba_usb_rapid_charge_get(toshiba, &state);
2027 if (ret < 0)
2028 return ret;
2029
2030 return sprintf(buf, "%d\n", state);
2031}
2032
Azael Avalos9d309842015-02-10 23:43:59 -07002033static ssize_t usb_rapid_charge_store(struct device *dev,
2034 struct device_attribute *attr,
2035 const char *buf, size_t count)
Azael Avalosbb3fe012015-01-18 18:30:24 -07002036{
2037 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2038 int state;
2039 int ret;
2040
2041 ret = kstrtoint(buf, 0, &state);
2042 if (ret)
2043 return ret;
2044 if (state != 0 && state != 1)
2045 return -EINVAL;
2046
2047 ret = toshiba_usb_rapid_charge_set(toshiba, state);
2048 if (ret)
2049 return ret;
2050
2051 return count;
2052}
Azael Avalos0c3c0f12015-02-10 23:44:00 -07002053static DEVICE_ATTR_RW(usb_rapid_charge);
Azael Avalosbb3fe012015-01-18 18:30:24 -07002054
Azael Avalos9d309842015-02-10 23:43:59 -07002055static ssize_t usb_sleep_music_show(struct device *dev,
2056 struct device_attribute *attr, char *buf)
Azael Avalos172ce0a2015-01-18 18:30:25 -07002057{
2058 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2059 u32 state;
2060 int ret;
2061
2062 ret = toshiba_usb_sleep_music_get(toshiba, &state);
2063 if (ret < 0)
2064 return ret;
2065
2066 return sprintf(buf, "%d\n", state);
2067}
2068
Azael Avalos9d309842015-02-10 23:43:59 -07002069static ssize_t usb_sleep_music_store(struct device *dev,
2070 struct device_attribute *attr,
2071 const char *buf, size_t count)
Azael Avalos172ce0a2015-01-18 18:30:25 -07002072{
2073 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2074 int state;
2075 int ret;
2076
2077 ret = kstrtoint(buf, 0, &state);
2078 if (ret)
2079 return ret;
2080 if (state != 0 && state != 1)
2081 return -EINVAL;
2082
2083 ret = toshiba_usb_sleep_music_set(toshiba, state);
2084 if (ret)
2085 return ret;
2086
2087 return count;
2088}
Azael Avalos0c3c0f12015-02-10 23:44:00 -07002089static DEVICE_ATTR_RW(usb_sleep_music);
Azael Avalos172ce0a2015-01-18 18:30:25 -07002090
Azael Avalos9d309842015-02-10 23:43:59 -07002091static ssize_t kbd_function_keys_show(struct device *dev,
2092 struct device_attribute *attr, char *buf)
Azael Avalosbae84192015-02-10 21:09:18 -07002093{
2094 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2095 int mode;
2096 int ret;
2097
2098 ret = toshiba_function_keys_get(toshiba, &mode);
2099 if (ret < 0)
2100 return ret;
2101
2102 return sprintf(buf, "%d\n", mode);
2103}
2104
Azael Avalos9d309842015-02-10 23:43:59 -07002105static ssize_t kbd_function_keys_store(struct device *dev,
2106 struct device_attribute *attr,
2107 const char *buf, size_t count)
Azael Avalosbae84192015-02-10 21:09:18 -07002108{
2109 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2110 int mode;
2111 int ret;
2112
2113 ret = kstrtoint(buf, 0, &mode);
2114 if (ret)
2115 return ret;
Darren Harte0769fe2015-02-11 20:50:08 -08002116 /*
2117 * Check for the function keys mode where:
Azael Avalosbae84192015-02-10 21:09:18 -07002118 * 0 - Normal operation (F{1-12} as usual and hotkeys via FN-F{1-12})
2119 * 1 - Special functions (Opposite of the above setting)
2120 */
2121 if (mode != 0 && mode != 1)
2122 return -EINVAL;
2123
2124 ret = toshiba_function_keys_set(toshiba, mode);
2125 if (ret)
2126 return ret;
2127
2128 pr_info("Reboot for changes to KBD Function Keys to take effect");
2129
2130 return count;
2131}
Azael Avalos0c3c0f12015-02-10 23:44:00 -07002132static DEVICE_ATTR_RW(kbd_function_keys);
Azael Avalosbae84192015-02-10 21:09:18 -07002133
Azael Avalos9d309842015-02-10 23:43:59 -07002134static ssize_t panel_power_on_show(struct device *dev,
2135 struct device_attribute *attr, char *buf)
Azael Avalos35d53ce2015-02-10 21:09:19 -07002136{
2137 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2138 u32 state;
2139 int ret;
2140
2141 ret = toshiba_panel_power_on_get(toshiba, &state);
2142 if (ret < 0)
2143 return ret;
2144
2145 return sprintf(buf, "%d\n", state);
2146}
2147
Azael Avalos9d309842015-02-10 23:43:59 -07002148static ssize_t panel_power_on_store(struct device *dev,
2149 struct device_attribute *attr,
2150 const char *buf, size_t count)
Azael Avalos35d53ce2015-02-10 21:09:19 -07002151{
2152 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2153 int state;
2154 int ret;
2155
2156 ret = kstrtoint(buf, 0, &state);
2157 if (ret)
2158 return ret;
2159 if (state != 0 && state != 1)
2160 return -EINVAL;
2161
2162 ret = toshiba_panel_power_on_set(toshiba, state);
2163 if (ret)
2164 return ret;
2165
2166 pr_info("Reboot for changes to Panel Power ON to take effect");
2167
2168 return count;
2169}
Azael Avalos0c3c0f12015-02-10 23:44:00 -07002170static DEVICE_ATTR_RW(panel_power_on);
Azael Avalos35d53ce2015-02-10 21:09:19 -07002171
Azael Avalos9d309842015-02-10 23:43:59 -07002172static ssize_t usb_three_show(struct device *dev,
2173 struct device_attribute *attr, char *buf)
Azael Avalos17fe4b32015-02-10 21:09:20 -07002174{
2175 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2176 u32 state;
2177 int ret;
2178
2179 ret = toshiba_usb_three_get(toshiba, &state);
2180 if (ret < 0)
2181 return ret;
2182
2183 return sprintf(buf, "%d\n", state);
2184}
2185
Azael Avalos9d309842015-02-10 23:43:59 -07002186static ssize_t usb_three_store(struct device *dev,
2187 struct device_attribute *attr,
2188 const char *buf, size_t count)
Azael Avalos17fe4b32015-02-10 21:09:20 -07002189{
2190 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2191 int state;
2192 int ret;
2193
2194 ret = kstrtoint(buf, 0, &state);
2195 if (ret)
2196 return ret;
Darren Harte0769fe2015-02-11 20:50:08 -08002197 /*
2198 * Check for USB 3 mode where:
Azael Avalos17fe4b32015-02-10 21:09:20 -07002199 * 0 - Disabled (Acts like a USB 2 port, saving power)
2200 * 1 - Enabled
2201 */
2202 if (state != 0 && state != 1)
2203 return -EINVAL;
2204
2205 ret = toshiba_usb_three_set(toshiba, state);
2206 if (ret)
2207 return ret;
2208
2209 pr_info("Reboot for changes to USB 3 to take effect");
2210
2211 return count;
2212}
Azael Avalos0c3c0f12015-02-10 23:44:00 -07002213static DEVICE_ATTR_RW(usb_three);
Azael Avalos9bd12132015-02-10 23:43:58 -07002214
2215static struct attribute *toshiba_attributes[] = {
2216 &dev_attr_version.attr,
2217 &dev_attr_fan.attr,
2218 &dev_attr_kbd_backlight_mode.attr,
2219 &dev_attr_kbd_type.attr,
2220 &dev_attr_available_kbd_modes.attr,
2221 &dev_attr_kbd_backlight_timeout.attr,
2222 &dev_attr_touchpad.attr,
2223 &dev_attr_position.attr,
2224 &dev_attr_usb_sleep_charge.attr,
2225 &dev_attr_sleep_functions_on_battery.attr,
2226 &dev_attr_usb_rapid_charge.attr,
2227 &dev_attr_usb_sleep_music.attr,
2228 &dev_attr_kbd_function_keys.attr,
2229 &dev_attr_panel_power_on.attr,
2230 &dev_attr_usb_three.attr,
2231 NULL,
2232};
2233
Azael Avalos360f0f32014-03-25 20:38:31 -06002234static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
2235 struct attribute *attr, int idx)
2236{
2237 struct device *dev = container_of(kobj, struct device, kobj);
2238 struct toshiba_acpi_dev *drv = dev_get_drvdata(dev);
2239 bool exists = true;
2240
Azael Avalos94477d42015-02-10 21:09:17 -07002241 if (attr == &dev_attr_fan.attr)
2242 exists = (drv->fan_supported) ? true : false;
2243 else if (attr == &dev_attr_kbd_backlight_mode.attr)
Azael Avalos360f0f32014-03-25 20:38:31 -06002244 exists = (drv->kbd_illum_supported) ? true : false;
2245 else if (attr == &dev_attr_kbd_backlight_timeout.attr)
2246 exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false;
Azael Avalos9d8658a2014-03-25 20:38:32 -06002247 else if (attr == &dev_attr_touchpad.attr)
2248 exists = (drv->touchpad_supported) ? true : false;
Azael Avalos5a2813e2014-03-25 20:38:34 -06002249 else if (attr == &dev_attr_position.attr)
2250 exists = (drv->accelerometer_supported) ? true : false;
Azael Avalose26ffe52015-01-18 18:30:22 -07002251 else if (attr == &dev_attr_usb_sleep_charge.attr)
2252 exists = (drv->usb_sleep_charge_supported) ? true : false;
Azael Avalos182bcaa2015-01-18 18:30:23 -07002253 else if (attr == &dev_attr_sleep_functions_on_battery.attr)
2254 exists = (drv->usb_sleep_charge_supported) ? true : false;
Azael Avalosbb3fe012015-01-18 18:30:24 -07002255 else if (attr == &dev_attr_usb_rapid_charge.attr)
2256 exists = (drv->usb_rapid_charge_supported) ? true : false;
Azael Avalos172ce0a2015-01-18 18:30:25 -07002257 else if (attr == &dev_attr_usb_sleep_music.attr)
2258 exists = (drv->usb_sleep_music_supported) ? true : false;
Azael Avalosbae84192015-02-10 21:09:18 -07002259 else if (attr == &dev_attr_kbd_function_keys.attr)
2260 exists = (drv->kbd_function_keys_supported) ? true : false;
Azael Avalos35d53ce2015-02-10 21:09:19 -07002261 else if (attr == &dev_attr_panel_power_on.attr)
2262 exists = (drv->panel_power_on_supported) ? true : false;
Azael Avalos17fe4b32015-02-10 21:09:20 -07002263 else if (attr == &dev_attr_usb_three.attr)
2264 exists = (drv->usb_three_supported) ? true : false;
Azael Avalos360f0f32014-03-25 20:38:31 -06002265
2266 return exists ? attr->mode : 0;
2267}
2268
Azael Avalos9bd12132015-02-10 23:43:58 -07002269static struct attribute_group toshiba_attr_group = {
2270 .is_visible = toshiba_sysfs_is_visible,
2271 .attrs = toshiba_attributes,
2272};
2273
Azael Avalos1f28f292014-12-04 20:22:45 -07002274/*
Azael Avalosfc5462f2015-07-22 18:09:11 -06002275 * Misc device
2276 */
2277static int toshiba_acpi_smm_bridge(SMMRegisters *regs)
2278{
2279 u32 in[TCI_WORDS] = { regs->eax, regs->ebx, regs->ecx,
2280 regs->edx, regs->esi, regs->edi };
2281 u32 out[TCI_WORDS];
2282 acpi_status status;
2283
2284 status = tci_raw(toshiba_acpi, in, out);
2285 if (ACPI_FAILURE(status)) {
2286 pr_err("ACPI call to query SMM registers failed\n");
2287 return -EIO;
2288 }
2289
2290 /* Fillout the SMM struct with the TCI call results */
2291 regs->eax = out[0];
2292 regs->ebx = out[1];
2293 regs->ecx = out[2];
2294 regs->edx = out[3];
2295 regs->esi = out[4];
2296 regs->edi = out[5];
2297
2298 return 0;
2299}
2300
2301static long toshiba_acpi_ioctl(struct file *fp, unsigned int cmd,
2302 unsigned long arg)
2303{
2304 SMMRegisters __user *argp = (SMMRegisters __user *)arg;
2305 SMMRegisters regs;
2306 int ret;
2307
2308 if (!argp)
2309 return -EINVAL;
2310
2311 switch (cmd) {
2312 case TOSH_SMM:
2313 if (copy_from_user(&regs, argp, sizeof(SMMRegisters)))
2314 return -EFAULT;
2315 ret = toshiba_acpi_smm_bridge(&regs);
2316 if (ret)
2317 return ret;
2318 if (copy_to_user(argp, &regs, sizeof(SMMRegisters)))
2319 return -EFAULT;
2320 break;
2321 case TOSHIBA_ACPI_SCI:
2322 if (copy_from_user(&regs, argp, sizeof(SMMRegisters)))
2323 return -EFAULT;
2324 /* Ensure we are being called with a SCI_{GET, SET} register */
2325 if (regs.eax != SCI_GET && regs.eax != SCI_SET)
2326 return -EINVAL;
2327 if (!sci_open(toshiba_acpi))
2328 return -EIO;
2329 ret = toshiba_acpi_smm_bridge(&regs);
2330 sci_close(toshiba_acpi);
2331 if (ret)
2332 return ret;
2333 if (copy_to_user(argp, &regs, sizeof(SMMRegisters)))
2334 return -EFAULT;
2335 break;
2336 default:
2337 return -EINVAL;
2338 }
2339
2340 return 0;
2341}
2342
2343static const struct file_operations toshiba_acpi_fops = {
2344 .owner = THIS_MODULE,
2345 .unlocked_ioctl = toshiba_acpi_ioctl,
2346 .llseek = noop_llseek,
2347};
2348
2349/*
Azael Avalos1f28f292014-12-04 20:22:45 -07002350 * Hotkeys
2351 */
2352static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev)
2353{
2354 acpi_status status;
2355 u32 result;
2356
2357 status = acpi_evaluate_object(dev->acpi_dev->handle,
2358 "ENAB", NULL, NULL);
2359 if (ACPI_FAILURE(status))
2360 return -ENODEV;
2361
Azael Avalosb116fd002015-09-09 11:28:19 -06002362 /*
2363 * Enable the "Special Functions" mode only if they are
2364 * supported and if they are activated.
2365 */
2366 if (dev->kbd_function_keys_supported && dev->special_functions)
2367 result = hci_write(dev, HCI_HOTKEY_EVENT,
2368 HCI_HOTKEY_SPECIAL_FUNCTIONS);
2369 else
2370 result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE);
2371
Azael Avalos1f28f292014-12-04 20:22:45 -07002372 if (result == TOS_FAILURE)
2373 return -EIO;
2374 else if (result == TOS_NOT_SUPPORTED)
2375 return -ENODEV;
2376
2377 return 0;
2378}
2379
Seth Forshee29cd2932012-01-18 13:44:09 -06002380static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
2381 struct serio *port)
2382{
Giedrius Statkevičius98280372014-10-18 02:57:20 +03002383 if (str & I8042_STR_AUXDATA)
Seth Forshee29cd2932012-01-18 13:44:09 -06002384 return false;
2385
2386 if (unlikely(data == 0xe0))
2387 return false;
2388
2389 if ((data & 0x7f) == TOS1900_FN_SCAN) {
2390 schedule_work(&toshiba_acpi->hotkey_work);
2391 return true;
2392 }
2393
2394 return false;
2395}
2396
2397static void toshiba_acpi_hotkey_work(struct work_struct *work)
2398{
2399 acpi_handle ec_handle = ec_get_handle();
2400 acpi_status status;
2401
2402 if (!ec_handle)
2403 return;
2404
2405 status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL);
2406 if (ACPI_FAILURE(status))
2407 pr_err("ACPI NTFY method execution failed\n");
2408}
2409
2410/*
2411 * Returns hotkey scancode, or < 0 on failure.
2412 */
2413static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev)
2414{
Zhang Rui74facaf2013-09-03 08:32:15 +08002415 unsigned long long value;
Seth Forshee29cd2932012-01-18 13:44:09 -06002416 acpi_status status;
2417
Zhang Rui74facaf2013-09-03 08:32:15 +08002418 status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO",
2419 NULL, &value);
2420 if (ACPI_FAILURE(status)) {
Seth Forshee29cd2932012-01-18 13:44:09 -06002421 pr_err("ACPI INFO method execution failed\n");
2422 return -EIO;
2423 }
2424
Zhang Rui74facaf2013-09-03 08:32:15 +08002425 return value;
Seth Forshee29cd2932012-01-18 13:44:09 -06002426}
2427
2428static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev,
2429 int scancode)
2430{
2431 if (scancode == 0x100)
2432 return;
2433
Darren Harte0769fe2015-02-11 20:50:08 -08002434 /* Act on key press; ignore key release */
Seth Forshee29cd2932012-01-18 13:44:09 -06002435 if (scancode & 0x80)
2436 return;
2437
2438 if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true))
2439 pr_info("Unknown key %x\n", scancode);
2440}
2441
Azael Avalos71454d72014-12-04 20:22:46 -07002442static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev)
2443{
Azael Avalos71454d72014-12-04 20:22:46 -07002444 if (dev->info_supported) {
Azael Avalos7deef552015-07-22 18:09:10 -06002445 int scancode = toshiba_acpi_query_hotkey(dev);
2446
2447 if (scancode < 0) {
Azael Avalos71454d72014-12-04 20:22:46 -07002448 pr_err("Failed to query hotkey event\n");
Azael Avalos7deef552015-07-22 18:09:10 -06002449 } else if (scancode != 0) {
Azael Avalos71454d72014-12-04 20:22:46 -07002450 toshiba_acpi_report_hotkey(dev, scancode);
Azael Avalos7deef552015-07-22 18:09:10 -06002451 dev->key_event_valid = 1;
2452 dev->last_key_event = scancode;
2453 }
Azael Avalos71454d72014-12-04 20:22:46 -07002454 } else if (dev->system_event_supported) {
Azael Avalos7deef552015-07-22 18:09:10 -06002455 u32 result;
2456 u32 value;
2457 int retries = 3;
2458
Azael Avalos71454d72014-12-04 20:22:46 -07002459 do {
Azael Avalos7deef552015-07-22 18:09:10 -06002460 result = hci_read(dev, HCI_SYSTEM_EVENT, &value);
2461 switch (result) {
Azael Avalos71454d72014-12-04 20:22:46 -07002462 case TOS_SUCCESS:
2463 toshiba_acpi_report_hotkey(dev, (int)value);
Azael Avalos7deef552015-07-22 18:09:10 -06002464 dev->key_event_valid = 1;
2465 dev->last_key_event = value;
Azael Avalos71454d72014-12-04 20:22:46 -07002466 break;
2467 case TOS_NOT_SUPPORTED:
2468 /*
2469 * This is a workaround for an unresolved
2470 * issue on some machines where system events
2471 * sporadically become disabled.
2472 */
Azael Avalos7deef552015-07-22 18:09:10 -06002473 result = hci_write(dev, HCI_SYSTEM_EVENT, 1);
2474 if (result == TOS_SUCCESS)
2475 pr_notice("Re-enabled hotkeys\n");
Darren Harte0769fe2015-02-11 20:50:08 -08002476 /* Fall through */
Azael Avalos71454d72014-12-04 20:22:46 -07002477 default:
2478 retries--;
2479 break;
2480 }
Azael Avalos7deef552015-07-22 18:09:10 -06002481 } while (retries && result != TOS_FIFO_EMPTY);
Azael Avalos71454d72014-12-04 20:22:46 -07002482 }
2483}
2484
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08002485static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
Matthew Garrett6335e4d2010-02-25 15:20:54 -05002486{
Takashi Iwaife808bfb2014-04-29 15:15:38 +02002487 const struct key_entry *keymap = toshiba_acpi_keymap;
Azael Avalosa2b34712015-03-20 16:55:17 -06002488 acpi_handle ec_handle;
Azael Avalosa2b34712015-03-20 16:55:17 -06002489 int error;
2490
Azael Avalosa88bc062015-07-22 18:09:12 -06002491 if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) {
2492 pr_info("WMI event detected, hotkeys will not be monitored\n");
2493 return 0;
2494 }
2495
Azael Avalosa2b34712015-03-20 16:55:17 -06002496 error = toshiba_acpi_enable_hotkeys(dev);
2497 if (error)
2498 return error;
2499
Azael Avalos10e6aaa2015-09-18 22:45:34 -06002500 if (toshiba_hotkey_event_type_get(dev, &dev->hotkey_event_type))
Azael Avalos53147b62015-09-09 11:25:45 -06002501 pr_notice("Unable to query Hotkey Event Type\n");
2502
Seth Forshee135740d2011-09-20 16:55:49 -05002503 dev->hotkey_dev = input_allocate_device();
Joe Perchesb222cca2013-10-23 12:14:52 -07002504 if (!dev->hotkey_dev)
Seth Forshee135740d2011-09-20 16:55:49 -05002505 return -ENOMEM;
Seth Forshee135740d2011-09-20 16:55:49 -05002506
2507 dev->hotkey_dev->name = "Toshiba input device";
Seth Forshee6e02cc72011-09-20 16:55:51 -05002508 dev->hotkey_dev->phys = "toshiba_acpi/input0";
Seth Forshee135740d2011-09-20 16:55:49 -05002509 dev->hotkey_dev->id.bustype = BUS_HOST;
2510
Azael Avalos10e6aaa2015-09-18 22:45:34 -06002511 if (dev->hotkey_event_type == HCI_SYSTEM_TYPE1 ||
Azael Avalosa2b34712015-03-20 16:55:17 -06002512 !dev->kbd_function_keys_supported)
2513 keymap = toshiba_acpi_keymap;
Azael Avalos10e6aaa2015-09-18 22:45:34 -06002514 else if (dev->hotkey_event_type == HCI_SYSTEM_TYPE2 ||
Azael Avalosa2b34712015-03-20 16:55:17 -06002515 dev->kbd_function_keys_supported)
Takashi Iwaife808bfb2014-04-29 15:15:38 +02002516 keymap = toshiba_acpi_alt_keymap;
Azael Avalosa2b34712015-03-20 16:55:17 -06002517 else
Azael Avalos10e6aaa2015-09-18 22:45:34 -06002518 pr_info("Unknown event type received %x\n",
2519 dev->hotkey_event_type);
Takashi Iwaife808bfb2014-04-29 15:15:38 +02002520 error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL);
Seth Forshee135740d2011-09-20 16:55:49 -05002521 if (error)
2522 goto err_free_dev;
2523
Seth Forshee29cd2932012-01-18 13:44:09 -06002524 /*
2525 * For some machines the SCI responsible for providing hotkey
2526 * notification doesn't fire. We can trigger the notification
2527 * whenever the Fn key is pressed using the NTFY method, if
2528 * supported, so if it's present set up an i8042 key filter
2529 * for this purpose.
2530 */
Seth Forshee29cd2932012-01-18 13:44:09 -06002531 ec_handle = ec_get_handle();
Zhang Ruie2e19602013-09-03 08:32:06 +08002532 if (ec_handle && acpi_has_method(ec_handle, "NTFY")) {
Seth Forshee29cd2932012-01-18 13:44:09 -06002533 INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work);
2534
2535 error = i8042_install_filter(toshiba_acpi_i8042_filter);
2536 if (error) {
2537 pr_err("Error installing key filter\n");
2538 goto err_free_keymap;
2539 }
2540
2541 dev->ntfy_supported = 1;
2542 }
2543
2544 /*
2545 * Determine hotkey query interface. Prefer using the INFO
2546 * method when it is available.
2547 */
Zhang Ruie2e19602013-09-03 08:32:06 +08002548 if (acpi_has_method(dev->acpi_dev->handle, "INFO"))
Seth Forshee29cd2932012-01-18 13:44:09 -06002549 dev->info_supported = 1;
Azael Avalos10e6aaa2015-09-18 22:45:34 -06002550 else if (hci_write(dev, HCI_SYSTEM_EVENT, 1) == TOS_SUCCESS)
2551 dev->system_event_supported = 1;
Seth Forshee29cd2932012-01-18 13:44:09 -06002552
2553 if (!dev->info_supported && !dev->system_event_supported) {
2554 pr_warn("No hotkey query interface found\n");
2555 goto err_remove_filter;
2556 }
2557
Seth Forshee135740d2011-09-20 16:55:49 -05002558 error = input_register_device(dev->hotkey_dev);
2559 if (error) {
2560 pr_info("Unable to register input device\n");
Seth Forshee29cd2932012-01-18 13:44:09 -06002561 goto err_remove_filter;
Seth Forshee135740d2011-09-20 16:55:49 -05002562 }
2563
2564 return 0;
2565
Seth Forshee29cd2932012-01-18 13:44:09 -06002566 err_remove_filter:
2567 if (dev->ntfy_supported)
2568 i8042_remove_filter(toshiba_acpi_i8042_filter);
Seth Forshee135740d2011-09-20 16:55:49 -05002569 err_free_keymap:
2570 sparse_keymap_free(dev->hotkey_dev);
2571 err_free_dev:
2572 input_free_device(dev->hotkey_dev);
2573 dev->hotkey_dev = NULL;
2574 return error;
2575}
2576
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08002577static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
Seth Forshee62cce752012-04-19 11:23:50 -05002578{
2579 struct backlight_properties props;
2580 int brightness;
2581 int ret;
2582
2583 /*
2584 * Some machines don't support the backlight methods at all, and
2585 * others support it read-only. Either of these is pretty useless,
2586 * so only register the backlight device if the backlight method
2587 * supports both reads and writes.
2588 */
2589 brightness = __get_lcd_brightness(dev);
2590 if (brightness < 0)
2591 return 0;
Azael Avalosbae53362015-11-15 20:32:47 -07002592 /*
2593 * If transflective backlight is supported and the brightness is zero
2594 * (lowest brightness level), the set_lcd_brightness function will
2595 * activate the transflective backlight, making the LCD appear to be
2596 * turned off, simply increment the brightness level to avoid that.
2597 */
2598 if (dev->tr_backlight_supported && brightness == 0)
2599 brightness++;
Seth Forshee62cce752012-04-19 11:23:50 -05002600 ret = set_lcd_brightness(dev, brightness);
2601 if (ret) {
2602 pr_debug("Backlight method is read-only, disabling backlight support\n");
2603 return 0;
2604 }
2605
Hans de Goede358d6a22015-04-21 12:01:32 +02002606 /*
2607 * Tell acpi-video-detect code to prefer vendor backlight on all
2608 * systems with transflective backlight and on dmi matched systems.
2609 */
2610 if (dev->tr_backlight_supported ||
2611 dmi_check_system(toshiba_vendor_backlight_dmi))
Hans de Goede234b7cf2015-06-16 16:28:11 +02002612 acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
Hans de Goede358d6a22015-04-21 12:01:32 +02002613
Hans de Goede234b7cf2015-06-16 16:28:11 +02002614 if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
Hans de Goede358d6a22015-04-21 12:01:32 +02002615 return 0;
2616
Matthew Garrett53039f22012-06-01 11:02:36 -04002617 memset(&props, 0, sizeof(props));
Seth Forshee62cce752012-04-19 11:23:50 -05002618 props.type = BACKLIGHT_PLATFORM;
2619 props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
Seth Forshee62cce752012-04-19 11:23:50 -05002620
Darren Harte0769fe2015-02-11 20:50:08 -08002621 /* Adding an extra level and having 0 change to transflective mode */
Akio Idehara121b7b02012-04-06 01:46:43 +09002622 if (dev->tr_backlight_supported)
2623 props.max_brightness++;
2624
Seth Forshee62cce752012-04-19 11:23:50 -05002625 dev->backlight_dev = backlight_device_register("toshiba",
2626 &dev->acpi_dev->dev,
2627 dev,
2628 &toshiba_backlight_data,
2629 &props);
2630 if (IS_ERR(dev->backlight_dev)) {
2631 ret = PTR_ERR(dev->backlight_dev);
2632 pr_err("Could not register toshiba backlight device\n");
2633 dev->backlight_dev = NULL;
2634 return ret;
2635 }
2636
2637 dev->backlight_dev->props.brightness = brightness;
2638 return 0;
2639}
2640
Azael Avalos0409cbc2015-07-31 21:58:13 -06002641static void print_supported_features(struct toshiba_acpi_dev *dev)
2642{
2643 pr_info("Supported laptop features:");
2644
2645 if (dev->hotkey_dev)
2646 pr_cont(" hotkeys");
2647 if (dev->backlight_dev)
2648 pr_cont(" backlight");
2649 if (dev->video_supported)
2650 pr_cont(" video-out");
2651 if (dev->fan_supported)
2652 pr_cont(" fan");
2653 if (dev->tr_backlight_supported)
2654 pr_cont(" transflective-backlight");
2655 if (dev->illumination_supported)
2656 pr_cont(" illumination");
2657 if (dev->kbd_illum_supported)
2658 pr_cont(" keyboard-backlight");
2659 if (dev->touchpad_supported)
2660 pr_cont(" touchpad");
2661 if (dev->eco_supported)
2662 pr_cont(" eco-led");
2663 if (dev->accelerometer_supported)
2664 pr_cont(" accelerometer-axes");
2665 if (dev->usb_sleep_charge_supported)
2666 pr_cont(" usb-sleep-charge");
2667 if (dev->usb_rapid_charge_supported)
2668 pr_cont(" usb-rapid-charge");
2669 if (dev->usb_sleep_music_supported)
2670 pr_cont(" usb-sleep-music");
2671 if (dev->kbd_function_keys_supported)
2672 pr_cont(" special-function-keys");
2673 if (dev->panel_power_on_supported)
2674 pr_cont(" panel-power-on");
2675 if (dev->usb_three_supported)
2676 pr_cont(" usb3");
Azael Avalos6873f462015-11-23 10:49:10 -07002677 if (dev->wwan_supported)
2678 pr_cont(" wwan");
Azael Avalos0409cbc2015-07-31 21:58:13 -06002679
2680 pr_cont("\n");
2681}
2682
Rafael J. Wysocki51fac832013-01-24 00:24:48 +01002683static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
Seth Forshee135740d2011-09-20 16:55:49 -05002684{
2685 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
2686
Azael Avalosfc5462f2015-07-22 18:09:11 -06002687 misc_deregister(&dev->miscdev);
2688
Seth Forshee36d03f92011-09-20 16:55:53 -05002689 remove_toshiba_proc_entries(dev);
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002690
Azael Avalos360f0f32014-03-25 20:38:31 -06002691 if (dev->sysfs_created)
2692 sysfs_remove_group(&dev->acpi_dev->dev.kobj,
2693 &toshiba_attr_group);
Seth Forshee135740d2011-09-20 16:55:49 -05002694
Seth Forshee29cd2932012-01-18 13:44:09 -06002695 if (dev->ntfy_supported) {
2696 i8042_remove_filter(toshiba_acpi_i8042_filter);
2697 cancel_work_sync(&dev->hotkey_work);
2698 }
2699
Seth Forshee135740d2011-09-20 16:55:49 -05002700 if (dev->hotkey_dev) {
2701 input_unregister_device(dev->hotkey_dev);
2702 sparse_keymap_free(dev->hotkey_dev);
2703 }
2704
Markus Elfring00981812014-11-24 20:30:29 +01002705 backlight_device_unregister(dev->backlight_dev);
Seth Forshee135740d2011-09-20 16:55:49 -05002706
Azael Avalosea215a3f2015-07-31 21:58:12 -06002707 if (dev->illumination_led_registered)
Seth Forshee135740d2011-09-20 16:55:49 -05002708 led_classdev_unregister(&dev->led_dev);
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002709
Azael Avalos360f0f32014-03-25 20:38:31 -06002710 if (dev->kbd_led_registered)
2711 led_classdev_unregister(&dev->kbd_led);
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002712
Azael Avalosea215a3f2015-07-31 21:58:12 -06002713 if (dev->eco_led_registered)
Azael Avalosdef6c4e2014-03-25 20:38:33 -06002714 led_classdev_unregister(&dev->eco_led);
Seth Forshee135740d2011-09-20 16:55:49 -05002715
Seth Forshee29cd2932012-01-18 13:44:09 -06002716 if (toshiba_acpi)
2717 toshiba_acpi = NULL;
2718
Seth Forshee135740d2011-09-20 16:55:49 -05002719 kfree(dev);
2720
2721 return 0;
2722}
2723
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08002724static const char *find_hci_method(acpi_handle handle)
Seth Forsheea540d6b2011-09-20 16:55:52 -05002725{
Zhang Ruie2e19602013-09-03 08:32:06 +08002726 if (acpi_has_method(handle, "GHCI"))
Seth Forsheea540d6b2011-09-20 16:55:52 -05002727 return "GHCI";
2728
Zhang Ruie2e19602013-09-03 08:32:06 +08002729 if (acpi_has_method(handle, "SPFC"))
Seth Forsheea540d6b2011-09-20 16:55:52 -05002730 return "SPFC";
2731
2732 return NULL;
2733}
2734
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08002735static int toshiba_acpi_add(struct acpi_device *acpi_dev)
Seth Forshee135740d2011-09-20 16:55:49 -05002736{
2737 struct toshiba_acpi_dev *dev;
Seth Forsheea540d6b2011-09-20 16:55:52 -05002738 const char *hci_method;
Seth Forshee36d03f92011-09-20 16:55:53 -05002739 u32 dummy;
Seth Forshee135740d2011-09-20 16:55:49 -05002740 int ret = 0;
Seth Forshee135740d2011-09-20 16:55:49 -05002741
Seth Forshee29cd2932012-01-18 13:44:09 -06002742 if (toshiba_acpi)
2743 return -EBUSY;
2744
Seth Forshee135740d2011-09-20 16:55:49 -05002745 pr_info("Toshiba Laptop ACPI Extras version %s\n",
2746 TOSHIBA_ACPI_VERSION);
2747
Seth Forsheea540d6b2011-09-20 16:55:52 -05002748 hci_method = find_hci_method(acpi_dev->handle);
2749 if (!hci_method) {
2750 pr_err("HCI interface not found\n");
Seth Forshee6e02cc72011-09-20 16:55:51 -05002751 return -ENODEV;
Seth Forsheea540d6b2011-09-20 16:55:52 -05002752 }
Seth Forshee6e02cc72011-09-20 16:55:51 -05002753
Seth Forshee135740d2011-09-20 16:55:49 -05002754 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
2755 if (!dev)
2756 return -ENOMEM;
2757 dev->acpi_dev = acpi_dev;
Seth Forsheea540d6b2011-09-20 16:55:52 -05002758 dev->method_hci = hci_method;
Azael Avalosfc5462f2015-07-22 18:09:11 -06002759 dev->miscdev.minor = MISC_DYNAMIC_MINOR;
2760 dev->miscdev.name = "toshiba_acpi";
2761 dev->miscdev.fops = &toshiba_acpi_fops;
2762
2763 ret = misc_register(&dev->miscdev);
2764 if (ret) {
2765 pr_err("Failed to register miscdevice\n");
2766 kfree(dev);
2767 return ret;
2768 }
2769
Seth Forshee135740d2011-09-20 16:55:49 -05002770 acpi_dev->driver_data = dev;
Azael Avalos360f0f32014-03-25 20:38:31 -06002771 dev_set_drvdata(&acpi_dev->dev, dev);
Seth Forshee135740d2011-09-20 16:55:49 -05002772
Azael Avalosa2b34712015-03-20 16:55:17 -06002773 /* Query the BIOS for supported features */
2774
2775 /*
2776 * The "Special Functions" are always supported by the laptops
2777 * with the new keyboard layout, query for its presence to help
2778 * determine the keymap layout to use.
2779 */
Azael Avalosb116fd002015-09-09 11:28:19 -06002780 ret = toshiba_function_keys_get(dev, &dev->special_functions);
Azael Avalosa2b34712015-03-20 16:55:17 -06002781 dev->kbd_function_keys_supported = !ret;
2782
Azael Avalosd2f20612015-11-04 09:28:26 -07002783 dev->hotkey_event_type = 0;
Seth Forshee6e02cc72011-09-20 16:55:51 -05002784 if (toshiba_acpi_setup_keyboard(dev))
2785 pr_info("Unable to activate hotkeys\n");
Seth Forshee135740d2011-09-20 16:55:49 -05002786
Azael Avalos695f6062015-07-22 18:09:13 -06002787 /* Determine whether or not BIOS supports transflective backlight */
2788 ret = get_tr_backlight_status(dev, &dummy);
2789 dev->tr_backlight_supported = !ret;
2790
Seth Forshee62cce752012-04-19 11:23:50 -05002791 ret = toshiba_acpi_setup_backlight(dev);
2792 if (ret)
Seth Forshee135740d2011-09-20 16:55:49 -05002793 goto error;
Seth Forshee135740d2011-09-20 16:55:49 -05002794
Azael Avalosea215a3f2015-07-31 21:58:12 -06002795 toshiba_illumination_available(dev);
2796 if (dev->illumination_supported) {
Seth Forshee135740d2011-09-20 16:55:49 -05002797 dev->led_dev.name = "toshiba::illumination";
2798 dev->led_dev.max_brightness = 1;
2799 dev->led_dev.brightness_set = toshiba_illumination_set;
2800 dev->led_dev.brightness_get = toshiba_illumination_get;
2801 if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev))
Azael Avalosea215a3f2015-07-31 21:58:12 -06002802 dev->illumination_led_registered = true;
Seth Forshee135740d2011-09-20 16:55:49 -05002803 }
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002804
Azael Avalosea215a3f2015-07-31 21:58:12 -06002805 toshiba_eco_mode_available(dev);
2806 if (dev->eco_supported) {
Azael Avalosdef6c4e2014-03-25 20:38:33 -06002807 dev->eco_led.name = "toshiba::eco_mode";
2808 dev->eco_led.max_brightness = 1;
2809 dev->eco_led.brightness_set = toshiba_eco_mode_set_status;
2810 dev->eco_led.brightness_get = toshiba_eco_mode_get_status;
2811 if (!led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led))
Azael Avalosea215a3f2015-07-31 21:58:12 -06002812 dev->eco_led_registered = true;
Azael Avalosdef6c4e2014-03-25 20:38:33 -06002813 }
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002814
Azael Avalosea215a3f2015-07-31 21:58:12 -06002815 toshiba_kbd_illum_available(dev);
Azael Avalos360f0f32014-03-25 20:38:31 -06002816 /*
2817 * Only register the LED if KBD illumination is supported
2818 * and the keyboard backlight operation mode is set to FN-Z
2819 */
2820 if (dev->kbd_illum_supported && dev->kbd_mode == SCI_KBD_MODE_FNZ) {
2821 dev->kbd_led.name = "toshiba::kbd_backlight";
2822 dev->kbd_led.max_brightness = 1;
2823 dev->kbd_led.brightness_set = toshiba_kbd_backlight_set;
2824 dev->kbd_led.brightness_get = toshiba_kbd_backlight_get;
2825 if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led))
Azael Avalosea215a3f2015-07-31 21:58:12 -06002826 dev->kbd_led_registered = true;
Azael Avalos360f0f32014-03-25 20:38:31 -06002827 }
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002828
Azael Avalos9d8658a2014-03-25 20:38:32 -06002829 ret = toshiba_touchpad_get(dev, &dummy);
2830 dev->touchpad_supported = !ret;
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002831
Azael Avalosea215a3f2015-07-31 21:58:12 -06002832 toshiba_accelerometer_available(dev);
Seth Forshee135740d2011-09-20 16:55:49 -05002833
Azael Avalosc8c91842015-04-02 19:26:20 -06002834 toshiba_usb_sleep_charge_available(dev);
Azael Avalose26ffe52015-01-18 18:30:22 -07002835
Azael Avalosbb3fe012015-01-18 18:30:24 -07002836 ret = toshiba_usb_rapid_charge_get(dev, &dummy);
2837 dev->usb_rapid_charge_supported = !ret;
2838
Azael Avalos172ce0a2015-01-18 18:30:25 -07002839 ret = toshiba_usb_sleep_music_get(dev, &dummy);
2840 dev->usb_sleep_music_supported = !ret;
2841
Azael Avalos35d53ce2015-02-10 21:09:19 -07002842 ret = toshiba_panel_power_on_get(dev, &dummy);
2843 dev->panel_power_on_supported = !ret;
2844
Azael Avalos17fe4b32015-02-10 21:09:20 -07002845 ret = toshiba_usb_three_get(dev, &dummy);
2846 dev->usb_three_supported = !ret;
2847
Seth Forshee36d03f92011-09-20 16:55:53 -05002848 ret = get_video_status(dev, &dummy);
2849 dev->video_supported = !ret;
2850
2851 ret = get_fan_status(dev, &dummy);
2852 dev->fan_supported = !ret;
2853
Azael Avalos6873f462015-11-23 10:49:10 -07002854 toshiba_wwan_available(dev);
2855
Azael Avalos0409cbc2015-07-31 21:58:13 -06002856 print_supported_features(dev);
2857
Azael Avalos360f0f32014-03-25 20:38:31 -06002858 ret = sysfs_create_group(&dev->acpi_dev->dev.kobj,
2859 &toshiba_attr_group);
2860 if (ret) {
2861 dev->sysfs_created = 0;
2862 goto error;
2863 }
2864 dev->sysfs_created = !ret;
2865
Seth Forshee36d03f92011-09-20 16:55:53 -05002866 create_toshiba_proc_entries(dev);
2867
Seth Forshee29cd2932012-01-18 13:44:09 -06002868 toshiba_acpi = dev;
2869
Seth Forshee135740d2011-09-20 16:55:49 -05002870 return 0;
2871
2872error:
Rafael J. Wysocki51fac832013-01-24 00:24:48 +01002873 toshiba_acpi_remove(acpi_dev);
Seth Forshee135740d2011-09-20 16:55:49 -05002874 return ret;
2875}
2876
2877static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
2878{
2879 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
Azael Avalos80546902014-12-04 20:22:47 -07002880 int ret;
Matthew Garrett6335e4d2010-02-25 15:20:54 -05002881
Azael Avalos71454d72014-12-04 20:22:46 -07002882 switch (event) {
2883 case 0x80: /* Hotkeys and some system events */
Azael Avalosa88bc062015-07-22 18:09:12 -06002884 /*
2885 * Machines with this WMI GUID aren't supported due to bugs in
2886 * their AML.
2887 *
2888 * Return silently to avoid triggering a netlink event.
2889 */
2890 if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
2891 return;
Azael Avalos71454d72014-12-04 20:22:46 -07002892 toshiba_acpi_process_hotkeys(dev);
2893 break;
Azael Avalosbab09e22015-03-06 18:14:41 -07002894 case 0x81: /* Dock events */
2895 case 0x82:
2896 case 0x83:
2897 pr_info("Dock event received %x\n", event);
2898 break;
2899 case 0x88: /* Thermal events */
2900 pr_info("Thermal event received\n");
2901 break;
2902 case 0x8f: /* LID closed */
2903 case 0x90: /* LID is closed and Dock has been ejected */
2904 break;
2905 case 0x8c: /* SATA power events */
2906 case 0x8b:
2907 pr_info("SATA power event received %x\n", event);
2908 break;
Azael Avalos80546902014-12-04 20:22:47 -07002909 case 0x92: /* Keyboard backlight mode changed */
2910 /* Update sysfs entries */
2911 ret = sysfs_update_group(&acpi_dev->dev.kobj,
2912 &toshiba_attr_group);
2913 if (ret)
2914 pr_err("Unable to update sysfs entries\n");
2915 break;
Azael Avalosbab09e22015-03-06 18:14:41 -07002916 case 0x85: /* Unknown */
2917 case 0x8d: /* Unknown */
Azael Avalos71454d72014-12-04 20:22:46 -07002918 case 0x8e: /* Unknown */
Azael Avalosbab09e22015-03-06 18:14:41 -07002919 case 0x94: /* Unknown */
2920 case 0x95: /* Unknown */
Azael Avalos71454d72014-12-04 20:22:46 -07002921 default:
2922 pr_info("Unknown event received %x\n", event);
2923 break;
Seth Forshee29cd2932012-01-18 13:44:09 -06002924 }
Azael Avalosbab09e22015-03-06 18:14:41 -07002925
2926 acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class,
2927 dev_name(&acpi_dev->dev),
Azael Avalos13ae84f2015-11-15 20:33:46 -07002928 event, (event == 0x80) ?
2929 dev->last_key_event : 0);
Matthew Garrett6335e4d2010-02-25 15:20:54 -05002930}
2931
Rafael J. Wysocki3567a4e22012-08-09 23:00:13 +02002932#ifdef CONFIG_PM_SLEEP
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02002933static int toshiba_acpi_suspend(struct device *device)
Seth Forshee29cd2932012-01-18 13:44:09 -06002934{
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02002935 struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
Seth Forshee29cd2932012-01-18 13:44:09 -06002936
Azael Avalos1e574db2015-07-22 19:37:49 -06002937 if (dev->hotkey_dev) {
2938 u32 result;
2939
Azael Avalosd37782b2015-05-06 09:35:10 -06002940 result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE);
Azael Avalos1e574db2015-07-22 19:37:49 -06002941 if (result != TOS_SUCCESS)
2942 pr_info("Unable to disable hotkeys\n");
2943 }
Seth Forshee29cd2932012-01-18 13:44:09 -06002944
2945 return 0;
2946}
2947
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02002948static int toshiba_acpi_resume(struct device *device)
Seth Forshee29cd2932012-01-18 13:44:09 -06002949{
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02002950 struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
Seth Forshee29cd2932012-01-18 13:44:09 -06002951
Benjamin Tissoirese7fdb762014-09-02 14:04:19 -04002952 if (dev->hotkey_dev) {
Azael Avalos1e574db2015-07-22 19:37:49 -06002953 int error = toshiba_acpi_enable_hotkeys(dev);
2954
Azael Avalos1f28f292014-12-04 20:22:45 -07002955 if (error)
Benjamin Tissoirese7fdb762014-09-02 14:04:19 -04002956 pr_info("Unable to re-enable hotkeys\n");
Benjamin Tissoirese7fdb762014-09-02 14:04:19 -04002957 }
Seth Forshee29cd2932012-01-18 13:44:09 -06002958
2959 return 0;
2960}
Rafael J. Wysocki3567a4e22012-08-09 23:00:13 +02002961#endif
Matthew Garrett6335e4d2010-02-25 15:20:54 -05002962
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02002963static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm,
2964 toshiba_acpi_suspend, toshiba_acpi_resume);
2965
Seth Forshee135740d2011-09-20 16:55:49 -05002966static struct acpi_driver toshiba_acpi_driver = {
2967 .name = "Toshiba ACPI driver",
2968 .owner = THIS_MODULE,
2969 .ids = toshiba_device_ids,
2970 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
2971 .ops = {
2972 .add = toshiba_acpi_add,
2973 .remove = toshiba_acpi_remove,
2974 .notify = toshiba_acpi_notify,
2975 },
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02002976 .drv.pm = &toshiba_acpi_pm,
Seth Forshee135740d2011-09-20 16:55:49 -05002977};
Holger Machtc9263552006-10-20 14:30:29 -07002978
Len Brown4be44fc2005-08-05 00:44:28 -04002979static int __init toshiba_acpi_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980{
Seth Forshee135740d2011-09-20 16:55:49 -05002981 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982
2983 toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
2984 if (!toshiba_proc_dir) {
Seth Forshee135740d2011-09-20 16:55:49 -05002985 pr_err("Unable to create proc dir " PROC_TOSHIBA "\n");
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04002986 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002987 }
2988
Seth Forshee135740d2011-09-20 16:55:49 -05002989 ret = acpi_bus_register_driver(&toshiba_acpi_driver);
2990 if (ret) {
2991 pr_err("Failed to register ACPI driver: %d\n", ret);
2992 remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
Holger Machtc9263552006-10-20 14:30:29 -07002993 }
2994
Seth Forshee135740d2011-09-20 16:55:49 -05002995 return ret;
2996}
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04002997
Seth Forshee135740d2011-09-20 16:55:49 -05002998static void __exit toshiba_acpi_exit(void)
2999{
3000 acpi_bus_unregister_driver(&toshiba_acpi_driver);
3001 if (toshiba_proc_dir)
3002 remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003}
3004
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005module_init(toshiba_acpi_init);
3006module_exit(toshiba_acpi_exit);