blob: d6e97aadde0b8f6049eb3e24f99d328c22cfbc5d [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 Avalos7216d702015-02-10 21:09:21 -07008 * Copyright (C) 2014-2015 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 Avalos7216d702015-02-10 21:09:21 -070041#define TOSHIBA_ACPI_VERSION "0.21"
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
Azael Avalos98fc4ec2015-02-09 20:55:02 -0700111#define TOS_NOT_INSTALLED 0x8e00
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112
113/* registers */
114#define HCI_FAN 0x0004
Akio Idehara121b7b02012-04-06 01:46:43 +0900115#define HCI_TR_BACKLIGHT 0x0005
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116#define HCI_SYSTEM_EVENT 0x0016
117#define HCI_VIDEO_OUT 0x001c
118#define HCI_HOTKEY_EVENT 0x001e
119#define HCI_LCD_BRIGHTNESS 0x002a
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400120#define HCI_WIRELESS 0x0056
Azael Avalos5a2813e2014-03-25 20:38:34 -0600121#define HCI_ACCELEROMETER 0x006d
Azael Avalos360f0f32014-03-25 20:38:31 -0600122#define HCI_KBD_ILLUMINATION 0x0095
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600123#define HCI_ECO_MODE 0x0097
Azael Avalos5a2813e2014-03-25 20:38:34 -0600124#define HCI_ACCELEROMETER2 0x00a6
Azael Avalos35d53ce2015-02-10 21:09:19 -0700125#define SCI_PANEL_POWER_ON 0x010d
Azael Avalosfdb79082014-03-25 20:38:30 -0600126#define SCI_ILLUMINATION 0x014e
Azael Avalose26ffe52015-01-18 18:30:22 -0700127#define SCI_USB_SLEEP_CHARGE 0x0150
Azael Avalos360f0f32014-03-25 20:38:31 -0600128#define SCI_KBD_ILLUM_STATUS 0x015c
Azael Avalos172ce0a2015-01-18 18:30:25 -0700129#define SCI_USB_SLEEP_MUSIC 0x015e
Azael Avalos17fe4b32015-02-10 21:09:20 -0700130#define SCI_USB_THREE 0x0169
Azael Avalos9d8658a2014-03-25 20:38:32 -0600131#define SCI_TOUCHPAD 0x050e
Azael Avalosbae84192015-02-10 21:09:18 -0700132#define SCI_KBD_FUNCTION_KEYS 0x0522
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
134/* field definitions */
Azael Avalos5a2813e2014-03-25 20:38:34 -0600135#define HCI_ACCEL_MASK 0x7fff
Seth Forshee29cd2932012-01-18 13:44:09 -0600136#define HCI_HOTKEY_DISABLE 0x0b
137#define HCI_HOTKEY_ENABLE 0x09
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138#define HCI_LCD_BRIGHTNESS_BITS 3
139#define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS)
140#define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS)
Azael Avalos360f0f32014-03-25 20:38:31 -0600141#define HCI_MISC_SHIFT 0x10
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142#define HCI_VIDEO_OUT_LCD 0x1
143#define HCI_VIDEO_OUT_CRT 0x2
144#define HCI_VIDEO_OUT_TV 0x4
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400145#define HCI_WIRELESS_KILL_SWITCH 0x01
146#define HCI_WIRELESS_BT_PRESENT 0x0f
147#define HCI_WIRELESS_BT_ATTACH 0x40
148#define HCI_WIRELESS_BT_POWER 0x80
Azael Avalos93f8c162014-09-12 18:50:36 -0600149#define SCI_KBD_MODE_MASK 0x1f
Azael Avalos360f0f32014-03-25 20:38:31 -0600150#define SCI_KBD_MODE_FNZ 0x1
151#define SCI_KBD_MODE_AUTO 0x2
Azael Avalos93f8c162014-09-12 18:50:36 -0600152#define SCI_KBD_MODE_ON 0x8
153#define SCI_KBD_MODE_OFF 0x10
154#define SCI_KBD_TIME_MAX 0x3c001a
Azael Avalose26ffe52015-01-18 18:30:22 -0700155#define SCI_USB_CHARGE_MODE_MASK 0xff
156#define SCI_USB_CHARGE_DISABLED 0x30000
157#define SCI_USB_CHARGE_ALTERNATE 0x30009
158#define SCI_USB_CHARGE_AUTO 0x30021
Azael Avalos182bcaa2015-01-18 18:30:23 -0700159#define SCI_USB_CHARGE_BAT_MASK 0x7
160#define SCI_USB_CHARGE_BAT_LVL_OFF 0x1
161#define SCI_USB_CHARGE_BAT_LVL_ON 0x4
162#define SCI_USB_CHARGE_BAT_LVL 0x0200
Azael Avalosbb3fe012015-01-18 18:30:24 -0700163#define SCI_USB_CHARGE_RAPID_DSP 0x0300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164
Seth Forshee135740d2011-09-20 16:55:49 -0500165struct toshiba_acpi_dev {
166 struct acpi_device *acpi_dev;
167 const char *method_hci;
168 struct rfkill *bt_rfk;
169 struct input_dev *hotkey_dev;
Seth Forshee29cd2932012-01-18 13:44:09 -0600170 struct work_struct hotkey_work;
Seth Forshee135740d2011-09-20 16:55:49 -0500171 struct backlight_device *backlight_dev;
172 struct led_classdev led_dev;
Azael Avalos360f0f32014-03-25 20:38:31 -0600173 struct led_classdev kbd_led;
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600174 struct led_classdev eco_led;
Seth Forshee36d03f92011-09-20 16:55:53 -0500175
Seth Forshee135740d2011-09-20 16:55:49 -0500176 int force_fan;
177 int last_key_event;
178 int key_event_valid;
Azael Avalos93f8c162014-09-12 18:50:36 -0600179 int kbd_type;
Azael Avalos360f0f32014-03-25 20:38:31 -0600180 int kbd_mode;
181 int kbd_time;
Azael Avalos182bcaa2015-01-18 18:30:23 -0700182 int usbsc_bat_level;
Seth Forshee135740d2011-09-20 16:55:49 -0500183
Dan Carpenter592b7462012-01-15 14:28:20 +0300184 unsigned int illumination_supported:1;
185 unsigned int video_supported:1;
186 unsigned int fan_supported:1;
187 unsigned int system_event_supported:1;
Seth Forshee29cd2932012-01-18 13:44:09 -0600188 unsigned int ntfy_supported:1;
189 unsigned int info_supported:1;
Akio Idehara121b7b02012-04-06 01:46:43 +0900190 unsigned int tr_backlight_supported:1;
Azael Avalos360f0f32014-03-25 20:38:31 -0600191 unsigned int kbd_illum_supported:1;
192 unsigned int kbd_led_registered:1;
Azael Avalos9d8658a2014-03-25 20:38:32 -0600193 unsigned int touchpad_supported:1;
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600194 unsigned int eco_supported:1;
Azael Avalos5a2813e2014-03-25 20:38:34 -0600195 unsigned int accelerometer_supported:1;
Azael Avalose26ffe52015-01-18 18:30:22 -0700196 unsigned int usb_sleep_charge_supported:1;
Azael Avalosbb3fe012015-01-18 18:30:24 -0700197 unsigned int usb_rapid_charge_supported:1;
Azael Avalos172ce0a2015-01-18 18:30:25 -0700198 unsigned int usb_sleep_music_supported:1;
Azael Avalosbae84192015-02-10 21:09:18 -0700199 unsigned int kbd_function_keys_supported:1;
Azael Avalos35d53ce2015-02-10 21:09:19 -0700200 unsigned int panel_power_on_supported:1;
Azael Avalos17fe4b32015-02-10 21:09:20 -0700201 unsigned int usb_three_supported:1;
Azael Avalos360f0f32014-03-25 20:38:31 -0600202 unsigned int sysfs_created:1;
Seth Forshee36d03f92011-09-20 16:55:53 -0500203
Seth Forshee135740d2011-09-20 16:55:49 -0500204 struct mutex mutex;
205};
206
Seth Forshee29cd2932012-01-18 13:44:09 -0600207static struct toshiba_acpi_dev *toshiba_acpi;
208
arvidjaar@mail.ru4db42c52008-03-04 15:06:34 -0800209static const struct acpi_device_id toshiba_device_ids[] = {
210 {"TOS6200", 0},
Ondrej Zary63a9e012014-11-10 00:11:54 +0100211 {"TOS6207", 0},
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400212 {"TOS6208", 0},
arvidjaar@mail.ru4db42c52008-03-04 15:06:34 -0800213 {"TOS1900", 0},
214 {"", 0},
215};
216MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
217
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -0800218static const struct key_entry toshiba_acpi_keymap[] = {
Unai Uribarrifec278a2014-01-14 11:06:47 +0100219 { KE_KEY, 0x9e, { KEY_RFKILL } },
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -0700220 { KE_KEY, 0x101, { KEY_MUTE } },
221 { KE_KEY, 0x102, { KEY_ZOOMOUT } },
222 { KE_KEY, 0x103, { KEY_ZOOMIN } },
Azael Avalos408a5d12014-09-05 11:14:03 -0600223 { KE_KEY, 0x10f, { KEY_TAB } },
Azael Avalosaf502832012-01-18 13:44:10 -0600224 { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
225 { KE_KEY, 0x139, { KEY_ZOOMRESET } },
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -0700226 { KE_KEY, 0x13b, { KEY_COFFEE } },
227 { KE_KEY, 0x13c, { KEY_BATTERY } },
228 { KE_KEY, 0x13d, { KEY_SLEEP } },
229 { KE_KEY, 0x13e, { KEY_SUSPEND } },
230 { KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } },
231 { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } },
232 { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } },
233 { KE_KEY, 0x142, { KEY_WLAN } },
Azael Avalosaf502832012-01-18 13:44:10 -0600234 { KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } },
Jon Dowlanda49010f2010-10-27 00:24:59 +0100235 { KE_KEY, 0x17f, { KEY_FN } },
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -0700236 { KE_KEY, 0xb05, { KEY_PROG2 } },
237 { KE_KEY, 0xb06, { KEY_WWW } },
238 { KE_KEY, 0xb07, { KEY_MAIL } },
239 { KE_KEY, 0xb30, { KEY_STOP } },
240 { KE_KEY, 0xb31, { KEY_PREVIOUSSONG } },
241 { KE_KEY, 0xb32, { KEY_NEXTSONG } },
242 { KE_KEY, 0xb33, { KEY_PLAYPAUSE } },
243 { KE_KEY, 0xb5a, { KEY_MEDIA } },
Azael Avalos408a5d12014-09-05 11:14:03 -0600244 { KE_IGNORE, 0x1430, { KEY_RESERVED } }, /* Wake from sleep */
245 { KE_IGNORE, 0x1501, { KEY_RESERVED } }, /* Output changed */
246 { KE_IGNORE, 0x1502, { KEY_RESERVED } }, /* HDMI plugged/unplugged */
247 { KE_IGNORE, 0x1ABE, { KEY_RESERVED } }, /* Protection level set */
248 { KE_IGNORE, 0x1ABF, { KEY_RESERVED } }, /* Protection level off */
Dmitry Torokhov384a7cd2010-08-04 22:30:19 -0700249 { KE_END, 0 },
Matthew Garrett6335e4d2010-02-25 15:20:54 -0500250};
251
Takashi Iwaife808bfb2014-04-29 15:15:38 +0200252/* alternative keymap */
253static const struct dmi_system_id toshiba_alt_keymap_dmi[] = {
254 {
255 .matches = {
256 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
257 DMI_MATCH(DMI_PRODUCT_NAME, "Satellite M840"),
258 },
259 },
Azael Avalose6efad72014-08-04 09:21:02 -0600260 {
261 .matches = {
262 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
263 DMI_MATCH(DMI_PRODUCT_NAME, "Qosmio X75-A"),
264 },
265 },
Aaron Lub1bde682014-10-23 16:18:02 +0800266 {
267 .matches = {
268 DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
269 DMI_MATCH(DMI_PRODUCT_NAME, "TECRA A50-A"),
270 },
271 },
Takashi Iwaife808bfb2014-04-29 15:15:38 +0200272 {}
273};
274
275static const struct key_entry toshiba_acpi_alt_keymap[] = {
276 { KE_KEY, 0x157, { KEY_MUTE } },
277 { KE_KEY, 0x102, { KEY_ZOOMOUT } },
278 { KE_KEY, 0x103, { KEY_ZOOMIN } },
Azael Avalose6efad72014-08-04 09:21:02 -0600279 { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
Takashi Iwaife808bfb2014-04-29 15:15:38 +0200280 { KE_KEY, 0x139, { KEY_ZOOMRESET } },
281 { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } },
282 { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } },
283 { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } },
284 { KE_KEY, 0x158, { KEY_WLAN } },
285 { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } },
286 { KE_END, 0 },
287};
288
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289/* utility
290 */
291
Len Brown4be44fc2005-08-05 00:44:28 -0400292static __inline__ void _set_bit(u32 * word, u32 mask, int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293{
294 *word = (*word & ~mask) | (mask * value);
295}
296
297/* acpi interface wrappers
298 */
299
Len Brown4be44fc2005-08-05 00:44:28 -0400300static int write_acpi_int(const char *methodName, int val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 acpi_status status;
303
Zhang Rui619400d2013-09-03 08:31:56 +0800304 status = acpi_execute_simple_method(NULL, (char *)methodName, val);
Seth Forshee32bcd5c2011-09-20 16:55:50 -0500305 return (status == AE_OK) ? 0 : -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306}
307
Azael Avalos258c5902014-09-29 20:40:07 -0600308/* Perform a raw configuration call. Here we don't care about input or output
309 * buffer format.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 */
Azael Avalos258c5902014-09-29 20:40:07 -0600311static acpi_status tci_raw(struct toshiba_acpi_dev *dev,
312 const u32 in[TCI_WORDS], u32 out[TCI_WORDS])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313{
314 struct acpi_object_list params;
Azael Avalos258c5902014-09-29 20:40:07 -0600315 union acpi_object in_objs[TCI_WORDS];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 struct acpi_buffer results;
Azael Avalos258c5902014-09-29 20:40:07 -0600317 union acpi_object out_objs[TCI_WORDS + 1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 acpi_status status;
319 int i;
320
Azael Avalos258c5902014-09-29 20:40:07 -0600321 params.count = TCI_WORDS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 params.pointer = in_objs;
Azael Avalos258c5902014-09-29 20:40:07 -0600323 for (i = 0; i < TCI_WORDS; ++i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 in_objs[i].type = ACPI_TYPE_INTEGER;
325 in_objs[i].integer.value = in[i];
326 }
327
328 results.length = sizeof(out_objs);
329 results.pointer = out_objs;
330
Seth Forshee6e02cc72011-09-20 16:55:51 -0500331 status = acpi_evaluate_object(dev->acpi_dev->handle,
332 (char *)dev->method_hci, &params,
Len Brown4be44fc2005-08-05 00:44:28 -0400333 &results);
Azael Avalos258c5902014-09-29 20:40:07 -0600334 if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 for (i = 0; i < out_objs->package.count; ++i) {
336 out[i] = out_objs->package.elements[i].integer.value;
337 }
338 }
339
340 return status;
341}
342
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400343/* common hci tasks (get or set one or two value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 *
345 * In addition to the ACPI status, the HCI system returns a result which
346 * may be useful (such as "not supported").
347 */
348
Azael Avalos893f3f62014-09-29 20:40:09 -0600349static u32 hci_write1(struct toshiba_acpi_dev *dev, u32 reg, u32 in1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350{
Azael Avalos258c5902014-09-29 20:40:07 -0600351 u32 in[TCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 };
352 u32 out[TCI_WORDS];
353 acpi_status status = tci_raw(dev, in, out);
Azael Avalos893f3f62014-09-29 20:40:09 -0600354
355 return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356}
357
Azael Avalos893f3f62014-09-29 20:40:09 -0600358static u32 hci_read1(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359{
Azael Avalos258c5902014-09-29 20:40:07 -0600360 u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 };
361 u32 out[TCI_WORDS];
362 acpi_status status = tci_raw(dev, in, out);
Azael Avalos893f3f62014-09-29 20:40:09 -0600363 if (ACPI_FAILURE(status))
364 return TOS_FAILURE;
365
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 *out1 = out[2];
Azael Avalos893f3f62014-09-29 20:40:09 -0600367
368 return out[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369}
370
Azael Avalos893f3f62014-09-29 20:40:09 -0600371static u32 hci_write2(struct toshiba_acpi_dev *dev, u32 reg, u32 in1, u32 in2)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400372{
Azael Avalos258c5902014-09-29 20:40:07 -0600373 u32 in[TCI_WORDS] = { HCI_SET, reg, in1, in2, 0, 0 };
374 u32 out[TCI_WORDS];
375 acpi_status status = tci_raw(dev, in, out);
Azael Avalos893f3f62014-09-29 20:40:09 -0600376
377 return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE;
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400378}
379
Azael Avalos893f3f62014-09-29 20:40:09 -0600380static u32 hci_read2(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1, u32 *out2)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400381{
Azael Avalos258c5902014-09-29 20:40:07 -0600382 u32 in[TCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 };
383 u32 out[TCI_WORDS];
384 acpi_status status = tci_raw(dev, in, out);
Azael Avalos893f3f62014-09-29 20:40:09 -0600385 if (ACPI_FAILURE(status))
386 return TOS_FAILURE;
387
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400388 *out1 = out[2];
389 *out2 = out[3];
Azael Avalos893f3f62014-09-29 20:40:09 -0600390
391 return out[0];
philipl@overt.orgc41a40c2008-08-30 11:57:39 -0400392}
393
Azael Avalos84a62732014-03-25 20:38:29 -0600394/* common sci tasks
395 */
396
397static int sci_open(struct toshiba_acpi_dev *dev)
398{
Azael Avalos258c5902014-09-29 20:40:07 -0600399 u32 in[TCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 };
400 u32 out[TCI_WORDS];
Azael Avalos84a62732014-03-25 20:38:29 -0600401 acpi_status status;
402
Azael Avalos258c5902014-09-29 20:40:07 -0600403 status = tci_raw(dev, in, out);
Azael Avalos1864bbc2014-09-29 20:40:08 -0600404 if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
Azael Avalos84a62732014-03-25 20:38:29 -0600405 pr_err("ACPI call to open SCI failed\n");
406 return 0;
407 }
408
Azael Avalos1864bbc2014-09-29 20:40:08 -0600409 if (out[0] == TOS_OPEN_CLOSE_OK) {
Azael Avalos84a62732014-03-25 20:38:29 -0600410 return 1;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600411 } else if (out[0] == TOS_ALREADY_OPEN) {
Azael Avalos84a62732014-03-25 20:38:29 -0600412 pr_info("Toshiba SCI already opened\n");
413 return 1;
Azael Avalosfa465732015-01-18 19:17:12 -0700414 } else if (out[0] == TOS_NOT_SUPPORTED) {
415 /* Some BIOSes do not have the SCI open/close functions
416 * implemented and return 0x8000 (Not Supported), failing to
417 * register some supported features.
418 *
419 * Simply return 1 if we hit those affected laptops to make the
420 * supported features work.
421 *
422 * In the case that some laptops really do not support the SCI,
423 * all the SCI dependent functions check for TOS_NOT_SUPPORTED,
424 * and thus, not registering support for the queried feature.
425 */
426 return 1;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600427 } else if (out[0] == TOS_NOT_PRESENT) {
Azael Avalos84a62732014-03-25 20:38:29 -0600428 pr_info("Toshiba SCI is not present\n");
429 }
430
431 return 0;
432}
433
434static void sci_close(struct toshiba_acpi_dev *dev)
435{
Azael Avalos258c5902014-09-29 20:40:07 -0600436 u32 in[TCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 };
437 u32 out[TCI_WORDS];
Azael Avalos84a62732014-03-25 20:38:29 -0600438 acpi_status status;
439
Azael Avalos258c5902014-09-29 20:40:07 -0600440 status = tci_raw(dev, in, out);
Azael Avalos1864bbc2014-09-29 20:40:08 -0600441 if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
Azael Avalos84a62732014-03-25 20:38:29 -0600442 pr_err("ACPI call to close SCI failed\n");
443 return;
444 }
445
Azael Avalos1864bbc2014-09-29 20:40:08 -0600446 if (out[0] == TOS_OPEN_CLOSE_OK)
Azael Avalos84a62732014-03-25 20:38:29 -0600447 return;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600448 else if (out[0] == TOS_NOT_OPENED)
Azael Avalos84a62732014-03-25 20:38:29 -0600449 pr_info("Toshiba SCI not opened\n");
Azael Avalos1864bbc2014-09-29 20:40:08 -0600450 else if (out[0] == TOS_NOT_PRESENT)
Azael Avalos84a62732014-03-25 20:38:29 -0600451 pr_info("Toshiba SCI is not present\n");
452}
453
Azael Avalos893f3f62014-09-29 20:40:09 -0600454static u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1)
Azael Avalos84a62732014-03-25 20:38:29 -0600455{
Azael Avalos258c5902014-09-29 20:40:07 -0600456 u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 };
457 u32 out[TCI_WORDS];
458 acpi_status status = tci_raw(dev, in, out);
Azael Avalos893f3f62014-09-29 20:40:09 -0600459 if (ACPI_FAILURE(status))
460 return TOS_FAILURE;
461
Azael Avalos84a62732014-03-25 20:38:29 -0600462 *out1 = out[2];
Azael Avalos893f3f62014-09-29 20:40:09 -0600463
464 return out[0];
Azael Avalos84a62732014-03-25 20:38:29 -0600465}
466
Azael Avalos893f3f62014-09-29 20:40:09 -0600467static u32 sci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1)
Azael Avalos84a62732014-03-25 20:38:29 -0600468{
Azael Avalos258c5902014-09-29 20:40:07 -0600469 u32 in[TCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 };
470 u32 out[TCI_WORDS];
471 acpi_status status = tci_raw(dev, in, out);
Azael Avalos893f3f62014-09-29 20:40:09 -0600472
473 return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE;
Azael Avalos84a62732014-03-25 20:38:29 -0600474}
475
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200476/* Illumination support */
Seth Forshee135740d2011-09-20 16:55:49 -0500477static int toshiba_illumination_available(struct toshiba_acpi_dev *dev)
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200478{
Azael Avalos258c5902014-09-29 20:40:07 -0600479 u32 in[TCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 };
480 u32 out[TCI_WORDS];
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200481 acpi_status status;
482
Azael Avalosfdb79082014-03-25 20:38:30 -0600483 if (!sci_open(dev))
484 return 0;
485
Azael Avalos258c5902014-09-29 20:40:07 -0600486 status = tci_raw(dev, in, out);
Azael Avalosfdb79082014-03-25 20:38:30 -0600487 sci_close(dev);
Azael Avalos1864bbc2014-09-29 20:40:08 -0600488 if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
Azael Avalosfdb79082014-03-25 20:38:30 -0600489 pr_err("ACPI call to query Illumination support failed\n");
490 return 0;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600491 } else if (out[0] == TOS_NOT_SUPPORTED) {
Joe Perches7e334602011-03-29 15:21:52 -0700492 pr_info("Illumination device not available\n");
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200493 return 0;
494 }
Azael Avalosfdb79082014-03-25 20:38:30 -0600495
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200496 return 1;
497}
498
499static void toshiba_illumination_set(struct led_classdev *cdev,
500 enum led_brightness brightness)
501{
Seth Forshee135740d2011-09-20 16:55:49 -0500502 struct toshiba_acpi_dev *dev = container_of(cdev,
503 struct toshiba_acpi_dev, led_dev);
Azael Avalosfdb79082014-03-25 20:38:30 -0600504 u32 state, result;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200505
506 /* First request : initialize communication. */
Azael Avalosfdb79082014-03-25 20:38:30 -0600507 if (!sci_open(dev))
508 return;
509
510 /* Switch the illumination on/off */
511 state = brightness ? 1 : 0;
Azael Avalos893f3f62014-09-29 20:40:09 -0600512 result = sci_write(dev, SCI_ILLUMINATION, state);
Azael Avalosfdb79082014-03-25 20:38:30 -0600513 sci_close(dev);
Azael Avalos893f3f62014-09-29 20:40:09 -0600514 if (result == TOS_FAILURE) {
Azael Avalosfdb79082014-03-25 20:38:30 -0600515 pr_err("ACPI call for illumination failed\n");
516 return;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600517 } else if (result == TOS_NOT_SUPPORTED) {
Azael Avalosfdb79082014-03-25 20:38:30 -0600518 pr_info("Illumination not supported\n");
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200519 return;
520 }
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200521}
522
523static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
524{
Seth Forshee135740d2011-09-20 16:55:49 -0500525 struct toshiba_acpi_dev *dev = container_of(cdev,
526 struct toshiba_acpi_dev, led_dev);
Azael Avalosfdb79082014-03-25 20:38:30 -0600527 u32 state, result;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200528
529 /* First request : initialize communication. */
Azael Avalosfdb79082014-03-25 20:38:30 -0600530 if (!sci_open(dev))
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200531 return LED_OFF;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200532
533 /* Check the illumination */
Azael Avalos893f3f62014-09-29 20:40:09 -0600534 result = sci_read(dev, SCI_ILLUMINATION, &state);
Azael Avalosfdb79082014-03-25 20:38:30 -0600535 sci_close(dev);
Azael Avalos893f3f62014-09-29 20:40:09 -0600536 if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
Azael Avalosfdb79082014-03-25 20:38:30 -0600537 pr_err("ACPI call for illumination failed\n");
538 return LED_OFF;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600539 } else if (result == TOS_NOT_SUPPORTED) {
Azael Avalosfdb79082014-03-25 20:38:30 -0600540 pr_info("Illumination not supported\n");
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200541 return LED_OFF;
542 }
543
Azael Avalosfdb79082014-03-25 20:38:30 -0600544 return state ? LED_FULL : LED_OFF;
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200545}
Matthew Garrettea6b31f2014-04-04 14:22:34 -0400546
Azael Avalos360f0f32014-03-25 20:38:31 -0600547/* KBD Illumination */
Azael Avalos93f8c162014-09-12 18:50:36 -0600548static int toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev)
549{
Azael Avalos258c5902014-09-29 20:40:07 -0600550 u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 };
551 u32 out[TCI_WORDS];
Azael Avalos93f8c162014-09-12 18:50:36 -0600552 acpi_status status;
553
554 if (!sci_open(dev))
555 return 0;
556
Azael Avalos258c5902014-09-29 20:40:07 -0600557 status = tci_raw(dev, in, out);
Azael Avalos93f8c162014-09-12 18:50:36 -0600558 sci_close(dev);
Azael Avalos1864bbc2014-09-29 20:40:08 -0600559 if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
Azael Avalos93f8c162014-09-12 18:50:36 -0600560 pr_err("ACPI call to query kbd illumination support failed\n");
561 return 0;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600562 } else if (out[0] == TOS_NOT_SUPPORTED) {
Azael Avalos93f8c162014-09-12 18:50:36 -0600563 pr_info("Keyboard illumination not available\n");
564 return 0;
565 }
566
567 /* Check for keyboard backlight timeout max value,
568 * previous kbd backlight implementation set this to
569 * 0x3c0003, and now the new implementation set this
570 * to 0x3c001a, use this to distinguish between them
571 */
572 if (out[3] == SCI_KBD_TIME_MAX)
573 dev->kbd_type = 2;
574 else
575 dev->kbd_type = 1;
576 /* Get the current keyboard backlight mode */
577 dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK;
578 /* Get the current time (1-60 seconds) */
579 dev->kbd_time = out[2] >> HCI_MISC_SHIFT;
580
581 return 1;
582}
583
Azael Avalos360f0f32014-03-25 20:38:31 -0600584static int toshiba_kbd_illum_status_set(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_write(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 set 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 int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time)
605{
606 u32 result;
Azael Avalos360f0f32014-03-25 20:38:31 -0600607
608 if (!sci_open(dev))
609 return -EIO;
610
Azael Avalos893f3f62014-09-29 20:40:09 -0600611 result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time);
Azael Avalos360f0f32014-03-25 20:38:31 -0600612 sci_close(dev);
Azael Avalos893f3f62014-09-29 20:40:09 -0600613 if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
Azael Avalos360f0f32014-03-25 20:38:31 -0600614 pr_err("ACPI call to get KBD backlight status failed\n");
615 return -EIO;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600616 } else if (result == TOS_NOT_SUPPORTED) {
Azael Avalos360f0f32014-03-25 20:38:31 -0600617 pr_info("Keyboard backlight status not supported\n");
618 return -ENODEV;
619 }
620
621 return 0;
622}
623
624static enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev)
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 /* Check the keyboard backlight state */
Azael Avalos893f3f62014-09-29 20:40:09 -0600631 result = hci_read1(dev, HCI_KBD_ILLUMINATION, &state);
632 if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
Azael Avalos360f0f32014-03-25 20:38:31 -0600633 pr_err("ACPI call to get the keyboard backlight failed\n");
634 return LED_OFF;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600635 } else if (result == TOS_NOT_SUPPORTED) {
Azael Avalos360f0f32014-03-25 20:38:31 -0600636 pr_info("Keyboard backlight not supported\n");
637 return LED_OFF;
638 }
639
640 return state ? LED_FULL : LED_OFF;
641}
642
643static void toshiba_kbd_backlight_set(struct led_classdev *cdev,
644 enum led_brightness brightness)
645{
646 struct toshiba_acpi_dev *dev = container_of(cdev,
647 struct toshiba_acpi_dev, kbd_led);
648 u32 state, result;
Azael Avalos360f0f32014-03-25 20:38:31 -0600649
650 /* Set the keyboard backlight state */
651 state = brightness ? 1 : 0;
Azael Avalos893f3f62014-09-29 20:40:09 -0600652 result = hci_write1(dev, HCI_KBD_ILLUMINATION, state);
653 if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
Azael Avalos360f0f32014-03-25 20:38:31 -0600654 pr_err("ACPI call to set KBD Illumination mode failed\n");
655 return;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600656 } else if (result == TOS_NOT_SUPPORTED) {
Azael Avalos360f0f32014-03-25 20:38:31 -0600657 pr_info("Keyboard backlight not supported\n");
658 return;
659 }
660}
Matthew Garrettea6b31f2014-04-04 14:22:34 -0400661
Azael Avalos9d8658a2014-03-25 20:38:32 -0600662/* TouchPad support */
663static int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state)
664{
665 u32 result;
Azael Avalos9d8658a2014-03-25 20:38:32 -0600666
667 if (!sci_open(dev))
668 return -EIO;
669
Azael Avalos893f3f62014-09-29 20:40:09 -0600670 result = sci_write(dev, SCI_TOUCHPAD, state);
Azael Avalos9d8658a2014-03-25 20:38:32 -0600671 sci_close(dev);
Azael Avalos893f3f62014-09-29 20:40:09 -0600672 if (result == TOS_FAILURE) {
Azael Avalos9d8658a2014-03-25 20:38:32 -0600673 pr_err("ACPI call to set the touchpad failed\n");
674 return -EIO;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600675 } else if (result == TOS_NOT_SUPPORTED) {
Azael Avalos9d8658a2014-03-25 20:38:32 -0600676 return -ENODEV;
677 }
678
679 return 0;
680}
681
682static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state)
683{
684 u32 result;
Azael Avalos9d8658a2014-03-25 20:38:32 -0600685
686 if (!sci_open(dev))
687 return -EIO;
688
Azael Avalos893f3f62014-09-29 20:40:09 -0600689 result = sci_read(dev, SCI_TOUCHPAD, state);
Azael Avalos9d8658a2014-03-25 20:38:32 -0600690 sci_close(dev);
Azael Avalos893f3f62014-09-29 20:40:09 -0600691 if (result == TOS_FAILURE) {
Azael Avalos9d8658a2014-03-25 20:38:32 -0600692 pr_err("ACPI call to query the touchpad failed\n");
693 return -EIO;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600694 } else if (result == TOS_NOT_SUPPORTED) {
Azael Avalos9d8658a2014-03-25 20:38:32 -0600695 return -ENODEV;
696 }
697
698 return 0;
699}
Pierre Ducroquet6c3f6e62010-07-29 11:56:59 +0200700
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600701/* Eco Mode support */
702static int toshiba_eco_mode_available(struct toshiba_acpi_dev *dev)
703{
704 acpi_status status;
Azael Avalos98fc4ec2015-02-09 20:55:02 -0700705 u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 };
Azael Avalos258c5902014-09-29 20:40:07 -0600706 u32 out[TCI_WORDS];
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600707
Azael Avalos258c5902014-09-29 20:40:07 -0600708 status = tci_raw(dev, in, out);
Azael Avalos98fc4ec2015-02-09 20:55:02 -0700709 if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
710 pr_err("ACPI call to get ECO led failed\n");
711 } else if (out[0] == TOS_NOT_INSTALLED) {
712 pr_info("ECO led not installed");
713 } else if (out[0] == TOS_INPUT_DATA_ERROR) {
714 /* If we receive 0x8300 (Input Data Error), it means that the
715 * LED device is present, but that we just screwed the input
716 * parameters.
717 *
718 * Let's query the status of the LED to see if we really have a
719 * success response, indicating the actual presense of the LED,
720 * bail out otherwise.
721 */
722 in[3] = 1;
723 status = tci_raw(dev, in, out);
724 if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE)
725 pr_err("ACPI call to get ECO led failed\n");
726 else if (out[0] == TOS_SUCCESS)
727 return 1;
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600728 }
729
Azael Avalos98fc4ec2015-02-09 20:55:02 -0700730 return 0;
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600731}
732
733static enum led_brightness toshiba_eco_mode_get_status(struct led_classdev *cdev)
734{
735 struct toshiba_acpi_dev *dev = container_of(cdev,
736 struct toshiba_acpi_dev, eco_led);
Azael Avalos258c5902014-09-29 20:40:07 -0600737 u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 };
738 u32 out[TCI_WORDS];
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600739 acpi_status status;
740
Azael Avalos258c5902014-09-29 20:40:07 -0600741 status = tci_raw(dev, in, out);
Azael Avalos1864bbc2014-09-29 20:40:08 -0600742 if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600743 pr_err("ACPI call to get ECO led failed\n");
744 return LED_OFF;
745 }
746
747 return out[2] ? LED_FULL : LED_OFF;
748}
749
750static void toshiba_eco_mode_set_status(struct led_classdev *cdev,
751 enum led_brightness brightness)
752{
753 struct toshiba_acpi_dev *dev = container_of(cdev,
754 struct toshiba_acpi_dev, eco_led);
Azael Avalos258c5902014-09-29 20:40:07 -0600755 u32 in[TCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 };
756 u32 out[TCI_WORDS];
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600757 acpi_status status;
758
759 /* Switch the Eco Mode led on/off */
760 in[2] = (brightness) ? 1 : 0;
Azael Avalos258c5902014-09-29 20:40:07 -0600761 status = tci_raw(dev, in, out);
Azael Avalos1864bbc2014-09-29 20:40:08 -0600762 if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600763 pr_err("ACPI call to set ECO led failed\n");
764 return;
765 }
766}
Matthew Garrettea6b31f2014-04-04 14:22:34 -0400767
Azael Avalos5a2813e2014-03-25 20:38:34 -0600768/* Accelerometer support */
769static int toshiba_accelerometer_supported(struct toshiba_acpi_dev *dev)
770{
Azael Avalos258c5902014-09-29 20:40:07 -0600771 u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 };
772 u32 out[TCI_WORDS];
Azael Avalos5a2813e2014-03-25 20:38:34 -0600773 acpi_status status;
774
775 /* Check if the accelerometer call exists,
776 * this call also serves as initialization
777 */
Azael Avalos258c5902014-09-29 20:40:07 -0600778 status = tci_raw(dev, in, out);
Azael Avalos1864bbc2014-09-29 20:40:08 -0600779 if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
Azael Avalos5a2813e2014-03-25 20:38:34 -0600780 pr_err("ACPI call to query the accelerometer failed\n");
781 return -EIO;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600782 } else if (out[0] == TOS_DATA_NOT_AVAILABLE ||
783 out[0] == TOS_NOT_INITIALIZED) {
Azael Avalos5a2813e2014-03-25 20:38:34 -0600784 pr_err("Accelerometer not initialized\n");
785 return -EIO;
Azael Avalos1864bbc2014-09-29 20:40:08 -0600786 } else if (out[0] == TOS_NOT_SUPPORTED) {
Azael Avalos5a2813e2014-03-25 20:38:34 -0600787 pr_info("Accelerometer not supported\n");
788 return -ENODEV;
789 }
790
791 return 0;
792}
793
794static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev,
795 u32 *xy, u32 *z)
796{
Azael Avalos258c5902014-09-29 20:40:07 -0600797 u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 };
798 u32 out[TCI_WORDS];
Azael Avalos5a2813e2014-03-25 20:38:34 -0600799 acpi_status status;
800
801 /* Check the Accelerometer status */
Azael Avalos258c5902014-09-29 20:40:07 -0600802 status = tci_raw(dev, in, out);
Azael Avalos1864bbc2014-09-29 20:40:08 -0600803 if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
Azael Avalos5a2813e2014-03-25 20:38:34 -0600804 pr_err("ACPI call to query the accelerometer failed\n");
805 return -EIO;
806 }
807
808 *xy = out[2];
809 *z = out[4];
810
811 return 0;
812}
Azael Avalosdef6c4e2014-03-25 20:38:33 -0600813
Azael Avalose26ffe52015-01-18 18:30:22 -0700814/* Sleep (Charge and Music) utilities support */
815static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev,
816 u32 *mode)
817{
818 u32 result;
819
820 if (!sci_open(dev))
821 return -EIO;
822
823 result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode);
824 sci_close(dev);
825 if (result == TOS_FAILURE) {
826 pr_err("ACPI call to set USB S&C mode failed\n");
827 return -EIO;
828 } else if (result == TOS_NOT_SUPPORTED) {
829 pr_info("USB Sleep and Charge not supported\n");
830 return -ENODEV;
831 } else if (result == TOS_INPUT_DATA_ERROR) {
832 return -EIO;
833 }
834
835 return 0;
836}
837
838static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev,
839 u32 mode)
840{
841 u32 result;
842
843 if (!sci_open(dev))
844 return -EIO;
845
846 result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode);
847 sci_close(dev);
848 if (result == TOS_FAILURE) {
849 pr_err("ACPI call to set USB S&C mode failed\n");
850 return -EIO;
851 } else if (result == TOS_NOT_SUPPORTED) {
852 pr_info("USB Sleep and Charge not supported\n");
853 return -ENODEV;
854 } else if (result == TOS_INPUT_DATA_ERROR) {
855 return -EIO;
856 }
857
858 return 0;
859}
860
Azael Avalos182bcaa2015-01-18 18:30:23 -0700861static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev,
862 u32 *mode)
863{
864 u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
865 u32 out[TCI_WORDS];
866 acpi_status status;
867
868 if (!sci_open(dev))
869 return -EIO;
870
871 in[5] = SCI_USB_CHARGE_BAT_LVL;
872 status = tci_raw(dev, in, out);
873 sci_close(dev);
874 if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
875 pr_err("ACPI call to get USB S&C battery level failed\n");
876 return -EIO;
877 } else if (out[0] == TOS_NOT_SUPPORTED) {
878 pr_info("USB Sleep and Charge not supported\n");
879 return -ENODEV;
880 } else if (out[0] == TOS_INPUT_DATA_ERROR) {
881 return -EIO;
882 }
883
884 *mode = out[2];
885
886 return 0;
887}
888
889static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev,
890 u32 mode)
891{
892 u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
893 u32 out[TCI_WORDS];
894 acpi_status status;
895
896 if (!sci_open(dev))
897 return -EIO;
898
899 in[2] = mode;
900 in[5] = SCI_USB_CHARGE_BAT_LVL;
901 status = tci_raw(dev, in, out);
902 sci_close(dev);
903 if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
904 pr_err("ACPI call to set USB S&C battery level failed\n");
905 return -EIO;
906 } else if (out[0] == TOS_NOT_SUPPORTED) {
907 pr_info("USB Sleep and Charge not supported\n");
908 return -ENODEV;
909 } else if (out[0] == TOS_INPUT_DATA_ERROR) {
910 return -EIO;
911 }
912
913 return 0;
914}
915
Azael Avalosbb3fe012015-01-18 18:30:24 -0700916static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev,
917 u32 *state)
918{
919 u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
920 u32 out[TCI_WORDS];
921 acpi_status status;
922
923 if (!sci_open(dev))
924 return -EIO;
925
926 in[5] = SCI_USB_CHARGE_RAPID_DSP;
927 status = tci_raw(dev, in, out);
928 sci_close(dev);
929 if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
930 pr_err("ACPI call to get USB S&C battery level failed\n");
931 return -EIO;
932 } else if (out[0] == TOS_NOT_SUPPORTED ||
933 out[0] == TOS_INPUT_DATA_ERROR) {
934 pr_info("USB Sleep and Charge not supported\n");
935 return -ENODEV;
936 }
937
938 *state = out[2];
939
940 return 0;
941}
942
943static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev,
944 u32 state)
945{
946 u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
947 u32 out[TCI_WORDS];
948 acpi_status status;
949
950 if (!sci_open(dev))
951 return -EIO;
952
953 in[2] = state;
954 in[5] = SCI_USB_CHARGE_RAPID_DSP;
955 status = tci_raw(dev, in, out);
956 sci_close(dev);
957 if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
958 pr_err("ACPI call to set USB S&C battery level failed\n");
959 return -EIO;
960 } else if (out[0] == TOS_NOT_SUPPORTED) {
961 pr_info("USB Sleep and Charge not supported\n");
962 return -ENODEV;
963 } else if (out[0] == TOS_INPUT_DATA_ERROR) {
964 return -EIO;
965 }
966
967 return 0;
968}
969
Azael Avalos172ce0a2015-01-18 18:30:25 -0700970static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state)
971{
972 u32 result;
973
974 if (!sci_open(dev))
975 return -EIO;
976
977 result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state);
978 sci_close(dev);
979 if (result == TOS_FAILURE) {
980 pr_err("ACPI call to set USB S&C mode failed\n");
981 return -EIO;
982 } else if (result == TOS_NOT_SUPPORTED) {
983 pr_info("USB Sleep and Charge not supported\n");
984 return -ENODEV;
985 } else if (result == TOS_INPUT_DATA_ERROR) {
986 return -EIO;
987 }
988
989 return 0;
990}
991
992static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state)
993{
994 u32 result;
995
996 if (!sci_open(dev))
997 return -EIO;
998
999 result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state);
1000 sci_close(dev);
1001 if (result == TOS_FAILURE) {
1002 pr_err("ACPI call to set USB S&C mode failed\n");
1003 return -EIO;
1004 } else if (result == TOS_NOT_SUPPORTED) {
1005 pr_info("USB Sleep and Charge not supported\n");
1006 return -ENODEV;
1007 } else if (result == TOS_INPUT_DATA_ERROR) {
1008 return -EIO;
1009 }
1010
1011 return 0;
1012}
1013
Azael Avalosbae84192015-02-10 21:09:18 -07001014/* Keyboard function keys */
1015static int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode)
1016{
1017 u32 result;
1018
1019 if (!sci_open(dev))
1020 return -EIO;
1021
1022 result = sci_read(dev, SCI_KBD_FUNCTION_KEYS, mode);
1023 sci_close(dev);
1024 if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
1025 pr_err("ACPI call to get KBD function keys failed\n");
1026 return -EIO;
1027 } else if (result == TOS_NOT_SUPPORTED) {
1028 pr_info("KBD function keys not supported\n");
1029 return -ENODEV;
1030 }
1031
1032 return 0;
1033}
1034
1035static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode)
1036{
1037 u32 result;
1038
1039 if (!sci_open(dev))
1040 return -EIO;
1041
1042 result = sci_write(dev, SCI_KBD_FUNCTION_KEYS, mode);
1043 sci_close(dev);
1044 if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
1045 pr_err("ACPI call to set KBD function keys failed\n");
1046 return -EIO;
1047 } else if (result == TOS_NOT_SUPPORTED) {
1048 pr_info("KBD function keys not supported\n");
1049 return -ENODEV;
1050 }
1051
1052 return 0;
1053}
1054
Azael Avalos35d53ce2015-02-10 21:09:19 -07001055/* Panel Power ON */
1056static int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state)
1057{
1058 u32 result;
1059
1060 if (!sci_open(dev))
1061 return -EIO;
1062
1063 result = sci_read(dev, SCI_PANEL_POWER_ON, state);
1064 sci_close(dev);
1065 if (result == TOS_FAILURE) {
1066 pr_err("ACPI call to get Panel Power ON failed\n");
1067 return -EIO;
1068 } else if (result == TOS_NOT_SUPPORTED) {
1069 pr_info("Panel Power on not supported\n");
1070 return -ENODEV;
1071 } else if (result == TOS_INPUT_DATA_ERROR) {
1072 return -EIO;
1073 }
1074
1075 return 0;
1076}
1077
1078static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state)
1079{
1080 u32 result;
1081
1082 if (!sci_open(dev))
1083 return -EIO;
1084
1085 result = sci_write(dev, SCI_PANEL_POWER_ON, state);
1086 sci_close(dev);
1087 if (result == TOS_FAILURE) {
1088 pr_err("ACPI call to set Panel Power ON failed\n");
1089 return -EIO;
1090 } else if (result == TOS_NOT_SUPPORTED) {
1091 pr_info("Panel Power ON not supported\n");
1092 return -ENODEV;
1093 } else if (result == TOS_INPUT_DATA_ERROR) {
1094 return -EIO;
1095 }
1096
1097 return 0;
1098}
1099
Azael Avalos17fe4b32015-02-10 21:09:20 -07001100/* USB Three */
1101static int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state)
1102{
1103 u32 result;
1104
1105 if (!sci_open(dev))
1106 return -EIO;
1107
1108 result = sci_read(dev, SCI_USB_THREE, state);
1109 sci_close(dev);
1110 if (result == TOS_FAILURE) {
1111 pr_err("ACPI call to get USB 3 failed\n");
1112 return -EIO;
1113 } else if (result == TOS_NOT_SUPPORTED) {
1114 pr_info("USB 3 not supported\n");
1115 return -ENODEV;
1116 } else if (result == TOS_INPUT_DATA_ERROR) {
1117 return -EIO;
1118 }
1119
1120 return 0;
1121}
1122
1123static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state)
1124{
1125 u32 result;
1126
1127 if (!sci_open(dev))
1128 return -EIO;
1129
1130 result = sci_write(dev, SCI_USB_THREE, state);
1131 sci_close(dev);
1132 if (result == TOS_FAILURE) {
1133 pr_err("ACPI call to set USB 3 failed\n");
1134 return -EIO;
1135 } else if (result == TOS_NOT_SUPPORTED) {
1136 pr_info("USB 3 not supported\n");
1137 return -ENODEV;
1138 } else if (result == TOS_INPUT_DATA_ERROR) {
1139 return -EIO;
1140 }
1141
1142 return 0;
1143}
1144
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001145/* Bluetooth rfkill handlers */
1146
Seth Forshee135740d2011-09-20 16:55:49 -05001147static u32 hci_get_bt_present(struct toshiba_acpi_dev *dev, bool *present)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001148{
1149 u32 hci_result;
1150 u32 value, value2;
1151
1152 value = 0;
1153 value2 = 0;
Azael Avalos893f3f62014-09-29 20:40:09 -06001154 hci_result = hci_read2(dev, HCI_WIRELESS, &value, &value2);
Azael Avalos1864bbc2014-09-29 20:40:08 -06001155 if (hci_result == TOS_SUCCESS)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001156 *present = (value & HCI_WIRELESS_BT_PRESENT) ? true : false;
1157
1158 return hci_result;
1159}
1160
Seth Forshee135740d2011-09-20 16:55:49 -05001161static u32 hci_get_radio_state(struct toshiba_acpi_dev *dev, bool *radio_state)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001162{
1163 u32 hci_result;
1164 u32 value, value2;
1165
1166 value = 0;
1167 value2 = 0x0001;
Azael Avalos893f3f62014-09-29 20:40:09 -06001168 hci_result = hci_read2(dev, HCI_WIRELESS, &value, &value2);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001169
1170 *radio_state = value & HCI_WIRELESS_KILL_SWITCH;
1171 return hci_result;
1172}
1173
Johannes Berg19d337d2009-06-02 13:01:37 +02001174static int bt_rfkill_set_block(void *data, bool blocked)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001175{
Johannes Berg19d337d2009-06-02 13:01:37 +02001176 struct toshiba_acpi_dev *dev = data;
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001177 u32 result1, result2;
1178 u32 value;
Johannes Berg19d337d2009-06-02 13:01:37 +02001179 int err;
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001180 bool radio_state;
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001181
Johannes Berg19d337d2009-06-02 13:01:37 +02001182 value = (blocked == false);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001183
1184 mutex_lock(&dev->mutex);
Azael Avalos1864bbc2014-09-29 20:40:08 -06001185 if (hci_get_radio_state(dev, &radio_state) != TOS_SUCCESS) {
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001186 err = -EIO;
Johannes Berg19d337d2009-06-02 13:01:37 +02001187 goto out;
1188 }
1189
1190 if (!radio_state) {
1191 err = 0;
1192 goto out;
1193 }
1194
Azael Avalos893f3f62014-09-29 20:40:09 -06001195 result1 = hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER);
1196 result2 = hci_write2(dev, HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001197
Azael Avalos1864bbc2014-09-29 20:40:08 -06001198 if (result1 != TOS_SUCCESS || result2 != TOS_SUCCESS)
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001199 err = -EIO;
Johannes Berg19d337d2009-06-02 13:01:37 +02001200 else
1201 err = 0;
1202 out:
1203 mutex_unlock(&dev->mutex);
1204 return err;
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001205}
1206
Johannes Berg19d337d2009-06-02 13:01:37 +02001207static void bt_rfkill_poll(struct rfkill *rfkill, void *data)
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001208{
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001209 bool new_rfk_state;
1210 bool value;
1211 u32 hci_result;
Johannes Berg19d337d2009-06-02 13:01:37 +02001212 struct toshiba_acpi_dev *dev = data;
1213
1214 mutex_lock(&dev->mutex);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001215
Seth Forshee135740d2011-09-20 16:55:49 -05001216 hci_result = hci_get_radio_state(dev, &value);
Azael Avalos1864bbc2014-09-29 20:40:08 -06001217 if (hci_result != TOS_SUCCESS) {
Johannes Berg19d337d2009-06-02 13:01:37 +02001218 /* Can't do anything useful */
1219 mutex_unlock(&dev->mutex);
Jiri Slaby82e77842009-08-06 15:57:51 -07001220 return;
Johannes Berg19d337d2009-06-02 13:01:37 +02001221 }
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001222
1223 new_rfk_state = value;
1224
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001225 mutex_unlock(&dev->mutex);
1226
Johannes Berg19d337d2009-06-02 13:01:37 +02001227 if (rfkill_set_hw_state(rfkill, !new_rfk_state))
1228 bt_rfkill_set_block(data, true);
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04001229}
1230
Johannes Berg19d337d2009-06-02 13:01:37 +02001231static const struct rfkill_ops toshiba_rfk_ops = {
1232 .set_block = bt_rfkill_set_block,
1233 .poll = bt_rfkill_poll,
1234};
1235
Akio Idehara121b7b02012-04-06 01:46:43 +09001236static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled)
1237{
1238 u32 hci_result;
1239 u32 status;
1240
Azael Avalos893f3f62014-09-29 20:40:09 -06001241 hci_result = hci_read1(dev, HCI_TR_BACKLIGHT, &status);
Akio Idehara121b7b02012-04-06 01:46:43 +09001242 *enabled = !status;
Azael Avalos1864bbc2014-09-29 20:40:08 -06001243 return hci_result == TOS_SUCCESS ? 0 : -EIO;
Akio Idehara121b7b02012-04-06 01:46:43 +09001244}
1245
1246static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable)
1247{
1248 u32 hci_result;
1249 u32 value = !enable;
1250
Azael Avalos893f3f62014-09-29 20:40:09 -06001251 hci_result = hci_write1(dev, HCI_TR_BACKLIGHT, value);
Azael Avalos1864bbc2014-09-29 20:40:08 -06001252 return hci_result == TOS_SUCCESS ? 0 : -EIO;
Akio Idehara121b7b02012-04-06 01:46:43 +09001253}
1254
Len Brown4be44fc2005-08-05 00:44:28 -04001255static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256
Seth Forshee62cce752012-04-19 11:23:50 -05001257static int __get_lcd_brightness(struct toshiba_acpi_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258{
1259 u32 hci_result;
1260 u32 value;
Akio Idehara121b7b02012-04-06 01:46:43 +09001261 int brightness = 0;
1262
1263 if (dev->tr_backlight_supported) {
1264 bool enabled;
1265 int ret = get_tr_backlight_status(dev, &enabled);
1266 if (ret)
1267 return ret;
1268 if (enabled)
1269 return 0;
1270 brightness++;
1271 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272
Azael Avalos893f3f62014-09-29 20:40:09 -06001273 hci_result = hci_read1(dev, HCI_LCD_BRIGHTNESS, &value);
Azael Avalos1864bbc2014-09-29 20:40:08 -06001274 if (hci_result == TOS_SUCCESS)
Akio Idehara121b7b02012-04-06 01:46:43 +09001275 return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT);
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001276
1277 return -EIO;
Holger Machtc9263552006-10-20 14:30:29 -07001278}
1279
Seth Forshee62cce752012-04-19 11:23:50 -05001280static int get_lcd_brightness(struct backlight_device *bd)
1281{
1282 struct toshiba_acpi_dev *dev = bl_get_data(bd);
1283 return __get_lcd_brightness(dev);
1284}
1285
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001286static int lcd_proc_show(struct seq_file *m, void *v)
Holger Machtc9263552006-10-20 14:30:29 -07001287{
Seth Forshee135740d2011-09-20 16:55:49 -05001288 struct toshiba_acpi_dev *dev = m->private;
1289 int value;
Akio Idehara121b7b02012-04-06 01:46:43 +09001290 int levels;
Holger Machtc9263552006-10-20 14:30:29 -07001291
Seth Forshee135740d2011-09-20 16:55:49 -05001292 if (!dev->backlight_dev)
1293 return -ENODEV;
1294
Akio Idehara121b7b02012-04-06 01:46:43 +09001295 levels = dev->backlight_dev->props.max_brightness + 1;
Seth Forshee62cce752012-04-19 11:23:50 -05001296 value = get_lcd_brightness(dev->backlight_dev);
Holger Machtc9263552006-10-20 14:30:29 -07001297 if (value >= 0) {
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001298 seq_printf(m, "brightness: %d\n", value);
Akio Idehara121b7b02012-04-06 01:46:43 +09001299 seq_printf(m, "brightness_levels: %d\n", levels);
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001300 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 }
1302
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001303 pr_err("Error reading LCD brightness\n");
1304 return -EIO;
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001305}
1306
1307static int lcd_proc_open(struct inode *inode, struct file *file)
1308{
Al Virod9dda782013-03-31 18:16:14 -04001309 return single_open(file, lcd_proc_show, PDE_DATA(inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310}
1311
Seth Forshee62cce752012-04-19 11:23:50 -05001312static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
Holger Machtc9263552006-10-20 14:30:29 -07001313{
Azael Avalosa39f46d2014-11-24 19:29:36 -07001314 u32 hci_result;
Holger Machtc9263552006-10-20 14:30:29 -07001315
Akio Idehara121b7b02012-04-06 01:46:43 +09001316 if (dev->tr_backlight_supported) {
1317 bool enable = !value;
1318 int ret = set_tr_backlight_status(dev, enable);
1319 if (ret)
1320 return ret;
1321 if (value)
1322 value--;
1323 }
1324
Azael Avalosa39f46d2014-11-24 19:29:36 -07001325 value = value << HCI_LCD_BRIGHTNESS_SHIFT;
1326 hci_result = hci_write1(dev, HCI_LCD_BRIGHTNESS, value);
1327 return hci_result == TOS_SUCCESS ? 0 : -EIO;
Holger Machtc9263552006-10-20 14:30:29 -07001328}
1329
1330static int set_lcd_status(struct backlight_device *bd)
1331{
Seth Forshee135740d2011-09-20 16:55:49 -05001332 struct toshiba_acpi_dev *dev = bl_get_data(bd);
Seth Forshee62cce752012-04-19 11:23:50 -05001333 return set_lcd_brightness(dev, bd->props.brightness);
Holger Machtc9263552006-10-20 14:30:29 -07001334}
1335
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001336static ssize_t lcd_proc_write(struct file *file, const char __user *buf,
1337 size_t count, loff_t *pos)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338{
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;
Matthijs van Otterdijkc8af57e2007-01-05 16:37:03 -08001343 int ret;
Akio Idehara121b7b02012-04-06 01:46:43 +09001344 int levels = dev->backlight_dev->props.max_brightness + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001346 len = min(count, sizeof(cmd) - 1);
1347 if (copy_from_user(cmd, buf, len))
1348 return -EFAULT;
1349 cmd[len] = '\0';
1350
1351 if (sscanf(cmd, " brightness : %i", &value) == 1 &&
Akio Idehara121b7b02012-04-06 01:46:43 +09001352 value >= 0 && value < levels) {
Seth Forshee62cce752012-04-19 11:23:50 -05001353 ret = set_lcd_brightness(dev, value);
Matthijs van Otterdijkc8af57e2007-01-05 16:37:03 -08001354 if (ret == 0)
1355 ret = count;
1356 } else {
Holger Machtc9263552006-10-20 14:30:29 -07001357 ret = -EINVAL;
Matthijs van Otterdijkc8af57e2007-01-05 16:37:03 -08001358 }
Holger Machtc9263552006-10-20 14:30:29 -07001359 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360}
1361
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001362static const struct file_operations lcd_proc_fops = {
1363 .owner = THIS_MODULE,
1364 .open = lcd_proc_open,
1365 .read = seq_read,
1366 .llseek = seq_lseek,
1367 .release = single_release,
1368 .write = lcd_proc_write,
1369};
1370
Seth Forshee36d03f92011-09-20 16:55:53 -05001371static int get_video_status(struct toshiba_acpi_dev *dev, u32 *status)
1372{
1373 u32 hci_result;
1374
Azael Avalos893f3f62014-09-29 20:40:09 -06001375 hci_result = hci_read1(dev, HCI_VIDEO_OUT, status);
Azael Avalos1864bbc2014-09-29 20:40:08 -06001376 return hci_result == TOS_SUCCESS ? 0 : -EIO;
Seth Forshee36d03f92011-09-20 16:55:53 -05001377}
1378
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001379static int video_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380{
Seth Forshee135740d2011-09-20 16:55:49 -05001381 struct toshiba_acpi_dev *dev = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 u32 value;
Seth Forshee36d03f92011-09-20 16:55:53 -05001383 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384
Seth Forshee36d03f92011-09-20 16:55:53 -05001385 ret = get_video_status(dev, &value);
1386 if (!ret) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0;
1388 int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0;
Len Brown4be44fc2005-08-05 00:44:28 -04001389 int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0;
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001390 seq_printf(m, "lcd_out: %d\n", is_lcd);
1391 seq_printf(m, "crt_out: %d\n", is_crt);
1392 seq_printf(m, "tv_out: %d\n", is_tv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 }
1394
Seth Forshee36d03f92011-09-20 16:55:53 -05001395 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396}
1397
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001398static int video_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399{
Al Virod9dda782013-03-31 18:16:14 -04001400 return single_open(file, video_proc_show, PDE_DATA(inode));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001401}
1402
1403static ssize_t video_proc_write(struct file *file, const char __user *buf,
1404 size_t count, loff_t *pos)
1405{
Al Virod9dda782013-03-31 18:16:14 -04001406 struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001407 char *cmd, *buffer;
Seth Forshee36d03f92011-09-20 16:55:53 -05001408 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 int value;
1410 int remain = count;
1411 int lcd_out = -1;
1412 int crt_out = -1;
1413 int tv_out = -1;
Al Virob4482a42007-10-14 19:35:40 +01001414 u32 video_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001416 cmd = kmalloc(count + 1, GFP_KERNEL);
1417 if (!cmd)
1418 return -ENOMEM;
1419 if (copy_from_user(cmd, buf, count)) {
1420 kfree(cmd);
1421 return -EFAULT;
1422 }
1423 cmd[count] = '\0';
1424
1425 buffer = cmd;
1426
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 /* scan expression. Multiple expressions may be delimited with ;
1428 *
1429 * NOTE: to keep scanning simple, invalid fields are ignored
1430 */
1431 while (remain) {
1432 if (sscanf(buffer, " lcd_out : %i", &value) == 1)
1433 lcd_out = value & 1;
1434 else if (sscanf(buffer, " crt_out : %i", &value) == 1)
1435 crt_out = value & 1;
1436 else if (sscanf(buffer, " tv_out : %i", &value) == 1)
1437 tv_out = value & 1;
1438 /* advance to one character past the next ; */
1439 do {
1440 ++buffer;
1441 --remain;
1442 }
Len Brown4be44fc2005-08-05 00:44:28 -04001443 while (remain && *(buffer - 1) != ';');
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 }
1445
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001446 kfree(cmd);
1447
Seth Forshee36d03f92011-09-20 16:55:53 -05001448 ret = get_video_status(dev, &video_out);
1449 if (!ret) {
Harvey Harrison9e113e02008-09-22 14:37:29 -07001450 unsigned int new_video_out = video_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 if (lcd_out != -1)
1452 _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out);
1453 if (crt_out != -1)
1454 _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out);
1455 if (tv_out != -1)
1456 _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out);
1457 /* To avoid unnecessary video disruption, only write the new
1458 * video setting if something changed. */
1459 if (new_video_out != video_out)
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001460 ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 }
1462
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001463 return ret ? ret : count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464}
1465
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001466static const struct file_operations video_proc_fops = {
1467 .owner = THIS_MODULE,
1468 .open = video_proc_open,
1469 .read = seq_read,
1470 .llseek = seq_lseek,
1471 .release = single_release,
1472 .write = video_proc_write,
1473};
1474
Seth Forshee36d03f92011-09-20 16:55:53 -05001475static int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status)
1476{
1477 u32 hci_result;
1478
Azael Avalos893f3f62014-09-29 20:40:09 -06001479 hci_result = hci_read1(dev, HCI_FAN, status);
Azael Avalos1864bbc2014-09-29 20:40:08 -06001480 return hci_result == TOS_SUCCESS ? 0 : -EIO;
Seth Forshee36d03f92011-09-20 16:55:53 -05001481}
1482
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001483static int fan_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484{
Seth Forshee135740d2011-09-20 16:55:49 -05001485 struct toshiba_acpi_dev *dev = m->private;
Seth Forshee36d03f92011-09-20 16:55:53 -05001486 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 u32 value;
1488
Seth Forshee36d03f92011-09-20 16:55:53 -05001489 ret = get_fan_status(dev, &value);
1490 if (!ret) {
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001491 seq_printf(m, "running: %d\n", (value > 0));
Seth Forshee135740d2011-09-20 16:55:49 -05001492 seq_printf(m, "force_on: %d\n", dev->force_fan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 }
1494
Seth Forshee36d03f92011-09-20 16:55:53 -05001495 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496}
1497
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001498static int fan_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001499{
Al Virod9dda782013-03-31 18:16:14 -04001500 return single_open(file, fan_proc_show, PDE_DATA(inode));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001501}
1502
1503static ssize_t fan_proc_write(struct file *file, const char __user *buf,
1504 size_t count, loff_t *pos)
1505{
Al Virod9dda782013-03-31 18:16:14 -04001506 struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001507 char cmd[42];
1508 size_t len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 int value;
1510 u32 hci_result;
1511
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001512 len = min(count, sizeof(cmd) - 1);
1513 if (copy_from_user(cmd, buf, len))
1514 return -EFAULT;
1515 cmd[len] = '\0';
1516
1517 if (sscanf(cmd, " force_on : %i", &value) == 1 &&
Len Brown4be44fc2005-08-05 00:44:28 -04001518 value >= 0 && value <= 1) {
Azael Avalos893f3f62014-09-29 20:40:09 -06001519 hci_result = hci_write1(dev, HCI_FAN, value);
Azael Avalos1864bbc2014-09-29 20:40:08 -06001520 if (hci_result != TOS_SUCCESS)
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001521 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 else
Seth Forshee135740d2011-09-20 16:55:49 -05001523 dev->force_fan = value;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 } else {
1525 return -EINVAL;
1526 }
1527
1528 return count;
1529}
1530
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001531static const struct file_operations fan_proc_fops = {
1532 .owner = THIS_MODULE,
1533 .open = fan_proc_open,
1534 .read = seq_read,
1535 .llseek = seq_lseek,
1536 .release = single_release,
1537 .write = fan_proc_write,
1538};
1539
1540static int keys_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541{
Seth Forshee135740d2011-09-20 16:55:49 -05001542 struct toshiba_acpi_dev *dev = m->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 u32 hci_result;
1544 u32 value;
1545
Seth Forshee11948b92011-11-16 17:37:45 -06001546 if (!dev->key_event_valid && dev->system_event_supported) {
Azael Avalos893f3f62014-09-29 20:40:09 -06001547 hci_result = hci_read1(dev, HCI_SYSTEM_EVENT, &value);
Azael Avalos1864bbc2014-09-29 20:40:08 -06001548 if (hci_result == TOS_SUCCESS) {
Seth Forshee135740d2011-09-20 16:55:49 -05001549 dev->key_event_valid = 1;
1550 dev->last_key_event = value;
Azael Avalos1864bbc2014-09-29 20:40:08 -06001551 } else if (hci_result == TOS_FIFO_EMPTY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 /* better luck next time */
Azael Avalos1864bbc2014-09-29 20:40:08 -06001553 } else if (hci_result == TOS_NOT_SUPPORTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 /* This is a workaround for an unresolved issue on
1555 * some machines where system events sporadically
1556 * become disabled. */
Azael Avalos893f3f62014-09-29 20:40:09 -06001557 hci_result = hci_write1(dev, HCI_SYSTEM_EVENT, 1);
Joe Perches7e334602011-03-29 15:21:52 -07001558 pr_notice("Re-enabled hotkeys\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 } else {
Joe Perches7e334602011-03-29 15:21:52 -07001560 pr_err("Error reading hotkey status\n");
Seth Forshee32bcd5c2011-09-20 16:55:50 -05001561 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 }
1563 }
1564
Seth Forshee135740d2011-09-20 16:55:49 -05001565 seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid);
1566 seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event);
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001567 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568}
1569
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001570static int keys_proc_open(struct inode *inode, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571{
Al Virod9dda782013-03-31 18:16:14 -04001572 return single_open(file, keys_proc_show, PDE_DATA(inode));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001573}
1574
1575static ssize_t keys_proc_write(struct file *file, const char __user *buf,
1576 size_t count, loff_t *pos)
1577{
Al Virod9dda782013-03-31 18:16:14 -04001578 struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001579 char cmd[42];
1580 size_t len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 int value;
1582
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001583 len = min(count, sizeof(cmd) - 1);
1584 if (copy_from_user(cmd, buf, len))
1585 return -EFAULT;
1586 cmd[len] = '\0';
1587
1588 if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) {
Seth Forshee135740d2011-09-20 16:55:49 -05001589 dev->key_event_valid = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 } else {
1591 return -EINVAL;
1592 }
1593
1594 return count;
1595}
1596
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001597static const struct file_operations keys_proc_fops = {
1598 .owner = THIS_MODULE,
1599 .open = keys_proc_open,
1600 .read = seq_read,
1601 .llseek = seq_lseek,
1602 .release = single_release,
1603 .write = keys_proc_write,
1604};
1605
1606static int version_proc_show(struct seq_file *m, void *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607{
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001608 seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION);
1609 seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION);
1610 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611}
1612
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001613static int version_proc_open(struct inode *inode, struct file *file)
1614{
Al Virod9dda782013-03-31 18:16:14 -04001615 return single_open(file, version_proc_show, PDE_DATA(inode));
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001616}
1617
1618static const struct file_operations version_proc_fops = {
1619 .owner = THIS_MODULE,
1620 .open = version_proc_open,
1621 .read = seq_read,
1622 .llseek = seq_lseek,
1623 .release = single_release,
1624};
1625
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626/* proc and module init
1627 */
1628
1629#define PROC_TOSHIBA "toshiba"
1630
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08001631static void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632{
Seth Forshee36d03f92011-09-20 16:55:53 -05001633 if (dev->backlight_dev)
1634 proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1635 &lcd_proc_fops, dev);
1636 if (dev->video_supported)
1637 proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1638 &video_proc_fops, dev);
1639 if (dev->fan_supported)
1640 proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1641 &fan_proc_fops, dev);
1642 if (dev->hotkey_dev)
1643 proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir,
1644 &keys_proc_fops, dev);
Seth Forshee135740d2011-09-20 16:55:49 -05001645 proc_create_data("version", S_IRUGO, toshiba_proc_dir,
1646 &version_proc_fops, dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647}
1648
Seth Forshee36d03f92011-09-20 16:55:53 -05001649static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650{
Seth Forshee36d03f92011-09-20 16:55:53 -05001651 if (dev->backlight_dev)
1652 remove_proc_entry("lcd", toshiba_proc_dir);
1653 if (dev->video_supported)
1654 remove_proc_entry("video", toshiba_proc_dir);
1655 if (dev->fan_supported)
1656 remove_proc_entry("fan", toshiba_proc_dir);
1657 if (dev->hotkey_dev)
1658 remove_proc_entry("keys", toshiba_proc_dir);
Alexey Dobriyan936c8bc2009-12-21 16:20:02 -08001659 remove_proc_entry("version", toshiba_proc_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660}
1661
Lionel Debrouxacc24722010-11-16 14:14:02 +01001662static const struct backlight_ops toshiba_backlight_data = {
Akio Idehara121b7b02012-04-06 01:46:43 +09001663 .options = BL_CORE_SUSPENDRESUME,
Seth Forshee62cce752012-04-19 11:23:50 -05001664 .get_brightness = get_lcd_brightness,
1665 .update_status = set_lcd_status,
Holger Machtc9263552006-10-20 14:30:29 -07001666};
Matthew Garrettea6b31f2014-04-04 14:22:34 -04001667
Azael Avalos360f0f32014-03-25 20:38:31 -06001668/*
1669 * Sysfs files
1670 */
Azael Avalosc6c68ff2015-02-10 21:09:16 -07001671static ssize_t toshiba_version_show(struct device *dev,
1672 struct device_attribute *attr, char *buf);
Azael Avalos94477d42015-02-10 21:09:17 -07001673static ssize_t toshiba_fan_store(struct device *dev,
1674 struct device_attribute *attr,
1675 const char *buf, size_t count);
1676static ssize_t toshiba_fan_show(struct device *dev,
1677 struct device_attribute *attr, char *buf);
Azael Avalos93f8c162014-09-12 18:50:36 -06001678static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
1679 struct device_attribute *attr,
1680 const char *buf, size_t count);
1681static ssize_t toshiba_kbd_bl_mode_show(struct device *dev,
1682 struct device_attribute *attr,
1683 char *buf);
1684static ssize_t toshiba_kbd_type_show(struct device *dev,
1685 struct device_attribute *attr,
1686 char *buf);
1687static ssize_t toshiba_available_kbd_modes_show(struct device *dev,
1688 struct device_attribute *attr,
1689 char *buf);
1690static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev,
1691 struct device_attribute *attr,
1692 const char *buf, size_t count);
1693static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev,
1694 struct device_attribute *attr,
1695 char *buf);
1696static ssize_t toshiba_touchpad_store(struct device *dev,
1697 struct device_attribute *attr,
1698 const char *buf, size_t count);
1699static ssize_t toshiba_touchpad_show(struct device *dev,
1700 struct device_attribute *attr,
1701 char *buf);
1702static ssize_t toshiba_position_show(struct device *dev,
1703 struct device_attribute *attr,
1704 char *buf);
Azael Avalose26ffe52015-01-18 18:30:22 -07001705static ssize_t toshiba_usb_sleep_charge_show(struct device *dev,
1706 struct device_attribute *attr,
1707 char *buf);
1708static ssize_t toshiba_usb_sleep_charge_store(struct device *dev,
1709 struct device_attribute *attr,
1710 const char *buf, size_t count);
Azael Avalos182bcaa2015-01-18 18:30:23 -07001711static ssize_t sleep_functions_on_battery_show(struct device *dev,
1712 struct device_attribute *attr,
1713 char *buf);
1714static ssize_t sleep_functions_on_battery_store(struct device *dev,
1715 struct device_attribute *attr,
1716 const char *buf, size_t count);
Azael Avalosbb3fe012015-01-18 18:30:24 -07001717static ssize_t toshiba_usb_rapid_charge_show(struct device *dev,
1718 struct device_attribute *attr,
1719 char *buf);
1720static ssize_t toshiba_usb_rapid_charge_store(struct device *dev,
1721 struct device_attribute *attr,
1722 const char *buf, size_t count);
Azael Avalos172ce0a2015-01-18 18:30:25 -07001723static ssize_t toshiba_usb_sleep_music_show(struct device *dev,
1724 struct device_attribute *attr,
1725 char *buf);
1726static ssize_t toshiba_usb_sleep_music_store(struct device *dev,
1727 struct device_attribute *attr,
1728 const char *buf, size_t count);
Azael Avalosbae84192015-02-10 21:09:18 -07001729static ssize_t toshiba_kbd_function_keys_show(struct device *dev,
1730 struct device_attribute *attr,
1731 char *buf);
1732static ssize_t toshiba_kbd_function_keys_store(struct device *dev,
1733 struct device_attribute *attr,
1734 const char *buf, size_t count);
Azael Avalos35d53ce2015-02-10 21:09:19 -07001735static ssize_t toshiba_panel_power_on_show(struct device *dev,
1736 struct device_attribute *attr,
1737 char *buf);
1738static ssize_t toshiba_panel_power_on_store(struct device *dev,
1739 struct device_attribute *attr,
1740 const char *buf, size_t count);
Azael Avalos17fe4b32015-02-10 21:09:20 -07001741static ssize_t toshiba_usb_three_show(struct device *dev,
1742 struct device_attribute *attr,
1743 char *buf);
1744static ssize_t toshiba_usb_three_store(struct device *dev,
1745 struct device_attribute *attr,
1746 const char *buf, size_t count);
Azael Avalos93f8c162014-09-12 18:50:36 -06001747
Azael Avalosc6c68ff2015-02-10 21:09:16 -07001748static DEVICE_ATTR(version, S_IRUGO, toshiba_version_show, NULL);
Azael Avalos94477d42015-02-10 21:09:17 -07001749static DEVICE_ATTR(fan, S_IRUGO | S_IWUSR,
1750 toshiba_fan_show, toshiba_fan_store);
Azael Avalos93f8c162014-09-12 18:50:36 -06001751static DEVICE_ATTR(kbd_backlight_mode, S_IRUGO | S_IWUSR,
1752 toshiba_kbd_bl_mode_show, toshiba_kbd_bl_mode_store);
1753static DEVICE_ATTR(kbd_type, S_IRUGO, toshiba_kbd_type_show, NULL);
1754static DEVICE_ATTR(available_kbd_modes, S_IRUGO,
1755 toshiba_available_kbd_modes_show, NULL);
1756static DEVICE_ATTR(kbd_backlight_timeout, S_IRUGO | S_IWUSR,
1757 toshiba_kbd_bl_timeout_show, toshiba_kbd_bl_timeout_store);
1758static DEVICE_ATTR(touchpad, S_IRUGO | S_IWUSR,
1759 toshiba_touchpad_show, toshiba_touchpad_store);
1760static DEVICE_ATTR(position, S_IRUGO, toshiba_position_show, NULL);
Azael Avalose26ffe52015-01-18 18:30:22 -07001761static DEVICE_ATTR(usb_sleep_charge, S_IRUGO | S_IWUSR,
1762 toshiba_usb_sleep_charge_show,
1763 toshiba_usb_sleep_charge_store);
Azael Avalos182bcaa2015-01-18 18:30:23 -07001764static DEVICE_ATTR(sleep_functions_on_battery, S_IRUGO | S_IWUSR,
1765 sleep_functions_on_battery_show,
1766 sleep_functions_on_battery_store);
Azael Avalosbb3fe012015-01-18 18:30:24 -07001767static DEVICE_ATTR(usb_rapid_charge, S_IRUGO | S_IWUSR,
1768 toshiba_usb_rapid_charge_show,
1769 toshiba_usb_rapid_charge_store);
Azael Avalos172ce0a2015-01-18 18:30:25 -07001770static DEVICE_ATTR(usb_sleep_music, S_IRUGO | S_IWUSR,
1771 toshiba_usb_sleep_music_show,
1772 toshiba_usb_sleep_music_store);
Azael Avalosbae84192015-02-10 21:09:18 -07001773static DEVICE_ATTR(kbd_function_keys, S_IRUGO | S_IWUSR,
1774 toshiba_kbd_function_keys_show,
1775 toshiba_kbd_function_keys_store);
Azael Avalos35d53ce2015-02-10 21:09:19 -07001776static DEVICE_ATTR(panel_power_on, S_IRUGO | S_IWUSR,
1777 toshiba_panel_power_on_show,
1778 toshiba_panel_power_on_store);
Azael Avalos17fe4b32015-02-10 21:09:20 -07001779static DEVICE_ATTR(usb_three, S_IRUGO | S_IWUSR,
1780 toshiba_usb_three_show, toshiba_usb_three_store);
Azael Avalos93f8c162014-09-12 18:50:36 -06001781
1782static struct attribute *toshiba_attributes[] = {
Azael Avalosc6c68ff2015-02-10 21:09:16 -07001783 &dev_attr_version.attr,
Azael Avalos94477d42015-02-10 21:09:17 -07001784 &dev_attr_fan.attr,
Azael Avalos93f8c162014-09-12 18:50:36 -06001785 &dev_attr_kbd_backlight_mode.attr,
1786 &dev_attr_kbd_type.attr,
1787 &dev_attr_available_kbd_modes.attr,
1788 &dev_attr_kbd_backlight_timeout.attr,
1789 &dev_attr_touchpad.attr,
1790 &dev_attr_position.attr,
Azael Avalose26ffe52015-01-18 18:30:22 -07001791 &dev_attr_usb_sleep_charge.attr,
Azael Avalos182bcaa2015-01-18 18:30:23 -07001792 &dev_attr_sleep_functions_on_battery.attr,
Azael Avalosbb3fe012015-01-18 18:30:24 -07001793 &dev_attr_usb_rapid_charge.attr,
Azael Avalos172ce0a2015-01-18 18:30:25 -07001794 &dev_attr_usb_sleep_music.attr,
Azael Avalosbae84192015-02-10 21:09:18 -07001795 &dev_attr_kbd_function_keys.attr,
Azael Avalos35d53ce2015-02-10 21:09:19 -07001796 &dev_attr_panel_power_on.attr,
Azael Avalos17fe4b32015-02-10 21:09:20 -07001797 &dev_attr_usb_three.attr,
Azael Avalos93f8c162014-09-12 18:50:36 -06001798 NULL,
1799};
1800
1801static umode_t toshiba_sysfs_is_visible(struct kobject *,
1802 struct attribute *, int);
1803
1804static struct attribute_group toshiba_attr_group = {
1805 .is_visible = toshiba_sysfs_is_visible,
1806 .attrs = toshiba_attributes,
1807};
Azael Avalos360f0f32014-03-25 20:38:31 -06001808
Azael Avalosc6c68ff2015-02-10 21:09:16 -07001809static ssize_t toshiba_version_show(struct device *dev,
1810 struct device_attribute *attr, char *buf)
1811{
1812 return sprintf(buf, "%s\n", TOSHIBA_ACPI_VERSION);
1813}
1814
Azael Avalos94477d42015-02-10 21:09:17 -07001815static ssize_t toshiba_fan_store(struct device *dev,
1816 struct device_attribute *attr,
1817 const char *buf, size_t count)
1818{
1819 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1820 u32 result;
1821 int state;
1822 int ret;
1823
1824 ret = kstrtoint(buf, 0, &state);
1825 if (ret)
1826 return ret;
1827
1828 if (state != 0 && state != 1)
1829 return -EINVAL;
1830
1831 result = hci_write1(toshiba, HCI_FAN, state);
1832 if (result == TOS_FAILURE)
1833 return -EIO;
1834 else if (result == TOS_NOT_SUPPORTED)
1835 return -ENODEV;
1836
1837 return count;
1838}
1839
1840static ssize_t toshiba_fan_show(struct device *dev,
1841 struct device_attribute *attr, char *buf)
1842{
1843 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1844 u32 value;
1845 int ret;
1846
1847 ret = get_fan_status(toshiba, &value);
1848 if (ret)
1849 return ret;
1850
1851 return sprintf(buf, "%d\n", value);
1852}
1853
Azael Avalos360f0f32014-03-25 20:38:31 -06001854static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
1855 struct device_attribute *attr,
1856 const char *buf, size_t count)
1857{
1858 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
Dan Carpenteraeaac092014-09-03 14:44:37 +03001859 int mode;
1860 int time;
1861 int ret;
Azael Avalos360f0f32014-03-25 20:38:31 -06001862
Dan Carpenteraeaac092014-09-03 14:44:37 +03001863
1864 ret = kstrtoint(buf, 0, &mode);
1865 if (ret)
1866 return ret;
Azael Avalos93f8c162014-09-12 18:50:36 -06001867
1868 /* Check for supported modes depending on keyboard backlight type */
1869 if (toshiba->kbd_type == 1) {
1870 /* Type 1 supports SCI_KBD_MODE_FNZ and SCI_KBD_MODE_AUTO */
1871 if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO)
1872 return -EINVAL;
1873 } else if (toshiba->kbd_type == 2) {
1874 /* Type 2 doesn't support SCI_KBD_MODE_FNZ */
1875 if (mode != SCI_KBD_MODE_AUTO && mode != SCI_KBD_MODE_ON &&
1876 mode != SCI_KBD_MODE_OFF)
1877 return -EINVAL;
1878 }
Azael Avalos360f0f32014-03-25 20:38:31 -06001879
1880 /* Set the Keyboard Backlight Mode where:
Azael Avalos360f0f32014-03-25 20:38:31 -06001881 * Auto - KBD backlight turns off automatically in given time
1882 * FN-Z - KBD backlight "toggles" when hotkey pressed
Azael Avalos93f8c162014-09-12 18:50:36 -06001883 * ON - KBD backlight is always on
1884 * OFF - KBD backlight is always off
Azael Avalos360f0f32014-03-25 20:38:31 -06001885 */
Azael Avalos93f8c162014-09-12 18:50:36 -06001886
1887 /* Only make a change if the actual mode has changed */
Dan Carpenteraeaac092014-09-03 14:44:37 +03001888 if (toshiba->kbd_mode != mode) {
Azael Avalos93f8c162014-09-12 18:50:36 -06001889 /* Shift the time to "base time" (0x3c0000 == 60 seconds) */
Azael Avalos360f0f32014-03-25 20:38:31 -06001890 time = toshiba->kbd_time << HCI_MISC_SHIFT;
Azael Avalos93f8c162014-09-12 18:50:36 -06001891
1892 /* OR the "base time" to the actual method format */
1893 if (toshiba->kbd_type == 1) {
1894 /* Type 1 requires the current mode */
1895 time |= toshiba->kbd_mode;
1896 } else if (toshiba->kbd_type == 2) {
1897 /* Type 2 requires the desired mode */
1898 time |= mode;
1899 }
1900
Dan Carpenteraeaac092014-09-03 14:44:37 +03001901 ret = toshiba_kbd_illum_status_set(toshiba, time);
1902 if (ret)
1903 return ret;
Azael Avalos93f8c162014-09-12 18:50:36 -06001904
Azael Avalos360f0f32014-03-25 20:38:31 -06001905 toshiba->kbd_mode = mode;
1906 }
1907
1908 return count;
1909}
1910
1911static ssize_t toshiba_kbd_bl_mode_show(struct device *dev,
1912 struct device_attribute *attr,
1913 char *buf)
1914{
1915 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1916 u32 time;
1917
1918 if (toshiba_kbd_illum_status_get(toshiba, &time) < 0)
1919 return -EIO;
1920
Azael Avalos93f8c162014-09-12 18:50:36 -06001921 return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK);
1922}
1923
1924static ssize_t toshiba_kbd_type_show(struct device *dev,
1925 struct device_attribute *attr,
1926 char *buf)
1927{
1928 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1929
1930 return sprintf(buf, "%d\n", toshiba->kbd_type);
1931}
1932
1933static ssize_t toshiba_available_kbd_modes_show(struct device *dev,
1934 struct device_attribute *attr,
1935 char *buf)
1936{
1937 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1938
1939 if (toshiba->kbd_type == 1)
1940 return sprintf(buf, "%x %x\n",
1941 SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO);
1942
1943 return sprintf(buf, "%x %x %x\n",
1944 SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF);
Azael Avalos360f0f32014-03-25 20:38:31 -06001945}
1946
1947static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev,
1948 struct device_attribute *attr,
1949 const char *buf, size_t count)
1950{
1951 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
Azael Avaloseabde0f2014-10-04 12:02:21 -06001952 int time;
1953 int ret;
Azael Avalos360f0f32014-03-25 20:38:31 -06001954
Azael Avaloseabde0f2014-10-04 12:02:21 -06001955 ret = kstrtoint(buf, 0, &time);
1956 if (ret)
1957 return ret;
Azael Avalos360f0f32014-03-25 20:38:31 -06001958
Azael Avaloseabde0f2014-10-04 12:02:21 -06001959 /* Check for supported values depending on kbd_type */
1960 if (toshiba->kbd_type == 1) {
1961 if (time < 0 || time > 60)
1962 return -EINVAL;
1963 } else if (toshiba->kbd_type == 2) {
1964 if (time < 1 || time > 60)
1965 return -EINVAL;
1966 }
1967
1968 /* Set the Keyboard Backlight Timeout */
1969
1970 /* Only make a change if the actual timeout has changed */
1971 if (toshiba->kbd_time != time) {
1972 /* Shift the time to "base time" (0x3c0000 == 60 seconds) */
Azael Avalos360f0f32014-03-25 20:38:31 -06001973 time = time << HCI_MISC_SHIFT;
Azael Avaloseabde0f2014-10-04 12:02:21 -06001974 /* OR the "base time" to the actual method format */
1975 if (toshiba->kbd_type == 1)
1976 time |= SCI_KBD_MODE_FNZ;
1977 else if (toshiba->kbd_type == 2)
1978 time |= SCI_KBD_MODE_AUTO;
1979
1980 ret = toshiba_kbd_illum_status_set(toshiba, time);
1981 if (ret)
1982 return ret;
1983
Azael Avalos360f0f32014-03-25 20:38:31 -06001984 toshiba->kbd_time = time >> HCI_MISC_SHIFT;
1985 }
1986
1987 return count;
1988}
1989
1990static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev,
1991 struct device_attribute *attr,
1992 char *buf)
1993{
1994 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
1995 u32 time;
1996
1997 if (toshiba_kbd_illum_status_get(toshiba, &time) < 0)
1998 return -EIO;
1999
2000 return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT);
2001}
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002002
Azael Avalos9d8658a2014-03-25 20:38:32 -06002003static ssize_t toshiba_touchpad_store(struct device *dev,
2004 struct device_attribute *attr,
2005 const char *buf, size_t count)
2006{
2007 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2008 int state;
Azael Avalosc8a41662014-09-10 21:01:57 -06002009 int ret;
Azael Avalos9d8658a2014-03-25 20:38:32 -06002010
2011 /* Set the TouchPad on/off, 0 - Disable | 1 - Enable */
Azael Avalosc8a41662014-09-10 21:01:57 -06002012 ret = kstrtoint(buf, 0, &state);
2013 if (ret)
2014 return ret;
2015 if (state != 0 && state != 1)
2016 return -EINVAL;
2017
2018 ret = toshiba_touchpad_set(toshiba, state);
2019 if (ret)
2020 return ret;
Azael Avalos9d8658a2014-03-25 20:38:32 -06002021
2022 return count;
2023}
2024
2025static ssize_t toshiba_touchpad_show(struct device *dev,
2026 struct device_attribute *attr, char *buf)
2027{
2028 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2029 u32 state;
2030 int ret;
2031
2032 ret = toshiba_touchpad_get(toshiba, &state);
2033 if (ret < 0)
2034 return ret;
2035
2036 return sprintf(buf, "%i\n", state);
2037}
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002038
Azael Avalos5a2813e2014-03-25 20:38:34 -06002039static ssize_t toshiba_position_show(struct device *dev,
2040 struct device_attribute *attr, char *buf)
2041{
2042 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2043 u32 xyval, zval, tmp;
2044 u16 x, y, z;
2045 int ret;
2046
2047 xyval = zval = 0;
2048 ret = toshiba_accelerometer_get(toshiba, &xyval, &zval);
2049 if (ret < 0)
2050 return ret;
2051
2052 x = xyval & HCI_ACCEL_MASK;
2053 tmp = xyval >> HCI_MISC_SHIFT;
2054 y = tmp & HCI_ACCEL_MASK;
2055 z = zval & HCI_ACCEL_MASK;
2056
2057 return sprintf(buf, "%d %d %d\n", x, y, z);
2058}
Azael Avalos360f0f32014-03-25 20:38:31 -06002059
Azael Avalose26ffe52015-01-18 18:30:22 -07002060static ssize_t toshiba_usb_sleep_charge_show(struct device *dev,
2061 struct device_attribute *attr,
2062 char *buf)
2063{
2064 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2065 u32 mode;
2066 int ret;
2067
2068 ret = toshiba_usb_sleep_charge_get(toshiba, &mode);
2069 if (ret < 0)
2070 return ret;
2071
2072 return sprintf(buf, "%x\n", mode & SCI_USB_CHARGE_MODE_MASK);
2073}
2074
2075static ssize_t toshiba_usb_sleep_charge_store(struct device *dev,
2076 struct device_attribute *attr,
2077 const char *buf, size_t count)
2078{
2079 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2080 u32 mode;
2081 int state;
2082 int ret;
2083
2084 ret = kstrtoint(buf, 0, &state);
2085 if (ret)
2086 return ret;
2087 /* Check for supported values, where:
2088 * 0 - Disabled
2089 * 1 - Alternate (Non USB conformant devices that require more power)
2090 * 2 - Auto (USB conformant devices)
2091 */
2092 if (state != 0 && state != 1 && state != 2)
2093 return -EINVAL;
2094
2095 /* Set the USB charging mode to internal value */
2096 if (state == 0)
2097 mode = SCI_USB_CHARGE_DISABLED;
2098 else if (state == 1)
2099 mode = SCI_USB_CHARGE_ALTERNATE;
2100 else if (state == 2)
2101 mode = SCI_USB_CHARGE_AUTO;
2102
2103 ret = toshiba_usb_sleep_charge_set(toshiba, mode);
2104 if (ret)
2105 return ret;
2106
2107 return count;
2108}
2109
Azael Avalos182bcaa2015-01-18 18:30:23 -07002110static ssize_t sleep_functions_on_battery_show(struct device *dev,
2111 struct device_attribute *attr,
2112 char *buf)
2113{
2114 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2115 u32 state;
2116 int bat_lvl;
2117 int status;
2118 int ret;
2119 int tmp;
2120
2121 ret = toshiba_sleep_functions_status_get(toshiba, &state);
2122 if (ret < 0)
2123 return ret;
2124
2125 /* Determine the status: 0x4 - Enabled | 0x1 - Disabled */
2126 tmp = state & SCI_USB_CHARGE_BAT_MASK;
2127 status = (tmp == 0x4) ? 1 : 0;
2128 /* Determine the battery level set */
2129 bat_lvl = state >> HCI_MISC_SHIFT;
2130
2131 return sprintf(buf, "%d %d\n", status, bat_lvl);
2132}
2133
2134static ssize_t sleep_functions_on_battery_store(struct device *dev,
2135 struct device_attribute *attr,
2136 const char *buf, size_t count)
2137{
2138 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2139 u32 status;
2140 int value;
2141 int ret;
2142 int tmp;
2143
2144 ret = kstrtoint(buf, 0, &value);
2145 if (ret)
2146 return ret;
2147
2148 /* Set the status of the function:
2149 * 0 - Disabled
2150 * 1-100 - Enabled
2151 */
2152 if (value < 0 || value > 100)
2153 return -EINVAL;
2154
2155 if (value == 0) {
2156 tmp = toshiba->usbsc_bat_level << HCI_MISC_SHIFT;
2157 status = tmp | SCI_USB_CHARGE_BAT_LVL_OFF;
2158 } else {
2159 tmp = value << HCI_MISC_SHIFT;
2160 status = tmp | SCI_USB_CHARGE_BAT_LVL_ON;
2161 }
2162 ret = toshiba_sleep_functions_status_set(toshiba, status);
2163 if (ret < 0)
2164 return ret;
2165
2166 toshiba->usbsc_bat_level = status >> HCI_MISC_SHIFT;
2167
2168 return count;
2169}
2170
Azael Avalosbb3fe012015-01-18 18:30:24 -07002171static ssize_t toshiba_usb_rapid_charge_show(struct device *dev,
2172 struct device_attribute *attr,
2173 char *buf)
2174{
2175 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2176 u32 state;
2177 int ret;
2178
2179 ret = toshiba_usb_rapid_charge_get(toshiba, &state);
2180 if (ret < 0)
2181 return ret;
2182
2183 return sprintf(buf, "%d\n", state);
2184}
2185
2186static ssize_t toshiba_usb_rapid_charge_store(struct device *dev,
2187 struct device_attribute *attr,
2188 const char *buf, size_t count)
2189{
2190 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2191 int state;
2192 int ret;
2193
2194 ret = kstrtoint(buf, 0, &state);
2195 if (ret)
2196 return ret;
2197 if (state != 0 && state != 1)
2198 return -EINVAL;
2199
2200 ret = toshiba_usb_rapid_charge_set(toshiba, state);
2201 if (ret)
2202 return ret;
2203
2204 return count;
2205}
2206
Azael Avalos172ce0a2015-01-18 18:30:25 -07002207static ssize_t toshiba_usb_sleep_music_show(struct device *dev,
2208 struct device_attribute *attr,
2209 char *buf)
2210{
2211 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2212 u32 state;
2213 int ret;
2214
2215 ret = toshiba_usb_sleep_music_get(toshiba, &state);
2216 if (ret < 0)
2217 return ret;
2218
2219 return sprintf(buf, "%d\n", state);
2220}
2221
2222static ssize_t toshiba_usb_sleep_music_store(struct device *dev,
2223 struct device_attribute *attr,
2224 const char *buf, size_t count)
2225{
2226 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2227 int state;
2228 int ret;
2229
2230 ret = kstrtoint(buf, 0, &state);
2231 if (ret)
2232 return ret;
2233 if (state != 0 && state != 1)
2234 return -EINVAL;
2235
2236 ret = toshiba_usb_sleep_music_set(toshiba, state);
2237 if (ret)
2238 return ret;
2239
2240 return count;
2241}
2242
Azael Avalosbae84192015-02-10 21:09:18 -07002243static ssize_t toshiba_kbd_function_keys_show(struct device *dev,
2244 struct device_attribute *attr,
2245 char *buf)
2246{
2247 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2248 int mode;
2249 int ret;
2250
2251 ret = toshiba_function_keys_get(toshiba, &mode);
2252 if (ret < 0)
2253 return ret;
2254
2255 return sprintf(buf, "%d\n", mode);
2256}
2257
2258static ssize_t toshiba_kbd_function_keys_store(struct device *dev,
2259 struct device_attribute *attr,
2260 const char *buf, size_t count)
2261{
2262 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2263 int mode;
2264 int ret;
2265
2266 ret = kstrtoint(buf, 0, &mode);
2267 if (ret)
2268 return ret;
2269 /* Check for the function keys mode where:
2270 * 0 - Normal operation (F{1-12} as usual and hotkeys via FN-F{1-12})
2271 * 1 - Special functions (Opposite of the above setting)
2272 */
2273 if (mode != 0 && mode != 1)
2274 return -EINVAL;
2275
2276 ret = toshiba_function_keys_set(toshiba, mode);
2277 if (ret)
2278 return ret;
2279
2280 pr_info("Reboot for changes to KBD Function Keys to take effect");
2281
2282 return count;
2283}
2284
Azael Avalos35d53ce2015-02-10 21:09:19 -07002285static ssize_t toshiba_panel_power_on_show(struct device *dev,
2286 struct device_attribute *attr,
2287 char *buf)
2288{
2289 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2290 u32 state;
2291 int ret;
2292
2293 ret = toshiba_panel_power_on_get(toshiba, &state);
2294 if (ret < 0)
2295 return ret;
2296
2297 return sprintf(buf, "%d\n", state);
2298}
2299
2300static ssize_t toshiba_panel_power_on_store(struct device *dev,
2301 struct device_attribute *attr,
2302 const char *buf, size_t count)
2303{
2304 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2305 int state;
2306 int ret;
2307
2308 ret = kstrtoint(buf, 0, &state);
2309 if (ret)
2310 return ret;
2311 if (state != 0 && state != 1)
2312 return -EINVAL;
2313
2314 ret = toshiba_panel_power_on_set(toshiba, state);
2315 if (ret)
2316 return ret;
2317
2318 pr_info("Reboot for changes to Panel Power ON to take effect");
2319
2320 return count;
2321}
2322
Azael Avalos17fe4b32015-02-10 21:09:20 -07002323static ssize_t toshiba_usb_three_show(struct device *dev,
2324 struct device_attribute *attr,
2325 char *buf)
2326{
2327 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2328 u32 state;
2329 int ret;
2330
2331 ret = toshiba_usb_three_get(toshiba, &state);
2332 if (ret < 0)
2333 return ret;
2334
2335 return sprintf(buf, "%d\n", state);
2336}
2337
2338static ssize_t toshiba_usb_three_store(struct device *dev,
2339 struct device_attribute *attr,
2340 const char *buf, size_t count)
2341{
2342 struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
2343 int state;
2344 int ret;
2345
2346 ret = kstrtoint(buf, 0, &state);
2347 if (ret)
2348 return ret;
2349 /* Check for USB 3 mode where:
2350 * 0 - Disabled (Acts like a USB 2 port, saving power)
2351 * 1 - Enabled
2352 */
2353 if (state != 0 && state != 1)
2354 return -EINVAL;
2355
2356 ret = toshiba_usb_three_set(toshiba, state);
2357 if (ret)
2358 return ret;
2359
2360 pr_info("Reboot for changes to USB 3 to take effect");
2361
2362 return count;
2363}
2364
Azael Avalos360f0f32014-03-25 20:38:31 -06002365static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
2366 struct attribute *attr, int idx)
2367{
2368 struct device *dev = container_of(kobj, struct device, kobj);
2369 struct toshiba_acpi_dev *drv = dev_get_drvdata(dev);
2370 bool exists = true;
2371
Azael Avalos94477d42015-02-10 21:09:17 -07002372 if (attr == &dev_attr_fan.attr)
2373 exists = (drv->fan_supported) ? true : false;
2374 else if (attr == &dev_attr_kbd_backlight_mode.attr)
Azael Avalos360f0f32014-03-25 20:38:31 -06002375 exists = (drv->kbd_illum_supported) ? true : false;
2376 else if (attr == &dev_attr_kbd_backlight_timeout.attr)
2377 exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false;
Azael Avalos9d8658a2014-03-25 20:38:32 -06002378 else if (attr == &dev_attr_touchpad.attr)
2379 exists = (drv->touchpad_supported) ? true : false;
Azael Avalos5a2813e2014-03-25 20:38:34 -06002380 else if (attr == &dev_attr_position.attr)
2381 exists = (drv->accelerometer_supported) ? true : false;
Azael Avalose26ffe52015-01-18 18:30:22 -07002382 else if (attr == &dev_attr_usb_sleep_charge.attr)
2383 exists = (drv->usb_sleep_charge_supported) ? true : false;
Azael Avalos182bcaa2015-01-18 18:30:23 -07002384 else if (attr == &dev_attr_sleep_functions_on_battery.attr)
2385 exists = (drv->usb_sleep_charge_supported) ? true : false;
Azael Avalosbb3fe012015-01-18 18:30:24 -07002386 else if (attr == &dev_attr_usb_rapid_charge.attr)
2387 exists = (drv->usb_rapid_charge_supported) ? true : false;
Azael Avalos172ce0a2015-01-18 18:30:25 -07002388 else if (attr == &dev_attr_usb_sleep_music.attr)
2389 exists = (drv->usb_sleep_music_supported) ? true : false;
Azael Avalosbae84192015-02-10 21:09:18 -07002390 else if (attr == &dev_attr_kbd_function_keys.attr)
2391 exists = (drv->kbd_function_keys_supported) ? true : false;
Azael Avalos35d53ce2015-02-10 21:09:19 -07002392 else if (attr == &dev_attr_panel_power_on.attr)
2393 exists = (drv->panel_power_on_supported) ? true : false;
Azael Avalos17fe4b32015-02-10 21:09:20 -07002394 else if (attr == &dev_attr_usb_three.attr)
2395 exists = (drv->usb_three_supported) ? true : false;
Azael Avalos360f0f32014-03-25 20:38:31 -06002396
2397 return exists ? attr->mode : 0;
2398}
2399
Azael Avalos1f28f292014-12-04 20:22:45 -07002400/*
2401 * Hotkeys
2402 */
2403static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev)
2404{
2405 acpi_status status;
2406 u32 result;
2407
2408 status = acpi_evaluate_object(dev->acpi_dev->handle,
2409 "ENAB", NULL, NULL);
2410 if (ACPI_FAILURE(status))
2411 return -ENODEV;
2412
2413 result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE);
2414 if (result == TOS_FAILURE)
2415 return -EIO;
2416 else if (result == TOS_NOT_SUPPORTED)
2417 return -ENODEV;
2418
2419 return 0;
2420}
2421
Seth Forshee29cd2932012-01-18 13:44:09 -06002422static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
2423 struct serio *port)
2424{
Giedrius Statkevičius98280372014-10-18 02:57:20 +03002425 if (str & I8042_STR_AUXDATA)
Seth Forshee29cd2932012-01-18 13:44:09 -06002426 return false;
2427
2428 if (unlikely(data == 0xe0))
2429 return false;
2430
2431 if ((data & 0x7f) == TOS1900_FN_SCAN) {
2432 schedule_work(&toshiba_acpi->hotkey_work);
2433 return true;
2434 }
2435
2436 return false;
2437}
2438
2439static void toshiba_acpi_hotkey_work(struct work_struct *work)
2440{
2441 acpi_handle ec_handle = ec_get_handle();
2442 acpi_status status;
2443
2444 if (!ec_handle)
2445 return;
2446
2447 status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL);
2448 if (ACPI_FAILURE(status))
2449 pr_err("ACPI NTFY method execution failed\n");
2450}
2451
2452/*
2453 * Returns hotkey scancode, or < 0 on failure.
2454 */
2455static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev)
2456{
Zhang Rui74facaf2013-09-03 08:32:15 +08002457 unsigned long long value;
Seth Forshee29cd2932012-01-18 13:44:09 -06002458 acpi_status status;
2459
Zhang Rui74facaf2013-09-03 08:32:15 +08002460 status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO",
2461 NULL, &value);
2462 if (ACPI_FAILURE(status)) {
Seth Forshee29cd2932012-01-18 13:44:09 -06002463 pr_err("ACPI INFO method execution failed\n");
2464 return -EIO;
2465 }
2466
Zhang Rui74facaf2013-09-03 08:32:15 +08002467 return value;
Seth Forshee29cd2932012-01-18 13:44:09 -06002468}
2469
2470static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev,
2471 int scancode)
2472{
2473 if (scancode == 0x100)
2474 return;
2475
2476 /* act on key press; ignore key release */
2477 if (scancode & 0x80)
2478 return;
2479
2480 if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true))
2481 pr_info("Unknown key %x\n", scancode);
2482}
2483
Azael Avalos71454d72014-12-04 20:22:46 -07002484static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev)
2485{
2486 u32 hci_result, value;
2487 int retries = 3;
2488 int scancode;
2489
2490 if (dev->info_supported) {
2491 scancode = toshiba_acpi_query_hotkey(dev);
2492 if (scancode < 0)
2493 pr_err("Failed to query hotkey event\n");
2494 else if (scancode != 0)
2495 toshiba_acpi_report_hotkey(dev, scancode);
2496 } else if (dev->system_event_supported) {
2497 do {
2498 hci_result = hci_read1(dev, HCI_SYSTEM_EVENT, &value);
2499 switch (hci_result) {
2500 case TOS_SUCCESS:
2501 toshiba_acpi_report_hotkey(dev, (int)value);
2502 break;
2503 case TOS_NOT_SUPPORTED:
2504 /*
2505 * This is a workaround for an unresolved
2506 * issue on some machines where system events
2507 * sporadically become disabled.
2508 */
2509 hci_result =
2510 hci_write1(dev, HCI_SYSTEM_EVENT, 1);
2511 pr_notice("Re-enabled hotkeys\n");
2512 /* fall through */
2513 default:
2514 retries--;
2515 break;
2516 }
2517 } while (retries && hci_result != TOS_FIFO_EMPTY);
2518 }
2519}
2520
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08002521static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
Matthew Garrett6335e4d2010-02-25 15:20:54 -05002522{
Zhang Ruie2e19602013-09-03 08:32:06 +08002523 acpi_handle ec_handle;
Seth Forshee135740d2011-09-20 16:55:49 -05002524 int error;
Seth Forshee29cd2932012-01-18 13:44:09 -06002525 u32 hci_result;
Takashi Iwaife808bfb2014-04-29 15:15:38 +02002526 const struct key_entry *keymap = toshiba_acpi_keymap;
Seth Forshee135740d2011-09-20 16:55:49 -05002527
Seth Forshee135740d2011-09-20 16:55:49 -05002528 dev->hotkey_dev = input_allocate_device();
Joe Perchesb222cca2013-10-23 12:14:52 -07002529 if (!dev->hotkey_dev)
Seth Forshee135740d2011-09-20 16:55:49 -05002530 return -ENOMEM;
Seth Forshee135740d2011-09-20 16:55:49 -05002531
2532 dev->hotkey_dev->name = "Toshiba input device";
Seth Forshee6e02cc72011-09-20 16:55:51 -05002533 dev->hotkey_dev->phys = "toshiba_acpi/input0";
Seth Forshee135740d2011-09-20 16:55:49 -05002534 dev->hotkey_dev->id.bustype = BUS_HOST;
2535
Takashi Iwaife808bfb2014-04-29 15:15:38 +02002536 if (dmi_check_system(toshiba_alt_keymap_dmi))
2537 keymap = toshiba_acpi_alt_keymap;
2538 error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL);
Seth Forshee135740d2011-09-20 16:55:49 -05002539 if (error)
2540 goto err_free_dev;
2541
Seth Forshee29cd2932012-01-18 13:44:09 -06002542 /*
2543 * For some machines the SCI responsible for providing hotkey
2544 * notification doesn't fire. We can trigger the notification
2545 * whenever the Fn key is pressed using the NTFY method, if
2546 * supported, so if it's present set up an i8042 key filter
2547 * for this purpose.
2548 */
Seth Forshee29cd2932012-01-18 13:44:09 -06002549 ec_handle = ec_get_handle();
Zhang Ruie2e19602013-09-03 08:32:06 +08002550 if (ec_handle && acpi_has_method(ec_handle, "NTFY")) {
Seth Forshee29cd2932012-01-18 13:44:09 -06002551 INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work);
2552
2553 error = i8042_install_filter(toshiba_acpi_i8042_filter);
2554 if (error) {
2555 pr_err("Error installing key filter\n");
2556 goto err_free_keymap;
2557 }
2558
2559 dev->ntfy_supported = 1;
2560 }
2561
2562 /*
2563 * Determine hotkey query interface. Prefer using the INFO
2564 * method when it is available.
2565 */
Zhang Ruie2e19602013-09-03 08:32:06 +08002566 if (acpi_has_method(dev->acpi_dev->handle, "INFO"))
Seth Forshee29cd2932012-01-18 13:44:09 -06002567 dev->info_supported = 1;
Zhang Ruie2e19602013-09-03 08:32:06 +08002568 else {
Azael Avalos893f3f62014-09-29 20:40:09 -06002569 hci_result = hci_write1(dev, HCI_SYSTEM_EVENT, 1);
Azael Avalos1864bbc2014-09-29 20:40:08 -06002570 if (hci_result == TOS_SUCCESS)
Seth Forshee29cd2932012-01-18 13:44:09 -06002571 dev->system_event_supported = 1;
2572 }
2573
2574 if (!dev->info_supported && !dev->system_event_supported) {
2575 pr_warn("No hotkey query interface found\n");
2576 goto err_remove_filter;
2577 }
2578
Azael Avalos1f28f292014-12-04 20:22:45 -07002579 error = toshiba_acpi_enable_hotkeys(dev);
2580 if (error) {
Seth Forshee135740d2011-09-20 16:55:49 -05002581 pr_info("Unable to enable hotkeys\n");
Seth Forshee29cd2932012-01-18 13:44:09 -06002582 goto err_remove_filter;
Seth Forshee135740d2011-09-20 16:55:49 -05002583 }
2584
2585 error = input_register_device(dev->hotkey_dev);
2586 if (error) {
2587 pr_info("Unable to register input device\n");
Seth Forshee29cd2932012-01-18 13:44:09 -06002588 goto err_remove_filter;
Seth Forshee135740d2011-09-20 16:55:49 -05002589 }
2590
2591 return 0;
2592
Seth Forshee29cd2932012-01-18 13:44:09 -06002593 err_remove_filter:
2594 if (dev->ntfy_supported)
2595 i8042_remove_filter(toshiba_acpi_i8042_filter);
Seth Forshee135740d2011-09-20 16:55:49 -05002596 err_free_keymap:
2597 sparse_keymap_free(dev->hotkey_dev);
2598 err_free_dev:
2599 input_free_device(dev->hotkey_dev);
2600 dev->hotkey_dev = NULL;
2601 return error;
2602}
2603
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08002604static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
Seth Forshee62cce752012-04-19 11:23:50 -05002605{
2606 struct backlight_properties props;
2607 int brightness;
2608 int ret;
Akio Idehara121b7b02012-04-06 01:46:43 +09002609 bool enabled;
Seth Forshee62cce752012-04-19 11:23:50 -05002610
2611 /*
2612 * Some machines don't support the backlight methods at all, and
2613 * others support it read-only. Either of these is pretty useless,
2614 * so only register the backlight device if the backlight method
2615 * supports both reads and writes.
2616 */
2617 brightness = __get_lcd_brightness(dev);
2618 if (brightness < 0)
2619 return 0;
2620 ret = set_lcd_brightness(dev, brightness);
2621 if (ret) {
2622 pr_debug("Backlight method is read-only, disabling backlight support\n");
2623 return 0;
2624 }
2625
Akio Idehara121b7b02012-04-06 01:46:43 +09002626 /* Determine whether or not BIOS supports transflective backlight */
2627 ret = get_tr_backlight_status(dev, &enabled);
2628 dev->tr_backlight_supported = !ret;
2629
Matthew Garrett53039f22012-06-01 11:02:36 -04002630 memset(&props, 0, sizeof(props));
Seth Forshee62cce752012-04-19 11:23:50 -05002631 props.type = BACKLIGHT_PLATFORM;
2632 props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
Seth Forshee62cce752012-04-19 11:23:50 -05002633
Akio Idehara121b7b02012-04-06 01:46:43 +09002634 /* adding an extra level and having 0 change to transflective mode */
2635 if (dev->tr_backlight_supported)
2636 props.max_brightness++;
2637
Seth Forshee62cce752012-04-19 11:23:50 -05002638 dev->backlight_dev = backlight_device_register("toshiba",
2639 &dev->acpi_dev->dev,
2640 dev,
2641 &toshiba_backlight_data,
2642 &props);
2643 if (IS_ERR(dev->backlight_dev)) {
2644 ret = PTR_ERR(dev->backlight_dev);
2645 pr_err("Could not register toshiba backlight device\n");
2646 dev->backlight_dev = NULL;
2647 return ret;
2648 }
2649
2650 dev->backlight_dev->props.brightness = brightness;
2651 return 0;
2652}
2653
Rafael J. Wysocki51fac832013-01-24 00:24:48 +01002654static int toshiba_acpi_remove(struct acpi_device *acpi_dev)
Seth Forshee135740d2011-09-20 16:55:49 -05002655{
2656 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
2657
Seth Forshee36d03f92011-09-20 16:55:53 -05002658 remove_toshiba_proc_entries(dev);
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002659
Azael Avalos360f0f32014-03-25 20:38:31 -06002660 if (dev->sysfs_created)
2661 sysfs_remove_group(&dev->acpi_dev->dev.kobj,
2662 &toshiba_attr_group);
Seth Forshee135740d2011-09-20 16:55:49 -05002663
Seth Forshee29cd2932012-01-18 13:44:09 -06002664 if (dev->ntfy_supported) {
2665 i8042_remove_filter(toshiba_acpi_i8042_filter);
2666 cancel_work_sync(&dev->hotkey_work);
2667 }
2668
Seth Forshee135740d2011-09-20 16:55:49 -05002669 if (dev->hotkey_dev) {
2670 input_unregister_device(dev->hotkey_dev);
2671 sparse_keymap_free(dev->hotkey_dev);
2672 }
2673
2674 if (dev->bt_rfk) {
2675 rfkill_unregister(dev->bt_rfk);
2676 rfkill_destroy(dev->bt_rfk);
2677 }
2678
Markus Elfring00981812014-11-24 20:30:29 +01002679 backlight_device_unregister(dev->backlight_dev);
Seth Forshee135740d2011-09-20 16:55:49 -05002680
Seth Forshee36d03f92011-09-20 16:55:53 -05002681 if (dev->illumination_supported)
Seth Forshee135740d2011-09-20 16:55:49 -05002682 led_classdev_unregister(&dev->led_dev);
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002683
Azael Avalos360f0f32014-03-25 20:38:31 -06002684 if (dev->kbd_led_registered)
2685 led_classdev_unregister(&dev->kbd_led);
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002686
Azael Avalosdef6c4e2014-03-25 20:38:33 -06002687 if (dev->eco_supported)
2688 led_classdev_unregister(&dev->eco_led);
Seth Forshee135740d2011-09-20 16:55:49 -05002689
Seth Forshee29cd2932012-01-18 13:44:09 -06002690 if (toshiba_acpi)
2691 toshiba_acpi = NULL;
2692
Seth Forshee135740d2011-09-20 16:55:49 -05002693 kfree(dev);
2694
2695 return 0;
2696}
2697
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08002698static const char *find_hci_method(acpi_handle handle)
Seth Forsheea540d6b2011-09-20 16:55:52 -05002699{
Zhang Ruie2e19602013-09-03 08:32:06 +08002700 if (acpi_has_method(handle, "GHCI"))
Seth Forsheea540d6b2011-09-20 16:55:52 -05002701 return "GHCI";
2702
Zhang Ruie2e19602013-09-03 08:32:06 +08002703 if (acpi_has_method(handle, "SPFC"))
Seth Forsheea540d6b2011-09-20 16:55:52 -05002704 return "SPFC";
2705
2706 return NULL;
2707}
2708
Greg Kroah-Hartmanb859f152012-12-21 13:18:33 -08002709static int toshiba_acpi_add(struct acpi_device *acpi_dev)
Seth Forshee135740d2011-09-20 16:55:49 -05002710{
2711 struct toshiba_acpi_dev *dev;
Seth Forsheea540d6b2011-09-20 16:55:52 -05002712 const char *hci_method;
Seth Forshee36d03f92011-09-20 16:55:53 -05002713 u32 dummy;
Seth Forshee135740d2011-09-20 16:55:49 -05002714 bool bt_present;
2715 int ret = 0;
Seth Forshee135740d2011-09-20 16:55:49 -05002716
Seth Forshee29cd2932012-01-18 13:44:09 -06002717 if (toshiba_acpi)
2718 return -EBUSY;
2719
Seth Forshee135740d2011-09-20 16:55:49 -05002720 pr_info("Toshiba Laptop ACPI Extras version %s\n",
2721 TOSHIBA_ACPI_VERSION);
2722
Seth Forsheea540d6b2011-09-20 16:55:52 -05002723 hci_method = find_hci_method(acpi_dev->handle);
2724 if (!hci_method) {
2725 pr_err("HCI interface not found\n");
Seth Forshee6e02cc72011-09-20 16:55:51 -05002726 return -ENODEV;
Seth Forsheea540d6b2011-09-20 16:55:52 -05002727 }
Seth Forshee6e02cc72011-09-20 16:55:51 -05002728
Seth Forshee135740d2011-09-20 16:55:49 -05002729 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
2730 if (!dev)
2731 return -ENOMEM;
2732 dev->acpi_dev = acpi_dev;
Seth Forsheea540d6b2011-09-20 16:55:52 -05002733 dev->method_hci = hci_method;
Seth Forshee135740d2011-09-20 16:55:49 -05002734 acpi_dev->driver_data = dev;
Azael Avalos360f0f32014-03-25 20:38:31 -06002735 dev_set_drvdata(&acpi_dev->dev, dev);
Seth Forshee135740d2011-09-20 16:55:49 -05002736
Seth Forshee6e02cc72011-09-20 16:55:51 -05002737 if (toshiba_acpi_setup_keyboard(dev))
2738 pr_info("Unable to activate hotkeys\n");
Seth Forshee135740d2011-09-20 16:55:49 -05002739
2740 mutex_init(&dev->mutex);
2741
Seth Forshee62cce752012-04-19 11:23:50 -05002742 ret = toshiba_acpi_setup_backlight(dev);
2743 if (ret)
Seth Forshee135740d2011-09-20 16:55:49 -05002744 goto error;
Seth Forshee135740d2011-09-20 16:55:49 -05002745
2746 /* Register rfkill switch for Bluetooth */
Azael Avalos1864bbc2014-09-29 20:40:08 -06002747 if (hci_get_bt_present(dev, &bt_present) == TOS_SUCCESS && bt_present) {
Seth Forshee135740d2011-09-20 16:55:49 -05002748 dev->bt_rfk = rfkill_alloc("Toshiba Bluetooth",
2749 &acpi_dev->dev,
2750 RFKILL_TYPE_BLUETOOTH,
2751 &toshiba_rfk_ops,
2752 dev);
2753 if (!dev->bt_rfk) {
2754 pr_err("unable to allocate rfkill device\n");
2755 ret = -ENOMEM;
2756 goto error;
2757 }
2758
2759 ret = rfkill_register(dev->bt_rfk);
2760 if (ret) {
2761 pr_err("unable to register rfkill device\n");
2762 rfkill_destroy(dev->bt_rfk);
2763 goto error;
2764 }
2765 }
2766
2767 if (toshiba_illumination_available(dev)) {
2768 dev->led_dev.name = "toshiba::illumination";
2769 dev->led_dev.max_brightness = 1;
2770 dev->led_dev.brightness_set = toshiba_illumination_set;
2771 dev->led_dev.brightness_get = toshiba_illumination_get;
2772 if (!led_classdev_register(&acpi_dev->dev, &dev->led_dev))
Seth Forshee36d03f92011-09-20 16:55:53 -05002773 dev->illumination_supported = 1;
Seth Forshee135740d2011-09-20 16:55:49 -05002774 }
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002775
Azael Avalosdef6c4e2014-03-25 20:38:33 -06002776 if (toshiba_eco_mode_available(dev)) {
2777 dev->eco_led.name = "toshiba::eco_mode";
2778 dev->eco_led.max_brightness = 1;
2779 dev->eco_led.brightness_set = toshiba_eco_mode_set_status;
2780 dev->eco_led.brightness_get = toshiba_eco_mode_get_status;
2781 if (!led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led))
2782 dev->eco_supported = 1;
2783 }
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002784
Azael Avalos93f8c162014-09-12 18:50:36 -06002785 dev->kbd_illum_supported = toshiba_kbd_illum_available(dev);
Azael Avalos360f0f32014-03-25 20:38:31 -06002786 /*
2787 * Only register the LED if KBD illumination is supported
2788 * and the keyboard backlight operation mode is set to FN-Z
2789 */
2790 if (dev->kbd_illum_supported && dev->kbd_mode == SCI_KBD_MODE_FNZ) {
2791 dev->kbd_led.name = "toshiba::kbd_backlight";
2792 dev->kbd_led.max_brightness = 1;
2793 dev->kbd_led.brightness_set = toshiba_kbd_backlight_set;
2794 dev->kbd_led.brightness_get = toshiba_kbd_backlight_get;
2795 if (!led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led))
2796 dev->kbd_led_registered = 1;
2797 }
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002798
Azael Avalos9d8658a2014-03-25 20:38:32 -06002799 ret = toshiba_touchpad_get(dev, &dummy);
2800 dev->touchpad_supported = !ret;
Matthew Garrettea6b31f2014-04-04 14:22:34 -04002801
Azael Avalos5a2813e2014-03-25 20:38:34 -06002802 ret = toshiba_accelerometer_supported(dev);
2803 dev->accelerometer_supported = !ret;
Seth Forshee135740d2011-09-20 16:55:49 -05002804
Azael Avalose26ffe52015-01-18 18:30:22 -07002805 ret = toshiba_usb_sleep_charge_get(dev, &dummy);
2806 dev->usb_sleep_charge_supported = !ret;
2807
Azael Avalosbb3fe012015-01-18 18:30:24 -07002808 ret = toshiba_usb_rapid_charge_get(dev, &dummy);
2809 dev->usb_rapid_charge_supported = !ret;
2810
Azael Avalos172ce0a2015-01-18 18:30:25 -07002811 ret = toshiba_usb_sleep_music_get(dev, &dummy);
2812 dev->usb_sleep_music_supported = !ret;
2813
Azael Avalosbae84192015-02-10 21:09:18 -07002814 ret = toshiba_function_keys_get(dev, &dummy);
2815 dev->kbd_function_keys_supported = !ret;
2816
Azael Avalos35d53ce2015-02-10 21:09:19 -07002817 ret = toshiba_panel_power_on_get(dev, &dummy);
2818 dev->panel_power_on_supported = !ret;
2819
Azael Avalos17fe4b32015-02-10 21:09:20 -07002820 ret = toshiba_usb_three_get(dev, &dummy);
2821 dev->usb_three_supported = !ret;
2822
Seth Forshee36d03f92011-09-20 16:55:53 -05002823 /* Determine whether or not BIOS supports fan and video interfaces */
2824
2825 ret = get_video_status(dev, &dummy);
2826 dev->video_supported = !ret;
2827
2828 ret = get_fan_status(dev, &dummy);
2829 dev->fan_supported = !ret;
2830
Azael Avalos360f0f32014-03-25 20:38:31 -06002831 ret = sysfs_create_group(&dev->acpi_dev->dev.kobj,
2832 &toshiba_attr_group);
2833 if (ret) {
2834 dev->sysfs_created = 0;
2835 goto error;
2836 }
2837 dev->sysfs_created = !ret;
2838
Seth Forshee36d03f92011-09-20 16:55:53 -05002839 create_toshiba_proc_entries(dev);
2840
Seth Forshee29cd2932012-01-18 13:44:09 -06002841 toshiba_acpi = dev;
2842
Seth Forshee135740d2011-09-20 16:55:49 -05002843 return 0;
2844
2845error:
Rafael J. Wysocki51fac832013-01-24 00:24:48 +01002846 toshiba_acpi_remove(acpi_dev);
Seth Forshee135740d2011-09-20 16:55:49 -05002847 return ret;
2848}
2849
2850static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
2851{
2852 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
Azael Avalos80546902014-12-04 20:22:47 -07002853 int ret;
Matthew Garrett6335e4d2010-02-25 15:20:54 -05002854
Azael Avalos71454d72014-12-04 20:22:46 -07002855 switch (event) {
2856 case 0x80: /* Hotkeys and some system events */
2857 toshiba_acpi_process_hotkeys(dev);
2858 break;
Azael Avalos80546902014-12-04 20:22:47 -07002859 case 0x92: /* Keyboard backlight mode changed */
2860 /* Update sysfs entries */
2861 ret = sysfs_update_group(&acpi_dev->dev.kobj,
2862 &toshiba_attr_group);
2863 if (ret)
2864 pr_err("Unable to update sysfs entries\n");
2865 break;
Azael Avalos71454d72014-12-04 20:22:46 -07002866 case 0x81: /* Unknown */
2867 case 0x82: /* Unknown */
2868 case 0x83: /* Unknown */
2869 case 0x8c: /* Unknown */
2870 case 0x8e: /* Unknown */
2871 case 0x8f: /* Unknown */
2872 case 0x90: /* Unknown */
2873 default:
2874 pr_info("Unknown event received %x\n", event);
2875 break;
Seth Forshee29cd2932012-01-18 13:44:09 -06002876 }
Matthew Garrett6335e4d2010-02-25 15:20:54 -05002877}
2878
Rafael J. Wysocki3567a4e22012-08-09 23:00:13 +02002879#ifdef CONFIG_PM_SLEEP
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02002880static int toshiba_acpi_suspend(struct device *device)
Seth Forshee29cd2932012-01-18 13:44:09 -06002881{
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02002882 struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
Seth Forshee29cd2932012-01-18 13:44:09 -06002883 u32 result;
2884
2885 if (dev->hotkey_dev)
Azael Avalos893f3f62014-09-29 20:40:09 -06002886 result = hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE);
Seth Forshee29cd2932012-01-18 13:44:09 -06002887
2888 return 0;
2889}
2890
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02002891static int toshiba_acpi_resume(struct device *device)
Seth Forshee29cd2932012-01-18 13:44:09 -06002892{
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02002893 struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
Azael Avalos1f28f292014-12-04 20:22:45 -07002894 int error;
Seth Forshee29cd2932012-01-18 13:44:09 -06002895
Benjamin Tissoirese7fdb762014-09-02 14:04:19 -04002896 if (dev->hotkey_dev) {
Azael Avalos1f28f292014-12-04 20:22:45 -07002897 error = toshiba_acpi_enable_hotkeys(dev);
2898 if (error)
Benjamin Tissoirese7fdb762014-09-02 14:04:19 -04002899 pr_info("Unable to re-enable hotkeys\n");
Benjamin Tissoirese7fdb762014-09-02 14:04:19 -04002900 }
Seth Forshee29cd2932012-01-18 13:44:09 -06002901
2902 return 0;
2903}
Rafael J. Wysocki3567a4e22012-08-09 23:00:13 +02002904#endif
Matthew Garrett6335e4d2010-02-25 15:20:54 -05002905
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02002906static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm,
2907 toshiba_acpi_suspend, toshiba_acpi_resume);
2908
Seth Forshee135740d2011-09-20 16:55:49 -05002909static struct acpi_driver toshiba_acpi_driver = {
2910 .name = "Toshiba ACPI driver",
2911 .owner = THIS_MODULE,
2912 .ids = toshiba_device_ids,
2913 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
2914 .ops = {
2915 .add = toshiba_acpi_add,
2916 .remove = toshiba_acpi_remove,
2917 .notify = toshiba_acpi_notify,
2918 },
Rafael J. Wysocki43d2fd32012-06-27 23:27:16 +02002919 .drv.pm = &toshiba_acpi_pm,
Seth Forshee135740d2011-09-20 16:55:49 -05002920};
Holger Machtc9263552006-10-20 14:30:29 -07002921
Len Brown4be44fc2005-08-05 00:44:28 -04002922static int __init toshiba_acpi_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923{
Seth Forshee135740d2011-09-20 16:55:49 -05002924 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925
Seth Forsheef11f9992012-01-18 13:44:11 -06002926 /*
2927 * Machines with this WMI guid aren't supported due to bugs in
2928 * their AML. This check relies on wmi initializing before
2929 * toshiba_acpi to guarantee guids have been identified.
2930 */
2931 if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
2932 return -ENODEV;
2933
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
2935 if (!toshiba_proc_dir) {
Seth Forshee135740d2011-09-20 16:55:49 -05002936 pr_err("Unable to create proc dir " PROC_TOSHIBA "\n");
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04002937 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 }
2939
Seth Forshee135740d2011-09-20 16:55:49 -05002940 ret = acpi_bus_register_driver(&toshiba_acpi_driver);
2941 if (ret) {
2942 pr_err("Failed to register ACPI driver: %d\n", ret);
2943 remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
Holger Machtc9263552006-10-20 14:30:29 -07002944 }
2945
Seth Forshee135740d2011-09-20 16:55:49 -05002946 return ret;
2947}
philipl@overt.orgc41a40c2008-08-30 11:57:39 -04002948
Seth Forshee135740d2011-09-20 16:55:49 -05002949static void __exit toshiba_acpi_exit(void)
2950{
2951 acpi_bus_unregister_driver(&toshiba_acpi_driver);
2952 if (toshiba_proc_dir)
2953 remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954}
2955
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956module_init(toshiba_acpi_init);
2957module_exit(toshiba_acpi_exit);