blob: 446ddc1fa3c2d7304e1f00222643945576ff71fa [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * toshiba_acpi.c - Toshiba Laptop ACPI Extras
3 *
4 *
5 * Copyright (C) 2002-2004 John Belmonte
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04006 * Copyright (C) 2008 Philip Langdale
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +02007 * Copyright (C) 2010 Pierre Ducroquet
Azael Avalos548c4302014-03-25 20:38:35 -06008 * Copyright (C) 2014 Azael Avalos
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 *
25 * The devolpment page for this driver is located at
26 * http://memebeam.org/toys/ToshibaAcpiDriver.
27 *
28 * Credits:
29 * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse
30 * engineering the Windows drivers
31 * Yasushi Nagato - changes for linux kernel 2.4 -> 2.5
32 * Rob Miller - TV out and hotkeys help
33 *
34 *
35 * TODO
36 *
37 */
38
Joe Perches7e334602011-03-29 15:21:52 -070039#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
40
Azael Avalos548c4302014-03-25 20:38:35 -060041#define TOSHIBA_ACPI_VERSION "0.20"
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#define PROC_INTERFACE_VERSION 1
43
44#include <linux/kernel.h>
45#include <linux/module.h>
46#include <linux/init.h>
47#include <linux/types.h>
48#include <linux/proc_fs.h>
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -080049#include <linux/seq_file.h>
Holger Machtc9263552006-10-20 14:30:29 -070050#include <linux/backlight.h>
philipl@overt.orgc41a40c2008-08-30 11:57:39 -040051#include <linux/rfkill.h>
Matthew Garrett6335e4d2010-02-25 15:20:54 -050052#include <linux/input.h>
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -070053#include <linux/input/sparse-keymap.h>
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +020054#include <linux/leds.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090055#include <linux/slab.h>
Seth Forshee29cd2932012-01-18 13:44:09 -060056#include <linux/workqueue.h>
57#include <linux/i8042.h>
Lv Zheng8b484632013-12-03 08:49:16 +080058#include <linux/acpi.h>
Takashi Iwaife808bfb2014-04-29 15:15:38 +020059#include <linux/dmi.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#include <asm/uaccess.h>
61
Linus Torvalds1da177e2005-04-16 15:20:36 -070062MODULE_AUTHOR("John Belmonte");
63MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
64MODULE_LICENSE("GPL");
65
Seth Forsheef11f9992012-01-18 13:44:11 -060066#define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100"
67
Seth Forshee29cd2932012-01-18 13:44:09 -060068/* Scan code for Fn key on TOS1900 models */
69#define TOS1900_FN_SCAN 0x6e
70
Linus Torvalds1da177e2005-04-16 15:20:36 -070071/* Toshiba ACPI method paths */
Linus Torvalds1da177e2005-04-16 15:20:36 -070072#define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX"
73
Azael Avalos258c5902014-09-29 20:40:07 -060074/* The Toshiba configuration interface is composed of the HCI and the SCI,
75 * which are defined as follows:
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 *
77 * HCI is Toshiba's "Hardware Control Interface" which is supposed to
78 * be uniform across all their models. Ideally we would just call
79 * dedicated ACPI methods instead of using this primitive interface.
80 * However the ACPI methods seem to be incomplete in some areas (for
81 * example they allow setting, but not reading, the LCD brightness value),
82 * so this is still useful.
Matthew Garrettea6b31f2014-04-04 14:22:34 -040083 *
Azael Avalos84a62732014-03-25 20:38:29 -060084 * SCI stands for "System Configuration Interface" which aim is to
85 * conceal differences in hardware between different models.
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 */
87
Azael Avalos258c5902014-09-29 20:40:07 -060088#define TCI_WORDS 6
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90/* operations */
91#define HCI_SET 0xff00
92#define HCI_GET 0xfe00
Azael Avalos84a62732014-03-25 20:38:29 -060093#define SCI_OPEN 0xf100
94#define SCI_CLOSE 0xf200
95#define SCI_GET 0xf300
96#define SCI_SET 0xf400
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
98/* return codes */
Azael Avalos1864bbc2014-09-29 20:40:08 -060099#define TOS_SUCCESS 0x0000
100#define TOS_OPEN_CLOSE_OK 0x0044
101#define TOS_FAILURE 0x1000
102#define TOS_NOT_SUPPORTED 0x8000
103#define TOS_ALREADY_OPEN 0x8100
104#define TOS_NOT_OPENED 0x8200
105#define TOS_INPUT_DATA_ERROR 0x8300
106#define TOS_WRITE_PROTECTED 0x8400
107#define TOS_NOT_PRESENT 0x8600
108#define TOS_FIFO_EMPTY 0x8c00
109#define TOS_DATA_NOT_AVAILABLE 0x8d20
110#define TOS_NOT_INITIALIZED 0x8d50
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
112/* registers */
113#define HCI_FAN 0x0004
Akio Idehara121b7b02012-04-06 01:46:43 +0900114#define HCI_TR_BACKLIGHT 0x0005
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115#define HCI_SYSTEM_EVENT 0x0016
116#define HCI_VIDEO_OUT 0x001c
117#define HCI_HOTKEY_EVENT 0x001e
118#define HCI_LCD_BRIGHTNESS 0x002a
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400119#define HCI_WIRELESS 0x0056
Azael Avalos5a2813e2014-03-25 20:38:34 -0600120#define HCI_ACCELEROMETER 0x006d
Azael Avalos360f0f32014-03-25 20:38:31 -0600121#define HCI_KBD_ILLUMINATION 0x0095
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600122#define HCI_ECO_MODE 0x0097
Azael Avalos5a2813e2014-03-25 20:38:34 -0600123#define HCI_ACCELEROMETER2 0x00a6
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 Avalos9d8658a2014-03-25 20:38:32 -0600128#define SCI_TOUCHPAD 0x050e
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
130/* field definitions */
Azael Avalos5a2813e2014-03-25 20:38:34 -0600131#define HCI_ACCEL_MASK 0x7fff
Seth Forshee29cd2932012-01-18 13:44:09 -0600132#define HCI_HOTKEY_DISABLE 0x0b
133#define HCI_HOTKEY_ENABLE 0x09
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134#define HCI_LCD_BRIGHTNESS_BITS 3
135#define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS)
136#define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS)
Azael Avalos360f0f32014-03-25 20:38:31 -0600137#define HCI_MISC_SHIFT 0x10
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138#define HCI_VIDEO_OUT_LCD 0x1
139#define HCI_VIDEO_OUT_CRT 0x2
140#define HCI_VIDEO_OUT_TV 0x4
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400141#define HCI_WIRELESS_KILL_SWITCH 0x01
142#define HCI_WIRELESS_BT_PRESENT 0x0f
143#define HCI_WIRELESS_BT_ATTACH 0x40
144#define HCI_WIRELESS_BT_POWER 0x80
Azael Avalos93f8c162014-09-12 18:50:36 -0600145#define SCI_KBD_MODE_MASK 0x1f
Azael Avalos360f0f32014-03-25 20:38:31 -0600146#define SCI_KBD_MODE_FNZ 0x1
147#define SCI_KBD_MODE_AUTO 0x2
Azael Avalos93f8c162014-09-12 18:50:36 -0600148#define SCI_KBD_MODE_ON 0x8
149#define SCI_KBD_MODE_OFF 0x10
150#define SCI_KBD_TIME_MAX 0x3c001a
Azael Avalose26ffe52015-01-18 18:30:22 -0700151#define SCI_USB_CHARGE_MODE_MASK 0xff
152#define SCI_USB_CHARGE_DISABLED 0x30000
153#define SCI_USB_CHARGE_ALTERNATE 0x30009
154#define SCI_USB_CHARGE_AUTO 0x30021
Azael Avalos182bcaa2015-01-18 18:30:23 -0700155#define SCI_USB_CHARGE_BAT_MASK 0x7
156#define SCI_USB_CHARGE_BAT_LVL_OFF 0x1
157#define SCI_USB_CHARGE_BAT_LVL_ON 0x4
158#define SCI_USB_CHARGE_BAT_LVL 0x0200
Azael Avalosbb3fe012015-01-18 18:30:24 -0700159#define SCI_USB_CHARGE_RAPID_DSP 0x0300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160
Seth Forshee135740d2011-09-20 16:55:49 -0500161struct toshiba_acpi_dev {
162 struct acpi_device *acpi_dev;
163 const char *method_hci;
164 struct rfkill *bt_rfk;
165 struct input_dev *hotkey_dev;
Seth Forshee29cd2932012-01-18 13:44:09 -0600166 struct work_struct hotkey_work;
Seth Forshee135740d2011-09-20 16:55:49 -0500167 struct backlight_device *backlight_dev;
168 struct led_classdev led_dev;
Azael Avalos360f0f32014-03-25 20:38:31 -0600169 struct led_classdev kbd_led;
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600170 struct led_classdev eco_led;
Seth Forshee36d03f92011-09-20 16:55:53 -0500171
Seth Forshee135740d2011-09-20 16:55:49 -0500172 int force_fan;
173 int last_key_event;
174 int key_event_valid;
Azael Avalos93f8c162014-09-12 18:50:36 -0600175 int kbd_type;
Azael Avalos360f0f32014-03-25 20:38:31 -0600176 int kbd_mode;
177 int kbd_time;
Azael Avalos182bcaa2015-01-18 18:30:23 -0700178 int usbsc_bat_level;
Seth Forshee135740d2011-09-20 16:55:49 -0500179
Dan Carpenter592b7462012-01-15 14:28:20 +0300180 unsigned int illumination_supported:1;
181 unsigned int video_supported:1;
182 unsigned int fan_supported:1;
183 unsigned int system_event_supported:1;
Seth Forshee29cd2932012-01-18 13:44:09 -0600184 unsigned int ntfy_supported:1;
185 unsigned int info_supported:1;
Akio Idehara121b7b02012-04-06 01:46:43 +0900186 unsigned int tr_backlight_supported:1;
Azael Avalos360f0f32014-03-25 20:38:31 -0600187 unsigned int kbd_illum_supported:1;
188 unsigned int kbd_led_registered:1;
Azael Avalos9d8658a2014-03-25 20:38:32 -0600189 unsigned int touchpad_supported:1;
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600190 unsigned int eco_supported:1;
Azael Avalos5a2813e2014-03-25 20:38:34 -0600191 unsigned int accelerometer_supported:1;
Azael Avalose26ffe52015-01-18 18:30:22 -0700192 unsigned int usb_sleep_charge_supported:1;
Azael Avalosbb3fe012015-01-18 18:30:24 -0700193 unsigned int usb_rapid_charge_supported:1;
Azael Avalos172ce0a2015-01-18 18:30:25 -0700194 unsigned int usb_sleep_music_supported:1;
Azael Avalos360f0f32014-03-25 20:38:31 -0600195 unsigned int sysfs_created:1;
Seth Forshee36d03f92011-09-20 16:55:53 -0500196
Seth Forshee135740d2011-09-20 16:55:49 -0500197 struct mutex mutex;
198};
199
Seth Forshee29cd2932012-01-18 13:44:09 -0600200static struct toshiba_acpi_dev *toshiba_acpi;
201
arvidjaar@mail.ru4db42c52008-03-04 15:06:34 -0800202static const struct acpi_device_id toshiba_device_ids[] = {
203 {"TOS6200", 0},
Ondrej Zary63a9e012014-11-10 00:11:54 +0100204 {"TOS6207", 0},
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400205 {"TOS6208", 0},
arvidjaar@mail.ru4db42c52008-03-04 15:06:34 -0800206 {"TOS1900", 0},
207 {"", 0},
208};
209MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
210
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -0800211static const struct key_entry toshiba_acpi_keymap[] = {
Unai Uribarrifec278a2014-01-14 11:06:47 +0100212 { KE_KEY, 0x9e, { KEY_RFKILL } },
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -0700213 { KE_KEY, 0x101, { KEY_MUTE } },
214 { KE_KEY, 0x102, { KEY_ZOOMOUT } },
215 { KE_KEY, 0x103, { KEY_ZOOMIN } },
Azael Avalos408a5d12014-09-05 11:14:03 -0600216 { KE_KEY, 0x10f, { KEY_TAB } },
Azael Avalosaf502832012-01-18 13:44:10 -0600217 { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
218 { KE_KEY, 0x139, { KEY_ZOOMRESET } },
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -0700219 { KE_KEY, 0x13b, { KEY_COFFEE } },
220 { KE_KEY, 0x13c, { KEY_BATTERY } },
221 { KE_KEY, 0x13d, { KEY_SLEEP } },
222 { KE_KEY, 0x13e, { KEY_SUSPEND } },
223 { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } },
224 { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } },
225 { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } },
226 { KE_KEY, 0x142, { KEY_WLAN } },
Azael Avalosaf502832012-01-18 13:44:10 -0600227 { KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } },
Jon Dowlanda49010f2010-10-27 00:24:59 +0100228 { KE_KEY, 0x17f, { KEY_FN } },
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -0700229 { KE_KEY, 0xb05, { KEY_PROG2 } },
230 { KE_KEY, 0xb06, { KEY_WWW } },
231 { KE_KEY, 0xb07, { KEY_MAIL } },
232 { KE_KEY, 0xb30, { KEY_STOP } },
233 { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } },
234 { KE_KEY, 0xb32, { KEY_NEXTSONG } },
235 { KE_KEY, 0xb33, { KEY_PLAYPAUSE } },
236 { KE_KEY, 0xb5a, { KEY_MEDIA } },
Azael Avalos408a5d12014-09-05 11:14:03 -0600237 { KE_IGNORE, 0x1430, { KEY_RESERVED } }, /* Wake from sleep */
238 { KE_IGNORE, 0x1501, { KEY_RESERVED } }, /* Output changed */
239 { KE_IGNORE, 0x1502, { KEY_RESERVED } }, /* HDMI plugged/unplugged */
240 { KE_IGNORE, 0x1ABE, { KEY_RESERVED } }, /* Protection level set */
241 { KE_IGNORE, 0x1ABF, { KEY_RESERVED } }, /* Protection level off */
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -0700242 { KE_END, 0 },
Matthew Garrett6335e4d2010-02-25 15:20:54 -0500243};
244
Takashi Iwaife808bfb2014-04-29 15:15:38 +0200245/* alternative keymap */
246static const struct dmi_system_id toshiba_alt_keymap_dmi[] = {
247 {
248 .matches = {
249 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
250 DMI_MATCH(DMI_PRODUCT_NAME, "Satellite M840"),
251 },
252 },
Azael Avalose6efad72014-08-04 09:21:02 -0600253 {
254 .matches = {
255 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
256 DMI_MATCH(DMI_PRODUCT_NAME, "Qosmio X75-A"),
257 },
258 },
Aaron Lub1bde682014-10-23 16:18:02 +0800259 {
260 .matches = {
261 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
262 DMI_MATCH(DMI_PRODUCT_NAME, "TECRA A50-A"),
263 },
264 },
Takashi Iwaife808bfb2014-04-29 15:15:38 +0200265 {}
266};
267
268static const struct key_entry toshiba_acpi_alt_keymap[] = {
269 { KE_KEY, 0x157, { KEY_MUTE } },
270 { KE_KEY, 0x102, { KEY_ZOOMOUT } },
271 { KE_KEY, 0x103, { KEY_ZOOMIN } },
Azael Avalose6efad72014-08-04 09:21:02 -0600272 { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
Takashi Iwaife808bfb2014-04-29 15:15:38 +0200273 { KE_KEY, 0x139, { KEY_ZOOMRESET } },
274 { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } },
275 { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } },
276 { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } },
277 { KE_KEY, 0x158, { KEY_WLAN } },
278 { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } },
279 { KE_END, 0 },
280};
281
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282/* utility
283 */
284
Len Brown4be44fc2005-08-05 00:44:28 -0400285static __inline__ void _set_bit(u32 * word, u32 mask, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286{
287 *word = (*word & ~mask) | (mask * value);
288}
289
290/* acpi interface wrappers
291 */
292
Len Brown4be44fc2005-08-05 00:44:28 -0400293static int write_acpi_int(const char *methodName, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 acpi_status status;
296
Zhang Rui619400d2013-09-03 08:31:56 +0800297 status = acpi_execute_simple_method(NULL, (char *)methodName, val);
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500298 return (status == AE_OK) ? 0 : -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299}
300
Azael Avalos258c5902014-09-29 20:40:07 -0600301/* Perform a raw configuration call. Here we don't care about input or output
302 * buffer format.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 */
Azael Avalos258c5902014-09-29 20:40:07 -0600304static acpi_status tci_raw(struct toshiba_acpi_dev *dev,
305 const u32 in[TCI_WORDS], u32 out[TCI_WORDS])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306{
307 struct acpi_object_list params;
Azael Avalos258c5902014-09-29 20:40:07 -0600308 union acpi_object in_objs[TCI_WORDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 struct acpi_buffer results;
Azael Avalos258c5902014-09-29 20:40:07 -0600310 union acpi_object out_objs[TCI_WORDS + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 acpi_status status;
312 int i;
313
Azael Avalos258c5902014-09-29 20:40:07 -0600314 params.count = TCI_WORDS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 params.pointer = in_objs;
Azael Avalos258c5902014-09-29 20:40:07 -0600316 for (i = 0; i < TCI_WORDS; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 in_objs[i].type = ACPI_TYPE_INTEGER;
318 in_objs[i].integer.value = in[i];
319 }
320
321 results.length = sizeof(out_objs);
322 results.pointer = out_objs;
323
Seth Forshee6e02cc72011-09-20 16:55:51 -0500324 status = acpi_evaluate_object(dev->acpi_dev->handle,
325 (char *)dev->method_hci, &params,
Len Brown4be44fc2005-08-05 00:44:28 -0400326 &results);
Azael Avalos258c5902014-09-29 20:40:07 -0600327 if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 for (i = 0; i < out_objs->package.count; ++i) {
329 out[i] = out_objs->package.elements[i].integer.value;
330 }
331 }
332
333 return status;
334}
335
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400336/* common hci tasks (get or set one or two value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 *
338 * In addition to the ACPI status, the HCI system returns a result which
339 * may be useful (such as "not supported").
340 */
341
Azael Avalos893f3f62014-09-29 20:40:09 -0600342static u32 hci_write1(struct toshiba_acpi_dev *dev, u32 reg, u32 in1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343{
Azael Avalos258c5902014-09-29 20:40:07 -0600344 u32 in[TCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 };
345 u32 out[TCI_WORDS];
346 acpi_status status = tci_raw(dev, in, out);
Azael Avalos893f3f62014-09-29 20:40:09 -0600347
348 return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349}
350
Azael Avalos893f3f62014-09-29 20:40:09 -0600351static u32 hci_read1(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352{
Azael Avalos258c5902014-09-29 20:40:07 -0600353 u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 };
354 u32 out[TCI_WORDS];
355 acpi_status status = tci_raw(dev, in, out);
Azael Avalos893f3f62014-09-29 20:40:09 -0600356 if (ACPI_FAILURE(status))
357 return TOS_FAILURE;
358
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 *out1 = out[2];
Azael Avalos893f3f62014-09-29 20:40:09 -0600360
361 return out[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362}
363
Azael Avalos893f3f62014-09-29 20:40:09 -0600364static u32 hci_write2(struct toshiba_acpi_dev *dev, u32 reg, u32 in1, u32 in2)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400365{
Azael Avalos258c5902014-09-29 20:40:07 -0600366 u32 in[TCI_WORDS] = { HCI_SET, reg, in1, in2, 0, 0 };
367 u32 out[TCI_WORDS];
368 acpi_status status = tci_raw(dev, in, out);
Azael Avalos893f3f62014-09-29 20:40:09 -0600369
370 return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE;
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400371}
372
Azael Avalos893f3f62014-09-29 20:40:09 -0600373static u32 hci_read2(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1, u32 *out2)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400374{
Azael Avalos258c5902014-09-29 20:40:07 -0600375 u32 in[TCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 };
376 u32 out[TCI_WORDS];
377 acpi_status status = tci_raw(dev, in, out);
Azael Avalos893f3f62014-09-29 20:40:09 -0600378 if (ACPI_FAILURE(status))
379 return TOS_FAILURE;
380
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400381 *out1 = out[2];
382 *out2 = out[3];
Azael Avalos893f3f62014-09-29 20:40:09 -0600383
384 return out[0];
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400385}
386
Azael Avalos84a62732014-03-25 20:38:29 -0600387/* common sci tasks
388 */
389
390static int sci_open(struct toshiba_acpi_dev *dev)
391{
Azael Avalos258c5902014-09-29 20:40:07 -0600392 u32 in[TCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 };
393 u32 out[TCI_WORDS];
Azael Avalos84a62732014-03-25 20:38:29 -0600394 acpi_status status;
395
Azael Avalos258c5902014-09-29 20:40:07 -0600396 status = tci_raw(dev, in, out);
Azael Avalos1864bbc2014-09-29 20:40:08 -0600397 if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
Azael Avalos84a62732014-03-25 20:38:29 -0600398 pr_err("ACPI call to open SCI failed\n");
399 return 0;
400 }
401
Azael Avalos1864bbc2014-09-29 20:40:08 -0600402 if (out[0] == TOS_OPEN_CLOSE_OK) {
Azael Avalos84a62732014-03-25 20:38:29 -0600403 return 1;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600404 } else if (out[0] == TOS_ALREADY_OPEN) {
Azael Avalos84a62732014-03-25 20:38:29 -0600405 pr_info("Toshiba SCI already opened\n");
406 return 1;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600407 } else if (out[0] == TOS_NOT_PRESENT) {
Azael Avalos84a62732014-03-25 20:38:29 -0600408 pr_info("Toshiba SCI is not present\n");
409 }
410
411 return 0;
412}
413
414static void sci_close(struct toshiba_acpi_dev *dev)
415{
Azael Avalos258c5902014-09-29 20:40:07 -0600416 u32 in[TCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 };
417 u32 out[TCI_WORDS];
Azael Avalos84a62732014-03-25 20:38:29 -0600418 acpi_status status;
419
Azael Avalos258c5902014-09-29 20:40:07 -0600420 status = tci_raw(dev, in, out);
Azael Avalos1864bbc2014-09-29 20:40:08 -0600421 if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
Azael Avalos84a62732014-03-25 20:38:29 -0600422 pr_err("ACPI call to close SCI failed\n");
423 return;
424 }
425
Azael Avalos1864bbc2014-09-29 20:40:08 -0600426 if (out[0] == TOS_OPEN_CLOSE_OK)
Azael Avalos84a62732014-03-25 20:38:29 -0600427 return;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600428 else if (out[0] == TOS_NOT_OPENED)
Azael Avalos84a62732014-03-25 20:38:29 -0600429 pr_info("Toshiba SCI not opened\n");
Azael Avalos1864bbc2014-09-29 20:40:08 -0600430 else if (out[0] == TOS_NOT_PRESENT)
Azael Avalos84a62732014-03-25 20:38:29 -0600431 pr_info("Toshiba SCI is not present\n");
432}
433
Azael Avalos893f3f62014-09-29 20:40:09 -0600434static u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1)
Azael Avalos84a62732014-03-25 20:38:29 -0600435{
Azael Avalos258c5902014-09-29 20:40:07 -0600436 u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 };
437 u32 out[TCI_WORDS];
438 acpi_status status = tci_raw(dev, in, out);
Azael Avalos893f3f62014-09-29 20:40:09 -0600439 if (ACPI_FAILURE(status))
440 return TOS_FAILURE;
441
Azael Avalos84a62732014-03-25 20:38:29 -0600442 *out1 = out[2];
Azael Avalos893f3f62014-09-29 20:40:09 -0600443
444 return out[0];
Azael Avalos84a62732014-03-25 20:38:29 -0600445}
446
Azael Avalos893f3f62014-09-29 20:40:09 -0600447static u32 sci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1)
Azael Avalos84a62732014-03-25 20:38:29 -0600448{
Azael Avalos258c5902014-09-29 20:40:07 -0600449 u32 in[TCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 };
450 u32 out[TCI_WORDS];
451 acpi_status status = tci_raw(dev, in, out);
Azael Avalos893f3f62014-09-29 20:40:09 -0600452
453 return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE;
Azael Avalos84a62732014-03-25 20:38:29 -0600454}
455
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200456/* Illumination support */
Seth Forshee135740d2011-09-20 16:55:49 -0500457static int toshiba_illumination_available(struct toshiba_acpi_dev *dev)
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200458{
Azael Avalos258c5902014-09-29 20:40:07 -0600459 u32 in[TCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 };
460 u32 out[TCI_WORDS];
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200461 acpi_status status;
462
Azael Avalosfdb79082014-03-25 20:38:30 -0600463 if (!sci_open(dev))
464 return 0;
465
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 Avalos1864bbc2014-09-29 20:40:08 -0600468 if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
Azael Avalosfdb79082014-03-25 20:38:30 -0600469 pr_err("ACPI call to query Illumination support failed\n");
470 return 0;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600471 } else if (out[0] == TOS_NOT_SUPPORTED) {
Joe Perches7e334602011-03-29 15:21:52 -0700472 pr_info("Illumination device not available\n");
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200473 return 0;
474 }
Azael Avalosfdb79082014-03-25 20:38:30 -0600475
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200476 return 1;
477}
478
479static void toshiba_illumination_set(struct led_classdev *cdev,
480 enum led_brightness brightness)
481{
Seth Forshee135740d2011-09-20 16:55:49 -0500482 struct toshiba_acpi_dev *dev = container_of(cdev,
483 struct toshiba_acpi_dev, led_dev);
Azael Avalosfdb79082014-03-25 20:38:30 -0600484 u32 state, result;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200485
486 /* First request : initialize communication. */
Azael Avalosfdb79082014-03-25 20:38:30 -0600487 if (!sci_open(dev))
488 return;
489
490 /* Switch the illumination on/off */
491 state = brightness ? 1 : 0;
Azael Avalos893f3f62014-09-29 20:40:09 -0600492 result = sci_write(dev, SCI_ILLUMINATION, state);
Azael Avalosfdb79082014-03-25 20:38:30 -0600493 sci_close(dev);
Azael Avalos893f3f62014-09-29 20:40:09 -0600494 if (result == TOS_FAILURE) {
Azael Avalosfdb79082014-03-25 20:38:30 -0600495 pr_err("ACPI call for illumination failed\n");
496 return;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600497 } else if (result == TOS_NOT_SUPPORTED) {
Azael Avalosfdb79082014-03-25 20:38:30 -0600498 pr_info("Illumination not supported\n");
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200499 return;
500 }
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200501}
502
503static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
504{
Seth Forshee135740d2011-09-20 16:55:49 -0500505 struct toshiba_acpi_dev *dev = container_of(cdev,
506 struct toshiba_acpi_dev, led_dev);
Azael Avalosfdb79082014-03-25 20:38:30 -0600507 u32 state, result;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200508
509 /* First request : initialize communication. */
Azael Avalosfdb79082014-03-25 20:38:30 -0600510 if (!sci_open(dev))
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200511 return LED_OFF;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200512
513 /* Check the illumination */
Azael Avalos893f3f62014-09-29 20:40:09 -0600514 result = sci_read(dev, SCI_ILLUMINATION, &state);
Azael Avalosfdb79082014-03-25 20:38:30 -0600515 sci_close(dev);
Azael Avalos893f3f62014-09-29 20:40:09 -0600516 if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
Azael Avalosfdb79082014-03-25 20:38:30 -0600517 pr_err("ACPI call for illumination failed\n");
518 return LED_OFF;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600519 } else if (result == TOS_NOT_SUPPORTED) {
Azael Avalosfdb79082014-03-25 20:38:30 -0600520 pr_info("Illumination not supported\n");
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200521 return LED_OFF;
522 }
523
Azael Avalosfdb79082014-03-25 20:38:30 -0600524 return state ? LED_FULL : LED_OFF;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200525}
Matthew Garrettea6b31f2014-04-04 14:22:34 -0400526
Azael Avalos360f0f32014-03-25 20:38:31 -0600527/* KBD Illumination */
Azael Avalos93f8c162014-09-12 18:50:36 -0600528static int toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev)
529{
Azael Avalos258c5902014-09-29 20:40:07 -0600530 u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 };
531 u32 out[TCI_WORDS];
Azael Avalos93f8c162014-09-12 18:50:36 -0600532 acpi_status status;
533
534 if (!sci_open(dev))
535 return 0;
536
Azael Avalos258c5902014-09-29 20:40:07 -0600537 status = tci_raw(dev, in, out);
Azael Avalos93f8c162014-09-12 18:50:36 -0600538 sci_close(dev);
Azael Avalos1864bbc2014-09-29 20:40:08 -0600539 if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
Azael Avalos93f8c162014-09-12 18:50:36 -0600540 pr_err("ACPI call to query kbd illumination support failed\n");
541 return 0;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600542 } else if (out[0] == TOS_NOT_SUPPORTED) {
Azael Avalos93f8c162014-09-12 18:50:36 -0600543 pr_info("Keyboard illumination not available\n");
544 return 0;
545 }
546
547 /* Check for keyboard backlight timeout max value,
548 * previous kbd backlight implementation set this to
549 * 0x3c0003, and now the new implementation set this
550 * to 0x3c001a, use this to distinguish between them
551 */
552 if (out[3] == SCI_KBD_TIME_MAX)
553 dev->kbd_type = 2;
554 else
555 dev->kbd_type = 1;
556 /* Get the current keyboard backlight mode */
557 dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK;
558 /* Get the current time (1-60 seconds) */
559 dev->kbd_time = out[2] >> HCI_MISC_SHIFT;
560
561 return 1;
562}
563
Azael Avalos360f0f32014-03-25 20:38:31 -0600564static int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time)
565{
566 u32 result;
Azael Avalos360f0f32014-03-25 20:38:31 -0600567
568 if (!sci_open(dev))
569 return -EIO;
570
Azael Avalos893f3f62014-09-29 20:40:09 -0600571 result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time);
Azael Avalos360f0f32014-03-25 20:38:31 -0600572 sci_close(dev);
Azael Avalos893f3f62014-09-29 20:40:09 -0600573 if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
Azael Avalos360f0f32014-03-25 20:38:31 -0600574 pr_err("ACPI call to set KBD backlight status failed\n");
575 return -EIO;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600576 } else if (result == TOS_NOT_SUPPORTED) {
Azael Avalos360f0f32014-03-25 20:38:31 -0600577 pr_info("Keyboard backlight status not supported\n");
578 return -ENODEV;
579 }
580
581 return 0;
582}
583
584static int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time)
585{
586 u32 result;
Azael Avalos360f0f32014-03-25 20:38:31 -0600587
588 if (!sci_open(dev))
589 return -EIO;
590
Azael Avalos893f3f62014-09-29 20:40:09 -0600591 result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time);
Azael Avalos360f0f32014-03-25 20:38:31 -0600592 sci_close(dev);
Azael Avalos893f3f62014-09-29 20:40:09 -0600593 if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
Azael Avalos360f0f32014-03-25 20:38:31 -0600594 pr_err("ACPI call to get KBD backlight status failed\n");
595 return -EIO;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600596 } else if (result == TOS_NOT_SUPPORTED) {
Azael Avalos360f0f32014-03-25 20:38:31 -0600597 pr_info("Keyboard backlight status not supported\n");
598 return -ENODEV;
599 }
600
601 return 0;
602}
603
604static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev)
605{
606 struct toshiba_acpi_dev *dev = container_of(cdev,
607 struct toshiba_acpi_dev, kbd_led);
608 u32 state, result;
Azael Avalos360f0f32014-03-25 20:38:31 -0600609
610 /* Check the keyboard backlight state */
Azael Avalos893f3f62014-09-29 20:40:09 -0600611 result = hci_read1(dev, HCI_KBD_ILLUMINATION, &state);
612 if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
Azael Avalos360f0f32014-03-25 20:38:31 -0600613 pr_err("ACPI call to get the keyboard backlight failed\n");
614 return LED_OFF;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600615 } else if (result == TOS_NOT_SUPPORTED) {
Azael Avalos360f0f32014-03-25 20:38:31 -0600616 pr_info("Keyboard backlight not supported\n");
617 return LED_OFF;
618 }
619
620 return state ? LED_FULL : LED_OFF;
621}
622
623static void toshiba_kbd_backlight_set(struct led_classdev *cdev,
624 enum led_brightness brightness)
625{
626 struct toshiba_acpi_dev *dev = container_of(cdev,
627 struct toshiba_acpi_dev, kbd_led);
628 u32 state, result;
Azael Avalos360f0f32014-03-25 20:38:31 -0600629
630 /* Set the keyboard backlight state */
631 state = brightness ? 1 : 0;
Azael Avalos893f3f62014-09-29 20:40:09 -0600632 result = hci_write1(dev, HCI_KBD_ILLUMINATION, state);
633 if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
Azael Avalos360f0f32014-03-25 20:38:31 -0600634 pr_err("ACPI call to set KBD Illumination mode failed\n");
635 return;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600636 } else if (result == TOS_NOT_SUPPORTED) {
Azael Avalos360f0f32014-03-25 20:38:31 -0600637 pr_info("Keyboard backlight not supported\n");
638 return;
639 }
640}
Matthew Garrettea6b31f2014-04-04 14:22:34 -0400641
Azael Avalos9d8658a2014-03-25 20:38:32 -0600642/* TouchPad support */
643static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state)
644{
645 u32 result;
Azael Avalos9d8658a2014-03-25 20:38:32 -0600646
647 if (!sci_open(dev))
648 return -EIO;
649
Azael Avalos893f3f62014-09-29 20:40:09 -0600650 result = sci_write(dev, SCI_TOUCHPAD, state);
Azael Avalos9d8658a2014-03-25 20:38:32 -0600651 sci_close(dev);
Azael Avalos893f3f62014-09-29 20:40:09 -0600652 if (result == TOS_FAILURE) {
Azael Avalos9d8658a2014-03-25 20:38:32 -0600653 pr_err("ACPI call to set the touchpad failed\n");
654 return -EIO;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600655 } else if (result == TOS_NOT_SUPPORTED) {
Azael Avalos9d8658a2014-03-25 20:38:32 -0600656 return -ENODEV;
657 }
658
659 return 0;
660}
661
662static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state)
663{
664 u32 result;
Azael Avalos9d8658a2014-03-25 20:38:32 -0600665
666 if (!sci_open(dev))
667 return -EIO;
668
Azael Avalos893f3f62014-09-29 20:40:09 -0600669 result = sci_read(dev, SCI_TOUCHPAD, state);
Azael Avalos9d8658a2014-03-25 20:38:32 -0600670 sci_close(dev);
Azael Avalos893f3f62014-09-29 20:40:09 -0600671 if (result == TOS_FAILURE) {
Azael Avalos9d8658a2014-03-25 20:38:32 -0600672 pr_err("ACPI call to query the touchpad failed\n");
673 return -EIO;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600674 } else if (result == TOS_NOT_SUPPORTED) {
Azael Avalos9d8658a2014-03-25 20:38:32 -0600675 return -ENODEV;
676 }
677
678 return 0;
679}
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200680
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600681/* Eco Mode support */
682static int toshiba_eco_mode_available(struct toshiba_acpi_dev *dev)
683{
684 acpi_status status;
Azael Avalos258c5902014-09-29 20:40:07 -0600685 u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 };
686 u32 out[TCI_WORDS];
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600687
Azael Avalos258c5902014-09-29 20:40:07 -0600688 status = tci_raw(dev, in, out);
Azael Avalos1864bbc2014-09-29 20:40:08 -0600689 if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600690 pr_info("ACPI call to get ECO led failed\n");
691 return 0;
692 }
693
694 return 1;
695}
696
697static enum led_brightness toshiba_eco_mode_get_status(struct led_classdev *cdev)
698{
699 struct toshiba_acpi_dev *dev = container_of(cdev,
700 struct toshiba_acpi_dev, eco_led);
Azael Avalos258c5902014-09-29 20:40:07 -0600701 u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 };
702 u32 out[TCI_WORDS];
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600703 acpi_status status;
704
Azael Avalos258c5902014-09-29 20:40:07 -0600705 status = tci_raw(dev, in, out);
Azael Avalos1864bbc2014-09-29 20:40:08 -0600706 if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600707 pr_err("ACPI call to get ECO led failed\n");
708 return LED_OFF;
709 }
710
711 return out[2] ? LED_FULL : LED_OFF;
712}
713
714static void toshiba_eco_mode_set_status(struct led_classdev *cdev,
715 enum led_brightness brightness)
716{
717 struct toshiba_acpi_dev *dev = container_of(cdev,
718 struct toshiba_acpi_dev, eco_led);
Azael Avalos258c5902014-09-29 20:40:07 -0600719 u32 in[TCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 };
720 u32 out[TCI_WORDS];
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600721 acpi_status status;
722
723 /* Switch the Eco Mode led on/off */
724 in[2] = (brightness) ? 1 : 0;
Azael Avalos258c5902014-09-29 20:40:07 -0600725 status = tci_raw(dev, in, out);
Azael Avalos1864bbc2014-09-29 20:40:08 -0600726 if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600727 pr_err("ACPI call to set ECO led failed\n");
728 return;
729 }
730}
Matthew Garrettea6b31f2014-04-04 14:22:34 -0400731
Azael Avalos5a2813e2014-03-25 20:38:34 -0600732/* Accelerometer support */
733static int toshiba_accelerometer_supported(struct toshiba_acpi_dev *dev)
734{
Azael Avalos258c5902014-09-29 20:40:07 -0600735 u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 };
736 u32 out[TCI_WORDS];
Azael Avalos5a2813e2014-03-25 20:38:34 -0600737 acpi_status status;
738
739 /* Check if the accelerometer call exists,
740 * this call also serves as initialization
741 */
Azael Avalos258c5902014-09-29 20:40:07 -0600742 status = tci_raw(dev, in, out);
Azael Avalos1864bbc2014-09-29 20:40:08 -0600743 if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
Azael Avalos5a2813e2014-03-25 20:38:34 -0600744 pr_err("ACPI call to query the accelerometer failed\n");
745 return -EIO;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600746 } else if (out[0] == TOS_DATA_NOT_AVAILABLE ||
747 out[0] == TOS_NOT_INITIALIZED) {
Azael Avalos5a2813e2014-03-25 20:38:34 -0600748 pr_err("Accelerometer not initialized\n");
749 return -EIO;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600750 } else if (out[0] == TOS_NOT_SUPPORTED) {
Azael Avalos5a2813e2014-03-25 20:38:34 -0600751 pr_info("Accelerometer not supported\n");
752 return -ENODEV;
753 }
754
755 return 0;
756}
757
758static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev,
759 u32 *xy, u32 *z)
760{
Azael Avalos258c5902014-09-29 20:40:07 -0600761 u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 };
762 u32 out[TCI_WORDS];
Azael Avalos5a2813e2014-03-25 20:38:34 -0600763 acpi_status status;
764
765 /* Check the Accelerometer status */
Azael Avalos258c5902014-09-29 20:40:07 -0600766 status = tci_raw(dev, in, out);
Azael Avalos1864bbc2014-09-29 20:40:08 -0600767 if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
Azael Avalos5a2813e2014-03-25 20:38:34 -0600768 pr_err("ACPI call to query the accelerometer failed\n");
769 return -EIO;
770 }
771
772 *xy = out[2];
773 *z = out[4];
774
775 return 0;
776}
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600777
Azael Avalose26ffe52015-01-18 18:30:22 -0700778/* Sleep (Charge and Music) utilities support */
779static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev,
780 u32 *mode)
781{
782 u32 result;
783
784 if (!sci_open(dev))
785 return -EIO;
786
787 result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode);
788 sci_close(dev);
789 if (result == TOS_FAILURE) {
790 pr_err("ACPI call to set USB S&C mode failed\n");
791 return -EIO;
792 } else if (result == TOS_NOT_SUPPORTED) {
793 pr_info("USB Sleep and Charge not supported\n");
794 return -ENODEV;
795 } else if (result == TOS_INPUT_DATA_ERROR) {
796 return -EIO;
797 }
798
799 return 0;
800}
801
802static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev,
803 u32 mode)
804{
805 u32 result;
806
807 if (!sci_open(dev))
808 return -EIO;
809
810 result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode);
811 sci_close(dev);
812 if (result == TOS_FAILURE) {
813 pr_err("ACPI call to set USB S&C mode failed\n");
814 return -EIO;
815 } else if (result == TOS_NOT_SUPPORTED) {
816 pr_info("USB Sleep and Charge not supported\n");
817 return -ENODEV;
818 } else if (result == TOS_INPUT_DATA_ERROR) {
819 return -EIO;
820 }
821
822 return 0;
823}
824
Azael Avalos182bcaa2015-01-18 18:30:23 -0700825static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev,
826 u32 *mode)
827{
828 u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
829 u32 out[TCI_WORDS];
830 acpi_status status;
831
832 if (!sci_open(dev))
833 return -EIO;
834
835 in[5] = SCI_USB_CHARGE_BAT_LVL;
836 status = tci_raw(dev, in, out);
837 sci_close(dev);
838 if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
839 pr_err("ACPI call to get USB S&C battery level failed\n");
840 return -EIO;
841 } else if (out[0] == TOS_NOT_SUPPORTED) {
842 pr_info("USB Sleep and Charge not supported\n");
843 return -ENODEV;
844 } else if (out[0] == TOS_INPUT_DATA_ERROR) {
845 return -EIO;
846 }
847
848 *mode = out[2];
849
850 return 0;
851}
852
853static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev,
854 u32 mode)
855{
856 u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
857 u32 out[TCI_WORDS];
858 acpi_status status;
859
860 if (!sci_open(dev))
861 return -EIO;
862
863 in[2] = mode;
864 in[5] = SCI_USB_CHARGE_BAT_LVL;
865 status = tci_raw(dev, in, out);
866 sci_close(dev);
867 if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
868 pr_err("ACPI call to set USB S&C battery level failed\n");
869 return -EIO;
870 } else if (out[0] == TOS_NOT_SUPPORTED) {
871 pr_info("USB Sleep and Charge not supported\n");
872 return -ENODEV;
873 } else if (out[0] == TOS_INPUT_DATA_ERROR) {
874 return -EIO;
875 }
876
877 return 0;
878}
879
Azael Avalosbb3fe012015-01-18 18:30:24 -0700880static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev,
881 u32 *state)
882{
883 u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
884 u32 out[TCI_WORDS];
885 acpi_status status;
886
887 if (!sci_open(dev))
888 return -EIO;
889
890 in[5] = SCI_USB_CHARGE_RAPID_DSP;
891 status = tci_raw(dev, in, out);
892 sci_close(dev);
893 if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
894 pr_err("ACPI call to get USB S&C battery level failed\n");
895 return -EIO;
896 } else if (out[0] == TOS_NOT_SUPPORTED ||
897 out[0] == TOS_INPUT_DATA_ERROR) {
898 pr_info("USB Sleep and Charge not supported\n");
899 return -ENODEV;
900 }
901
902 *state = out[2];
903
904 return 0;
905}
906
907static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev,
908 u32 state)
909{
910 u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
911 u32 out[TCI_WORDS];
912 acpi_status status;
913
914 if (!sci_open(dev))
915 return -EIO;
916
917 in[2] = state;
918 in[5] = SCI_USB_CHARGE_RAPID_DSP;
919 status = tci_raw(dev, in, out);
920 sci_close(dev);
921 if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
922 pr_err("ACPI call to set USB S&C battery level failed\n");
923 return -EIO;
924 } else if (out[0] == TOS_NOT_SUPPORTED) {
925 pr_info("USB Sleep and Charge not supported\n");
926 return -ENODEV;
927 } else if (out[0] == TOS_INPUT_DATA_ERROR) {
928 return -EIO;
929 }
930
931 return 0;
932}
933
Azael Avalos172ce0a2015-01-18 18:30:25 -0700934static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state)
935{
936 u32 result;
937
938 if (!sci_open(dev))
939 return -EIO;
940
941 result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state);
942 sci_close(dev);
943 if (result == TOS_FAILURE) {
944 pr_err("ACPI call to set USB S&C mode failed\n");
945 return -EIO;
946 } else if (result == TOS_NOT_SUPPORTED) {
947 pr_info("USB Sleep and Charge not supported\n");
948 return -ENODEV;
949 } else if (result == TOS_INPUT_DATA_ERROR) {
950 return -EIO;
951 }
952
953 return 0;
954}
955
956static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state)
957{
958 u32 result;
959
960 if (!sci_open(dev))
961 return -EIO;
962
963 result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state);
964 sci_close(dev);
965 if (result == TOS_FAILURE) {
966 pr_err("ACPI call to set USB S&C mode failed\n");
967 return -EIO;
968 } else if (result == TOS_NOT_SUPPORTED) {
969 pr_info("USB Sleep and Charge not supported\n");
970 return -ENODEV;
971 } else if (result == TOS_INPUT_DATA_ERROR) {
972 return -EIO;
973 }
974
975 return 0;
976}
977
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400978/* Bluetooth rfkill handlers */
979
Seth Forshee135740d2011-09-20 16:55:49 -0500980static u32 hci_get_bt_present(struct toshiba_acpi_dev *dev, bool *present)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400981{
982 u32 hci_result;
983 u32 value, value2;
984
985 value = 0;
986 value2 = 0;
Azael Avalos893f3f62014-09-29 20:40:09 -0600987 hci_result = hci_read2(dev, HCI_WIRELESS, &value, &value2);
Azael Avalos1864bbc2014-09-29 20:40:08 -0600988 if (hci_result == TOS_SUCCESS)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400989 *present = (value & HCI_WIRELESS_BT_PRESENT) ? true : false;
990
991 return hci_result;
992}
993
Seth Forshee135740d2011-09-20 16:55:49 -0500994static u32 hci_get_radio_state(struct toshiba_acpi_dev *dev, bool *radio_state)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400995{
996 u32 hci_result;
997 u32 value, value2;
998
999 value = 0;
1000 value2 = 0x0001;
Azael Avalos893f3f62014-09-29 20:40:09 -06001001 hci_result = hci_read2(dev, HCI_WIRELESS, &value, &value2);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001002
1003 *radio_state = value & HCI_WIRELESS_KILL_SWITCH;
1004 return hci_result;
1005}
1006
Johannes Berg19d337d2009-06-02 13:01:37 +02001007static int bt_rfkill_set_block(void *data, bool blocked)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001008{
Johannes Berg19d337d2009-06-02 13:01:37 +02001009 struct toshiba_acpi_dev *dev = data;
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001010 u32 result1, result2;
1011 u32 value;
Johannes Berg19d337d2009-06-02 13:01:37 +02001012 int err;
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001013 bool radio_state;
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001014
Johannes Berg19d337d2009-06-02 13:01:37 +02001015 value = (blocked == false);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001016
1017 mutex_lock(&dev->mutex);
Azael Avalos1864bbc2014-09-29 20:40:08 -06001018 if (hci_get_radio_state(dev, &radio_state) != TOS_SUCCESS) {
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001019 err = -EIO;
Johannes Berg19d337d2009-06-02 13:01:37 +02001020 goto out;
1021 }
1022
1023 if (!radio_state) {
1024 err = 0;
1025 goto out;
1026 }
1027
Azael Avalos893f3f62014-09-29 20:40:09 -06001028 result1 = hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER);
1029 result2 = hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001030
Azael Avalos1864bbc2014-09-29 20:40:08 -06001031 if (result1 != TOS_SUCCESS || result2 != TOS_SUCCESS)
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001032 err = -EIO;
Johannes Berg19d337d2009-06-02 13:01:37 +02001033 else
1034 err = 0;
1035 out:
1036 mutex_unlock(&dev->mutex);
1037 return err;
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001038}
1039
Johannes Berg19d337d2009-06-02 13:01:37 +02001040static void bt_rfkill_poll(struct rfkill *rfkill, void *data)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001041{
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001042 bool new_rfk_state;
1043 bool value;
1044 u32 hci_result;
Johannes Berg19d337d2009-06-02 13:01:37 +02001045 struct toshiba_acpi_dev *dev = data;
1046
1047 mutex_lock(&dev->mutex);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001048
Seth Forshee135740d2011-09-20 16:55:49 -05001049 hci_result = hci_get_radio_state(dev, &value);
Azael Avalos1864bbc2014-09-29 20:40:08 -06001050 if (hci_result != TOS_SUCCESS) {
Johannes Berg19d337d2009-06-02 13:01:37 +02001051 /* Can't do anything useful */
1052 mutex_unlock(&dev->mutex);
Jiri Slaby82e77842009-08-06 15:57:51 -07001053 return;
Johannes Berg19d337d2009-06-02 13:01:37 +02001054 }
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001055
1056 new_rfk_state = value;
1057
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001058 mutex_unlock(&dev->mutex);
1059
Johannes Berg19d337d2009-06-02 13:01:37 +02001060 if (rfkill_set_hw_state(rfkill, !new_rfk_state))
1061 bt_rfkill_set_block(data, true);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001062}
1063
Johannes Berg19d337d2009-06-02 13:01:37 +02001064static const struct rfkill_ops toshiba_rfk_ops = {
1065 .set_block = bt_rfkill_set_block,
1066 .poll = bt_rfkill_poll,
1067};
1068
Akio Idehara121b7b02012-04-06 01:46:43 +09001069static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled)
1070{
1071 u32 hci_result;
1072 u32 status;
1073
Azael Avalos893f3f62014-09-29 20:40:09 -06001074 hci_result = hci_read1(dev, HCI_TR_BACKLIGHT, &status);
Akio Idehara121b7b02012-04-06 01:46:43 +09001075 *enabled = !status;
Azael Avalos1864bbc2014-09-29 20:40:08 -06001076 return hci_result == TOS_SUCCESS ? 0 : -EIO;
Akio Idehara121b7b02012-04-06 01:46:43 +09001077}
1078
1079static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable)
1080{
1081 u32 hci_result;
1082 u32 value = !enable;
1083
Azael Avalos893f3f62014-09-29 20:40:09 -06001084 hci_result = hci_write1(dev, HCI_TR_BACKLIGHT, value);
Azael Avalos1864bbc2014-09-29 20:40:08 -06001085 return hci_result == TOS_SUCCESS ? 0 : -EIO;
Akio Idehara121b7b02012-04-06 01:46:43 +09001086}
1087
Len Brown4be44fc2005-08-05 00:44:28 -04001088static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
Seth Forshee62cce752012-04-19 11:23:50 -05001090static int __get_lcd_brightness(struct toshiba_acpi_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091{
1092 u32 hci_result;
1093 u32 value;
Akio Idehara121b7b02012-04-06 01:46:43 +09001094 int brightness = 0;
1095
1096 if (dev->tr_backlight_supported) {
1097 bool enabled;
1098 int ret = get_tr_backlight_status(dev, &enabled);
1099 if (ret)
1100 return ret;
1101 if (enabled)
1102 return 0;
1103 brightness++;
1104 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
Azael Avalos893f3f62014-09-29 20:40:09 -06001106 hci_result = hci_read1(dev, HCI_LCD_BRIGHTNESS, &value);
Azael Avalos1864bbc2014-09-29 20:40:08 -06001107 if (hci_result == TOS_SUCCESS)
Akio Idehara121b7b02012-04-06 01:46:43 +09001108 return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT);
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001109
1110 return -EIO;
Holger Machtc9263552006-10-20 14:30:29 -07001111}
1112
Seth Forshee62cce752012-04-19 11:23:50 -05001113static int get_lcd_brightness(struct backlight_device *bd)
1114{
1115 struct toshiba_acpi_dev *dev = bl_get_data(bd);
1116 return __get_lcd_brightness(dev);
1117}
1118
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001119static int lcd_proc_show(struct seq_file *m, void *v)
Holger Machtc9263552006-10-20 14:30:29 -07001120{
Seth Forshee135740d2011-09-20 16:55:49 -05001121 struct toshiba_acpi_dev *dev = m->private;
1122 int value;
Akio Idehara121b7b02012-04-06 01:46:43 +09001123 int levels;
Holger Machtc9263552006-10-20 14:30:29 -07001124
Seth Forshee135740d2011-09-20 16:55:49 -05001125 if (!dev->backlight_dev)
1126 return -ENODEV;
1127
Akio Idehara121b7b02012-04-06 01:46:43 +09001128 levels = dev->backlight_dev->props.max_brightness + 1;
Seth Forshee62cce752012-04-19 11:23:50 -05001129 value = get_lcd_brightness(dev->backlight_dev);
Holger Machtc9263552006-10-20 14:30:29 -07001130 if (value >= 0) {
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001131 seq_printf(m, "brightness: %d\n", value);
Akio Idehara121b7b02012-04-06 01:46:43 +09001132 seq_printf(m, "brightness_levels: %d\n", levels);
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001133 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 }
1135
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001136 pr_err("Error reading LCD brightness\n");
1137 return -EIO;
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001138}
1139
1140static int lcd_proc_open(struct inode *inode, struct file *file)
1141{
Al Virod9dda782013-03-31 18:16:14 -04001142 return single_open(file, lcd_proc_show, PDE_DATA(inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143}
1144
Seth Forshee62cce752012-04-19 11:23:50 -05001145static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
Holger Machtc9263552006-10-20 14:30:29 -07001146{
Azael Avalosa39f46d2014-11-24 19:29:36 -07001147 u32 hci_result;
Holger Machtc9263552006-10-20 14:30:29 -07001148
Akio Idehara121b7b02012-04-06 01:46:43 +09001149 if (dev->tr_backlight_supported) {
1150 bool enable = !value;
1151 int ret = set_tr_backlight_status(dev, enable);
1152 if (ret)
1153 return ret;
1154 if (value)
1155 value--;
1156 }
1157
Azael Avalosa39f46d2014-11-24 19:29:36 -07001158 value = value << HCI_LCD_BRIGHTNESS_SHIFT;
1159 hci_result = hci_write1(dev, HCI_LCD_BRIGHTNESS, value);
1160 return hci_result == TOS_SUCCESS ? 0 : -EIO;
Holger Machtc9263552006-10-20 14:30:29 -07001161}
1162
1163static int set_lcd_status(struct backlight_device *bd)
1164{
Seth Forshee135740d2011-09-20 16:55:49 -05001165 struct toshiba_acpi_dev *dev = bl_get_data(bd);
Seth Forshee62cce752012-04-19 11:23:50 -05001166 return set_lcd_brightness(dev, bd->props.brightness);
Holger Machtc9263552006-10-20 14:30:29 -07001167}
1168
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001169static ssize_t lcd_proc_write(struct file *file, const char __user *buf,
1170 size_t count, loff_t *pos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171{
Al Virod9dda782013-03-31 18:16:14 -04001172 struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001173 char cmd[42];
1174 size_t len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 int value;
Matthijs van Otterdijkc8af57e2007-01-05 16:37:03 -08001176 int ret;
Akio Idehara121b7b02012-04-06 01:46:43 +09001177 int levels = dev->backlight_dev->props.max_brightness + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001179 len = min(count, sizeof(cmd) - 1);
1180 if (copy_from_user(cmd, buf, len))
1181 return -EFAULT;
1182 cmd[len] = '\0';
1183
1184 if (sscanf(cmd, " brightness : %i", &value) == 1 &&
Akio Idehara121b7b02012-04-06 01:46:43 +09001185 value >= 0 && value < levels) {
Seth Forshee62cce752012-04-19 11:23:50 -05001186 ret = set_lcd_brightness(dev, value);
Matthijs van Otterdijkc8af57e2007-01-05 16:37:03 -08001187 if (ret == 0)
1188 ret = count;
1189 } else {
Holger Machtc9263552006-10-20 14:30:29 -07001190 ret = -EINVAL;
Matthijs van Otterdijkc8af57e2007-01-05 16:37:03 -08001191 }
Holger Machtc9263552006-10-20 14:30:29 -07001192 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193}
1194
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001195static const struct file_operations lcd_proc_fops = {
1196 .owner = THIS_MODULE,
1197 .open = lcd_proc_open,
1198 .read = seq_read,
1199 .llseek = seq_lseek,
1200 .release = single_release,
1201 .write = lcd_proc_write,
1202};
1203
Seth Forshee36d03f92011-09-20 16:55:53 -05001204static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status)
1205{
1206 u32 hci_result;
1207
Azael Avalos893f3f62014-09-29 20:40:09 -06001208 hci_result = hci_read1(dev, HCI_VIDEO_OUT, status);
Azael Avalos1864bbc2014-09-29 20:40:08 -06001209 return hci_result == TOS_SUCCESS ? 0 : -EIO;
Seth Forshee36d03f92011-09-20 16:55:53 -05001210}
1211
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001212static int video_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213{
Seth Forshee135740d2011-09-20 16:55:49 -05001214 struct toshiba_acpi_dev *dev = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 u32 value;
Seth Forshee36d03f92011-09-20 16:55:53 -05001216 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217
Seth Forshee36d03f92011-09-20 16:55:53 -05001218 ret = get_video_status(dev, &value);
1219 if (!ret) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0;
1221 int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0;
Len Brown4be44fc2005-08-05 00:44:28 -04001222 int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0;
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001223 seq_printf(m, "lcd_out: %d\n", is_lcd);
1224 seq_printf(m, "crt_out: %d\n", is_crt);
1225 seq_printf(m, "tv_out: %d\n", is_tv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 }
1227
Seth Forshee36d03f92011-09-20 16:55:53 -05001228 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229}
1230
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001231static int video_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232{
Al Virod9dda782013-03-31 18:16:14 -04001233 return single_open(file, video_proc_show, PDE_DATA(inode));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001234}
1235
1236static ssize_t video_proc_write(struct file *file, const char __user *buf,
1237 size_t count, loff_t *pos)
1238{
Al Virod9dda782013-03-31 18:16:14 -04001239 struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001240 char *cmd, *buffer;
Seth Forshee36d03f92011-09-20 16:55:53 -05001241 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 int value;
1243 int remain = count;
1244 int lcd_out = -1;
1245 int crt_out = -1;
1246 int tv_out = -1;
Al Virob4482a42007-10-14 19:35:40 +01001247 u32 video_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001249 cmd = kmalloc(count + 1, GFP_KERNEL);
1250 if (!cmd)
1251 return -ENOMEM;
1252 if (copy_from_user(cmd, buf, count)) {
1253 kfree(cmd);
1254 return -EFAULT;
1255 }
1256 cmd[count] = '\0';
1257
1258 buffer = cmd;
1259
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 /* scan expression. Multiple expressions may be delimited with ;
1261 *
1262 * NOTE: to keep scanning simple, invalid fields are ignored
1263 */
1264 while (remain) {
1265 if (sscanf(buffer, " lcd_out : %i", &value) == 1)
1266 lcd_out = value & 1;
1267 else if (sscanf(buffer, " crt_out : %i", &value) == 1)
1268 crt_out = value & 1;
1269 else if (sscanf(buffer, " tv_out : %i", &value) == 1)
1270 tv_out = value & 1;
1271 /* advance to one character past the next ; */
1272 do {
1273 ++buffer;
1274 --remain;
1275 }
Len Brown4be44fc2005-08-05 00:44:28 -04001276 while (remain && *(buffer - 1) != ';');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 }
1278
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001279 kfree(cmd);
1280
Seth Forshee36d03f92011-09-20 16:55:53 -05001281 ret = get_video_status(dev, &video_out);
1282 if (!ret) {
Harvey Harrison9e113e02008-09-22 14:37:29 -07001283 unsigned int new_video_out = video_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284 if (lcd_out != -1)
1285 _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out);
1286 if (crt_out != -1)
1287 _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out);
1288 if (tv_out != -1)
1289 _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out);
1290 /* To avoid unnecessary video disruption, only write the new
1291 * video setting if something changed. */
1292 if (new_video_out != video_out)
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001293 ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 }
1295
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001296 return ret ? ret : count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297}
1298
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001299static const struct file_operations video_proc_fops = {
1300 .owner = THIS_MODULE,
1301 .open = video_proc_open,
1302 .read = seq_read,
1303 .llseek = seq_lseek,
1304 .release = single_release,
1305 .write = video_proc_write,
1306};
1307
Seth Forshee36d03f92011-09-20 16:55:53 -05001308static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status)
1309{
1310 u32 hci_result;
1311
Azael Avalos893f3f62014-09-29 20:40:09 -06001312 hci_result = hci_read1(dev, HCI_FAN, status);
Azael Avalos1864bbc2014-09-29 20:40:08 -06001313 return hci_result == TOS_SUCCESS ? 0 : -EIO;
Seth Forshee36d03f92011-09-20 16:55:53 -05001314}
1315
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001316static int fan_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317{
Seth Forshee135740d2011-09-20 16:55:49 -05001318 struct toshiba_acpi_dev *dev = m->private;
Seth Forshee36d03f92011-09-20 16:55:53 -05001319 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 u32 value;
1321
Seth Forshee36d03f92011-09-20 16:55:53 -05001322 ret = get_fan_status(dev, &value);
1323 if (!ret) {
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001324 seq_printf(m, "running: %d\n", (value > 0));
Seth Forshee135740d2011-09-20 16:55:49 -05001325 seq_printf(m, "force_on: %d\n", dev->force_fan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 }
1327
Seth Forshee36d03f92011-09-20 16:55:53 -05001328 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329}
1330
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001331static int fan_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332{
Al Virod9dda782013-03-31 18:16:14 -04001333 return single_open(file, fan_proc_show, PDE_DATA(inode));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001334}
1335
1336static ssize_t fan_proc_write(struct file *file, const char __user *buf,
1337 size_t count, loff_t *pos)
1338{
Al Virod9dda782013-03-31 18:16:14 -04001339 struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001340 char cmd[42];
1341 size_t len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 int value;
1343 u32 hci_result;
1344
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001345 len = min(count, sizeof(cmd) - 1);
1346 if (copy_from_user(cmd, buf, len))
1347 return -EFAULT;
1348 cmd[len] = '\0';
1349
1350 if (sscanf(cmd, " force_on : %i", &value) == 1 &&
Len Brown4be44fc2005-08-05 00:44:28 -04001351 value >= 0 && value <= 1) {
Azael Avalos893f3f62014-09-29 20:40:09 -06001352 hci_result = hci_write1(dev, HCI_FAN, value);
Azael Avalos1864bbc2014-09-29 20:40:08 -06001353 if (hci_result != TOS_SUCCESS)
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001354 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 else
Seth Forshee135740d2011-09-20 16:55:49 -05001356 dev->force_fan = value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 } else {
1358 return -EINVAL;
1359 }
1360
1361 return count;
1362}
1363
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001364static const struct file_operations fan_proc_fops = {
1365 .owner = THIS_MODULE,
1366 .open = fan_proc_open,
1367 .read = seq_read,
1368 .llseek = seq_lseek,
1369 .release = single_release,
1370 .write = fan_proc_write,
1371};
1372
1373static int keys_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374{
Seth Forshee135740d2011-09-20 16:55:49 -05001375 struct toshiba_acpi_dev *dev = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 u32 hci_result;
1377 u32 value;
1378
Seth Forshee11948b92011-11-16 17:37:45 -06001379 if (!dev->key_event_valid && dev->system_event_supported) {
Azael Avalos893f3f62014-09-29 20:40:09 -06001380 hci_result = hci_read1(dev, HCI_SYSTEM_EVENT, &value);
Azael Avalos1864bbc2014-09-29 20:40:08 -06001381 if (hci_result == TOS_SUCCESS) {
Seth Forshee135740d2011-09-20 16:55:49 -05001382 dev->key_event_valid = 1;
1383 dev->last_key_event = value;
Azael Avalos1864bbc2014-09-29 20:40:08 -06001384 } else if (hci_result == TOS_FIFO_EMPTY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 /* better luck next time */
Azael Avalos1864bbc2014-09-29 20:40:08 -06001386 } else if (hci_result == TOS_NOT_SUPPORTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 /* This is a workaround for an unresolved issue on
1388 * some machines where system events sporadically
1389 * become disabled. */
Azael Avalos893f3f62014-09-29 20:40:09 -06001390 hci_result = hci_write1(dev, HCI_SYSTEM_EVENT, 1);
Joe Perches7e334602011-03-29 15:21:52 -07001391 pr_notice("Re-enabled hotkeys\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 } else {
Joe Perches7e334602011-03-29 15:21:52 -07001393 pr_err("Error reading hotkey status\n");
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001394 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 }
1396 }
1397
Seth Forshee135740d2011-09-20 16:55:49 -05001398 seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid);
1399 seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event);
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001400 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401}
1402
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001403static int keys_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404{
Al Virod9dda782013-03-31 18:16:14 -04001405 return single_open(file, keys_proc_show, PDE_DATA(inode));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001406}
1407
1408static ssize_t keys_proc_write(struct file *file, const char __user *buf,
1409 size_t count, loff_t *pos)
1410{
Al Virod9dda782013-03-31 18:16:14 -04001411 struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001412 char cmd[42];
1413 size_t len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 int value;
1415
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001416 len = min(count, sizeof(cmd) - 1);
1417 if (copy_from_user(cmd, buf, len))
1418 return -EFAULT;
1419 cmd[len] = '\0';
1420
1421 if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) {
Seth Forshee135740d2011-09-20 16:55:49 -05001422 dev->key_event_valid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 } else {
1424 return -EINVAL;
1425 }
1426
1427 return count;
1428}
1429
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001430static const struct file_operations keys_proc_fops = {
1431 .owner = THIS_MODULE,
1432 .open = keys_proc_open,
1433 .read = seq_read,
1434 .llseek = seq_lseek,
1435 .release = single_release,
1436 .write = keys_proc_write,
1437};
1438
1439static int version_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440{
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001441 seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION);
1442 seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION);
1443 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444}
1445
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001446static int version_proc_open(struct inode *inode, struct file *file)
1447{
Al Virod9dda782013-03-31 18:16:14 -04001448 return single_open(file, version_proc_show, PDE_DATA(inode));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001449}
1450
1451static const struct file_operations version_proc_fops = {
1452 .owner = THIS_MODULE,
1453 .open = version_proc_open,
1454 .read = seq_read,
1455 .llseek = seq_lseek,
1456 .release = single_release,
1457};
1458
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459/* proc and module init
1460 */
1461
1462#define PROC_TOSHIBA "toshiba"
1463
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08001464static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465{
Seth Forshee36d03f92011-09-20 16:55:53 -05001466 if (dev->backlight_dev)
1467 proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1468 &lcd_proc_fops, dev);
1469 if (dev->video_supported)
1470 proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1471 &video_proc_fops, dev);
1472 if (dev->fan_supported)
1473 proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1474 &fan_proc_fops, dev);
1475 if (dev->hotkey_dev)
1476 proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1477 &keys_proc_fops, dev);
Seth Forshee135740d2011-09-20 16:55:49 -05001478 proc_create_data("version", S_IRUGO, toshiba_proc_dir,
1479 &version_proc_fops, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480}
1481
Seth Forshee36d03f92011-09-20 16:55:53 -05001482static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483{
Seth Forshee36d03f92011-09-20 16:55:53 -05001484 if (dev->backlight_dev)
1485 remove_proc_entry("lcd", toshiba_proc_dir);
1486 if (dev->video_supported)
1487 remove_proc_entry("video", toshiba_proc_dir);
1488 if (dev->fan_supported)
1489 remove_proc_entry("fan", toshiba_proc_dir);
1490 if (dev->hotkey_dev)
1491 remove_proc_entry("keys", toshiba_proc_dir);
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001492 remove_proc_entry("version", toshiba_proc_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493}
1494
Lionel Debrouxacc24722010-11-16 14:14:02 +01001495static const struct backlight_ops toshiba_backlight_data = {
Akio Idehara121b7b02012-04-06 01:46:43 +09001496 .options = BL_CORE_SUSPENDRESUME,
Seth Forshee62cce752012-04-19 11:23:50 -05001497 .get_brightness = get_lcd_brightness,
1498 .update_status = set_lcd_status,
Holger Machtc9263552006-10-20 14:30:29 -07001499};
Matthew Garrettea6b31f2014-04-04 14:22:34 -04001500
Azael Avalos360f0f32014-03-25 20:38:31 -06001501/*
1502 * Sysfs files
1503 */
Azael Avalos93f8c162014-09-12 18:50:36 -06001504static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
1505 struct device_attribute *attr,
1506 const char *buf, size_t count);
1507static ssize_t toshiba_kbd_bl_mode_show(struct device *dev,
1508 struct device_attribute *attr,
1509 char *buf);
1510static ssize_t toshiba_kbd_type_show(struct device *dev,
1511 struct device_attribute *attr,
1512 char *buf);
1513static ssize_t toshiba_available_kbd_modes_show(struct device *dev,
1514 struct device_attribute *attr,
1515 char *buf);
1516static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev,
1517 struct device_attribute *attr,
1518 const char *buf, size_t count);
1519static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev,
1520 struct device_attribute *attr,
1521 char *buf);
1522static ssize_t toshiba_touchpad_store(struct device *dev,
1523 struct device_attribute *attr,
1524 const char *buf, size_t count);
1525static ssize_t toshiba_touchpad_show(struct device *dev,
1526 struct device_attribute *attr,
1527 char *buf);
1528static ssize_t toshiba_position_show(struct device *dev,
1529 struct device_attribute *attr,
1530 char *buf);
Azael Avalose26ffe52015-01-18 18:30:22 -07001531static ssize_t toshiba_usb_sleep_charge_show(struct device *dev,
1532 struct device_attribute *attr,
1533 char *buf);
1534static ssize_t toshiba_usb_sleep_charge_store(struct device *dev,
1535 struct device_attribute *attr,
1536 const char *buf, size_t count);
Azael Avalos182bcaa2015-01-18 18:30:23 -07001537static ssize_t sleep_functions_on_battery_show(struct device *dev,
1538 struct device_attribute *attr,
1539 char *buf);
1540static ssize_t sleep_functions_on_battery_store(struct device *dev,
1541 struct device_attribute *attr,
1542 const char *buf, size_t count);
Azael Avalosbb3fe012015-01-18 18:30:24 -07001543static ssize_t toshiba_usb_rapid_charge_show(struct device *dev,
1544 struct device_attribute *attr,
1545 char *buf);
1546static ssize_t toshiba_usb_rapid_charge_store(struct device *dev,
1547 struct device_attribute *attr,
1548 const char *buf, size_t count);
Azael Avalos172ce0a2015-01-18 18:30:25 -07001549static ssize_t toshiba_usb_sleep_music_show(struct device *dev,
1550 struct device_attribute *attr,
1551 char *buf);
1552static ssize_t toshiba_usb_sleep_music_store(struct device *dev,
1553 struct device_attribute *attr,
1554 const char *buf, size_t count);
Azael Avalos93f8c162014-09-12 18:50:36 -06001555
1556static DEVICE_ATTR(kbd_backlight_mode, S_IRUGO | S_IWUSR,
1557 toshiba_kbd_bl_mode_show, toshiba_kbd_bl_mode_store);
1558static DEVICE_ATTR(kbd_type, S_IRUGO, toshiba_kbd_type_show, NULL);
1559static DEVICE_ATTR(available_kbd_modes, S_IRUGO,
1560 toshiba_available_kbd_modes_show, NULL);
1561static DEVICE_ATTR(kbd_backlight_timeout, S_IRUGO | S_IWUSR,
1562 toshiba_kbd_bl_timeout_show, toshiba_kbd_bl_timeout_store);
1563static DEVICE_ATTR(touchpad, S_IRUGO | S_IWUSR,
1564 toshiba_touchpad_show, toshiba_touchpad_store);
1565static DEVICE_ATTR(position, S_IRUGO, toshiba_position_show, NULL);
Azael Avalose26ffe52015-01-18 18:30:22 -07001566static DEVICE_ATTR(usb_sleep_charge, S_IRUGO | S_IWUSR,
1567 toshiba_usb_sleep_charge_show,
1568 toshiba_usb_sleep_charge_store);
Azael Avalos182bcaa2015-01-18 18:30:23 -07001569static DEVICE_ATTR(sleep_functions_on_battery, S_IRUGO | S_IWUSR,
1570 sleep_functions_on_battery_show,
1571 sleep_functions_on_battery_store);
Azael Avalosbb3fe012015-01-18 18:30:24 -07001572static DEVICE_ATTR(usb_rapid_charge, S_IRUGO | S_IWUSR,
1573 toshiba_usb_rapid_charge_show,
1574 toshiba_usb_rapid_charge_store);
Azael Avalos172ce0a2015-01-18 18:30:25 -07001575static DEVICE_ATTR(usb_sleep_music, S_IRUGO | S_IWUSR,
1576 toshiba_usb_sleep_music_show,
1577 toshiba_usb_sleep_music_store);
Azael Avalos93f8c162014-09-12 18:50:36 -06001578
1579static struct attribute *toshiba_attributes[] = {
1580 &dev_attr_kbd_backlight_mode.attr,
1581 &dev_attr_kbd_type.attr,
1582 &dev_attr_available_kbd_modes.attr,
1583 &dev_attr_kbd_backlight_timeout.attr,
1584 &dev_attr_touchpad.attr,
1585 &dev_attr_position.attr,
Azael Avalose26ffe52015-01-18 18:30:22 -07001586 &dev_attr_usb_sleep_charge.attr,
Azael Avalos182bcaa2015-01-18 18:30:23 -07001587 &dev_attr_sleep_functions_on_battery.attr,
Azael Avalosbb3fe012015-01-18 18:30:24 -07001588 &dev_attr_usb_rapid_charge.attr,
Azael Avalos172ce0a2015-01-18 18:30:25 -07001589 &dev_attr_usb_sleep_music.attr,
Azael Avalos93f8c162014-09-12 18:50:36 -06001590 NULL,
1591};
1592
1593static umode_t toshiba_sysfs_is_visible(struct kobject *,
1594 struct attribute *, int);
1595
1596static struct attribute_group toshiba_attr_group = {
1597 .is_visible = toshiba_sysfs_is_visible,
1598 .attrs = toshiba_attributes,
1599};
Azael Avalos360f0f32014-03-25 20:38:31 -06001600
1601static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
1602 struct device_attribute *attr,
1603 const char *buf, size_t count)
1604{
1605 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
Dan Carpenteraeaac092014-09-03 14:44:37 +03001606 int mode;
1607 int time;
1608 int ret;
Azael Avalos360f0f32014-03-25 20:38:31 -06001609
Dan Carpenteraeaac092014-09-03 14:44:37 +03001610
1611 ret = kstrtoint(buf, 0, &mode);
1612 if (ret)
1613 return ret;
Azael Avalos93f8c162014-09-12 18:50:36 -06001614
1615 /* Check for supported modes depending on keyboard backlight type */
1616 if (toshiba->kbd_type == 1) {
1617 /* Type 1 supports SCI_KBD_MODE_FNZ and SCI_KBD_MODE_AUTO */
1618 if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO)
1619 return -EINVAL;
1620 } else if (toshiba->kbd_type == 2) {
1621 /* Type 2 doesn't support SCI_KBD_MODE_FNZ */
1622 if (mode != SCI_KBD_MODE_AUTO && mode != SCI_KBD_MODE_ON &&
1623 mode != SCI_KBD_MODE_OFF)
1624 return -EINVAL;
1625 }
Azael Avalos360f0f32014-03-25 20:38:31 -06001626
1627 /* Set the Keyboard Backlight Mode where:
Azael Avalos360f0f32014-03-25 20:38:31 -06001628 * Auto - KBD backlight turns off automatically in given time
1629 * FN-Z - KBD backlight "toggles" when hotkey pressed
Azael Avalos93f8c162014-09-12 18:50:36 -06001630 * ON - KBD backlight is always on
1631 * OFF - KBD backlight is always off
Azael Avalos360f0f32014-03-25 20:38:31 -06001632 */
Azael Avalos93f8c162014-09-12 18:50:36 -06001633
1634 /* Only make a change if the actual mode has changed */
Dan Carpenteraeaac092014-09-03 14:44:37 +03001635 if (toshiba->kbd_mode != mode) {
Azael Avalos93f8c162014-09-12 18:50:36 -06001636 /* Shift the time to "base time" (0x3c0000 == 60 seconds) */
Azael Avalos360f0f32014-03-25 20:38:31 -06001637 time = toshiba->kbd_time << HCI_MISC_SHIFT;
Azael Avalos93f8c162014-09-12 18:50:36 -06001638
1639 /* OR the "base time" to the actual method format */
1640 if (toshiba->kbd_type == 1) {
1641 /* Type 1 requires the current mode */
1642 time |= toshiba->kbd_mode;
1643 } else if (toshiba->kbd_type == 2) {
1644 /* Type 2 requires the desired mode */
1645 time |= mode;
1646 }
1647
Dan Carpenteraeaac092014-09-03 14:44:37 +03001648 ret = toshiba_kbd_illum_status_set(toshiba, time);
1649 if (ret)
1650 return ret;
Azael Avalos93f8c162014-09-12 18:50:36 -06001651
Azael Avalos360f0f32014-03-25 20:38:31 -06001652 toshiba->kbd_mode = mode;
1653 }
1654
1655 return count;
1656}
1657
1658static ssize_t toshiba_kbd_bl_mode_show(struct device *dev,
1659 struct device_attribute *attr,
1660 char *buf)
1661{
1662 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1663 u32 time;
1664
1665 if (toshiba_kbd_illum_status_get(toshiba, &time) < 0)
1666 return -EIO;
1667
Azael Avalos93f8c162014-09-12 18:50:36 -06001668 return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK);
1669}
1670
1671static ssize_t toshiba_kbd_type_show(struct device *dev,
1672 struct device_attribute *attr,
1673 char *buf)
1674{
1675 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1676
1677 return sprintf(buf, "%d\n", toshiba->kbd_type);
1678}
1679
1680static ssize_t toshiba_available_kbd_modes_show(struct device *dev,
1681 struct device_attribute *attr,
1682 char *buf)
1683{
1684 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1685
1686 if (toshiba->kbd_type == 1)
1687 return sprintf(buf, "%x %x\n",
1688 SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO);
1689
1690 return sprintf(buf, "%x %x %x\n",
1691 SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF);
Azael Avalos360f0f32014-03-25 20:38:31 -06001692}
1693
1694static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev,
1695 struct device_attribute *attr,
1696 const char *buf, size_t count)
1697{
1698 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
Azael Avaloseabde0f2014-10-04 12:02:21 -06001699 int time;
1700 int ret;
Azael Avalos360f0f32014-03-25 20:38:31 -06001701
Azael Avaloseabde0f2014-10-04 12:02:21 -06001702 ret = kstrtoint(buf, 0, &time);
1703 if (ret)
1704 return ret;
Azael Avalos360f0f32014-03-25 20:38:31 -06001705
Azael Avaloseabde0f2014-10-04 12:02:21 -06001706 /* Check for supported values depending on kbd_type */
1707 if (toshiba->kbd_type == 1) {
1708 if (time < 0 || time > 60)
1709 return -EINVAL;
1710 } else if (toshiba->kbd_type == 2) {
1711 if (time < 1 || time > 60)
1712 return -EINVAL;
1713 }
1714
1715 /* Set the Keyboard Backlight Timeout */
1716
1717 /* Only make a change if the actual timeout has changed */
1718 if (toshiba->kbd_time != time) {
1719 /* Shift the time to "base time" (0x3c0000 == 60 seconds) */
Azael Avalos360f0f32014-03-25 20:38:31 -06001720 time = time << HCI_MISC_SHIFT;
Azael Avaloseabde0f2014-10-04 12:02:21 -06001721 /* OR the "base time" to the actual method format */
1722 if (toshiba->kbd_type == 1)
1723 time |= SCI_KBD_MODE_FNZ;
1724 else if (toshiba->kbd_type == 2)
1725 time |= SCI_KBD_MODE_AUTO;
1726
1727 ret = toshiba_kbd_illum_status_set(toshiba, time);
1728 if (ret)
1729 return ret;
1730
Azael Avalos360f0f32014-03-25 20:38:31 -06001731 toshiba->kbd_time = time >> HCI_MISC_SHIFT;
1732 }
1733
1734 return count;
1735}
1736
1737static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev,
1738 struct device_attribute *attr,
1739 char *buf)
1740{
1741 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1742 u32 time;
1743
1744 if (toshiba_kbd_illum_status_get(toshiba, &time) < 0)
1745 return -EIO;
1746
1747 return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT);
1748}
Matthew Garrettea6b31f2014-04-04 14:22:34 -04001749
Azael Avalos9d8658a2014-03-25 20:38:32 -06001750static ssize_t toshiba_touchpad_store(struct device *dev,
1751 struct device_attribute *attr,
1752 const char *buf, size_t count)
1753{
1754 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1755 int state;
Azael Avalosc8a41662014-09-10 21:01:57 -06001756 int ret;
Azael Avalos9d8658a2014-03-25 20:38:32 -06001757
1758 /* Set the TouchPad on/off, 0 - Disable | 1 - Enable */
Azael Avalosc8a41662014-09-10 21:01:57 -06001759 ret = kstrtoint(buf, 0, &state);
1760 if (ret)
1761 return ret;
1762 if (state != 0 && state != 1)
1763 return -EINVAL;
1764
1765 ret = toshiba_touchpad_set(toshiba, state);
1766 if (ret)
1767 return ret;
Azael Avalos9d8658a2014-03-25 20:38:32 -06001768
1769 return count;
1770}
1771
1772static ssize_t toshiba_touchpad_show(struct device *dev,
1773 struct device_attribute *attr, char *buf)
1774{
1775 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1776 u32 state;
1777 int ret;
1778
1779 ret = toshiba_touchpad_get(toshiba, &state);
1780 if (ret < 0)
1781 return ret;
1782
1783 return sprintf(buf, "%i\n", state);
1784}
Matthew Garrettea6b31f2014-04-04 14:22:34 -04001785
Azael Avalos5a2813e2014-03-25 20:38:34 -06001786static ssize_t toshiba_position_show(struct device *dev,
1787 struct device_attribute *attr, char *buf)
1788{
1789 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1790 u32 xyval, zval, tmp;
1791 u16 x, y, z;
1792 int ret;
1793
1794 xyval = zval = 0;
1795 ret = toshiba_accelerometer_get(toshiba, &xyval, &zval);
1796 if (ret < 0)
1797 return ret;
1798
1799 x = xyval & HCI_ACCEL_MASK;
1800 tmp = xyval >> HCI_MISC_SHIFT;
1801 y = tmp & HCI_ACCEL_MASK;
1802 z = zval & HCI_ACCEL_MASK;
1803
1804 return sprintf(buf, "%d %d %d\n", x, y, z);
1805}
Azael Avalos360f0f32014-03-25 20:38:31 -06001806
Azael Avalose26ffe52015-01-18 18:30:22 -07001807static ssize_t toshiba_usb_sleep_charge_show(struct device *dev,
1808 struct device_attribute *attr,
1809 char *buf)
1810{
1811 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1812 u32 mode;
1813 int ret;
1814
1815 ret = toshiba_usb_sleep_charge_get(toshiba, &mode);
1816 if (ret < 0)
1817 return ret;
1818
1819 return sprintf(buf, "%x\n", mode & SCI_USB_CHARGE_MODE_MASK);
1820}
1821
1822static ssize_t toshiba_usb_sleep_charge_store(struct device *dev,
1823 struct device_attribute *attr,
1824 const char *buf, size_t count)
1825{
1826 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1827 u32 mode;
1828 int state;
1829 int ret;
1830
1831 ret = kstrtoint(buf, 0, &state);
1832 if (ret)
1833 return ret;
1834 /* Check for supported values, where:
1835 * 0 - Disabled
1836 * 1 - Alternate (Non USB conformant devices that require more power)
1837 * 2 - Auto (USB conformant devices)
1838 */
1839 if (state != 0 && state != 1 && state != 2)
1840 return -EINVAL;
1841
1842 /* Set the USB charging mode to internal value */
1843 if (state == 0)
1844 mode = SCI_USB_CHARGE_DISABLED;
1845 else if (state == 1)
1846 mode = SCI_USB_CHARGE_ALTERNATE;
1847 else if (state == 2)
1848 mode = SCI_USB_CHARGE_AUTO;
1849
1850 ret = toshiba_usb_sleep_charge_set(toshiba, mode);
1851 if (ret)
1852 return ret;
1853
1854 return count;
1855}
1856
Azael Avalos182bcaa2015-01-18 18:30:23 -07001857static ssize_t sleep_functions_on_battery_show(struct device *dev,
1858 struct device_attribute *attr,
1859 char *buf)
1860{
1861 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1862 u32 state;
1863 int bat_lvl;
1864 int status;
1865 int ret;
1866 int tmp;
1867
1868 ret = toshiba_sleep_functions_status_get(toshiba, &state);
1869 if (ret < 0)
1870 return ret;
1871
1872 /* Determine the status: 0x4 - Enabled | 0x1 - Disabled */
1873 tmp = state & SCI_USB_CHARGE_BAT_MASK;
1874 status = (tmp == 0x4) ? 1 : 0;
1875 /* Determine the battery level set */
1876 bat_lvl = state >> HCI_MISC_SHIFT;
1877
1878 return sprintf(buf, "%d %d\n", status, bat_lvl);
1879}
1880
1881static ssize_t sleep_functions_on_battery_store(struct device *dev,
1882 struct device_attribute *attr,
1883 const char *buf, size_t count)
1884{
1885 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1886 u32 status;
1887 int value;
1888 int ret;
1889 int tmp;
1890
1891 ret = kstrtoint(buf, 0, &value);
1892 if (ret)
1893 return ret;
1894
1895 /* Set the status of the function:
1896 * 0 - Disabled
1897 * 1-100 - Enabled
1898 */
1899 if (value < 0 || value > 100)
1900 return -EINVAL;
1901
1902 if (value == 0) {
1903 tmp = toshiba->usbsc_bat_level << HCI_MISC_SHIFT;
1904 status = tmp | SCI_USB_CHARGE_BAT_LVL_OFF;
1905 } else {
1906 tmp = value << HCI_MISC_SHIFT;
1907 status = tmp | SCI_USB_CHARGE_BAT_LVL_ON;
1908 }
1909 ret = toshiba_sleep_functions_status_set(toshiba, status);
1910 if (ret < 0)
1911 return ret;
1912
1913 toshiba->usbsc_bat_level = status >> HCI_MISC_SHIFT;
1914
1915 return count;
1916}
1917
Azael Avalosbb3fe012015-01-18 18:30:24 -07001918static ssize_t toshiba_usb_rapid_charge_show(struct device *dev,
1919 struct device_attribute *attr,
1920 char *buf)
1921{
1922 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1923 u32 state;
1924 int ret;
1925
1926 ret = toshiba_usb_rapid_charge_get(toshiba, &state);
1927 if (ret < 0)
1928 return ret;
1929
1930 return sprintf(buf, "%d\n", state);
1931}
1932
1933static ssize_t toshiba_usb_rapid_charge_store(struct device *dev,
1934 struct device_attribute *attr,
1935 const char *buf, size_t count)
1936{
1937 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1938 int state;
1939 int ret;
1940
1941 ret = kstrtoint(buf, 0, &state);
1942 if (ret)
1943 return ret;
1944 if (state != 0 && state != 1)
1945 return -EINVAL;
1946
1947 ret = toshiba_usb_rapid_charge_set(toshiba, state);
1948 if (ret)
1949 return ret;
1950
1951 return count;
1952}
1953
Azael Avalos172ce0a2015-01-18 18:30:25 -07001954static ssize_t toshiba_usb_sleep_music_show(struct device *dev,
1955 struct device_attribute *attr,
1956 char *buf)
1957{
1958 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1959 u32 state;
1960 int ret;
1961
1962 ret = toshiba_usb_sleep_music_get(toshiba, &state);
1963 if (ret < 0)
1964 return ret;
1965
1966 return sprintf(buf, "%d\n", state);
1967}
1968
1969static ssize_t toshiba_usb_sleep_music_store(struct device *dev,
1970 struct device_attribute *attr,
1971 const char *buf, size_t count)
1972{
1973 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1974 int state;
1975 int ret;
1976
1977 ret = kstrtoint(buf, 0, &state);
1978 if (ret)
1979 return ret;
1980 if (state != 0 && state != 1)
1981 return -EINVAL;
1982
1983 ret = toshiba_usb_sleep_music_set(toshiba, state);
1984 if (ret)
1985 return ret;
1986
1987 return count;
1988}
1989
Azael Avalos360f0f32014-03-25 20:38:31 -06001990static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
1991 struct attribute *attr, int idx)
1992{
1993 struct device *dev = container_of(kobj, struct device, kobj);
1994 struct toshiba_acpi_dev *drv = dev_get_drvdata(dev);
1995 bool exists = true;
1996
1997 if (attr == &dev_attr_kbd_backlight_mode.attr)
1998 exists = (drv->kbd_illum_supported) ? true : false;
1999 else if (attr == &dev_attr_kbd_backlight_timeout.attr)
2000 exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false;
Azael Avalos9d8658a2014-03-25 20:38:32 -06002001 else if (attr == &dev_attr_touchpad.attr)
2002 exists = (drv->touchpad_supported) ? true : false;
Azael Avalos5a2813e2014-03-25 20:38:34 -06002003 else if (attr == &dev_attr_position.attr)
2004 exists = (drv->accelerometer_supported) ? true : false;
Azael Avalose26ffe52015-01-18 18:30:22 -07002005 else if (attr == &dev_attr_usb_sleep_charge.attr)
2006 exists = (drv->usb_sleep_charge_supported) ? true : false;
Azael Avalos182bcaa2015-01-18 18:30:23 -07002007 else if (attr == &dev_attr_sleep_functions_on_battery.attr)
2008 exists = (drv->usb_sleep_charge_supported) ? true : false;
Azael Avalosbb3fe012015-01-18 18:30:24 -07002009 else if (attr == &dev_attr_usb_rapid_charge.attr)
2010 exists = (drv->usb_rapid_charge_supported) ? true : false;
Azael Avalos172ce0a2015-01-18 18:30:25 -07002011 else if (attr == &dev_attr_usb_sleep_music.attr)
2012 exists = (drv->usb_sleep_music_supported) ? true : false;
Azael Avalos360f0f32014-03-25 20:38:31 -06002013
2014 return exists ? attr->mode : 0;
2015}
2016
Azael Avalos1f28f292014-12-04 20:22:45 -07002017/*
2018 * Hotkeys
2019 */
2020static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev)
2021{
2022 acpi_status status;
2023 u32 result;
2024
2025 status = acpi_evaluate_object(dev->acpi_dev->handle,
2026 "ENAB", NULL, NULL);
2027 if (ACPI_FAILURE(status))
2028 return -ENODEV;
2029
2030 result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE);
2031 if (result == TOS_FAILURE)
2032 return -EIO;
2033 else if (result == TOS_NOT_SUPPORTED)
2034 return -ENODEV;
2035
2036 return 0;
2037}
2038
Seth Forshee29cd2932012-01-18 13:44:09 -06002039static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
2040 struct serio *port)
2041{
Giedrius Statkevičius98280372014-10-18 02:57:20 +03002042 if (str & I8042_STR_AUXDATA)
Seth Forshee29cd2932012-01-18 13:44:09 -06002043 return false;
2044
2045 if (unlikely(data == 0xe0))
2046 return false;
2047
2048 if ((data & 0x7f) == TOS1900_FN_SCAN) {
2049 schedule_work(&toshiba_acpi->hotkey_work);
2050 return true;
2051 }
2052
2053 return false;
2054}
2055
2056static void toshiba_acpi_hotkey_work(struct work_struct *work)
2057{
2058 acpi_handle ec_handle = ec_get_handle();
2059 acpi_status status;
2060
2061 if (!ec_handle)
2062 return;
2063
2064 status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL);
2065 if (ACPI_FAILURE(status))
2066 pr_err("ACPI NTFY method execution failed\n");
2067}
2068
2069/*
2070 * Returns hotkey scancode, or < 0 on failure.
2071 */
2072static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev)
2073{
Zhang Rui74facaf2013-09-03 08:32:15 +08002074 unsigned long long value;
Seth Forshee29cd2932012-01-18 13:44:09 -06002075 acpi_status status;
2076
Zhang Rui74facaf2013-09-03 08:32:15 +08002077 status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO",
2078 NULL, &value);
2079 if (ACPI_FAILURE(status)) {
Seth Forshee29cd2932012-01-18 13:44:09 -06002080 pr_err("ACPI INFO method execution failed\n");
2081 return -EIO;
2082 }
2083
Zhang Rui74facaf2013-09-03 08:32:15 +08002084 return value;
Seth Forshee29cd2932012-01-18 13:44:09 -06002085}
2086
2087static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev,
2088 int scancode)
2089{
2090 if (scancode == 0x100)
2091 return;
2092
2093 /* act on key press; ignore key release */
2094 if (scancode & 0x80)
2095 return;
2096
2097 if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true))
2098 pr_info("Unknown key %x\n", scancode);
2099}
2100
Azael Avalos71454d72014-12-04 20:22:46 -07002101static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev)
2102{
2103 u32 hci_result, value;
2104 int retries = 3;
2105 int scancode;
2106
2107 if (dev->info_supported) {
2108 scancode = toshiba_acpi_query_hotkey(dev);
2109 if (scancode < 0)
2110 pr_err("Failed to query hotkey event\n");
2111 else if (scancode != 0)
2112 toshiba_acpi_report_hotkey(dev, scancode);
2113 } else if (dev->system_event_supported) {
2114 do {
2115 hci_result = hci_read1(dev, HCI_SYSTEM_EVENT, &value);
2116 switch (hci_result) {
2117 case TOS_SUCCESS:
2118 toshiba_acpi_report_hotkey(dev, (int)value);
2119 break;
2120 case TOS_NOT_SUPPORTED:
2121 /*
2122 * This is a workaround for an unresolved
2123 * issue on some machines where system events
2124 * sporadically become disabled.
2125 */
2126 hci_result =
2127 hci_write1(dev, HCI_SYSTEM_EVENT, 1);
2128 pr_notice("Re-enabled hotkeys\n");
2129 /* fall through */
2130 default:
2131 retries--;
2132 break;
2133 }
2134 } while (retries && hci_result != TOS_FIFO_EMPTY);
2135 }
2136}
2137
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08002138static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
Matthew Garrett6335e4d2010-02-25 15:20:54 -05002139{
Zhang Ruie2e19602013-09-03 08:32:06 +08002140 acpi_handle ec_handle;
Seth Forshee135740d2011-09-20 16:55:49 -05002141 int error;
Seth Forshee29cd2932012-01-18 13:44:09 -06002142 u32 hci_result;
Takashi Iwaife808bfb2014-04-29 15:15:38 +02002143 const struct key_entry *keymap = toshiba_acpi_keymap;
Seth Forshee135740d2011-09-20 16:55:49 -05002144
Seth Forshee135740d2011-09-20 16:55:49 -05002145 dev->hotkey_dev = input_allocate_device();
Joe Perchesb222cca2013-10-23 12:14:52 -07002146 if (!dev->hotkey_dev)
Seth Forshee135740d2011-09-20 16:55:49 -05002147 return -ENOMEM;
Seth Forshee135740d2011-09-20 16:55:49 -05002148
2149 dev->hotkey_dev->name = "Toshiba input device";
Seth Forshee6e02cc72011-09-20 16:55:51 -05002150 dev->hotkey_dev->phys = "toshiba_acpi/input0";
Seth Forshee135740d2011-09-20 16:55:49 -05002151 dev->hotkey_dev->id.bustype = BUS_HOST;
2152
Takashi Iwaife808bfb2014-04-29 15:15:38 +02002153 if (dmi_check_system(toshiba_alt_keymap_dmi))
2154 keymap = toshiba_acpi_alt_keymap;
2155 error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL);
Seth Forshee135740d2011-09-20 16:55:49 -05002156 if (error)
2157 goto err_free_dev;
2158
Seth Forshee29cd2932012-01-18 13:44:09 -06002159 /*
2160 * For some machines the SCI responsible for providing hotkey
2161 * notification doesn't fire. We can trigger the notification
2162 * whenever the Fn key is pressed using the NTFY method, if
2163 * supported, so if it's present set up an i8042 key filter
2164 * for this purpose.
2165 */
Seth Forshee29cd2932012-01-18 13:44:09 -06002166 ec_handle = ec_get_handle();
Zhang Ruie2e19602013-09-03 08:32:06 +08002167 if (ec_handle && acpi_has_method(ec_handle, "NTFY")) {
Seth Forshee29cd2932012-01-18 13:44:09 -06002168 INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work);
2169
2170 error = i8042_install_filter(toshiba_acpi_i8042_filter);
2171 if (error) {
2172 pr_err("Error installing key filter\n");
2173 goto err_free_keymap;
2174 }
2175
2176 dev->ntfy_supported = 1;
2177 }
2178
2179 /*
2180 * Determine hotkey query interface. Prefer using the INFO
2181 * method when it is available.
2182 */
Zhang Ruie2e19602013-09-03 08:32:06 +08002183 if (acpi_has_method(dev->acpi_dev->handle, "INFO"))
Seth Forshee29cd2932012-01-18 13:44:09 -06002184 dev->info_supported = 1;
Zhang Ruie2e19602013-09-03 08:32:06 +08002185 else {
Azael Avalos893f3f62014-09-29 20:40:09 -06002186 hci_result = hci_write1(dev, HCI_SYSTEM_EVENT, 1);
Azael Avalos1864bbc2014-09-29 20:40:08 -06002187 if (hci_result == TOS_SUCCESS)
Seth Forshee29cd2932012-01-18 13:44:09 -06002188 dev->system_event_supported = 1;
2189 }
2190
2191 if (!dev->info_supported && !dev->system_event_supported) {
2192 pr_warn("No hotkey query interface found\n");
2193 goto err_remove_filter;
2194 }
2195
Azael Avalos1f28f292014-12-04 20:22:45 -07002196 error = toshiba_acpi_enable_hotkeys(dev);
2197 if (error) {
Seth Forshee135740d2011-09-20 16:55:49 -05002198 pr_info("Unable to enable hotkeys\n");
Seth Forshee29cd2932012-01-18 13:44:09 -06002199 goto err_remove_filter;
Seth Forshee135740d2011-09-20 16:55:49 -05002200 }
2201
2202 error = input_register_device(dev->hotkey_dev);
2203 if (error) {
2204 pr_info("Unable to register input device\n");
Seth Forshee29cd2932012-01-18 13:44:09 -06002205 goto err_remove_filter;
Seth Forshee135740d2011-09-20 16:55:49 -05002206 }
2207
2208 return 0;
2209
Seth Forshee29cd2932012-01-18 13:44:09 -06002210 err_remove_filter:
2211 if (dev->ntfy_supported)
2212 i8042_remove_filter(toshiba_acpi_i8042_filter);
Seth Forshee135740d2011-09-20 16:55:49 -05002213 err_free_keymap:
2214 sparse_keymap_free(dev->hotkey_dev);
2215 err_free_dev:
2216 input_free_device(dev->hotkey_dev);
2217 dev->hotkey_dev = NULL;
2218 return error;
2219}
2220
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08002221static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
Seth Forshee62cce752012-04-19 11:23:50 -05002222{
2223 struct backlight_properties props;
2224 int brightness;
2225 int ret;
Akio Idehara121b7b02012-04-06 01:46:43 +09002226 bool enabled;
Seth Forshee62cce752012-04-19 11:23:50 -05002227
2228 /*
2229 * Some machines don't support the backlight methods at all, and
2230 * others support it read-only. Either of these is pretty useless,
2231 * so only register the backlight device if the backlight method
2232 * supports both reads and writes.
2233 */
2234 brightness = __get_lcd_brightness(dev);
2235 if (brightness < 0)
2236 return 0;
2237 ret = set_lcd_brightness(dev, brightness);
2238 if (ret) {
2239 pr_debug("Backlight method is read-only, disabling backlight support\n");
2240 return 0;
2241 }
2242
Akio Idehara121b7b02012-04-06 01:46:43 +09002243 /* Determine whether or not BIOS supports transflective backlight */
2244 ret = get_tr_backlight_status(dev, &enabled);
2245 dev->tr_backlight_supported = !ret;
2246
Matthew Garrett53039f22012-06-01 11:02:36 -04002247 memset(&props, 0, sizeof(props));
Seth Forshee62cce752012-04-19 11:23:50 -05002248 props.type = BACKLIGHT_PLATFORM;
2249 props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
Seth Forshee62cce752012-04-19 11:23:50 -05002250
Akio Idehara121b7b02012-04-06 01:46:43 +09002251 /* adding an extra level and having 0 change to transflective mode */
2252 if (dev->tr_backlight_supported)
2253 props.max_brightness++;
2254
Seth Forshee62cce752012-04-19 11:23:50 -05002255 dev->backlight_dev = backlight_device_register("toshiba",
2256 &dev->acpi_dev->dev,
2257 dev,
2258 &toshiba_backlight_data,
2259 &props);
2260 if (IS_ERR(dev->backlight_dev)) {
2261 ret = PTR_ERR(dev->backlight_dev);
2262 pr_err("Could not register toshiba backlight device\n");
2263 dev->backlight_dev = NULL;
2264 return ret;
2265 }
2266
2267 dev->backlight_dev->props.brightness = brightness;
2268 return 0;
2269}
2270
Rafael J. Wysocki51fac832013-01-24 00:24:48 +01002271static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
Seth Forshee135740d2011-09-20 16:55:49 -05002272{
2273 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
2274
Seth Forshee36d03f92011-09-20 16:55:53 -05002275 remove_toshiba_proc_entries(dev);
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002276
Azael Avalos360f0f32014-03-25 20:38:31 -06002277 if (dev->sysfs_created)
2278 sysfs_remove_group(&dev->acpi_dev->dev.kobj,
2279 &toshiba_attr_group);
Seth Forshee135740d2011-09-20 16:55:49 -05002280
Seth Forshee29cd2932012-01-18 13:44:09 -06002281 if (dev->ntfy_supported) {
2282 i8042_remove_filter(toshiba_acpi_i8042_filter);
2283 cancel_work_sync(&dev->hotkey_work);
2284 }
2285
Seth Forshee135740d2011-09-20 16:55:49 -05002286 if (dev->hotkey_dev) {
2287 input_unregister_device(dev->hotkey_dev);
2288 sparse_keymap_free(dev->hotkey_dev);
2289 }
2290
2291 if (dev->bt_rfk) {
2292 rfkill_unregister(dev->bt_rfk);
2293 rfkill_destroy(dev->bt_rfk);
2294 }
2295
Markus Elfring00981812014-11-24 20:30:29 +01002296 backlight_device_unregister(dev->backlight_dev);
Seth Forshee135740d2011-09-20 16:55:49 -05002297
Seth Forshee36d03f92011-09-20 16:55:53 -05002298 if (dev->illumination_supported)
Seth Forshee135740d2011-09-20 16:55:49 -05002299 led_classdev_unregister(&dev->led_dev);
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002300
Azael Avalos360f0f32014-03-25 20:38:31 -06002301 if (dev->kbd_led_registered)
2302 led_classdev_unregister(&dev->kbd_led);
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002303
Azael Avalosdef6c4e2014-03-25 20:38:33 -06002304 if (dev->eco_supported)
2305 led_classdev_unregister(&dev->eco_led);
Seth Forshee135740d2011-09-20 16:55:49 -05002306
Seth Forshee29cd2932012-01-18 13:44:09 -06002307 if (toshiba_acpi)
2308 toshiba_acpi = NULL;
2309
Seth Forshee135740d2011-09-20 16:55:49 -05002310 kfree(dev);
2311
2312 return 0;
2313}
2314
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08002315static const char *find_hci_method(acpi_handle handle)
Seth Forsheea540d6b2011-09-20 16:55:52 -05002316{
Zhang Ruie2e19602013-09-03 08:32:06 +08002317 if (acpi_has_method(handle, "GHCI"))
Seth Forsheea540d6b2011-09-20 16:55:52 -05002318 return "GHCI";
2319
Zhang Ruie2e19602013-09-03 08:32:06 +08002320 if (acpi_has_method(handle, "SPFC"))
Seth Forsheea540d6b2011-09-20 16:55:52 -05002321 return "SPFC";
2322
2323 return NULL;
2324}
2325
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08002326static int toshiba_acpi_add(struct acpi_device *acpi_dev)
Seth Forshee135740d2011-09-20 16:55:49 -05002327{
2328 struct toshiba_acpi_dev *dev;
Seth Forsheea540d6b2011-09-20 16:55:52 -05002329 const char *hci_method;
Seth Forshee36d03f92011-09-20 16:55:53 -05002330 u32 dummy;
Seth Forshee135740d2011-09-20 16:55:49 -05002331 bool bt_present;
2332 int ret = 0;
Seth Forshee135740d2011-09-20 16:55:49 -05002333
Seth Forshee29cd2932012-01-18 13:44:09 -06002334 if (toshiba_acpi)
2335 return -EBUSY;
2336
Seth Forshee135740d2011-09-20 16:55:49 -05002337 pr_info("Toshiba Laptop ACPI Extras version %s\n",
2338 TOSHIBA_ACPI_VERSION);
2339
Seth Forsheea540d6b2011-09-20 16:55:52 -05002340 hci_method = find_hci_method(acpi_dev->handle);
2341 if (!hci_method) {
2342 pr_err("HCI interface not found\n");
Seth Forshee6e02cc72011-09-20 16:55:51 -05002343 return -ENODEV;
Seth Forsheea540d6b2011-09-20 16:55:52 -05002344 }
Seth Forshee6e02cc72011-09-20 16:55:51 -05002345
Seth Forshee135740d2011-09-20 16:55:49 -05002346 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
2347 if (!dev)
2348 return -ENOMEM;
2349 dev->acpi_dev = acpi_dev;
Seth Forsheea540d6b2011-09-20 16:55:52 -05002350 dev->method_hci = hci_method;
Seth Forshee135740d2011-09-20 16:55:49 -05002351 acpi_dev->driver_data = dev;
Azael Avalos360f0f32014-03-25 20:38:31 -06002352 dev_set_drvdata(&acpi_dev->dev, dev);
Seth Forshee135740d2011-09-20 16:55:49 -05002353
Seth Forshee6e02cc72011-09-20 16:55:51 -05002354 if (toshiba_acpi_setup_keyboard(dev))
2355 pr_info("Unable to activate hotkeys\n");
Seth Forshee135740d2011-09-20 16:55:49 -05002356
2357 mutex_init(&dev->mutex);
2358
Seth Forshee62cce752012-04-19 11:23:50 -05002359 ret = toshiba_acpi_setup_backlight(dev);
2360 if (ret)
Seth Forshee135740d2011-09-20 16:55:49 -05002361 goto error;
Seth Forshee135740d2011-09-20 16:55:49 -05002362
2363 /* Register rfkill switch for Bluetooth */
Azael Avalos1864bbc2014-09-29 20:40:08 -06002364 if (hci_get_bt_present(dev, &bt_present) == TOS_SUCCESS && bt_present) {
Seth Forshee135740d2011-09-20 16:55:49 -05002365 dev->bt_rfk = rfkill_alloc("Toshiba Bluetooth",
2366 &acpi_dev->dev,
2367 RFKILL_TYPE_BLUETOOTH,
2368 &toshiba_rfk_ops,
2369 dev);
2370 if (!dev->bt_rfk) {
2371 pr_err("unable to allocate rfkill device\n");
2372 ret = -ENOMEM;
2373 goto error;
2374 }
2375
2376 ret = rfkill_register(dev->bt_rfk);
2377 if (ret) {
2378 pr_err("unable to register rfkill device\n");
2379 rfkill_destroy(dev->bt_rfk);
2380 goto error;
2381 }
2382 }
2383
2384 if (toshiba_illumination_available(dev)) {
2385 dev->led_dev.name = "toshiba::illumination";
2386 dev->led_dev.max_brightness = 1;
2387 dev->led_dev.brightness_set = toshiba_illumination_set;
2388 dev->led_dev.brightness_get = toshiba_illumination_get;
2389 if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev))
Seth Forshee36d03f92011-09-20 16:55:53 -05002390 dev->illumination_supported = 1;
Seth Forshee135740d2011-09-20 16:55:49 -05002391 }
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002392
Azael Avalosdef6c4e2014-03-25 20:38:33 -06002393 if (toshiba_eco_mode_available(dev)) {
2394 dev->eco_led.name = "toshiba::eco_mode";
2395 dev->eco_led.max_brightness = 1;
2396 dev->eco_led.brightness_set = toshiba_eco_mode_set_status;
2397 dev->eco_led.brightness_get = toshiba_eco_mode_get_status;
2398 if (!led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led))
2399 dev->eco_supported = 1;
2400 }
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002401
Azael Avalos93f8c162014-09-12 18:50:36 -06002402 dev->kbd_illum_supported = toshiba_kbd_illum_available(dev);
Azael Avalos360f0f32014-03-25 20:38:31 -06002403 /*
2404 * Only register the LED if KBD illumination is supported
2405 * and the keyboard backlight operation mode is set to FN-Z
2406 */
2407 if (dev->kbd_illum_supported && dev->kbd_mode == SCI_KBD_MODE_FNZ) {
2408 dev->kbd_led.name = "toshiba::kbd_backlight";
2409 dev->kbd_led.max_brightness = 1;
2410 dev->kbd_led.brightness_set = toshiba_kbd_backlight_set;
2411 dev->kbd_led.brightness_get = toshiba_kbd_backlight_get;
2412 if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led))
2413 dev->kbd_led_registered = 1;
2414 }
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002415
Azael Avalos9d8658a2014-03-25 20:38:32 -06002416 ret = toshiba_touchpad_get(dev, &dummy);
2417 dev->touchpad_supported = !ret;
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002418
Azael Avalos5a2813e2014-03-25 20:38:34 -06002419 ret = toshiba_accelerometer_supported(dev);
2420 dev->accelerometer_supported = !ret;
Seth Forshee135740d2011-09-20 16:55:49 -05002421
Azael Avalose26ffe52015-01-18 18:30:22 -07002422 ret = toshiba_usb_sleep_charge_get(dev, &dummy);
2423 dev->usb_sleep_charge_supported = !ret;
2424
Azael Avalosbb3fe012015-01-18 18:30:24 -07002425 ret = toshiba_usb_rapid_charge_get(dev, &dummy);
2426 dev->usb_rapid_charge_supported = !ret;
2427
Azael Avalos172ce0a2015-01-18 18:30:25 -07002428 ret = toshiba_usb_sleep_music_get(dev, &dummy);
2429 dev->usb_sleep_music_supported = !ret;
2430
Seth Forshee36d03f92011-09-20 16:55:53 -05002431 /* Determine whether or not BIOS supports fan and video interfaces */
2432
2433 ret = get_video_status(dev, &dummy);
2434 dev->video_supported = !ret;
2435
2436 ret = get_fan_status(dev, &dummy);
2437 dev->fan_supported = !ret;
2438
Azael Avalos360f0f32014-03-25 20:38:31 -06002439 ret = sysfs_create_group(&dev->acpi_dev->dev.kobj,
2440 &toshiba_attr_group);
2441 if (ret) {
2442 dev->sysfs_created = 0;
2443 goto error;
2444 }
2445 dev->sysfs_created = !ret;
2446
Seth Forshee36d03f92011-09-20 16:55:53 -05002447 create_toshiba_proc_entries(dev);
2448
Seth Forshee29cd2932012-01-18 13:44:09 -06002449 toshiba_acpi = dev;
2450
Seth Forshee135740d2011-09-20 16:55:49 -05002451 return 0;
2452
2453error:
Rafael J. Wysocki51fac832013-01-24 00:24:48 +01002454 toshiba_acpi_remove(acpi_dev);
Seth Forshee135740d2011-09-20 16:55:49 -05002455 return ret;
2456}
2457
2458static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
2459{
2460 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
Azael Avalos80546902014-12-04 20:22:47 -07002461 int ret;
Matthew Garrett6335e4d2010-02-25 15:20:54 -05002462
Azael Avalos71454d72014-12-04 20:22:46 -07002463 switch (event) {
2464 case 0x80: /* Hotkeys and some system events */
2465 toshiba_acpi_process_hotkeys(dev);
2466 break;
Azael Avalos80546902014-12-04 20:22:47 -07002467 case 0x92: /* Keyboard backlight mode changed */
2468 /* Update sysfs entries */
2469 ret = sysfs_update_group(&acpi_dev->dev.kobj,
2470 &toshiba_attr_group);
2471 if (ret)
2472 pr_err("Unable to update sysfs entries\n");
2473 break;
Azael Avalos71454d72014-12-04 20:22:46 -07002474 case 0x81: /* Unknown */
2475 case 0x82: /* Unknown */
2476 case 0x83: /* Unknown */
2477 case 0x8c: /* Unknown */
2478 case 0x8e: /* Unknown */
2479 case 0x8f: /* Unknown */
2480 case 0x90: /* Unknown */
2481 default:
2482 pr_info("Unknown event received %x\n", event);
2483 break;
Seth Forshee29cd2932012-01-18 13:44:09 -06002484 }
Matthew Garrett6335e4d2010-02-25 15:20:54 -05002485}
2486
Rafael J. Wysocki3567a4e2012-08-09 23:00:13 +02002487#ifdef CONFIG_PM_SLEEP
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02002488static int toshiba_acpi_suspend(struct device *device)
Seth Forshee29cd2932012-01-18 13:44:09 -06002489{
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02002490 struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
Seth Forshee29cd2932012-01-18 13:44:09 -06002491 u32 result;
2492
2493 if (dev->hotkey_dev)
Azael Avalos893f3f62014-09-29 20:40:09 -06002494 result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE);
Seth Forshee29cd2932012-01-18 13:44:09 -06002495
2496 return 0;
2497}
2498
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02002499static int toshiba_acpi_resume(struct device *device)
Seth Forshee29cd2932012-01-18 13:44:09 -06002500{
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02002501 struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
Azael Avalos1f28f292014-12-04 20:22:45 -07002502 int error;
Seth Forshee29cd2932012-01-18 13:44:09 -06002503
Benjamin Tissoirese7fdb762014-09-02 14:04:19 -04002504 if (dev->hotkey_dev) {
Azael Avalos1f28f292014-12-04 20:22:45 -07002505 error = toshiba_acpi_enable_hotkeys(dev);
2506 if (error)
Benjamin Tissoirese7fdb762014-09-02 14:04:19 -04002507 pr_info("Unable to re-enable hotkeys\n");
Benjamin Tissoirese7fdb762014-09-02 14:04:19 -04002508 }
Seth Forshee29cd2932012-01-18 13:44:09 -06002509
2510 return 0;
2511}
Rafael J. Wysocki3567a4e2012-08-09 23:00:13 +02002512#endif
Matthew Garrett6335e4d2010-02-25 15:20:54 -05002513
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02002514static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm,
2515 toshiba_acpi_suspend, toshiba_acpi_resume);
2516
Seth Forshee135740d2011-09-20 16:55:49 -05002517static struct acpi_driver toshiba_acpi_driver = {
2518 .name = "Toshiba ACPI driver",
2519 .owner = THIS_MODULE,
2520 .ids = toshiba_device_ids,
2521 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
2522 .ops = {
2523 .add = toshiba_acpi_add,
2524 .remove = toshiba_acpi_remove,
2525 .notify = toshiba_acpi_notify,
2526 },
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02002527 .drv.pm = &toshiba_acpi_pm,
Seth Forshee135740d2011-09-20 16:55:49 -05002528};
Holger Machtc9263552006-10-20 14:30:29 -07002529
Len Brown4be44fc2005-08-05 00:44:28 -04002530static int __init toshiba_acpi_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531{
Seth Forshee135740d2011-09-20 16:55:49 -05002532 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533
Seth Forsheef11f9992012-01-18 13:44:11 -06002534 /*
2535 * Machines with this WMI guid aren't supported due to bugs in
2536 * their AML. This check relies on wmi initializing before
2537 * toshiba_acpi to guarantee guids have been identified.
2538 */
2539 if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
2540 return -ENODEV;
2541
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542 toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
2543 if (!toshiba_proc_dir) {
Seth Forshee135740d2011-09-20 16:55:49 -05002544 pr_err("Unable to create proc dir " PROC_TOSHIBA "\n");
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04002545 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 }
2547
Seth Forshee135740d2011-09-20 16:55:49 -05002548 ret = acpi_bus_register_driver(&toshiba_acpi_driver);
2549 if (ret) {
2550 pr_err("Failed to register ACPI driver: %d\n", ret);
2551 remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
Holger Machtc9263552006-10-20 14:30:29 -07002552 }
2553
Seth Forshee135740d2011-09-20 16:55:49 -05002554 return ret;
2555}
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04002556
Seth Forshee135740d2011-09-20 16:55:49 -05002557static void __exit toshiba_acpi_exit(void)
2558{
2559 acpi_bus_unregister_driver(&toshiba_acpi_driver);
2560 if (toshiba_proc_dir)
2561 remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562}
2563
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564module_init(toshiba_acpi_init);
2565module_exit(toshiba_acpi_exit);