18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  toshiba_acpi.c - Toshiba Laptop ACPI Extras
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2002-2004 John Belmonte
68c2ecf20Sopenharmony_ci *  Copyright (C) 2008 Philip Langdale
78c2ecf20Sopenharmony_ci *  Copyright (C) 2010 Pierre Ducroquet
88c2ecf20Sopenharmony_ci *  Copyright (C) 2014-2016 Azael Avalos
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *  The devolpment page for this driver is located at
118c2ecf20Sopenharmony_ci *  http://memebeam.org/toys/ToshibaAcpiDriver.
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci *  Credits:
148c2ecf20Sopenharmony_ci *	Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse
158c2ecf20Sopenharmony_ci *		engineering the Windows drivers
168c2ecf20Sopenharmony_ci *	Yasushi Nagato - changes for linux kernel 2.4 -> 2.5
178c2ecf20Sopenharmony_ci *	Rob Miller - TV out and hotkeys help
188c2ecf20Sopenharmony_ci */
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define TOSHIBA_ACPI_VERSION	"0.24"
238c2ecf20Sopenharmony_ci#define PROC_INTERFACE_VERSION	1
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include <linux/compiler.h>
268c2ecf20Sopenharmony_ci#include <linux/kernel.h>
278c2ecf20Sopenharmony_ci#include <linux/module.h>
288c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
298c2ecf20Sopenharmony_ci#include <linux/init.h>
308c2ecf20Sopenharmony_ci#include <linux/types.h>
318c2ecf20Sopenharmony_ci#include <linux/proc_fs.h>
328c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
338c2ecf20Sopenharmony_ci#include <linux/backlight.h>
348c2ecf20Sopenharmony_ci#include <linux/input.h>
358c2ecf20Sopenharmony_ci#include <linux/input/sparse-keymap.h>
368c2ecf20Sopenharmony_ci#include <linux/leds.h>
378c2ecf20Sopenharmony_ci#include <linux/slab.h>
388c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
398c2ecf20Sopenharmony_ci#include <linux/i8042.h>
408c2ecf20Sopenharmony_ci#include <linux/acpi.h>
418c2ecf20Sopenharmony_ci#include <linux/dmi.h>
428c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
438c2ecf20Sopenharmony_ci#include <linux/miscdevice.h>
448c2ecf20Sopenharmony_ci#include <linux/rfkill.h>
458c2ecf20Sopenharmony_ci#include <linux/iio/iio.h>
468c2ecf20Sopenharmony_ci#include <linux/toshiba.h>
478c2ecf20Sopenharmony_ci#include <acpi/video.h>
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ciMODULE_AUTHOR("John Belmonte");
508c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
518c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100"
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/* Scan code for Fn key on TOS1900 models */
568c2ecf20Sopenharmony_ci#define TOS1900_FN_SCAN		0x6e
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/* Toshiba ACPI method paths */
598c2ecf20Sopenharmony_ci#define METHOD_VIDEO_OUT	"\\_SB_.VALX.DSSX"
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/*
628c2ecf20Sopenharmony_ci * The Toshiba configuration interface is composed of the HCI and the SCI,
638c2ecf20Sopenharmony_ci * which are defined as follows:
648c2ecf20Sopenharmony_ci *
658c2ecf20Sopenharmony_ci * HCI is Toshiba's "Hardware Control Interface" which is supposed to
668c2ecf20Sopenharmony_ci * be uniform across all their models.  Ideally we would just call
678c2ecf20Sopenharmony_ci * dedicated ACPI methods instead of using this primitive interface.
688c2ecf20Sopenharmony_ci * However the ACPI methods seem to be incomplete in some areas (for
698c2ecf20Sopenharmony_ci * example they allow setting, but not reading, the LCD brightness value),
708c2ecf20Sopenharmony_ci * so this is still useful.
718c2ecf20Sopenharmony_ci *
728c2ecf20Sopenharmony_ci * SCI stands for "System Configuration Interface" which aim is to
738c2ecf20Sopenharmony_ci * conceal differences in hardware between different models.
748c2ecf20Sopenharmony_ci */
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci#define TCI_WORDS			6
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci/* Operations */
798c2ecf20Sopenharmony_ci#define HCI_SET				0xff00
808c2ecf20Sopenharmony_ci#define HCI_GET				0xfe00
818c2ecf20Sopenharmony_ci#define SCI_OPEN			0xf100
828c2ecf20Sopenharmony_ci#define SCI_CLOSE			0xf200
838c2ecf20Sopenharmony_ci#define SCI_GET				0xf300
848c2ecf20Sopenharmony_ci#define SCI_SET				0xf400
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci/* Return codes */
878c2ecf20Sopenharmony_ci#define TOS_SUCCESS			0x0000
888c2ecf20Sopenharmony_ci#define TOS_SUCCESS2			0x0001
898c2ecf20Sopenharmony_ci#define TOS_OPEN_CLOSE_OK		0x0044
908c2ecf20Sopenharmony_ci#define TOS_FAILURE			0x1000
918c2ecf20Sopenharmony_ci#define TOS_NOT_SUPPORTED		0x8000
928c2ecf20Sopenharmony_ci#define TOS_ALREADY_OPEN		0x8100
938c2ecf20Sopenharmony_ci#define TOS_NOT_OPENED			0x8200
948c2ecf20Sopenharmony_ci#define TOS_INPUT_DATA_ERROR		0x8300
958c2ecf20Sopenharmony_ci#define TOS_WRITE_PROTECTED		0x8400
968c2ecf20Sopenharmony_ci#define TOS_NOT_PRESENT			0x8600
978c2ecf20Sopenharmony_ci#define TOS_FIFO_EMPTY			0x8c00
988c2ecf20Sopenharmony_ci#define TOS_DATA_NOT_AVAILABLE		0x8d20
998c2ecf20Sopenharmony_ci#define TOS_NOT_INITIALIZED		0x8d50
1008c2ecf20Sopenharmony_ci#define TOS_NOT_INSTALLED		0x8e00
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci/* Registers */
1038c2ecf20Sopenharmony_ci#define HCI_FAN				0x0004
1048c2ecf20Sopenharmony_ci#define HCI_TR_BACKLIGHT		0x0005
1058c2ecf20Sopenharmony_ci#define HCI_SYSTEM_EVENT		0x0016
1068c2ecf20Sopenharmony_ci#define HCI_VIDEO_OUT			0x001c
1078c2ecf20Sopenharmony_ci#define HCI_HOTKEY_EVENT		0x001e
1088c2ecf20Sopenharmony_ci#define HCI_LCD_BRIGHTNESS		0x002a
1098c2ecf20Sopenharmony_ci#define HCI_WIRELESS			0x0056
1108c2ecf20Sopenharmony_ci#define HCI_ACCELEROMETER		0x006d
1118c2ecf20Sopenharmony_ci#define HCI_COOLING_METHOD		0x007f
1128c2ecf20Sopenharmony_ci#define HCI_KBD_ILLUMINATION		0x0095
1138c2ecf20Sopenharmony_ci#define HCI_ECO_MODE			0x0097
1148c2ecf20Sopenharmony_ci#define HCI_ACCELEROMETER2		0x00a6
1158c2ecf20Sopenharmony_ci#define HCI_SYSTEM_INFO			0xc000
1168c2ecf20Sopenharmony_ci#define SCI_PANEL_POWER_ON		0x010d
1178c2ecf20Sopenharmony_ci#define SCI_ILLUMINATION		0x014e
1188c2ecf20Sopenharmony_ci#define SCI_USB_SLEEP_CHARGE		0x0150
1198c2ecf20Sopenharmony_ci#define SCI_KBD_ILLUM_STATUS		0x015c
1208c2ecf20Sopenharmony_ci#define SCI_USB_SLEEP_MUSIC		0x015e
1218c2ecf20Sopenharmony_ci#define SCI_USB_THREE			0x0169
1228c2ecf20Sopenharmony_ci#define SCI_TOUCHPAD			0x050e
1238c2ecf20Sopenharmony_ci#define SCI_KBD_FUNCTION_KEYS		0x0522
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci/* Field definitions */
1268c2ecf20Sopenharmony_ci#define HCI_ACCEL_MASK			0x7fff
1278c2ecf20Sopenharmony_ci#define HCI_ACCEL_DIRECTION_MASK	0x8000
1288c2ecf20Sopenharmony_ci#define HCI_HOTKEY_DISABLE		0x0b
1298c2ecf20Sopenharmony_ci#define HCI_HOTKEY_ENABLE		0x09
1308c2ecf20Sopenharmony_ci#define HCI_HOTKEY_SPECIAL_FUNCTIONS	0x10
1318c2ecf20Sopenharmony_ci#define HCI_LCD_BRIGHTNESS_BITS		3
1328c2ecf20Sopenharmony_ci#define HCI_LCD_BRIGHTNESS_SHIFT	(16-HCI_LCD_BRIGHTNESS_BITS)
1338c2ecf20Sopenharmony_ci#define HCI_LCD_BRIGHTNESS_LEVELS	(1 << HCI_LCD_BRIGHTNESS_BITS)
1348c2ecf20Sopenharmony_ci#define HCI_MISC_SHIFT			0x10
1358c2ecf20Sopenharmony_ci#define HCI_SYSTEM_TYPE1		0x10
1368c2ecf20Sopenharmony_ci#define HCI_SYSTEM_TYPE2		0x11
1378c2ecf20Sopenharmony_ci#define HCI_VIDEO_OUT_LCD		0x1
1388c2ecf20Sopenharmony_ci#define HCI_VIDEO_OUT_CRT		0x2
1398c2ecf20Sopenharmony_ci#define HCI_VIDEO_OUT_TV		0x4
1408c2ecf20Sopenharmony_ci#define SCI_KBD_MODE_MASK		0x1f
1418c2ecf20Sopenharmony_ci#define SCI_KBD_MODE_FNZ		0x1
1428c2ecf20Sopenharmony_ci#define SCI_KBD_MODE_AUTO		0x2
1438c2ecf20Sopenharmony_ci#define SCI_KBD_MODE_ON			0x8
1448c2ecf20Sopenharmony_ci#define SCI_KBD_MODE_OFF		0x10
1458c2ecf20Sopenharmony_ci#define SCI_KBD_TIME_MAX		0x3c001a
1468c2ecf20Sopenharmony_ci#define HCI_WIRELESS_STATUS		0x1
1478c2ecf20Sopenharmony_ci#define HCI_WIRELESS_WWAN		0x3
1488c2ecf20Sopenharmony_ci#define HCI_WIRELESS_WWAN_STATUS	0x2000
1498c2ecf20Sopenharmony_ci#define HCI_WIRELESS_WWAN_POWER		0x4000
1508c2ecf20Sopenharmony_ci#define SCI_USB_CHARGE_MODE_MASK	0xff
1518c2ecf20Sopenharmony_ci#define SCI_USB_CHARGE_DISABLED		0x00
1528c2ecf20Sopenharmony_ci#define SCI_USB_CHARGE_ALTERNATE	0x09
1538c2ecf20Sopenharmony_ci#define SCI_USB_CHARGE_TYPICAL		0x11
1548c2ecf20Sopenharmony_ci#define SCI_USB_CHARGE_AUTO		0x21
1558c2ecf20Sopenharmony_ci#define SCI_USB_CHARGE_BAT_MASK		0x7
1568c2ecf20Sopenharmony_ci#define SCI_USB_CHARGE_BAT_LVL_OFF	0x1
1578c2ecf20Sopenharmony_ci#define SCI_USB_CHARGE_BAT_LVL_ON	0x4
1588c2ecf20Sopenharmony_ci#define SCI_USB_CHARGE_BAT_LVL		0x0200
1598c2ecf20Sopenharmony_ci#define SCI_USB_CHARGE_RAPID_DSP	0x0300
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistruct toshiba_acpi_dev {
1628c2ecf20Sopenharmony_ci	struct acpi_device *acpi_dev;
1638c2ecf20Sopenharmony_ci	const char *method_hci;
1648c2ecf20Sopenharmony_ci	struct input_dev *hotkey_dev;
1658c2ecf20Sopenharmony_ci	struct work_struct hotkey_work;
1668c2ecf20Sopenharmony_ci	struct backlight_device *backlight_dev;
1678c2ecf20Sopenharmony_ci	struct led_classdev led_dev;
1688c2ecf20Sopenharmony_ci	struct led_classdev kbd_led;
1698c2ecf20Sopenharmony_ci	struct led_classdev eco_led;
1708c2ecf20Sopenharmony_ci	struct miscdevice miscdev;
1718c2ecf20Sopenharmony_ci	struct rfkill *wwan_rfk;
1728c2ecf20Sopenharmony_ci	struct iio_dev *indio_dev;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	int force_fan;
1758c2ecf20Sopenharmony_ci	int last_key_event;
1768c2ecf20Sopenharmony_ci	int key_event_valid;
1778c2ecf20Sopenharmony_ci	int kbd_type;
1788c2ecf20Sopenharmony_ci	int kbd_mode;
1798c2ecf20Sopenharmony_ci	int kbd_time;
1808c2ecf20Sopenharmony_ci	int usbsc_bat_level;
1818c2ecf20Sopenharmony_ci	int usbsc_mode_base;
1828c2ecf20Sopenharmony_ci	int hotkey_event_type;
1838c2ecf20Sopenharmony_ci	int max_cooling_method;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	unsigned int illumination_supported:1;
1868c2ecf20Sopenharmony_ci	unsigned int video_supported:1;
1878c2ecf20Sopenharmony_ci	unsigned int fan_supported:1;
1888c2ecf20Sopenharmony_ci	unsigned int system_event_supported:1;
1898c2ecf20Sopenharmony_ci	unsigned int ntfy_supported:1;
1908c2ecf20Sopenharmony_ci	unsigned int info_supported:1;
1918c2ecf20Sopenharmony_ci	unsigned int tr_backlight_supported:1;
1928c2ecf20Sopenharmony_ci	unsigned int kbd_illum_supported:1;
1938c2ecf20Sopenharmony_ci	unsigned int touchpad_supported:1;
1948c2ecf20Sopenharmony_ci	unsigned int eco_supported:1;
1958c2ecf20Sopenharmony_ci	unsigned int accelerometer_supported:1;
1968c2ecf20Sopenharmony_ci	unsigned int usb_sleep_charge_supported:1;
1978c2ecf20Sopenharmony_ci	unsigned int usb_rapid_charge_supported:1;
1988c2ecf20Sopenharmony_ci	unsigned int usb_sleep_music_supported:1;
1998c2ecf20Sopenharmony_ci	unsigned int kbd_function_keys_supported:1;
2008c2ecf20Sopenharmony_ci	unsigned int panel_power_on_supported:1;
2018c2ecf20Sopenharmony_ci	unsigned int usb_three_supported:1;
2028c2ecf20Sopenharmony_ci	unsigned int wwan_supported:1;
2038c2ecf20Sopenharmony_ci	unsigned int cooling_method_supported:1;
2048c2ecf20Sopenharmony_ci	unsigned int sysfs_created:1;
2058c2ecf20Sopenharmony_ci	unsigned int special_functions;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	bool kbd_event_generated;
2088c2ecf20Sopenharmony_ci	bool killswitch;
2098c2ecf20Sopenharmony_ci};
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic struct toshiba_acpi_dev *toshiba_acpi;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cistatic bool disable_hotkeys;
2148c2ecf20Sopenharmony_cimodule_param(disable_hotkeys, bool, 0444);
2158c2ecf20Sopenharmony_ciMODULE_PARM_DESC(disable_hotkeys, "Disables the hotkeys activation");
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic const struct acpi_device_id toshiba_device_ids[] = {
2188c2ecf20Sopenharmony_ci	{"TOS6200", 0},
2198c2ecf20Sopenharmony_ci	{"TOS6207", 0},
2208c2ecf20Sopenharmony_ci	{"TOS6208", 0},
2218c2ecf20Sopenharmony_ci	{"TOS1900", 0},
2228c2ecf20Sopenharmony_ci	{"", 0},
2238c2ecf20Sopenharmony_ci};
2248c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cistatic const struct key_entry toshiba_acpi_keymap[] = {
2278c2ecf20Sopenharmony_ci	{ KE_KEY, 0x9e, { KEY_RFKILL } },
2288c2ecf20Sopenharmony_ci	{ KE_KEY, 0x101, { KEY_MUTE } },
2298c2ecf20Sopenharmony_ci	{ KE_KEY, 0x102, { KEY_ZOOMOUT } },
2308c2ecf20Sopenharmony_ci	{ KE_KEY, 0x103, { KEY_ZOOMIN } },
2318c2ecf20Sopenharmony_ci	{ KE_KEY, 0x10f, { KEY_TAB } },
2328c2ecf20Sopenharmony_ci	{ KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
2338c2ecf20Sopenharmony_ci	{ KE_KEY, 0x139, { KEY_ZOOMRESET } },
2348c2ecf20Sopenharmony_ci	{ KE_KEY, 0x13b, { KEY_COFFEE } },
2358c2ecf20Sopenharmony_ci	{ KE_KEY, 0x13c, { KEY_BATTERY } },
2368c2ecf20Sopenharmony_ci	{ KE_KEY, 0x13d, { KEY_SLEEP } },
2378c2ecf20Sopenharmony_ci	{ KE_KEY, 0x13e, { KEY_SUSPEND } },
2388c2ecf20Sopenharmony_ci	{ KE_KEY, 0x13f, { KEY_SWITCHVIDEOMODE } },
2398c2ecf20Sopenharmony_ci	{ KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } },
2408c2ecf20Sopenharmony_ci	{ KE_KEY, 0x141, { KEY_BRIGHTNESSUP } },
2418c2ecf20Sopenharmony_ci	{ KE_KEY, 0x142, { KEY_WLAN } },
2428c2ecf20Sopenharmony_ci	{ KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } },
2438c2ecf20Sopenharmony_ci	{ KE_KEY, 0x17f, { KEY_FN } },
2448c2ecf20Sopenharmony_ci	{ KE_KEY, 0xb05, { KEY_PROG2 } },
2458c2ecf20Sopenharmony_ci	{ KE_KEY, 0xb06, { KEY_WWW } },
2468c2ecf20Sopenharmony_ci	{ KE_KEY, 0xb07, { KEY_MAIL } },
2478c2ecf20Sopenharmony_ci	{ KE_KEY, 0xb30, { KEY_STOP } },
2488c2ecf20Sopenharmony_ci	{ KE_KEY, 0xb31, { KEY_PREVIOUSSONG } },
2498c2ecf20Sopenharmony_ci	{ KE_KEY, 0xb32, { KEY_NEXTSONG } },
2508c2ecf20Sopenharmony_ci	{ KE_KEY, 0xb33, { KEY_PLAYPAUSE } },
2518c2ecf20Sopenharmony_ci	{ KE_KEY, 0xb5a, { KEY_MEDIA } },
2528c2ecf20Sopenharmony_ci	{ KE_IGNORE, 0x1430, { KEY_RESERVED } }, /* Wake from sleep */
2538c2ecf20Sopenharmony_ci	{ KE_IGNORE, 0x1501, { KEY_RESERVED } }, /* Output changed */
2548c2ecf20Sopenharmony_ci	{ KE_IGNORE, 0x1502, { KEY_RESERVED } }, /* HDMI plugged/unplugged */
2558c2ecf20Sopenharmony_ci	{ KE_IGNORE, 0x1ABE, { KEY_RESERVED } }, /* Protection level set */
2568c2ecf20Sopenharmony_ci	{ KE_IGNORE, 0x1ABF, { KEY_RESERVED } }, /* Protection level off */
2578c2ecf20Sopenharmony_ci	{ KE_END, 0 },
2588c2ecf20Sopenharmony_ci};
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic const struct key_entry toshiba_acpi_alt_keymap[] = {
2618c2ecf20Sopenharmony_ci	{ KE_KEY, 0x102, { KEY_ZOOMOUT } },
2628c2ecf20Sopenharmony_ci	{ KE_KEY, 0x103, { KEY_ZOOMIN } },
2638c2ecf20Sopenharmony_ci	{ KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
2648c2ecf20Sopenharmony_ci	{ KE_KEY, 0x139, { KEY_ZOOMRESET } },
2658c2ecf20Sopenharmony_ci	{ KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } },
2668c2ecf20Sopenharmony_ci	{ KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } },
2678c2ecf20Sopenharmony_ci	{ KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } },
2688c2ecf20Sopenharmony_ci	{ KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } },
2698c2ecf20Sopenharmony_ci	{ KE_KEY, 0x157, { KEY_MUTE } },
2708c2ecf20Sopenharmony_ci	{ KE_KEY, 0x158, { KEY_WLAN } },
2718c2ecf20Sopenharmony_ci	{ KE_END, 0 },
2728c2ecf20Sopenharmony_ci};
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci/*
2758c2ecf20Sopenharmony_ci * List of models which have a broken acpi-video backlight interface and thus
2768c2ecf20Sopenharmony_ci * need to use the toshiba (vendor) interface instead.
2778c2ecf20Sopenharmony_ci */
2788c2ecf20Sopenharmony_cistatic const struct dmi_system_id toshiba_vendor_backlight_dmi[] = {
2798c2ecf20Sopenharmony_ci	{}
2808c2ecf20Sopenharmony_ci};
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci/*
2838c2ecf20Sopenharmony_ci * Utility
2848c2ecf20Sopenharmony_ci */
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_cistatic inline void _set_bit(u32 *word, u32 mask, int value)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	*word = (*word & ~mask) | (mask * value);
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci/*
2928c2ecf20Sopenharmony_ci * ACPI interface wrappers
2938c2ecf20Sopenharmony_ci */
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic int write_acpi_int(const char *methodName, int val)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	acpi_status status;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	status = acpi_execute_simple_method(NULL, (char *)methodName, val);
3008c2ecf20Sopenharmony_ci	return (status == AE_OK) ? 0 : -EIO;
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci/*
3048c2ecf20Sopenharmony_ci * Perform a raw configuration call.  Here we don't care about input or output
3058c2ecf20Sopenharmony_ci * buffer format.
3068c2ecf20Sopenharmony_ci */
3078c2ecf20Sopenharmony_cistatic acpi_status tci_raw(struct toshiba_acpi_dev *dev,
3088c2ecf20Sopenharmony_ci			   const u32 in[TCI_WORDS], u32 out[TCI_WORDS])
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	union acpi_object in_objs[TCI_WORDS], out_objs[TCI_WORDS + 1];
3118c2ecf20Sopenharmony_ci	struct acpi_object_list params;
3128c2ecf20Sopenharmony_ci	struct acpi_buffer results;
3138c2ecf20Sopenharmony_ci	acpi_status status;
3148c2ecf20Sopenharmony_ci	int i;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	params.count = TCI_WORDS;
3178c2ecf20Sopenharmony_ci	params.pointer = in_objs;
3188c2ecf20Sopenharmony_ci	for (i = 0; i < TCI_WORDS; ++i) {
3198c2ecf20Sopenharmony_ci		in_objs[i].type = ACPI_TYPE_INTEGER;
3208c2ecf20Sopenharmony_ci		in_objs[i].integer.value = in[i];
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	results.length = sizeof(out_objs);
3248c2ecf20Sopenharmony_ci	results.pointer = out_objs;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	status = acpi_evaluate_object(dev->acpi_dev->handle,
3278c2ecf20Sopenharmony_ci				      (char *)dev->method_hci, &params,
3288c2ecf20Sopenharmony_ci				      &results);
3298c2ecf20Sopenharmony_ci	if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) {
3308c2ecf20Sopenharmony_ci		for (i = 0; i < out_objs->package.count; ++i)
3318c2ecf20Sopenharmony_ci			out[i] = out_objs->package.elements[i].integer.value;
3328c2ecf20Sopenharmony_ci	}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	return status;
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci/*
3388c2ecf20Sopenharmony_ci * Common hci tasks
3398c2ecf20Sopenharmony_ci *
3408c2ecf20Sopenharmony_ci * In addition to the ACPI status, the HCI system returns a result which
3418c2ecf20Sopenharmony_ci * may be useful (such as "not supported").
3428c2ecf20Sopenharmony_ci */
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_cistatic u32 hci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 };
3478c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
3488c2ecf20Sopenharmony_ci	acpi_status status = tci_raw(dev, in, out);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE;
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_cistatic u32 hci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 };
3568c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
3578c2ecf20Sopenharmony_ci	acpi_status status = tci_raw(dev, in, out);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status))
3608c2ecf20Sopenharmony_ci		return TOS_FAILURE;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	*out1 = out[2];
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	return out[0];
3658c2ecf20Sopenharmony_ci}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci/*
3688c2ecf20Sopenharmony_ci * Common sci tasks
3698c2ecf20Sopenharmony_ci */
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_cistatic int sci_open(struct toshiba_acpi_dev *dev)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { SCI_OPEN, 0, 0, 0, 0, 0 };
3748c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
3758c2ecf20Sopenharmony_ci	acpi_status status = tci_raw(dev, in, out);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	if  (ACPI_FAILURE(status)) {
3788c2ecf20Sopenharmony_ci		pr_err("ACPI call to open SCI failed\n");
3798c2ecf20Sopenharmony_ci		return 0;
3808c2ecf20Sopenharmony_ci	}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	if (out[0] == TOS_OPEN_CLOSE_OK) {
3838c2ecf20Sopenharmony_ci		return 1;
3848c2ecf20Sopenharmony_ci	} else if (out[0] == TOS_ALREADY_OPEN) {
3858c2ecf20Sopenharmony_ci		pr_info("Toshiba SCI already opened\n");
3868c2ecf20Sopenharmony_ci		return 1;
3878c2ecf20Sopenharmony_ci	} else if (out[0] == TOS_NOT_SUPPORTED) {
3888c2ecf20Sopenharmony_ci		/*
3898c2ecf20Sopenharmony_ci		 * Some BIOSes do not have the SCI open/close functions
3908c2ecf20Sopenharmony_ci		 * implemented and return 0x8000 (Not Supported), failing to
3918c2ecf20Sopenharmony_ci		 * register some supported features.
3928c2ecf20Sopenharmony_ci		 *
3938c2ecf20Sopenharmony_ci		 * Simply return 1 if we hit those affected laptops to make the
3948c2ecf20Sopenharmony_ci		 * supported features work.
3958c2ecf20Sopenharmony_ci		 *
3968c2ecf20Sopenharmony_ci		 * In the case that some laptops really do not support the SCI,
3978c2ecf20Sopenharmony_ci		 * all the SCI dependent functions check for TOS_NOT_SUPPORTED,
3988c2ecf20Sopenharmony_ci		 * and thus, not registering support for the queried feature.
3998c2ecf20Sopenharmony_ci		 */
4008c2ecf20Sopenharmony_ci		return 1;
4018c2ecf20Sopenharmony_ci	} else if (out[0] == TOS_NOT_PRESENT) {
4028c2ecf20Sopenharmony_ci		pr_info("Toshiba SCI is not present\n");
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	return 0;
4068c2ecf20Sopenharmony_ci}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_cistatic void sci_close(struct toshiba_acpi_dev *dev)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { SCI_CLOSE, 0, 0, 0, 0, 0 };
4118c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
4128c2ecf20Sopenharmony_ci	acpi_status status = tci_raw(dev, in, out);
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
4158c2ecf20Sopenharmony_ci		pr_err("ACPI call to close SCI failed\n");
4168c2ecf20Sopenharmony_ci		return;
4178c2ecf20Sopenharmony_ci	}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	if (out[0] == TOS_OPEN_CLOSE_OK)
4208c2ecf20Sopenharmony_ci		return;
4218c2ecf20Sopenharmony_ci	else if (out[0] == TOS_NOT_OPENED)
4228c2ecf20Sopenharmony_ci		pr_info("Toshiba SCI not opened\n");
4238c2ecf20Sopenharmony_ci	else if (out[0] == TOS_NOT_PRESENT)
4248c2ecf20Sopenharmony_ci		pr_info("Toshiba SCI is not present\n");
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistatic u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1)
4288c2ecf20Sopenharmony_ci{
4298c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 };
4308c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
4318c2ecf20Sopenharmony_ci	acpi_status status = tci_raw(dev, in, out);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status))
4348c2ecf20Sopenharmony_ci		return TOS_FAILURE;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	*out1 = out[2];
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	return out[0];
4398c2ecf20Sopenharmony_ci}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_cistatic u32 sci_write(struct toshiba_acpi_dev *dev, u32 reg, u32 in1)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { SCI_SET, reg, in1, 0, 0, 0 };
4448c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
4458c2ecf20Sopenharmony_ci	acpi_status status = tci_raw(dev, in, out);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE;
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci/* Illumination support */
4518c2ecf20Sopenharmony_cistatic void toshiba_illumination_available(struct toshiba_acpi_dev *dev)
4528c2ecf20Sopenharmony_ci{
4538c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { SCI_GET, SCI_ILLUMINATION, 0, 0, 0, 0 };
4548c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
4558c2ecf20Sopenharmony_ci	acpi_status status;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	dev->illumination_supported = 0;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	if (!sci_open(dev))
4608c2ecf20Sopenharmony_ci		return;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	status = tci_raw(dev, in, out);
4638c2ecf20Sopenharmony_ci	sci_close(dev);
4648c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
4658c2ecf20Sopenharmony_ci		pr_err("ACPI call to query Illumination support failed\n");
4668c2ecf20Sopenharmony_ci		return;
4678c2ecf20Sopenharmony_ci	}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	if (out[0] != TOS_SUCCESS)
4708c2ecf20Sopenharmony_ci		return;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	dev->illumination_supported = 1;
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_cistatic void toshiba_illumination_set(struct led_classdev *cdev,
4768c2ecf20Sopenharmony_ci				     enum led_brightness brightness)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = container_of(cdev,
4798c2ecf20Sopenharmony_ci			struct toshiba_acpi_dev, led_dev);
4808c2ecf20Sopenharmony_ci	u32 result;
4818c2ecf20Sopenharmony_ci	u32 state;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	/* First request : initialize communication. */
4848c2ecf20Sopenharmony_ci	if (!sci_open(dev))
4858c2ecf20Sopenharmony_ci		return;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	/* Switch the illumination on/off */
4888c2ecf20Sopenharmony_ci	state = brightness ? 1 : 0;
4898c2ecf20Sopenharmony_ci	result = sci_write(dev, SCI_ILLUMINATION, state);
4908c2ecf20Sopenharmony_ci	sci_close(dev);
4918c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
4928c2ecf20Sopenharmony_ci		pr_err("ACPI call for illumination failed\n");
4938c2ecf20Sopenharmony_ci}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_cistatic enum led_brightness toshiba_illumination_get(struct led_classdev *cdev)
4968c2ecf20Sopenharmony_ci{
4978c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = container_of(cdev,
4988c2ecf20Sopenharmony_ci			struct toshiba_acpi_dev, led_dev);
4998c2ecf20Sopenharmony_ci	u32 result;
5008c2ecf20Sopenharmony_ci	u32 state;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	/* First request : initialize communication. */
5038c2ecf20Sopenharmony_ci	if (!sci_open(dev))
5048c2ecf20Sopenharmony_ci		return LED_OFF;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	/* Check the illumination */
5078c2ecf20Sopenharmony_ci	result = sci_read(dev, SCI_ILLUMINATION, &state);
5088c2ecf20Sopenharmony_ci	sci_close(dev);
5098c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE) {
5108c2ecf20Sopenharmony_ci		pr_err("ACPI call for illumination failed\n");
5118c2ecf20Sopenharmony_ci		return LED_OFF;
5128c2ecf20Sopenharmony_ci	} else if (result != TOS_SUCCESS) {
5138c2ecf20Sopenharmony_ci		return LED_OFF;
5148c2ecf20Sopenharmony_ci	}
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	return state ? LED_FULL : LED_OFF;
5178c2ecf20Sopenharmony_ci}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci/* KBD Illumination */
5208c2ecf20Sopenharmony_cistatic void toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev)
5218c2ecf20Sopenharmony_ci{
5228c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { SCI_GET, SCI_KBD_ILLUM_STATUS, 0, 0, 0, 0 };
5238c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
5248c2ecf20Sopenharmony_ci	acpi_status status;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	dev->kbd_illum_supported = 0;
5278c2ecf20Sopenharmony_ci	dev->kbd_event_generated = false;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	if (!sci_open(dev))
5308c2ecf20Sopenharmony_ci		return;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	status = tci_raw(dev, in, out);
5338c2ecf20Sopenharmony_ci	sci_close(dev);
5348c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
5358c2ecf20Sopenharmony_ci		pr_err("ACPI call to query kbd illumination support failed\n");
5368c2ecf20Sopenharmony_ci		return;
5378c2ecf20Sopenharmony_ci	}
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	if (out[0] != TOS_SUCCESS)
5408c2ecf20Sopenharmony_ci		return;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	/*
5438c2ecf20Sopenharmony_ci	 * Check for keyboard backlight timeout max value,
5448c2ecf20Sopenharmony_ci	 * previous kbd backlight implementation set this to
5458c2ecf20Sopenharmony_ci	 * 0x3c0003, and now the new implementation set this
5468c2ecf20Sopenharmony_ci	 * to 0x3c001a, use this to distinguish between them.
5478c2ecf20Sopenharmony_ci	 */
5488c2ecf20Sopenharmony_ci	if (out[3] == SCI_KBD_TIME_MAX)
5498c2ecf20Sopenharmony_ci		dev->kbd_type = 2;
5508c2ecf20Sopenharmony_ci	else
5518c2ecf20Sopenharmony_ci		dev->kbd_type = 1;
5528c2ecf20Sopenharmony_ci	/* Get the current keyboard backlight mode */
5538c2ecf20Sopenharmony_ci	dev->kbd_mode = out[2] & SCI_KBD_MODE_MASK;
5548c2ecf20Sopenharmony_ci	/* Get the current time (1-60 seconds) */
5558c2ecf20Sopenharmony_ci	dev->kbd_time = out[2] >> HCI_MISC_SHIFT;
5568c2ecf20Sopenharmony_ci	/* Flag as supported */
5578c2ecf20Sopenharmony_ci	dev->kbd_illum_supported = 1;
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_cistatic int toshiba_kbd_illum_status_set(struct toshiba_acpi_dev *dev, u32 time)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	u32 result;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	if (!sci_open(dev))
5658c2ecf20Sopenharmony_ci		return -EIO;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	result = sci_write(dev, SCI_KBD_ILLUM_STATUS, time);
5688c2ecf20Sopenharmony_ci	sci_close(dev);
5698c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
5708c2ecf20Sopenharmony_ci		pr_err("ACPI call to set KBD backlight status failed\n");
5718c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
5728c2ecf20Sopenharmony_ci		return -ENODEV;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	return result == TOS_SUCCESS ? 0 : -EIO;
5758c2ecf20Sopenharmony_ci}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_cistatic int toshiba_kbd_illum_status_get(struct toshiba_acpi_dev *dev, u32 *time)
5788c2ecf20Sopenharmony_ci{
5798c2ecf20Sopenharmony_ci	u32 result;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	if (!sci_open(dev))
5828c2ecf20Sopenharmony_ci		return -EIO;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	result = sci_read(dev, SCI_KBD_ILLUM_STATUS, time);
5858c2ecf20Sopenharmony_ci	sci_close(dev);
5868c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
5878c2ecf20Sopenharmony_ci		pr_err("ACPI call to get KBD backlight status failed\n");
5888c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
5898c2ecf20Sopenharmony_ci		return -ENODEV;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	return result == TOS_SUCCESS ? 0 : -EIO;
5928c2ecf20Sopenharmony_ci}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_cistatic enum led_brightness toshiba_kbd_backlight_get(struct led_classdev *cdev)
5958c2ecf20Sopenharmony_ci{
5968c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = container_of(cdev,
5978c2ecf20Sopenharmony_ci			struct toshiba_acpi_dev, kbd_led);
5988c2ecf20Sopenharmony_ci	u32 result;
5998c2ecf20Sopenharmony_ci	u32 state;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	/* Check the keyboard backlight state */
6028c2ecf20Sopenharmony_ci	result = hci_read(dev, HCI_KBD_ILLUMINATION, &state);
6038c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE) {
6048c2ecf20Sopenharmony_ci		pr_err("ACPI call to get the keyboard backlight failed\n");
6058c2ecf20Sopenharmony_ci		return LED_OFF;
6068c2ecf20Sopenharmony_ci	} else if (result != TOS_SUCCESS) {
6078c2ecf20Sopenharmony_ci		return LED_OFF;
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	return state ? LED_FULL : LED_OFF;
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_cistatic void toshiba_kbd_backlight_set(struct led_classdev *cdev,
6148c2ecf20Sopenharmony_ci				     enum led_brightness brightness)
6158c2ecf20Sopenharmony_ci{
6168c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = container_of(cdev,
6178c2ecf20Sopenharmony_ci			struct toshiba_acpi_dev, kbd_led);
6188c2ecf20Sopenharmony_ci	u32 result;
6198c2ecf20Sopenharmony_ci	u32 state;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	/* Set the keyboard backlight state */
6228c2ecf20Sopenharmony_ci	state = brightness ? 1 : 0;
6238c2ecf20Sopenharmony_ci	result = hci_write(dev, HCI_KBD_ILLUMINATION, state);
6248c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
6258c2ecf20Sopenharmony_ci		pr_err("ACPI call to set KBD Illumination mode failed\n");
6268c2ecf20Sopenharmony_ci}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci/* TouchPad support */
6298c2ecf20Sopenharmony_cistatic int toshiba_touchpad_set(struct toshiba_acpi_dev *dev, u32 state)
6308c2ecf20Sopenharmony_ci{
6318c2ecf20Sopenharmony_ci	u32 result;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	if (!sci_open(dev))
6348c2ecf20Sopenharmony_ci		return -EIO;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	result = sci_write(dev, SCI_TOUCHPAD, state);
6378c2ecf20Sopenharmony_ci	sci_close(dev);
6388c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
6398c2ecf20Sopenharmony_ci		pr_err("ACPI call to set the touchpad failed\n");
6408c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
6418c2ecf20Sopenharmony_ci		return -ENODEV;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	return result == TOS_SUCCESS ? 0 : -EIO;
6448c2ecf20Sopenharmony_ci}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_cistatic int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state)
6478c2ecf20Sopenharmony_ci{
6488c2ecf20Sopenharmony_ci	u32 result;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	if (!sci_open(dev))
6518c2ecf20Sopenharmony_ci		return -EIO;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	result = sci_read(dev, SCI_TOUCHPAD, state);
6548c2ecf20Sopenharmony_ci	sci_close(dev);
6558c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
6568c2ecf20Sopenharmony_ci		pr_err("ACPI call to query the touchpad failed\n");
6578c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
6588c2ecf20Sopenharmony_ci		return -ENODEV;
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	return result == TOS_SUCCESS ? 0 : -EIO;
6618c2ecf20Sopenharmony_ci}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci/* Eco Mode support */
6648c2ecf20Sopenharmony_cistatic void toshiba_eco_mode_available(struct toshiba_acpi_dev *dev)
6658c2ecf20Sopenharmony_ci{
6668c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 };
6678c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
6688c2ecf20Sopenharmony_ci	acpi_status status;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	dev->eco_supported = 0;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	status = tci_raw(dev, in, out);
6738c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
6748c2ecf20Sopenharmony_ci		pr_err("ACPI call to get ECO led failed\n");
6758c2ecf20Sopenharmony_ci		return;
6768c2ecf20Sopenharmony_ci	}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	if (out[0] == TOS_INPUT_DATA_ERROR) {
6798c2ecf20Sopenharmony_ci		/*
6808c2ecf20Sopenharmony_ci		 * If we receive 0x8300 (Input Data Error), it means that the
6818c2ecf20Sopenharmony_ci		 * LED device is present, but that we just screwed the input
6828c2ecf20Sopenharmony_ci		 * parameters.
6838c2ecf20Sopenharmony_ci		 *
6848c2ecf20Sopenharmony_ci		 * Let's query the status of the LED to see if we really have a
6858c2ecf20Sopenharmony_ci		 * success response, indicating the actual presense of the LED,
6868c2ecf20Sopenharmony_ci		 * bail out otherwise.
6878c2ecf20Sopenharmony_ci		 */
6888c2ecf20Sopenharmony_ci		in[3] = 1;
6898c2ecf20Sopenharmony_ci		status = tci_raw(dev, in, out);
6908c2ecf20Sopenharmony_ci		if (ACPI_FAILURE(status)) {
6918c2ecf20Sopenharmony_ci			pr_err("ACPI call to get ECO led failed\n");
6928c2ecf20Sopenharmony_ci			return;
6938c2ecf20Sopenharmony_ci		}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci		if (out[0] != TOS_SUCCESS)
6968c2ecf20Sopenharmony_ci			return;
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci		dev->eco_supported = 1;
6998c2ecf20Sopenharmony_ci	}
7008c2ecf20Sopenharmony_ci}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_cistatic enum led_brightness
7038c2ecf20Sopenharmony_citoshiba_eco_mode_get_status(struct led_classdev *cdev)
7048c2ecf20Sopenharmony_ci{
7058c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = container_of(cdev,
7068c2ecf20Sopenharmony_ci			struct toshiba_acpi_dev, eco_led);
7078c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 };
7088c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
7098c2ecf20Sopenharmony_ci	acpi_status status;
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	status = tci_raw(dev, in, out);
7128c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
7138c2ecf20Sopenharmony_ci		pr_err("ACPI call to get ECO led failed\n");
7148c2ecf20Sopenharmony_ci		return LED_OFF;
7158c2ecf20Sopenharmony_ci	}
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	if (out[0] != TOS_SUCCESS)
7188c2ecf20Sopenharmony_ci		return LED_OFF;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	return out[2] ? LED_FULL : LED_OFF;
7218c2ecf20Sopenharmony_ci}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_cistatic void toshiba_eco_mode_set_status(struct led_classdev *cdev,
7248c2ecf20Sopenharmony_ci				     enum led_brightness brightness)
7258c2ecf20Sopenharmony_ci{
7268c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = container_of(cdev,
7278c2ecf20Sopenharmony_ci			struct toshiba_acpi_dev, eco_led);
7288c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { HCI_SET, HCI_ECO_MODE, 0, 1, 0, 0 };
7298c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
7308c2ecf20Sopenharmony_ci	acpi_status status;
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	/* Switch the Eco Mode led on/off */
7338c2ecf20Sopenharmony_ci	in[2] = (brightness) ? 1 : 0;
7348c2ecf20Sopenharmony_ci	status = tci_raw(dev, in, out);
7358c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status))
7368c2ecf20Sopenharmony_ci		pr_err("ACPI call to set ECO led failed\n");
7378c2ecf20Sopenharmony_ci}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci/* Accelerometer support */
7408c2ecf20Sopenharmony_cistatic void toshiba_accelerometer_available(struct toshiba_acpi_dev *dev)
7418c2ecf20Sopenharmony_ci{
7428c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER2, 0, 0, 0, 0 };
7438c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
7448c2ecf20Sopenharmony_ci	acpi_status status;
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	dev->accelerometer_supported = 0;
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	/*
7498c2ecf20Sopenharmony_ci	 * Check if the accelerometer call exists,
7508c2ecf20Sopenharmony_ci	 * this call also serves as initialization
7518c2ecf20Sopenharmony_ci	 */
7528c2ecf20Sopenharmony_ci	status = tci_raw(dev, in, out);
7538c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
7548c2ecf20Sopenharmony_ci		pr_err("ACPI call to query the accelerometer failed\n");
7558c2ecf20Sopenharmony_ci		return;
7568c2ecf20Sopenharmony_ci	}
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	if (out[0] != TOS_SUCCESS)
7598c2ecf20Sopenharmony_ci		return;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	dev->accelerometer_supported = 1;
7628c2ecf20Sopenharmony_ci}
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_cistatic int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev,
7658c2ecf20Sopenharmony_ci				     u32 *xy, u32 *z)
7668c2ecf20Sopenharmony_ci{
7678c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { HCI_GET, HCI_ACCELEROMETER, 0, 1, 0, 0 };
7688c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
7698c2ecf20Sopenharmony_ci	acpi_status status;
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	/* Check the Accelerometer status */
7728c2ecf20Sopenharmony_ci	status = tci_raw(dev, in, out);
7738c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
7748c2ecf20Sopenharmony_ci		pr_err("ACPI call to query the accelerometer failed\n");
7758c2ecf20Sopenharmony_ci		return -EIO;
7768c2ecf20Sopenharmony_ci	}
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	if (out[0] == TOS_NOT_SUPPORTED)
7798c2ecf20Sopenharmony_ci		return -ENODEV;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	if (out[0] != TOS_SUCCESS)
7828c2ecf20Sopenharmony_ci		return -EIO;
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	*xy = out[2];
7858c2ecf20Sopenharmony_ci	*z = out[4];
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	return 0;
7888c2ecf20Sopenharmony_ci}
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci/* Sleep (Charge and Music) utilities support */
7918c2ecf20Sopenharmony_cistatic void toshiba_usb_sleep_charge_available(struct toshiba_acpi_dev *dev)
7928c2ecf20Sopenharmony_ci{
7938c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
7948c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
7958c2ecf20Sopenharmony_ci	acpi_status status;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	dev->usb_sleep_charge_supported = 0;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	if (!sci_open(dev))
8008c2ecf20Sopenharmony_ci		return;
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	status = tci_raw(dev, in, out);
8038c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
8048c2ecf20Sopenharmony_ci		pr_err("ACPI call to get USB Sleep and Charge mode failed\n");
8058c2ecf20Sopenharmony_ci		sci_close(dev);
8068c2ecf20Sopenharmony_ci		return;
8078c2ecf20Sopenharmony_ci	}
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	if (out[0] != TOS_SUCCESS) {
8108c2ecf20Sopenharmony_ci		sci_close(dev);
8118c2ecf20Sopenharmony_ci		return;
8128c2ecf20Sopenharmony_ci	}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	dev->usbsc_mode_base = out[4];
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	in[5] = SCI_USB_CHARGE_BAT_LVL;
8178c2ecf20Sopenharmony_ci	status = tci_raw(dev, in, out);
8188c2ecf20Sopenharmony_ci	sci_close(dev);
8198c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
8208c2ecf20Sopenharmony_ci		pr_err("ACPI call to get USB Sleep and Charge mode failed\n");
8218c2ecf20Sopenharmony_ci		return;
8228c2ecf20Sopenharmony_ci	}
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	if (out[0] != TOS_SUCCESS)
8258c2ecf20Sopenharmony_ci		return;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	dev->usbsc_bat_level = out[2];
8288c2ecf20Sopenharmony_ci	/* Flag as supported */
8298c2ecf20Sopenharmony_ci	dev->usb_sleep_charge_supported = 1;
8308c2ecf20Sopenharmony_ci}
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_cistatic int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev,
8338c2ecf20Sopenharmony_ci					u32 *mode)
8348c2ecf20Sopenharmony_ci{
8358c2ecf20Sopenharmony_ci	u32 result;
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	if (!sci_open(dev))
8388c2ecf20Sopenharmony_ci		return -EIO;
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode);
8418c2ecf20Sopenharmony_ci	sci_close(dev);
8428c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
8438c2ecf20Sopenharmony_ci		pr_err("ACPI call to set USB S&C mode failed\n");
8448c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
8458c2ecf20Sopenharmony_ci		return -ENODEV;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	return result == TOS_SUCCESS ? 0 : -EIO;
8488c2ecf20Sopenharmony_ci}
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_cistatic int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev,
8518c2ecf20Sopenharmony_ci					u32 mode)
8528c2ecf20Sopenharmony_ci{
8538c2ecf20Sopenharmony_ci	u32 result;
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	if (!sci_open(dev))
8568c2ecf20Sopenharmony_ci		return -EIO;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode);
8598c2ecf20Sopenharmony_ci	sci_close(dev);
8608c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
8618c2ecf20Sopenharmony_ci		pr_err("ACPI call to set USB S&C mode failed\n");
8628c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
8638c2ecf20Sopenharmony_ci		return -ENODEV;
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	return result == TOS_SUCCESS ? 0 : -EIO;
8668c2ecf20Sopenharmony_ci}
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_cistatic int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev,
8698c2ecf20Sopenharmony_ci					      u32 *mode)
8708c2ecf20Sopenharmony_ci{
8718c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
8728c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
8738c2ecf20Sopenharmony_ci	acpi_status status;
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	if (!sci_open(dev))
8768c2ecf20Sopenharmony_ci		return -EIO;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	in[5] = SCI_USB_CHARGE_BAT_LVL;
8798c2ecf20Sopenharmony_ci	status = tci_raw(dev, in, out);
8808c2ecf20Sopenharmony_ci	sci_close(dev);
8818c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
8828c2ecf20Sopenharmony_ci		pr_err("ACPI call to get USB S&C battery level failed\n");
8838c2ecf20Sopenharmony_ci		return -EIO;
8848c2ecf20Sopenharmony_ci	}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	if (out[0] == TOS_NOT_SUPPORTED)
8878c2ecf20Sopenharmony_ci		return -ENODEV;
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	if (out[0] != TOS_SUCCESS)
8908c2ecf20Sopenharmony_ci		return -EIO;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	*mode = out[2];
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	return 0;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci}
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_cistatic int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev,
8998c2ecf20Sopenharmony_ci					      u32 mode)
9008c2ecf20Sopenharmony_ci{
9018c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
9028c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
9038c2ecf20Sopenharmony_ci	acpi_status status;
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	if (!sci_open(dev))
9068c2ecf20Sopenharmony_ci		return -EIO;
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	in[2] = mode;
9098c2ecf20Sopenharmony_ci	in[5] = SCI_USB_CHARGE_BAT_LVL;
9108c2ecf20Sopenharmony_ci	status = tci_raw(dev, in, out);
9118c2ecf20Sopenharmony_ci	sci_close(dev);
9128c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
9138c2ecf20Sopenharmony_ci		pr_err("ACPI call to set USB S&C battery level failed\n");
9148c2ecf20Sopenharmony_ci		return -EIO;
9158c2ecf20Sopenharmony_ci	}
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	if (out[0] == TOS_NOT_SUPPORTED)
9188c2ecf20Sopenharmony_ci		return -ENODEV;
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	return out[0] == TOS_SUCCESS ? 0 : -EIO;
9218c2ecf20Sopenharmony_ci}
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_cistatic int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev,
9248c2ecf20Sopenharmony_ci					u32 *state)
9258c2ecf20Sopenharmony_ci{
9268c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
9278c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
9288c2ecf20Sopenharmony_ci	acpi_status status;
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	if (!sci_open(dev))
9318c2ecf20Sopenharmony_ci		return -EIO;
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	in[5] = SCI_USB_CHARGE_RAPID_DSP;
9348c2ecf20Sopenharmony_ci	status = tci_raw(dev, in, out);
9358c2ecf20Sopenharmony_ci	sci_close(dev);
9368c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
9378c2ecf20Sopenharmony_ci		pr_err("ACPI call to get USB Rapid Charge failed\n");
9388c2ecf20Sopenharmony_ci		return -EIO;
9398c2ecf20Sopenharmony_ci	}
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	if (out[0] == TOS_NOT_SUPPORTED)
9428c2ecf20Sopenharmony_ci		return -ENODEV;
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci	if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2)
9458c2ecf20Sopenharmony_ci		return -EIO;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	*state = out[2];
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	return 0;
9508c2ecf20Sopenharmony_ci}
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_cistatic int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev,
9538c2ecf20Sopenharmony_ci					u32 state)
9548c2ecf20Sopenharmony_ci{
9558c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
9568c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
9578c2ecf20Sopenharmony_ci	acpi_status status;
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	if (!sci_open(dev))
9608c2ecf20Sopenharmony_ci		return -EIO;
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci	in[2] = state;
9638c2ecf20Sopenharmony_ci	in[5] = SCI_USB_CHARGE_RAPID_DSP;
9648c2ecf20Sopenharmony_ci	status = tci_raw(dev, in, out);
9658c2ecf20Sopenharmony_ci	sci_close(dev);
9668c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
9678c2ecf20Sopenharmony_ci		pr_err("ACPI call to set USB Rapid Charge failed\n");
9688c2ecf20Sopenharmony_ci		return -EIO;
9698c2ecf20Sopenharmony_ci	}
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	if (out[0] == TOS_NOT_SUPPORTED)
9728c2ecf20Sopenharmony_ci		return -ENODEV;
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci	return (out[0] == TOS_SUCCESS || out[0] == TOS_SUCCESS2) ? 0 : -EIO;
9758c2ecf20Sopenharmony_ci}
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_cistatic int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state)
9788c2ecf20Sopenharmony_ci{
9798c2ecf20Sopenharmony_ci	u32 result;
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	if (!sci_open(dev))
9828c2ecf20Sopenharmony_ci		return -EIO;
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state);
9858c2ecf20Sopenharmony_ci	sci_close(dev);
9868c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
9878c2ecf20Sopenharmony_ci		pr_err("ACPI call to get Sleep and Music failed\n");
9888c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
9898c2ecf20Sopenharmony_ci		return -ENODEV;
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	return result == TOS_SUCCESS ? 0 : -EIO;
9928c2ecf20Sopenharmony_ci}
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_cistatic int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state)
9958c2ecf20Sopenharmony_ci{
9968c2ecf20Sopenharmony_ci	u32 result;
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	if (!sci_open(dev))
9998c2ecf20Sopenharmony_ci		return -EIO;
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state);
10028c2ecf20Sopenharmony_ci	sci_close(dev);
10038c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
10048c2ecf20Sopenharmony_ci		pr_err("ACPI call to set Sleep and Music failed\n");
10058c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
10068c2ecf20Sopenharmony_ci		return -ENODEV;
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	return result == TOS_SUCCESS ? 0 : -EIO;
10098c2ecf20Sopenharmony_ci}
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci/* Keyboard function keys */
10128c2ecf20Sopenharmony_cistatic int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode)
10138c2ecf20Sopenharmony_ci{
10148c2ecf20Sopenharmony_ci	u32 result;
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	if (!sci_open(dev))
10178c2ecf20Sopenharmony_ci		return -EIO;
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	result = sci_read(dev, SCI_KBD_FUNCTION_KEYS, mode);
10208c2ecf20Sopenharmony_ci	sci_close(dev);
10218c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
10228c2ecf20Sopenharmony_ci		pr_err("ACPI call to get KBD function keys failed\n");
10238c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
10248c2ecf20Sopenharmony_ci		return -ENODEV;
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
10278c2ecf20Sopenharmony_ci}
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_cistatic int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode)
10308c2ecf20Sopenharmony_ci{
10318c2ecf20Sopenharmony_ci	u32 result;
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	if (!sci_open(dev))
10348c2ecf20Sopenharmony_ci		return -EIO;
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	result = sci_write(dev, SCI_KBD_FUNCTION_KEYS, mode);
10378c2ecf20Sopenharmony_ci	sci_close(dev);
10388c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
10398c2ecf20Sopenharmony_ci		pr_err("ACPI call to set KBD function keys failed\n");
10408c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
10418c2ecf20Sopenharmony_ci		return -ENODEV;
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
10448c2ecf20Sopenharmony_ci}
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci/* Panel Power ON */
10478c2ecf20Sopenharmony_cistatic int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state)
10488c2ecf20Sopenharmony_ci{
10498c2ecf20Sopenharmony_ci	u32 result;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	if (!sci_open(dev))
10528c2ecf20Sopenharmony_ci		return -EIO;
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	result = sci_read(dev, SCI_PANEL_POWER_ON, state);
10558c2ecf20Sopenharmony_ci	sci_close(dev);
10568c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
10578c2ecf20Sopenharmony_ci		pr_err("ACPI call to get Panel Power ON failed\n");
10588c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
10598c2ecf20Sopenharmony_ci		return -ENODEV;
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	return result == TOS_SUCCESS ? 0 : -EIO;
10628c2ecf20Sopenharmony_ci}
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_cistatic int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state)
10658c2ecf20Sopenharmony_ci{
10668c2ecf20Sopenharmony_ci	u32 result;
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	if (!sci_open(dev))
10698c2ecf20Sopenharmony_ci		return -EIO;
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	result = sci_write(dev, SCI_PANEL_POWER_ON, state);
10728c2ecf20Sopenharmony_ci	sci_close(dev);
10738c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
10748c2ecf20Sopenharmony_ci		pr_err("ACPI call to set Panel Power ON failed\n");
10758c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
10768c2ecf20Sopenharmony_ci		return -ENODEV;
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	return result == TOS_SUCCESS ? 0 : -EIO;
10798c2ecf20Sopenharmony_ci}
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci/* USB Three */
10828c2ecf20Sopenharmony_cistatic int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state)
10838c2ecf20Sopenharmony_ci{
10848c2ecf20Sopenharmony_ci	u32 result;
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	if (!sci_open(dev))
10878c2ecf20Sopenharmony_ci		return -EIO;
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	result = sci_read(dev, SCI_USB_THREE, state);
10908c2ecf20Sopenharmony_ci	sci_close(dev);
10918c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
10928c2ecf20Sopenharmony_ci		pr_err("ACPI call to get USB 3 failed\n");
10938c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
10948c2ecf20Sopenharmony_ci		return -ENODEV;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
10978c2ecf20Sopenharmony_ci}
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_cistatic int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state)
11008c2ecf20Sopenharmony_ci{
11018c2ecf20Sopenharmony_ci	u32 result;
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	if (!sci_open(dev))
11048c2ecf20Sopenharmony_ci		return -EIO;
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	result = sci_write(dev, SCI_USB_THREE, state);
11078c2ecf20Sopenharmony_ci	sci_close(dev);
11088c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
11098c2ecf20Sopenharmony_ci		pr_err("ACPI call to set USB 3 failed\n");
11108c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
11118c2ecf20Sopenharmony_ci		return -ENODEV;
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci	return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
11148c2ecf20Sopenharmony_ci}
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci/* Hotkey Event type */
11178c2ecf20Sopenharmony_cistatic int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev,
11188c2ecf20Sopenharmony_ci					 u32 *type)
11198c2ecf20Sopenharmony_ci{
11208c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { HCI_GET, HCI_SYSTEM_INFO, 0x03, 0, 0, 0 };
11218c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
11228c2ecf20Sopenharmony_ci	acpi_status status;
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	status = tci_raw(dev, in, out);
11258c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
11268c2ecf20Sopenharmony_ci		pr_err("ACPI call to get System type failed\n");
11278c2ecf20Sopenharmony_ci		return -EIO;
11288c2ecf20Sopenharmony_ci	}
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	if (out[0] == TOS_NOT_SUPPORTED)
11318c2ecf20Sopenharmony_ci		return -ENODEV;
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci	if (out[0] != TOS_SUCCESS)
11348c2ecf20Sopenharmony_ci		return -EIO;
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci	*type = out[3];
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	return 0;
11398c2ecf20Sopenharmony_ci}
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci/* Wireless status (RFKill, WLAN, BT, WWAN) */
11428c2ecf20Sopenharmony_cistatic int toshiba_wireless_status(struct toshiba_acpi_dev *dev)
11438c2ecf20Sopenharmony_ci{
11448c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { HCI_GET, HCI_WIRELESS, 0, 0, 0, 0 };
11458c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
11468c2ecf20Sopenharmony_ci	acpi_status status;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	in[3] = HCI_WIRELESS_STATUS;
11498c2ecf20Sopenharmony_ci	status = tci_raw(dev, in, out);
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
11528c2ecf20Sopenharmony_ci		pr_err("ACPI call to get Wireless status failed\n");
11538c2ecf20Sopenharmony_ci		return -EIO;
11548c2ecf20Sopenharmony_ci	}
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci	if (out[0] == TOS_NOT_SUPPORTED)
11578c2ecf20Sopenharmony_ci		return -ENODEV;
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	if (out[0] != TOS_SUCCESS)
11608c2ecf20Sopenharmony_ci		return -EIO;
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	dev->killswitch = !!(out[2] & HCI_WIRELESS_STATUS);
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci	return 0;
11658c2ecf20Sopenharmony_ci}
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci/* WWAN */
11688c2ecf20Sopenharmony_cistatic void toshiba_wwan_available(struct toshiba_acpi_dev *dev)
11698c2ecf20Sopenharmony_ci{
11708c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { HCI_GET, HCI_WIRELESS, 0, 0, 0, 0 };
11718c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
11728c2ecf20Sopenharmony_ci	acpi_status status;
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci	dev->wwan_supported = 0;
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	/*
11778c2ecf20Sopenharmony_ci	 * WWAN support can be queried by setting the in[3] value to
11788c2ecf20Sopenharmony_ci	 * HCI_WIRELESS_WWAN (0x03).
11798c2ecf20Sopenharmony_ci	 *
11808c2ecf20Sopenharmony_ci	 * If supported, out[0] contains TOS_SUCCESS and out[2] contains
11818c2ecf20Sopenharmony_ci	 * HCI_WIRELESS_WWAN_STATUS (0x2000).
11828c2ecf20Sopenharmony_ci	 *
11838c2ecf20Sopenharmony_ci	 * If not supported, out[0] contains TOS_INPUT_DATA_ERROR (0x8300)
11848c2ecf20Sopenharmony_ci	 * or TOS_NOT_SUPPORTED (0x8000).
11858c2ecf20Sopenharmony_ci	 */
11868c2ecf20Sopenharmony_ci	in[3] = HCI_WIRELESS_WWAN;
11878c2ecf20Sopenharmony_ci	status = tci_raw(dev, in, out);
11888c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
11898c2ecf20Sopenharmony_ci		pr_err("ACPI call to get WWAN status failed\n");
11908c2ecf20Sopenharmony_ci		return;
11918c2ecf20Sopenharmony_ci	}
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	if (out[0] != TOS_SUCCESS)
11948c2ecf20Sopenharmony_ci		return;
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci	dev->wwan_supported = (out[2] == HCI_WIRELESS_WWAN_STATUS);
11978c2ecf20Sopenharmony_ci}
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_cistatic int toshiba_wwan_set(struct toshiba_acpi_dev *dev, u32 state)
12008c2ecf20Sopenharmony_ci{
12018c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { HCI_SET, HCI_WIRELESS, state, 0, 0, 0 };
12028c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
12038c2ecf20Sopenharmony_ci	acpi_status status;
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	in[3] = HCI_WIRELESS_WWAN_STATUS;
12068c2ecf20Sopenharmony_ci	status = tci_raw(dev, in, out);
12078c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
12088c2ecf20Sopenharmony_ci		pr_err("ACPI call to set WWAN status failed\n");
12098c2ecf20Sopenharmony_ci		return -EIO;
12108c2ecf20Sopenharmony_ci	}
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	if (out[0] == TOS_NOT_SUPPORTED)
12138c2ecf20Sopenharmony_ci		return -ENODEV;
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	if (out[0] != TOS_SUCCESS)
12168c2ecf20Sopenharmony_ci		return -EIO;
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	/*
12198c2ecf20Sopenharmony_ci	 * Some devices only need to call HCI_WIRELESS_WWAN_STATUS to
12208c2ecf20Sopenharmony_ci	 * (de)activate the device, but some others need the
12218c2ecf20Sopenharmony_ci	 * HCI_WIRELESS_WWAN_POWER call as well.
12228c2ecf20Sopenharmony_ci	 */
12238c2ecf20Sopenharmony_ci	in[3] = HCI_WIRELESS_WWAN_POWER;
12248c2ecf20Sopenharmony_ci	status = tci_raw(dev, in, out);
12258c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
12268c2ecf20Sopenharmony_ci		pr_err("ACPI call to set WWAN power failed\n");
12278c2ecf20Sopenharmony_ci		return -EIO;
12288c2ecf20Sopenharmony_ci	}
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	if (out[0] == TOS_NOT_SUPPORTED)
12318c2ecf20Sopenharmony_ci		return -ENODEV;
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	return out[0] == TOS_SUCCESS ? 0 : -EIO;
12348c2ecf20Sopenharmony_ci}
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci/* Cooling Method */
12378c2ecf20Sopenharmony_cistatic void toshiba_cooling_method_available(struct toshiba_acpi_dev *dev)
12388c2ecf20Sopenharmony_ci{
12398c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { HCI_GET, HCI_COOLING_METHOD, 0, 0, 0, 0 };
12408c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
12418c2ecf20Sopenharmony_ci	acpi_status status;
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	dev->cooling_method_supported = 0;
12448c2ecf20Sopenharmony_ci	dev->max_cooling_method = 0;
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	status = tci_raw(dev, in, out);
12478c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
12488c2ecf20Sopenharmony_ci		pr_err("ACPI call to get Cooling Method failed\n");
12498c2ecf20Sopenharmony_ci		return;
12508c2ecf20Sopenharmony_ci	}
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2)
12538c2ecf20Sopenharmony_ci		return;
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci	dev->cooling_method_supported = 1;
12568c2ecf20Sopenharmony_ci	dev->max_cooling_method = out[3];
12578c2ecf20Sopenharmony_ci}
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_cistatic int toshiba_cooling_method_get(struct toshiba_acpi_dev *dev, u32 *state)
12608c2ecf20Sopenharmony_ci{
12618c2ecf20Sopenharmony_ci	u32 result = hci_read(dev, HCI_COOLING_METHOD, state);
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
12648c2ecf20Sopenharmony_ci		pr_err("ACPI call to get Cooling Method failed\n");
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	if (result == TOS_NOT_SUPPORTED)
12678c2ecf20Sopenharmony_ci		return -ENODEV;
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci	return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
12708c2ecf20Sopenharmony_ci}
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_cistatic int toshiba_cooling_method_set(struct toshiba_acpi_dev *dev, u32 state)
12738c2ecf20Sopenharmony_ci{
12748c2ecf20Sopenharmony_ci	u32 result = hci_write(dev, HCI_COOLING_METHOD, state);
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
12778c2ecf20Sopenharmony_ci		pr_err("ACPI call to set Cooling Method failed\n");
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	if (result == TOS_NOT_SUPPORTED)
12808c2ecf20Sopenharmony_ci		return -ENODEV;
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci	return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO;
12838c2ecf20Sopenharmony_ci}
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_ci/* Transflective Backlight */
12868c2ecf20Sopenharmony_cistatic int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status)
12878c2ecf20Sopenharmony_ci{
12888c2ecf20Sopenharmony_ci	u32 result = hci_read(dev, HCI_TR_BACKLIGHT, status);
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
12918c2ecf20Sopenharmony_ci		pr_err("ACPI call to get Transflective Backlight failed\n");
12928c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
12938c2ecf20Sopenharmony_ci		return -ENODEV;
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci	return result == TOS_SUCCESS ? 0 : -EIO;
12968c2ecf20Sopenharmony_ci}
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_cistatic int set_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 status)
12998c2ecf20Sopenharmony_ci{
13008c2ecf20Sopenharmony_ci	u32 result = hci_write(dev, HCI_TR_BACKLIGHT, !status);
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
13038c2ecf20Sopenharmony_ci		pr_err("ACPI call to set Transflective Backlight failed\n");
13048c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
13058c2ecf20Sopenharmony_ci		return -ENODEV;
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	return result == TOS_SUCCESS ? 0 : -EIO;
13088c2ecf20Sopenharmony_ci}
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_cistatic struct proc_dir_entry *toshiba_proc_dir;
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci/* LCD Brightness */
13138c2ecf20Sopenharmony_cistatic int __get_lcd_brightness(struct toshiba_acpi_dev *dev)
13148c2ecf20Sopenharmony_ci{
13158c2ecf20Sopenharmony_ci	int brightness = 0;
13168c2ecf20Sopenharmony_ci	u32 result;
13178c2ecf20Sopenharmony_ci	u32 value;
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci	if (dev->tr_backlight_supported) {
13208c2ecf20Sopenharmony_ci		int ret = get_tr_backlight_status(dev, &value);
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci		if (ret)
13238c2ecf20Sopenharmony_ci			return ret;
13248c2ecf20Sopenharmony_ci		if (value)
13258c2ecf20Sopenharmony_ci			return 0;
13268c2ecf20Sopenharmony_ci		brightness++;
13278c2ecf20Sopenharmony_ci	}
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci	result = hci_read(dev, HCI_LCD_BRIGHTNESS, &value);
13308c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
13318c2ecf20Sopenharmony_ci		pr_err("ACPI call to get LCD Brightness failed\n");
13328c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
13338c2ecf20Sopenharmony_ci		return -ENODEV;
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci	return result == TOS_SUCCESS ?
13368c2ecf20Sopenharmony_ci			brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT) :
13378c2ecf20Sopenharmony_ci			-EIO;
13388c2ecf20Sopenharmony_ci}
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_cistatic int get_lcd_brightness(struct backlight_device *bd)
13418c2ecf20Sopenharmony_ci{
13428c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = bl_get_data(bd);
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	return __get_lcd_brightness(dev);
13458c2ecf20Sopenharmony_ci}
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_cistatic int lcd_proc_show(struct seq_file *m, void *v)
13488c2ecf20Sopenharmony_ci{
13498c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = m->private;
13508c2ecf20Sopenharmony_ci	int levels;
13518c2ecf20Sopenharmony_ci	int value;
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci	if (!dev->backlight_dev)
13548c2ecf20Sopenharmony_ci		return -ENODEV;
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	levels = dev->backlight_dev->props.max_brightness + 1;
13578c2ecf20Sopenharmony_ci	value = get_lcd_brightness(dev->backlight_dev);
13588c2ecf20Sopenharmony_ci	if (value < 0) {
13598c2ecf20Sopenharmony_ci		pr_err("Error reading LCD brightness\n");
13608c2ecf20Sopenharmony_ci		return value;
13618c2ecf20Sopenharmony_ci	}
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	seq_printf(m, "brightness:              %d\n", value);
13648c2ecf20Sopenharmony_ci	seq_printf(m, "brightness_levels:       %d\n", levels);
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_ci	return 0;
13678c2ecf20Sopenharmony_ci}
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_cistatic int lcd_proc_open(struct inode *inode, struct file *file)
13708c2ecf20Sopenharmony_ci{
13718c2ecf20Sopenharmony_ci	return single_open(file, lcd_proc_show, PDE_DATA(inode));
13728c2ecf20Sopenharmony_ci}
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_cistatic int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
13758c2ecf20Sopenharmony_ci{
13768c2ecf20Sopenharmony_ci	u32 result;
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	if (dev->tr_backlight_supported) {
13798c2ecf20Sopenharmony_ci		int ret = set_tr_backlight_status(dev, !value);
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci		if (ret)
13828c2ecf20Sopenharmony_ci			return ret;
13838c2ecf20Sopenharmony_ci		if (value)
13848c2ecf20Sopenharmony_ci			value--;
13858c2ecf20Sopenharmony_ci	}
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci	value = value << HCI_LCD_BRIGHTNESS_SHIFT;
13888c2ecf20Sopenharmony_ci	result = hci_write(dev, HCI_LCD_BRIGHTNESS, value);
13898c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
13908c2ecf20Sopenharmony_ci		pr_err("ACPI call to set LCD Brightness failed\n");
13918c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
13928c2ecf20Sopenharmony_ci		return -ENODEV;
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	return result == TOS_SUCCESS ? 0 : -EIO;
13958c2ecf20Sopenharmony_ci}
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_cistatic int set_lcd_status(struct backlight_device *bd)
13988c2ecf20Sopenharmony_ci{
13998c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = bl_get_data(bd);
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	return set_lcd_brightness(dev, bd->props.brightness);
14028c2ecf20Sopenharmony_ci}
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_cistatic ssize_t lcd_proc_write(struct file *file, const char __user *buf,
14058c2ecf20Sopenharmony_ci			      size_t count, loff_t *pos)
14068c2ecf20Sopenharmony_ci{
14078c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
14088c2ecf20Sopenharmony_ci	char cmd[42];
14098c2ecf20Sopenharmony_ci	size_t len;
14108c2ecf20Sopenharmony_ci	int levels;
14118c2ecf20Sopenharmony_ci	int value;
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	len = min(count, sizeof(cmd) - 1);
14148c2ecf20Sopenharmony_ci	if (copy_from_user(cmd, buf, len))
14158c2ecf20Sopenharmony_ci		return -EFAULT;
14168c2ecf20Sopenharmony_ci	cmd[len] = '\0';
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	levels = dev->backlight_dev->props.max_brightness + 1;
14198c2ecf20Sopenharmony_ci	if (sscanf(cmd, " brightness : %i", &value) != 1 &&
14208c2ecf20Sopenharmony_ci	    value < 0 && value > levels)
14218c2ecf20Sopenharmony_ci		return -EINVAL;
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci	if (set_lcd_brightness(dev, value))
14248c2ecf20Sopenharmony_ci		return -EIO;
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci	return count;
14278c2ecf20Sopenharmony_ci}
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_cistatic const struct proc_ops lcd_proc_ops = {
14308c2ecf20Sopenharmony_ci	.proc_open	= lcd_proc_open,
14318c2ecf20Sopenharmony_ci	.proc_read	= seq_read,
14328c2ecf20Sopenharmony_ci	.proc_lseek	= seq_lseek,
14338c2ecf20Sopenharmony_ci	.proc_release	= single_release,
14348c2ecf20Sopenharmony_ci	.proc_write	= lcd_proc_write,
14358c2ecf20Sopenharmony_ci};
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_ci/* Video-Out */
14388c2ecf20Sopenharmony_cistatic int get_video_status(struct toshiba_acpi_dev *dev, u32 *status)
14398c2ecf20Sopenharmony_ci{
14408c2ecf20Sopenharmony_ci	u32 result = hci_read(dev, HCI_VIDEO_OUT, status);
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
14438c2ecf20Sopenharmony_ci		pr_err("ACPI call to get Video-Out failed\n");
14448c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
14458c2ecf20Sopenharmony_ci		return -ENODEV;
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci	return result == TOS_SUCCESS ? 0 : -EIO;
14488c2ecf20Sopenharmony_ci}
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_cistatic int video_proc_show(struct seq_file *m, void *v)
14518c2ecf20Sopenharmony_ci{
14528c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = m->private;
14538c2ecf20Sopenharmony_ci	int is_lcd, is_crt, is_tv;
14548c2ecf20Sopenharmony_ci	u32 value;
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci	if (get_video_status(dev, &value))
14578c2ecf20Sopenharmony_ci		return -EIO;
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0;
14608c2ecf20Sopenharmony_ci	is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0;
14618c2ecf20Sopenharmony_ci	is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0;
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	seq_printf(m, "lcd_out:                 %d\n", is_lcd);
14648c2ecf20Sopenharmony_ci	seq_printf(m, "crt_out:                 %d\n", is_crt);
14658c2ecf20Sopenharmony_ci	seq_printf(m, "tv_out:                  %d\n", is_tv);
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci	return 0;
14688c2ecf20Sopenharmony_ci}
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_cistatic int video_proc_open(struct inode *inode, struct file *file)
14718c2ecf20Sopenharmony_ci{
14728c2ecf20Sopenharmony_ci	return single_open(file, video_proc_show, PDE_DATA(inode));
14738c2ecf20Sopenharmony_ci}
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_cistatic ssize_t video_proc_write(struct file *file, const char __user *buf,
14768c2ecf20Sopenharmony_ci				size_t count, loff_t *pos)
14778c2ecf20Sopenharmony_ci{
14788c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
14798c2ecf20Sopenharmony_ci	char *buffer;
14808c2ecf20Sopenharmony_ci	char *cmd;
14818c2ecf20Sopenharmony_ci	int lcd_out = -1, crt_out = -1, tv_out = -1;
14828c2ecf20Sopenharmony_ci	int remain = count;
14838c2ecf20Sopenharmony_ci	int value;
14848c2ecf20Sopenharmony_ci	int ret;
14858c2ecf20Sopenharmony_ci	u32 video_out;
14868c2ecf20Sopenharmony_ci
14878c2ecf20Sopenharmony_ci	cmd = memdup_user_nul(buf, count);
14888c2ecf20Sopenharmony_ci	if (IS_ERR(cmd))
14898c2ecf20Sopenharmony_ci		return PTR_ERR(cmd);
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci	buffer = cmd;
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_ci	/*
14948c2ecf20Sopenharmony_ci	 * Scan expression.  Multiple expressions may be delimited with ;
14958c2ecf20Sopenharmony_ci	 * NOTE: To keep scanning simple, invalid fields are ignored.
14968c2ecf20Sopenharmony_ci	 */
14978c2ecf20Sopenharmony_ci	while (remain) {
14988c2ecf20Sopenharmony_ci		if (sscanf(buffer, " lcd_out : %i", &value) == 1)
14998c2ecf20Sopenharmony_ci			lcd_out = value & 1;
15008c2ecf20Sopenharmony_ci		else if (sscanf(buffer, " crt_out : %i", &value) == 1)
15018c2ecf20Sopenharmony_ci			crt_out = value & 1;
15028c2ecf20Sopenharmony_ci		else if (sscanf(buffer, " tv_out : %i", &value) == 1)
15038c2ecf20Sopenharmony_ci			tv_out = value & 1;
15048c2ecf20Sopenharmony_ci		/* Advance to one character past the next ; */
15058c2ecf20Sopenharmony_ci		do {
15068c2ecf20Sopenharmony_ci			++buffer;
15078c2ecf20Sopenharmony_ci			--remain;
15088c2ecf20Sopenharmony_ci		} while (remain && *(buffer - 1) != ';');
15098c2ecf20Sopenharmony_ci	}
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci	kfree(cmd);
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci	ret = get_video_status(dev, &video_out);
15148c2ecf20Sopenharmony_ci	if (!ret) {
15158c2ecf20Sopenharmony_ci		unsigned int new_video_out = video_out;
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci		if (lcd_out != -1)
15188c2ecf20Sopenharmony_ci			_set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out);
15198c2ecf20Sopenharmony_ci		if (crt_out != -1)
15208c2ecf20Sopenharmony_ci			_set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out);
15218c2ecf20Sopenharmony_ci		if (tv_out != -1)
15228c2ecf20Sopenharmony_ci			_set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out);
15238c2ecf20Sopenharmony_ci		/*
15248c2ecf20Sopenharmony_ci		 * To avoid unnecessary video disruption, only write the new
15258c2ecf20Sopenharmony_ci		 * video setting if something changed.
15268c2ecf20Sopenharmony_ci		 */
15278c2ecf20Sopenharmony_ci		if (new_video_out != video_out)
15288c2ecf20Sopenharmony_ci			ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out);
15298c2ecf20Sopenharmony_ci	}
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci	return ret ? -EIO : count;
15328c2ecf20Sopenharmony_ci}
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_cistatic const struct proc_ops video_proc_ops = {
15358c2ecf20Sopenharmony_ci	.proc_open	= video_proc_open,
15368c2ecf20Sopenharmony_ci	.proc_read	= seq_read,
15378c2ecf20Sopenharmony_ci	.proc_lseek	= seq_lseek,
15388c2ecf20Sopenharmony_ci	.proc_release	= single_release,
15398c2ecf20Sopenharmony_ci	.proc_write	= video_proc_write,
15408c2ecf20Sopenharmony_ci};
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci/* Fan status */
15438c2ecf20Sopenharmony_cistatic int get_fan_status(struct toshiba_acpi_dev *dev, u32 *status)
15448c2ecf20Sopenharmony_ci{
15458c2ecf20Sopenharmony_ci	u32 result = hci_read(dev, HCI_FAN, status);
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
15488c2ecf20Sopenharmony_ci		pr_err("ACPI call to get Fan status failed\n");
15498c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
15508c2ecf20Sopenharmony_ci		return -ENODEV;
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci	return result == TOS_SUCCESS ? 0 : -EIO;
15538c2ecf20Sopenharmony_ci}
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_cistatic int set_fan_status(struct toshiba_acpi_dev *dev, u32 status)
15568c2ecf20Sopenharmony_ci{
15578c2ecf20Sopenharmony_ci	u32 result = hci_write(dev, HCI_FAN, status);
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
15608c2ecf20Sopenharmony_ci		pr_err("ACPI call to set Fan status failed\n");
15618c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
15628c2ecf20Sopenharmony_ci		return -ENODEV;
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ci	return result == TOS_SUCCESS ? 0 : -EIO;
15658c2ecf20Sopenharmony_ci}
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_cistatic int fan_proc_show(struct seq_file *m, void *v)
15688c2ecf20Sopenharmony_ci{
15698c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = m->private;
15708c2ecf20Sopenharmony_ci	u32 value;
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci	if (get_fan_status(dev, &value))
15738c2ecf20Sopenharmony_ci		return -EIO;
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci	seq_printf(m, "running:                 %d\n", (value > 0));
15768c2ecf20Sopenharmony_ci	seq_printf(m, "force_on:                %d\n", dev->force_fan);
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci	return 0;
15798c2ecf20Sopenharmony_ci}
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_cistatic int fan_proc_open(struct inode *inode, struct file *file)
15828c2ecf20Sopenharmony_ci{
15838c2ecf20Sopenharmony_ci	return single_open(file, fan_proc_show, PDE_DATA(inode));
15848c2ecf20Sopenharmony_ci}
15858c2ecf20Sopenharmony_ci
15868c2ecf20Sopenharmony_cistatic ssize_t fan_proc_write(struct file *file, const char __user *buf,
15878c2ecf20Sopenharmony_ci			      size_t count, loff_t *pos)
15888c2ecf20Sopenharmony_ci{
15898c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
15908c2ecf20Sopenharmony_ci	char cmd[42];
15918c2ecf20Sopenharmony_ci	size_t len;
15928c2ecf20Sopenharmony_ci	int value;
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_ci	len = min(count, sizeof(cmd) - 1);
15958c2ecf20Sopenharmony_ci	if (copy_from_user(cmd, buf, len))
15968c2ecf20Sopenharmony_ci		return -EFAULT;
15978c2ecf20Sopenharmony_ci	cmd[len] = '\0';
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci	if (sscanf(cmd, " force_on : %i", &value) != 1 &&
16008c2ecf20Sopenharmony_ci	    value != 0 && value != 1)
16018c2ecf20Sopenharmony_ci		return -EINVAL;
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci	if (set_fan_status(dev, value))
16048c2ecf20Sopenharmony_ci		return -EIO;
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	dev->force_fan = value;
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci	return count;
16098c2ecf20Sopenharmony_ci}
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_cistatic const struct proc_ops fan_proc_ops = {
16128c2ecf20Sopenharmony_ci	.proc_open	= fan_proc_open,
16138c2ecf20Sopenharmony_ci	.proc_read	= seq_read,
16148c2ecf20Sopenharmony_ci	.proc_lseek	= seq_lseek,
16158c2ecf20Sopenharmony_ci	.proc_release	= single_release,
16168c2ecf20Sopenharmony_ci	.proc_write	= fan_proc_write,
16178c2ecf20Sopenharmony_ci};
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_cistatic int keys_proc_show(struct seq_file *m, void *v)
16208c2ecf20Sopenharmony_ci{
16218c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = m->private;
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci	seq_printf(m, "hotkey_ready:            %d\n", dev->key_event_valid);
16248c2ecf20Sopenharmony_ci	seq_printf(m, "hotkey:                  0x%04x\n", dev->last_key_event);
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	return 0;
16278c2ecf20Sopenharmony_ci}
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_cistatic int keys_proc_open(struct inode *inode, struct file *file)
16308c2ecf20Sopenharmony_ci{
16318c2ecf20Sopenharmony_ci	return single_open(file, keys_proc_show, PDE_DATA(inode));
16328c2ecf20Sopenharmony_ci}
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_cistatic ssize_t keys_proc_write(struct file *file, const char __user *buf,
16358c2ecf20Sopenharmony_ci			       size_t count, loff_t *pos)
16368c2ecf20Sopenharmony_ci{
16378c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = PDE_DATA(file_inode(file));
16388c2ecf20Sopenharmony_ci	char cmd[42];
16398c2ecf20Sopenharmony_ci	size_t len;
16408c2ecf20Sopenharmony_ci	int value;
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_ci	len = min(count, sizeof(cmd) - 1);
16438c2ecf20Sopenharmony_ci	if (copy_from_user(cmd, buf, len))
16448c2ecf20Sopenharmony_ci		return -EFAULT;
16458c2ecf20Sopenharmony_ci	cmd[len] = '\0';
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci	if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0)
16488c2ecf20Sopenharmony_ci		dev->key_event_valid = 0;
16498c2ecf20Sopenharmony_ci	else
16508c2ecf20Sopenharmony_ci		return -EINVAL;
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	return count;
16538c2ecf20Sopenharmony_ci}
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_cistatic const struct proc_ops keys_proc_ops = {
16568c2ecf20Sopenharmony_ci	.proc_open	= keys_proc_open,
16578c2ecf20Sopenharmony_ci	.proc_read	= seq_read,
16588c2ecf20Sopenharmony_ci	.proc_lseek	= seq_lseek,
16598c2ecf20Sopenharmony_ci	.proc_release	= single_release,
16608c2ecf20Sopenharmony_ci	.proc_write	= keys_proc_write,
16618c2ecf20Sopenharmony_ci};
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_cistatic int __maybe_unused version_proc_show(struct seq_file *m, void *v)
16648c2ecf20Sopenharmony_ci{
16658c2ecf20Sopenharmony_ci	seq_printf(m, "driver:                  %s\n", TOSHIBA_ACPI_VERSION);
16668c2ecf20Sopenharmony_ci	seq_printf(m, "proc_interface:          %d\n", PROC_INTERFACE_VERSION);
16678c2ecf20Sopenharmony_ci	return 0;
16688c2ecf20Sopenharmony_ci}
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci/*
16718c2ecf20Sopenharmony_ci * Proc and module init
16728c2ecf20Sopenharmony_ci */
16738c2ecf20Sopenharmony_ci
16748c2ecf20Sopenharmony_ci#define PROC_TOSHIBA		"toshiba"
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_cistatic void create_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
16778c2ecf20Sopenharmony_ci{
16788c2ecf20Sopenharmony_ci	if (dev->backlight_dev)
16798c2ecf20Sopenharmony_ci		proc_create_data("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir,
16808c2ecf20Sopenharmony_ci				 &lcd_proc_ops, dev);
16818c2ecf20Sopenharmony_ci	if (dev->video_supported)
16828c2ecf20Sopenharmony_ci		proc_create_data("video", S_IRUGO | S_IWUSR, toshiba_proc_dir,
16838c2ecf20Sopenharmony_ci				 &video_proc_ops, dev);
16848c2ecf20Sopenharmony_ci	if (dev->fan_supported)
16858c2ecf20Sopenharmony_ci		proc_create_data("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir,
16868c2ecf20Sopenharmony_ci				 &fan_proc_ops, dev);
16878c2ecf20Sopenharmony_ci	if (dev->hotkey_dev)
16888c2ecf20Sopenharmony_ci		proc_create_data("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir,
16898c2ecf20Sopenharmony_ci				 &keys_proc_ops, dev);
16908c2ecf20Sopenharmony_ci	proc_create_single_data("version", S_IRUGO, toshiba_proc_dir,
16918c2ecf20Sopenharmony_ci			version_proc_show, dev);
16928c2ecf20Sopenharmony_ci}
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_cistatic void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
16958c2ecf20Sopenharmony_ci{
16968c2ecf20Sopenharmony_ci	if (dev->backlight_dev)
16978c2ecf20Sopenharmony_ci		remove_proc_entry("lcd", toshiba_proc_dir);
16988c2ecf20Sopenharmony_ci	if (dev->video_supported)
16998c2ecf20Sopenharmony_ci		remove_proc_entry("video", toshiba_proc_dir);
17008c2ecf20Sopenharmony_ci	if (dev->fan_supported)
17018c2ecf20Sopenharmony_ci		remove_proc_entry("fan", toshiba_proc_dir);
17028c2ecf20Sopenharmony_ci	if (dev->hotkey_dev)
17038c2ecf20Sopenharmony_ci		remove_proc_entry("keys", toshiba_proc_dir);
17048c2ecf20Sopenharmony_ci	remove_proc_entry("version", toshiba_proc_dir);
17058c2ecf20Sopenharmony_ci}
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_cistatic const struct backlight_ops toshiba_backlight_data = {
17088c2ecf20Sopenharmony_ci	.options = BL_CORE_SUSPENDRESUME,
17098c2ecf20Sopenharmony_ci	.get_brightness = get_lcd_brightness,
17108c2ecf20Sopenharmony_ci	.update_status  = set_lcd_status,
17118c2ecf20Sopenharmony_ci};
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci/* Keyboard backlight work */
17148c2ecf20Sopenharmony_cistatic void toshiba_acpi_kbd_bl_work(struct work_struct *work);
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_cistatic DECLARE_WORK(kbd_bl_work, toshiba_acpi_kbd_bl_work);
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci/*
17198c2ecf20Sopenharmony_ci * Sysfs files
17208c2ecf20Sopenharmony_ci */
17218c2ecf20Sopenharmony_cistatic ssize_t version_show(struct device *dev,
17228c2ecf20Sopenharmony_ci			    struct device_attribute *attr, char *buf)
17238c2ecf20Sopenharmony_ci{
17248c2ecf20Sopenharmony_ci	return sprintf(buf, "%s\n", TOSHIBA_ACPI_VERSION);
17258c2ecf20Sopenharmony_ci}
17268c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(version);
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_cistatic ssize_t fan_store(struct device *dev,
17298c2ecf20Sopenharmony_ci			 struct device_attribute *attr,
17308c2ecf20Sopenharmony_ci			 const char *buf, size_t count)
17318c2ecf20Sopenharmony_ci{
17328c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
17338c2ecf20Sopenharmony_ci	int state;
17348c2ecf20Sopenharmony_ci	int ret;
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci	ret = kstrtoint(buf, 0, &state);
17378c2ecf20Sopenharmony_ci	if (ret)
17388c2ecf20Sopenharmony_ci		return ret;
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci	if (state != 0 && state != 1)
17418c2ecf20Sopenharmony_ci		return -EINVAL;
17428c2ecf20Sopenharmony_ci
17438c2ecf20Sopenharmony_ci	ret = set_fan_status(toshiba, state);
17448c2ecf20Sopenharmony_ci	if (ret)
17458c2ecf20Sopenharmony_ci		return ret;
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci	return count;
17488c2ecf20Sopenharmony_ci}
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_cistatic ssize_t fan_show(struct device *dev,
17518c2ecf20Sopenharmony_ci			struct device_attribute *attr, char *buf)
17528c2ecf20Sopenharmony_ci{
17538c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
17548c2ecf20Sopenharmony_ci	u32 value;
17558c2ecf20Sopenharmony_ci	int ret;
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	ret = get_fan_status(toshiba, &value);
17588c2ecf20Sopenharmony_ci	if (ret)
17598c2ecf20Sopenharmony_ci		return ret;
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", value);
17628c2ecf20Sopenharmony_ci}
17638c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(fan);
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_cistatic ssize_t kbd_backlight_mode_store(struct device *dev,
17668c2ecf20Sopenharmony_ci					struct device_attribute *attr,
17678c2ecf20Sopenharmony_ci					const char *buf, size_t count)
17688c2ecf20Sopenharmony_ci{
17698c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
17708c2ecf20Sopenharmony_ci	int mode;
17718c2ecf20Sopenharmony_ci	int ret;
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci
17748c2ecf20Sopenharmony_ci	ret = kstrtoint(buf, 0, &mode);
17758c2ecf20Sopenharmony_ci	if (ret)
17768c2ecf20Sopenharmony_ci		return ret;
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_ci	/* Check for supported modes depending on keyboard backlight type */
17798c2ecf20Sopenharmony_ci	if (toshiba->kbd_type == 1) {
17808c2ecf20Sopenharmony_ci		/* Type 1 supports SCI_KBD_MODE_FNZ and SCI_KBD_MODE_AUTO */
17818c2ecf20Sopenharmony_ci		if (mode != SCI_KBD_MODE_FNZ && mode != SCI_KBD_MODE_AUTO)
17828c2ecf20Sopenharmony_ci			return -EINVAL;
17838c2ecf20Sopenharmony_ci	} else if (toshiba->kbd_type == 2) {
17848c2ecf20Sopenharmony_ci		/* Type 2 doesn't support SCI_KBD_MODE_FNZ */
17858c2ecf20Sopenharmony_ci		if (mode != SCI_KBD_MODE_AUTO && mode != SCI_KBD_MODE_ON &&
17868c2ecf20Sopenharmony_ci		    mode != SCI_KBD_MODE_OFF)
17878c2ecf20Sopenharmony_ci			return -EINVAL;
17888c2ecf20Sopenharmony_ci	}
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci	/*
17918c2ecf20Sopenharmony_ci	 * Set the Keyboard Backlight Mode where:
17928c2ecf20Sopenharmony_ci	 *	Auto - KBD backlight turns off automatically in given time
17938c2ecf20Sopenharmony_ci	 *	FN-Z - KBD backlight "toggles" when hotkey pressed
17948c2ecf20Sopenharmony_ci	 *	ON   - KBD backlight is always on
17958c2ecf20Sopenharmony_ci	 *	OFF  - KBD backlight is always off
17968c2ecf20Sopenharmony_ci	 */
17978c2ecf20Sopenharmony_ci
17988c2ecf20Sopenharmony_ci	/* Only make a change if the actual mode has changed */
17998c2ecf20Sopenharmony_ci	if (toshiba->kbd_mode != mode) {
18008c2ecf20Sopenharmony_ci		/* Shift the time to "base time" (0x3c0000 == 60 seconds) */
18018c2ecf20Sopenharmony_ci		int time = toshiba->kbd_time << HCI_MISC_SHIFT;
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci		/* OR the "base time" to the actual method format */
18048c2ecf20Sopenharmony_ci		if (toshiba->kbd_type == 1) {
18058c2ecf20Sopenharmony_ci			/* Type 1 requires the current mode */
18068c2ecf20Sopenharmony_ci			time |= toshiba->kbd_mode;
18078c2ecf20Sopenharmony_ci		} else if (toshiba->kbd_type == 2) {
18088c2ecf20Sopenharmony_ci			/* Type 2 requires the desired mode */
18098c2ecf20Sopenharmony_ci			time |= mode;
18108c2ecf20Sopenharmony_ci		}
18118c2ecf20Sopenharmony_ci
18128c2ecf20Sopenharmony_ci		ret = toshiba_kbd_illum_status_set(toshiba, time);
18138c2ecf20Sopenharmony_ci		if (ret)
18148c2ecf20Sopenharmony_ci			return ret;
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_ci		toshiba->kbd_mode = mode;
18178c2ecf20Sopenharmony_ci		toshiba_acpi->kbd_mode = mode;
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci		/*
18208c2ecf20Sopenharmony_ci		 * Some laptop models with the second generation backlit
18218c2ecf20Sopenharmony_ci		 * keyboard (type 2) do not generate the keyboard backlight
18228c2ecf20Sopenharmony_ci		 * changed event (0x92), and thus, the driver will never update
18238c2ecf20Sopenharmony_ci		 * the sysfs entries.
18248c2ecf20Sopenharmony_ci		 *
18258c2ecf20Sopenharmony_ci		 * The event is generated right when changing the keyboard
18268c2ecf20Sopenharmony_ci		 * backlight mode and the *notify function will set the
18278c2ecf20Sopenharmony_ci		 * kbd_event_generated to true.
18288c2ecf20Sopenharmony_ci		 *
18298c2ecf20Sopenharmony_ci		 * In case the event is not generated, schedule the keyboard
18308c2ecf20Sopenharmony_ci		 * backlight work to update the sysfs entries and emulate the
18318c2ecf20Sopenharmony_ci		 * event via genetlink.
18328c2ecf20Sopenharmony_ci		 */
18338c2ecf20Sopenharmony_ci		if (toshiba->kbd_type == 2 &&
18348c2ecf20Sopenharmony_ci		    !toshiba->kbd_event_generated)
18358c2ecf20Sopenharmony_ci			schedule_work(&kbd_bl_work);
18368c2ecf20Sopenharmony_ci	}
18378c2ecf20Sopenharmony_ci
18388c2ecf20Sopenharmony_ci	return count;
18398c2ecf20Sopenharmony_ci}
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_cistatic ssize_t kbd_backlight_mode_show(struct device *dev,
18428c2ecf20Sopenharmony_ci				       struct device_attribute *attr,
18438c2ecf20Sopenharmony_ci				       char *buf)
18448c2ecf20Sopenharmony_ci{
18458c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
18468c2ecf20Sopenharmony_ci	u32 time;
18478c2ecf20Sopenharmony_ci
18488c2ecf20Sopenharmony_ci	if (toshiba_kbd_illum_status_get(toshiba, &time) < 0)
18498c2ecf20Sopenharmony_ci		return -EIO;
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci	return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK);
18528c2ecf20Sopenharmony_ci}
18538c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(kbd_backlight_mode);
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_cistatic ssize_t kbd_type_show(struct device *dev,
18568c2ecf20Sopenharmony_ci			     struct device_attribute *attr, char *buf)
18578c2ecf20Sopenharmony_ci{
18588c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", toshiba->kbd_type);
18618c2ecf20Sopenharmony_ci}
18628c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(kbd_type);
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_cistatic ssize_t available_kbd_modes_show(struct device *dev,
18658c2ecf20Sopenharmony_ci					struct device_attribute *attr,
18668c2ecf20Sopenharmony_ci					char *buf)
18678c2ecf20Sopenharmony_ci{
18688c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
18698c2ecf20Sopenharmony_ci
18708c2ecf20Sopenharmony_ci	if (toshiba->kbd_type == 1)
18718c2ecf20Sopenharmony_ci		return sprintf(buf, "0x%x 0x%x\n",
18728c2ecf20Sopenharmony_ci			       SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO);
18738c2ecf20Sopenharmony_ci
18748c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%x 0x%x 0x%x\n",
18758c2ecf20Sopenharmony_ci		       SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF);
18768c2ecf20Sopenharmony_ci}
18778c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(available_kbd_modes);
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_cistatic ssize_t kbd_backlight_timeout_store(struct device *dev,
18808c2ecf20Sopenharmony_ci					   struct device_attribute *attr,
18818c2ecf20Sopenharmony_ci					   const char *buf, size_t count)
18828c2ecf20Sopenharmony_ci{
18838c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
18848c2ecf20Sopenharmony_ci	int time;
18858c2ecf20Sopenharmony_ci	int ret;
18868c2ecf20Sopenharmony_ci
18878c2ecf20Sopenharmony_ci	ret = kstrtoint(buf, 0, &time);
18888c2ecf20Sopenharmony_ci	if (ret)
18898c2ecf20Sopenharmony_ci		return ret;
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci	/* Check for supported values depending on kbd_type */
18928c2ecf20Sopenharmony_ci	if (toshiba->kbd_type == 1) {
18938c2ecf20Sopenharmony_ci		if (time < 0 || time > 60)
18948c2ecf20Sopenharmony_ci			return -EINVAL;
18958c2ecf20Sopenharmony_ci	} else if (toshiba->kbd_type == 2) {
18968c2ecf20Sopenharmony_ci		if (time < 1 || time > 60)
18978c2ecf20Sopenharmony_ci			return -EINVAL;
18988c2ecf20Sopenharmony_ci	}
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci	/* Set the Keyboard Backlight Timeout */
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci	/* Only make a change if the actual timeout has changed */
19038c2ecf20Sopenharmony_ci	if (toshiba->kbd_time != time) {
19048c2ecf20Sopenharmony_ci		/* Shift the time to "base time" (0x3c0000 == 60 seconds) */
19058c2ecf20Sopenharmony_ci		time = time << HCI_MISC_SHIFT;
19068c2ecf20Sopenharmony_ci		/* OR the "base time" to the actual method format */
19078c2ecf20Sopenharmony_ci		if (toshiba->kbd_type == 1)
19088c2ecf20Sopenharmony_ci			time |= SCI_KBD_MODE_FNZ;
19098c2ecf20Sopenharmony_ci		else if (toshiba->kbd_type == 2)
19108c2ecf20Sopenharmony_ci			time |= SCI_KBD_MODE_AUTO;
19118c2ecf20Sopenharmony_ci
19128c2ecf20Sopenharmony_ci		ret = toshiba_kbd_illum_status_set(toshiba, time);
19138c2ecf20Sopenharmony_ci		if (ret)
19148c2ecf20Sopenharmony_ci			return ret;
19158c2ecf20Sopenharmony_ci
19168c2ecf20Sopenharmony_ci		toshiba->kbd_time = time >> HCI_MISC_SHIFT;
19178c2ecf20Sopenharmony_ci	}
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci	return count;
19208c2ecf20Sopenharmony_ci}
19218c2ecf20Sopenharmony_ci
19228c2ecf20Sopenharmony_cistatic ssize_t kbd_backlight_timeout_show(struct device *dev,
19238c2ecf20Sopenharmony_ci					  struct device_attribute *attr,
19248c2ecf20Sopenharmony_ci					  char *buf)
19258c2ecf20Sopenharmony_ci{
19268c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
19278c2ecf20Sopenharmony_ci	u32 time;
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_ci	if (toshiba_kbd_illum_status_get(toshiba, &time) < 0)
19308c2ecf20Sopenharmony_ci		return -EIO;
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_ci	return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT);
19338c2ecf20Sopenharmony_ci}
19348c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(kbd_backlight_timeout);
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_cistatic ssize_t touchpad_store(struct device *dev,
19378c2ecf20Sopenharmony_ci			      struct device_attribute *attr,
19388c2ecf20Sopenharmony_ci			      const char *buf, size_t count)
19398c2ecf20Sopenharmony_ci{
19408c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
19418c2ecf20Sopenharmony_ci	int state;
19428c2ecf20Sopenharmony_ci	int ret;
19438c2ecf20Sopenharmony_ci
19448c2ecf20Sopenharmony_ci	/* Set the TouchPad on/off, 0 - Disable | 1 - Enable */
19458c2ecf20Sopenharmony_ci	ret = kstrtoint(buf, 0, &state);
19468c2ecf20Sopenharmony_ci	if (ret)
19478c2ecf20Sopenharmony_ci		return ret;
19488c2ecf20Sopenharmony_ci	if (state != 0 && state != 1)
19498c2ecf20Sopenharmony_ci		return -EINVAL;
19508c2ecf20Sopenharmony_ci
19518c2ecf20Sopenharmony_ci	ret = toshiba_touchpad_set(toshiba, state);
19528c2ecf20Sopenharmony_ci	if (ret)
19538c2ecf20Sopenharmony_ci		return ret;
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ci	return count;
19568c2ecf20Sopenharmony_ci}
19578c2ecf20Sopenharmony_ci
19588c2ecf20Sopenharmony_cistatic ssize_t touchpad_show(struct device *dev,
19598c2ecf20Sopenharmony_ci			     struct device_attribute *attr, char *buf)
19608c2ecf20Sopenharmony_ci{
19618c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
19628c2ecf20Sopenharmony_ci	u32 state;
19638c2ecf20Sopenharmony_ci	int ret;
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci	ret = toshiba_touchpad_get(toshiba, &state);
19668c2ecf20Sopenharmony_ci	if (ret < 0)
19678c2ecf20Sopenharmony_ci		return ret;
19688c2ecf20Sopenharmony_ci
19698c2ecf20Sopenharmony_ci	return sprintf(buf, "%i\n", state);
19708c2ecf20Sopenharmony_ci}
19718c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(touchpad);
19728c2ecf20Sopenharmony_ci
19738c2ecf20Sopenharmony_cistatic ssize_t usb_sleep_charge_show(struct device *dev,
19748c2ecf20Sopenharmony_ci				     struct device_attribute *attr, char *buf)
19758c2ecf20Sopenharmony_ci{
19768c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
19778c2ecf20Sopenharmony_ci	u32 mode;
19788c2ecf20Sopenharmony_ci	int ret;
19798c2ecf20Sopenharmony_ci
19808c2ecf20Sopenharmony_ci	ret = toshiba_usb_sleep_charge_get(toshiba, &mode);
19818c2ecf20Sopenharmony_ci	if (ret < 0)
19828c2ecf20Sopenharmony_ci		return ret;
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	return sprintf(buf, "%x\n", mode & SCI_USB_CHARGE_MODE_MASK);
19858c2ecf20Sopenharmony_ci}
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_cistatic ssize_t usb_sleep_charge_store(struct device *dev,
19888c2ecf20Sopenharmony_ci				      struct device_attribute *attr,
19898c2ecf20Sopenharmony_ci				      const char *buf, size_t count)
19908c2ecf20Sopenharmony_ci{
19918c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
19928c2ecf20Sopenharmony_ci	int state;
19938c2ecf20Sopenharmony_ci	u32 mode;
19948c2ecf20Sopenharmony_ci	int ret;
19958c2ecf20Sopenharmony_ci
19968c2ecf20Sopenharmony_ci	ret = kstrtoint(buf, 0, &state);
19978c2ecf20Sopenharmony_ci	if (ret)
19988c2ecf20Sopenharmony_ci		return ret;
19998c2ecf20Sopenharmony_ci	/*
20008c2ecf20Sopenharmony_ci	 * Check for supported values, where:
20018c2ecf20Sopenharmony_ci	 * 0 - Disabled
20028c2ecf20Sopenharmony_ci	 * 1 - Alternate (Non USB conformant devices that require more power)
20038c2ecf20Sopenharmony_ci	 * 2 - Auto (USB conformant devices)
20048c2ecf20Sopenharmony_ci	 * 3 - Typical
20058c2ecf20Sopenharmony_ci	 */
20068c2ecf20Sopenharmony_ci	if (state != 0 && state != 1 && state != 2 && state != 3)
20078c2ecf20Sopenharmony_ci		return -EINVAL;
20088c2ecf20Sopenharmony_ci
20098c2ecf20Sopenharmony_ci	/* Set the USB charging mode to internal value */
20108c2ecf20Sopenharmony_ci	mode = toshiba->usbsc_mode_base;
20118c2ecf20Sopenharmony_ci	if (state == 0)
20128c2ecf20Sopenharmony_ci		mode |= SCI_USB_CHARGE_DISABLED;
20138c2ecf20Sopenharmony_ci	else if (state == 1)
20148c2ecf20Sopenharmony_ci		mode |= SCI_USB_CHARGE_ALTERNATE;
20158c2ecf20Sopenharmony_ci	else if (state == 2)
20168c2ecf20Sopenharmony_ci		mode |= SCI_USB_CHARGE_AUTO;
20178c2ecf20Sopenharmony_ci	else if (state == 3)
20188c2ecf20Sopenharmony_ci		mode |= SCI_USB_CHARGE_TYPICAL;
20198c2ecf20Sopenharmony_ci
20208c2ecf20Sopenharmony_ci	ret = toshiba_usb_sleep_charge_set(toshiba, mode);
20218c2ecf20Sopenharmony_ci	if (ret)
20228c2ecf20Sopenharmony_ci		return ret;
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_ci	return count;
20258c2ecf20Sopenharmony_ci}
20268c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(usb_sleep_charge);
20278c2ecf20Sopenharmony_ci
20288c2ecf20Sopenharmony_cistatic ssize_t sleep_functions_on_battery_show(struct device *dev,
20298c2ecf20Sopenharmony_ci					       struct device_attribute *attr,
20308c2ecf20Sopenharmony_ci					       char *buf)
20318c2ecf20Sopenharmony_ci{
20328c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
20338c2ecf20Sopenharmony_ci	int bat_lvl, status;
20348c2ecf20Sopenharmony_ci	u32 state;
20358c2ecf20Sopenharmony_ci	int ret;
20368c2ecf20Sopenharmony_ci	int tmp;
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_ci	ret = toshiba_sleep_functions_status_get(toshiba, &state);
20398c2ecf20Sopenharmony_ci	if (ret < 0)
20408c2ecf20Sopenharmony_ci		return ret;
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci	/* Determine the status: 0x4 - Enabled | 0x1 - Disabled */
20438c2ecf20Sopenharmony_ci	tmp = state & SCI_USB_CHARGE_BAT_MASK;
20448c2ecf20Sopenharmony_ci	status = (tmp == 0x4) ? 1 : 0;
20458c2ecf20Sopenharmony_ci	/* Determine the battery level set */
20468c2ecf20Sopenharmony_ci	bat_lvl = state >> HCI_MISC_SHIFT;
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci	return sprintf(buf, "%d %d\n", status, bat_lvl);
20498c2ecf20Sopenharmony_ci}
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_cistatic ssize_t sleep_functions_on_battery_store(struct device *dev,
20528c2ecf20Sopenharmony_ci						struct device_attribute *attr,
20538c2ecf20Sopenharmony_ci						const char *buf, size_t count)
20548c2ecf20Sopenharmony_ci{
20558c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
20568c2ecf20Sopenharmony_ci	u32 status;
20578c2ecf20Sopenharmony_ci	int value;
20588c2ecf20Sopenharmony_ci	int ret;
20598c2ecf20Sopenharmony_ci	int tmp;
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_ci	ret = kstrtoint(buf, 0, &value);
20628c2ecf20Sopenharmony_ci	if (ret)
20638c2ecf20Sopenharmony_ci		return ret;
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_ci	/*
20668c2ecf20Sopenharmony_ci	 * Set the status of the function:
20678c2ecf20Sopenharmony_ci	 * 0 - Disabled
20688c2ecf20Sopenharmony_ci	 * 1-100 - Enabled
20698c2ecf20Sopenharmony_ci	 */
20708c2ecf20Sopenharmony_ci	if (value < 0 || value > 100)
20718c2ecf20Sopenharmony_ci		return -EINVAL;
20728c2ecf20Sopenharmony_ci
20738c2ecf20Sopenharmony_ci	if (value == 0) {
20748c2ecf20Sopenharmony_ci		tmp = toshiba->usbsc_bat_level << HCI_MISC_SHIFT;
20758c2ecf20Sopenharmony_ci		status = tmp | SCI_USB_CHARGE_BAT_LVL_OFF;
20768c2ecf20Sopenharmony_ci	} else {
20778c2ecf20Sopenharmony_ci		tmp = value << HCI_MISC_SHIFT;
20788c2ecf20Sopenharmony_ci		status = tmp | SCI_USB_CHARGE_BAT_LVL_ON;
20798c2ecf20Sopenharmony_ci	}
20808c2ecf20Sopenharmony_ci	ret = toshiba_sleep_functions_status_set(toshiba, status);
20818c2ecf20Sopenharmony_ci	if (ret < 0)
20828c2ecf20Sopenharmony_ci		return ret;
20838c2ecf20Sopenharmony_ci
20848c2ecf20Sopenharmony_ci	toshiba->usbsc_bat_level = status >> HCI_MISC_SHIFT;
20858c2ecf20Sopenharmony_ci
20868c2ecf20Sopenharmony_ci	return count;
20878c2ecf20Sopenharmony_ci}
20888c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(sleep_functions_on_battery);
20898c2ecf20Sopenharmony_ci
20908c2ecf20Sopenharmony_cistatic ssize_t usb_rapid_charge_show(struct device *dev,
20918c2ecf20Sopenharmony_ci				     struct device_attribute *attr, char *buf)
20928c2ecf20Sopenharmony_ci{
20938c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
20948c2ecf20Sopenharmony_ci	u32 state;
20958c2ecf20Sopenharmony_ci	int ret;
20968c2ecf20Sopenharmony_ci
20978c2ecf20Sopenharmony_ci	ret = toshiba_usb_rapid_charge_get(toshiba, &state);
20988c2ecf20Sopenharmony_ci	if (ret < 0)
20998c2ecf20Sopenharmony_ci		return ret;
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", state);
21028c2ecf20Sopenharmony_ci}
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_cistatic ssize_t usb_rapid_charge_store(struct device *dev,
21058c2ecf20Sopenharmony_ci				      struct device_attribute *attr,
21068c2ecf20Sopenharmony_ci				      const char *buf, size_t count)
21078c2ecf20Sopenharmony_ci{
21088c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
21098c2ecf20Sopenharmony_ci	int state;
21108c2ecf20Sopenharmony_ci	int ret;
21118c2ecf20Sopenharmony_ci
21128c2ecf20Sopenharmony_ci	ret = kstrtoint(buf, 0, &state);
21138c2ecf20Sopenharmony_ci	if (ret)
21148c2ecf20Sopenharmony_ci		return ret;
21158c2ecf20Sopenharmony_ci	if (state != 0 && state != 1)
21168c2ecf20Sopenharmony_ci		return -EINVAL;
21178c2ecf20Sopenharmony_ci
21188c2ecf20Sopenharmony_ci	ret = toshiba_usb_rapid_charge_set(toshiba, state);
21198c2ecf20Sopenharmony_ci	if (ret)
21208c2ecf20Sopenharmony_ci		return ret;
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_ci	return count;
21238c2ecf20Sopenharmony_ci}
21248c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(usb_rapid_charge);
21258c2ecf20Sopenharmony_ci
21268c2ecf20Sopenharmony_cistatic ssize_t usb_sleep_music_show(struct device *dev,
21278c2ecf20Sopenharmony_ci				    struct device_attribute *attr, char *buf)
21288c2ecf20Sopenharmony_ci{
21298c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
21308c2ecf20Sopenharmony_ci	u32 state;
21318c2ecf20Sopenharmony_ci	int ret;
21328c2ecf20Sopenharmony_ci
21338c2ecf20Sopenharmony_ci	ret = toshiba_usb_sleep_music_get(toshiba, &state);
21348c2ecf20Sopenharmony_ci	if (ret < 0)
21358c2ecf20Sopenharmony_ci		return ret;
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", state);
21388c2ecf20Sopenharmony_ci}
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_cistatic ssize_t usb_sleep_music_store(struct device *dev,
21418c2ecf20Sopenharmony_ci				     struct device_attribute *attr,
21428c2ecf20Sopenharmony_ci				     const char *buf, size_t count)
21438c2ecf20Sopenharmony_ci{
21448c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
21458c2ecf20Sopenharmony_ci	int state;
21468c2ecf20Sopenharmony_ci	int ret;
21478c2ecf20Sopenharmony_ci
21488c2ecf20Sopenharmony_ci	ret = kstrtoint(buf, 0, &state);
21498c2ecf20Sopenharmony_ci	if (ret)
21508c2ecf20Sopenharmony_ci		return ret;
21518c2ecf20Sopenharmony_ci	if (state != 0 && state != 1)
21528c2ecf20Sopenharmony_ci		return -EINVAL;
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_ci	ret = toshiba_usb_sleep_music_set(toshiba, state);
21558c2ecf20Sopenharmony_ci	if (ret)
21568c2ecf20Sopenharmony_ci		return ret;
21578c2ecf20Sopenharmony_ci
21588c2ecf20Sopenharmony_ci	return count;
21598c2ecf20Sopenharmony_ci}
21608c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(usb_sleep_music);
21618c2ecf20Sopenharmony_ci
21628c2ecf20Sopenharmony_cistatic ssize_t kbd_function_keys_show(struct device *dev,
21638c2ecf20Sopenharmony_ci				      struct device_attribute *attr, char *buf)
21648c2ecf20Sopenharmony_ci{
21658c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
21668c2ecf20Sopenharmony_ci	int mode;
21678c2ecf20Sopenharmony_ci	int ret;
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_ci	ret = toshiba_function_keys_get(toshiba, &mode);
21708c2ecf20Sopenharmony_ci	if (ret < 0)
21718c2ecf20Sopenharmony_ci		return ret;
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", mode);
21748c2ecf20Sopenharmony_ci}
21758c2ecf20Sopenharmony_ci
21768c2ecf20Sopenharmony_cistatic ssize_t kbd_function_keys_store(struct device *dev,
21778c2ecf20Sopenharmony_ci				       struct device_attribute *attr,
21788c2ecf20Sopenharmony_ci				       const char *buf, size_t count)
21798c2ecf20Sopenharmony_ci{
21808c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
21818c2ecf20Sopenharmony_ci	int mode;
21828c2ecf20Sopenharmony_ci	int ret;
21838c2ecf20Sopenharmony_ci
21848c2ecf20Sopenharmony_ci	ret = kstrtoint(buf, 0, &mode);
21858c2ecf20Sopenharmony_ci	if (ret)
21868c2ecf20Sopenharmony_ci		return ret;
21878c2ecf20Sopenharmony_ci	/*
21888c2ecf20Sopenharmony_ci	 * Check for the function keys mode where:
21898c2ecf20Sopenharmony_ci	 * 0 - Normal operation (F{1-12} as usual and hotkeys via FN-F{1-12})
21908c2ecf20Sopenharmony_ci	 * 1 - Special functions (Opposite of the above setting)
21918c2ecf20Sopenharmony_ci	 */
21928c2ecf20Sopenharmony_ci	if (mode != 0 && mode != 1)
21938c2ecf20Sopenharmony_ci		return -EINVAL;
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_ci	ret = toshiba_function_keys_set(toshiba, mode);
21968c2ecf20Sopenharmony_ci	if (ret)
21978c2ecf20Sopenharmony_ci		return ret;
21988c2ecf20Sopenharmony_ci
21998c2ecf20Sopenharmony_ci	pr_info("Reboot for changes to KBD Function Keys to take effect");
22008c2ecf20Sopenharmony_ci
22018c2ecf20Sopenharmony_ci	return count;
22028c2ecf20Sopenharmony_ci}
22038c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(kbd_function_keys);
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_cistatic ssize_t panel_power_on_show(struct device *dev,
22068c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
22078c2ecf20Sopenharmony_ci{
22088c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
22098c2ecf20Sopenharmony_ci	u32 state;
22108c2ecf20Sopenharmony_ci	int ret;
22118c2ecf20Sopenharmony_ci
22128c2ecf20Sopenharmony_ci	ret = toshiba_panel_power_on_get(toshiba, &state);
22138c2ecf20Sopenharmony_ci	if (ret < 0)
22148c2ecf20Sopenharmony_ci		return ret;
22158c2ecf20Sopenharmony_ci
22168c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", state);
22178c2ecf20Sopenharmony_ci}
22188c2ecf20Sopenharmony_ci
22198c2ecf20Sopenharmony_cistatic ssize_t panel_power_on_store(struct device *dev,
22208c2ecf20Sopenharmony_ci				    struct device_attribute *attr,
22218c2ecf20Sopenharmony_ci				    const char *buf, size_t count)
22228c2ecf20Sopenharmony_ci{
22238c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
22248c2ecf20Sopenharmony_ci	int state;
22258c2ecf20Sopenharmony_ci	int ret;
22268c2ecf20Sopenharmony_ci
22278c2ecf20Sopenharmony_ci	ret = kstrtoint(buf, 0, &state);
22288c2ecf20Sopenharmony_ci	if (ret)
22298c2ecf20Sopenharmony_ci		return ret;
22308c2ecf20Sopenharmony_ci	if (state != 0 && state != 1)
22318c2ecf20Sopenharmony_ci		return -EINVAL;
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_ci	ret = toshiba_panel_power_on_set(toshiba, state);
22348c2ecf20Sopenharmony_ci	if (ret)
22358c2ecf20Sopenharmony_ci		return ret;
22368c2ecf20Sopenharmony_ci
22378c2ecf20Sopenharmony_ci	pr_info("Reboot for changes to Panel Power ON to take effect");
22388c2ecf20Sopenharmony_ci
22398c2ecf20Sopenharmony_ci	return count;
22408c2ecf20Sopenharmony_ci}
22418c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(panel_power_on);
22428c2ecf20Sopenharmony_ci
22438c2ecf20Sopenharmony_cistatic ssize_t usb_three_show(struct device *dev,
22448c2ecf20Sopenharmony_ci			      struct device_attribute *attr, char *buf)
22458c2ecf20Sopenharmony_ci{
22468c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
22478c2ecf20Sopenharmony_ci	u32 state;
22488c2ecf20Sopenharmony_ci	int ret;
22498c2ecf20Sopenharmony_ci
22508c2ecf20Sopenharmony_ci	ret = toshiba_usb_three_get(toshiba, &state);
22518c2ecf20Sopenharmony_ci	if (ret < 0)
22528c2ecf20Sopenharmony_ci		return ret;
22538c2ecf20Sopenharmony_ci
22548c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", state);
22558c2ecf20Sopenharmony_ci}
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_cistatic ssize_t usb_three_store(struct device *dev,
22588c2ecf20Sopenharmony_ci			       struct device_attribute *attr,
22598c2ecf20Sopenharmony_ci			       const char *buf, size_t count)
22608c2ecf20Sopenharmony_ci{
22618c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
22628c2ecf20Sopenharmony_ci	int state;
22638c2ecf20Sopenharmony_ci	int ret;
22648c2ecf20Sopenharmony_ci
22658c2ecf20Sopenharmony_ci	ret = kstrtoint(buf, 0, &state);
22668c2ecf20Sopenharmony_ci	if (ret)
22678c2ecf20Sopenharmony_ci		return ret;
22688c2ecf20Sopenharmony_ci	/*
22698c2ecf20Sopenharmony_ci	 * Check for USB 3 mode where:
22708c2ecf20Sopenharmony_ci	 * 0 - Disabled (Acts like a USB 2 port, saving power)
22718c2ecf20Sopenharmony_ci	 * 1 - Enabled
22728c2ecf20Sopenharmony_ci	 */
22738c2ecf20Sopenharmony_ci	if (state != 0 && state != 1)
22748c2ecf20Sopenharmony_ci		return -EINVAL;
22758c2ecf20Sopenharmony_ci
22768c2ecf20Sopenharmony_ci	ret = toshiba_usb_three_set(toshiba, state);
22778c2ecf20Sopenharmony_ci	if (ret)
22788c2ecf20Sopenharmony_ci		return ret;
22798c2ecf20Sopenharmony_ci
22808c2ecf20Sopenharmony_ci	pr_info("Reboot for changes to USB 3 to take effect");
22818c2ecf20Sopenharmony_ci
22828c2ecf20Sopenharmony_ci	return count;
22838c2ecf20Sopenharmony_ci}
22848c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(usb_three);
22858c2ecf20Sopenharmony_ci
22868c2ecf20Sopenharmony_cistatic ssize_t cooling_method_show(struct device *dev,
22878c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
22888c2ecf20Sopenharmony_ci{
22898c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
22908c2ecf20Sopenharmony_ci	int state;
22918c2ecf20Sopenharmony_ci	int ret;
22928c2ecf20Sopenharmony_ci
22938c2ecf20Sopenharmony_ci	ret = toshiba_cooling_method_get(toshiba, &state);
22948c2ecf20Sopenharmony_ci	if (ret < 0)
22958c2ecf20Sopenharmony_ci		return ret;
22968c2ecf20Sopenharmony_ci
22978c2ecf20Sopenharmony_ci	return sprintf(buf, "%d %d\n", state, toshiba->max_cooling_method);
22988c2ecf20Sopenharmony_ci}
22998c2ecf20Sopenharmony_ci
23008c2ecf20Sopenharmony_cistatic ssize_t cooling_method_store(struct device *dev,
23018c2ecf20Sopenharmony_ci				    struct device_attribute *attr,
23028c2ecf20Sopenharmony_ci				    const char *buf, size_t count)
23038c2ecf20Sopenharmony_ci{
23048c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
23058c2ecf20Sopenharmony_ci	int state;
23068c2ecf20Sopenharmony_ci	int ret;
23078c2ecf20Sopenharmony_ci
23088c2ecf20Sopenharmony_ci	ret = kstrtoint(buf, 0, &state);
23098c2ecf20Sopenharmony_ci	if (ret)
23108c2ecf20Sopenharmony_ci		return ret;
23118c2ecf20Sopenharmony_ci
23128c2ecf20Sopenharmony_ci	/*
23138c2ecf20Sopenharmony_ci	 * Check for supported values
23148c2ecf20Sopenharmony_ci	 * Depending on the laptop model, some only support these two:
23158c2ecf20Sopenharmony_ci	 * 0 - Maximum Performance
23168c2ecf20Sopenharmony_ci	 * 1 - Battery Optimized
23178c2ecf20Sopenharmony_ci	 *
23188c2ecf20Sopenharmony_ci	 * While some others support all three methods:
23198c2ecf20Sopenharmony_ci	 * 0 - Maximum Performance
23208c2ecf20Sopenharmony_ci	 * 1 - Performance
23218c2ecf20Sopenharmony_ci	 * 2 - Battery Optimized
23228c2ecf20Sopenharmony_ci	 */
23238c2ecf20Sopenharmony_ci	if (state < 0 || state > toshiba->max_cooling_method)
23248c2ecf20Sopenharmony_ci		return -EINVAL;
23258c2ecf20Sopenharmony_ci
23268c2ecf20Sopenharmony_ci	ret = toshiba_cooling_method_set(toshiba, state);
23278c2ecf20Sopenharmony_ci	if (ret)
23288c2ecf20Sopenharmony_ci		return ret;
23298c2ecf20Sopenharmony_ci
23308c2ecf20Sopenharmony_ci	return count;
23318c2ecf20Sopenharmony_ci}
23328c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(cooling_method);
23338c2ecf20Sopenharmony_ci
23348c2ecf20Sopenharmony_cistatic struct attribute *toshiba_attributes[] = {
23358c2ecf20Sopenharmony_ci	&dev_attr_version.attr,
23368c2ecf20Sopenharmony_ci	&dev_attr_fan.attr,
23378c2ecf20Sopenharmony_ci	&dev_attr_kbd_backlight_mode.attr,
23388c2ecf20Sopenharmony_ci	&dev_attr_kbd_type.attr,
23398c2ecf20Sopenharmony_ci	&dev_attr_available_kbd_modes.attr,
23408c2ecf20Sopenharmony_ci	&dev_attr_kbd_backlight_timeout.attr,
23418c2ecf20Sopenharmony_ci	&dev_attr_touchpad.attr,
23428c2ecf20Sopenharmony_ci	&dev_attr_usb_sleep_charge.attr,
23438c2ecf20Sopenharmony_ci	&dev_attr_sleep_functions_on_battery.attr,
23448c2ecf20Sopenharmony_ci	&dev_attr_usb_rapid_charge.attr,
23458c2ecf20Sopenharmony_ci	&dev_attr_usb_sleep_music.attr,
23468c2ecf20Sopenharmony_ci	&dev_attr_kbd_function_keys.attr,
23478c2ecf20Sopenharmony_ci	&dev_attr_panel_power_on.attr,
23488c2ecf20Sopenharmony_ci	&dev_attr_usb_three.attr,
23498c2ecf20Sopenharmony_ci	&dev_attr_cooling_method.attr,
23508c2ecf20Sopenharmony_ci	NULL,
23518c2ecf20Sopenharmony_ci};
23528c2ecf20Sopenharmony_ci
23538c2ecf20Sopenharmony_cistatic umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
23548c2ecf20Sopenharmony_ci					struct attribute *attr, int idx)
23558c2ecf20Sopenharmony_ci{
23568c2ecf20Sopenharmony_ci	struct device *dev = container_of(kobj, struct device, kobj);
23578c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *drv = dev_get_drvdata(dev);
23588c2ecf20Sopenharmony_ci	bool exists = true;
23598c2ecf20Sopenharmony_ci
23608c2ecf20Sopenharmony_ci	if (attr == &dev_attr_fan.attr)
23618c2ecf20Sopenharmony_ci		exists = (drv->fan_supported) ? true : false;
23628c2ecf20Sopenharmony_ci	else if (attr == &dev_attr_kbd_backlight_mode.attr)
23638c2ecf20Sopenharmony_ci		exists = (drv->kbd_illum_supported) ? true : false;
23648c2ecf20Sopenharmony_ci	else if (attr == &dev_attr_kbd_backlight_timeout.attr)
23658c2ecf20Sopenharmony_ci		exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false;
23668c2ecf20Sopenharmony_ci	else if (attr == &dev_attr_touchpad.attr)
23678c2ecf20Sopenharmony_ci		exists = (drv->touchpad_supported) ? true : false;
23688c2ecf20Sopenharmony_ci	else if (attr == &dev_attr_usb_sleep_charge.attr)
23698c2ecf20Sopenharmony_ci		exists = (drv->usb_sleep_charge_supported) ? true : false;
23708c2ecf20Sopenharmony_ci	else if (attr == &dev_attr_sleep_functions_on_battery.attr)
23718c2ecf20Sopenharmony_ci		exists = (drv->usb_sleep_charge_supported) ? true : false;
23728c2ecf20Sopenharmony_ci	else if (attr == &dev_attr_usb_rapid_charge.attr)
23738c2ecf20Sopenharmony_ci		exists = (drv->usb_rapid_charge_supported) ? true : false;
23748c2ecf20Sopenharmony_ci	else if (attr == &dev_attr_usb_sleep_music.attr)
23758c2ecf20Sopenharmony_ci		exists = (drv->usb_sleep_music_supported) ? true : false;
23768c2ecf20Sopenharmony_ci	else if (attr == &dev_attr_kbd_function_keys.attr)
23778c2ecf20Sopenharmony_ci		exists = (drv->kbd_function_keys_supported) ? true : false;
23788c2ecf20Sopenharmony_ci	else if (attr == &dev_attr_panel_power_on.attr)
23798c2ecf20Sopenharmony_ci		exists = (drv->panel_power_on_supported) ? true : false;
23808c2ecf20Sopenharmony_ci	else if (attr == &dev_attr_usb_three.attr)
23818c2ecf20Sopenharmony_ci		exists = (drv->usb_three_supported) ? true : false;
23828c2ecf20Sopenharmony_ci	else if (attr == &dev_attr_cooling_method.attr)
23838c2ecf20Sopenharmony_ci		exists = (drv->cooling_method_supported) ? true : false;
23848c2ecf20Sopenharmony_ci
23858c2ecf20Sopenharmony_ci	return exists ? attr->mode : 0;
23868c2ecf20Sopenharmony_ci}
23878c2ecf20Sopenharmony_ci
23888c2ecf20Sopenharmony_cistatic const struct attribute_group toshiba_attr_group = {
23898c2ecf20Sopenharmony_ci	.is_visible = toshiba_sysfs_is_visible,
23908c2ecf20Sopenharmony_ci	.attrs = toshiba_attributes,
23918c2ecf20Sopenharmony_ci};
23928c2ecf20Sopenharmony_ci
23938c2ecf20Sopenharmony_cistatic void toshiba_acpi_kbd_bl_work(struct work_struct *work)
23948c2ecf20Sopenharmony_ci{
23958c2ecf20Sopenharmony_ci	/* Update the sysfs entries */
23968c2ecf20Sopenharmony_ci	if (sysfs_update_group(&toshiba_acpi->acpi_dev->dev.kobj,
23978c2ecf20Sopenharmony_ci			       &toshiba_attr_group))
23988c2ecf20Sopenharmony_ci		pr_err("Unable to update sysfs entries\n");
23998c2ecf20Sopenharmony_ci
24008c2ecf20Sopenharmony_ci	/* Notify LED subsystem about keyboard backlight change */
24018c2ecf20Sopenharmony_ci	if (toshiba_acpi->kbd_type == 2 &&
24028c2ecf20Sopenharmony_ci	    toshiba_acpi->kbd_mode != SCI_KBD_MODE_AUTO)
24038c2ecf20Sopenharmony_ci		led_classdev_notify_brightness_hw_changed(&toshiba_acpi->kbd_led,
24048c2ecf20Sopenharmony_ci				(toshiba_acpi->kbd_mode == SCI_KBD_MODE_ON) ?
24058c2ecf20Sopenharmony_ci				LED_FULL : LED_OFF);
24068c2ecf20Sopenharmony_ci
24078c2ecf20Sopenharmony_ci	/* Emulate the keyboard backlight event */
24088c2ecf20Sopenharmony_ci	acpi_bus_generate_netlink_event(toshiba_acpi->acpi_dev->pnp.device_class,
24098c2ecf20Sopenharmony_ci					dev_name(&toshiba_acpi->acpi_dev->dev),
24108c2ecf20Sopenharmony_ci					0x92, 0);
24118c2ecf20Sopenharmony_ci}
24128c2ecf20Sopenharmony_ci
24138c2ecf20Sopenharmony_ci/*
24148c2ecf20Sopenharmony_ci * IIO device
24158c2ecf20Sopenharmony_ci */
24168c2ecf20Sopenharmony_ci
24178c2ecf20Sopenharmony_cienum toshiba_iio_accel_chan {
24188c2ecf20Sopenharmony_ci	AXIS_X,
24198c2ecf20Sopenharmony_ci	AXIS_Y,
24208c2ecf20Sopenharmony_ci	AXIS_Z
24218c2ecf20Sopenharmony_ci};
24228c2ecf20Sopenharmony_ci
24238c2ecf20Sopenharmony_cistatic int toshiba_iio_accel_get_axis(enum toshiba_iio_accel_chan chan)
24248c2ecf20Sopenharmony_ci{
24258c2ecf20Sopenharmony_ci	u32 xyval, zval;
24268c2ecf20Sopenharmony_ci	int ret;
24278c2ecf20Sopenharmony_ci
24288c2ecf20Sopenharmony_ci	ret = toshiba_accelerometer_get(toshiba_acpi, &xyval, &zval);
24298c2ecf20Sopenharmony_ci	if (ret < 0)
24308c2ecf20Sopenharmony_ci		return ret;
24318c2ecf20Sopenharmony_ci
24328c2ecf20Sopenharmony_ci	switch (chan) {
24338c2ecf20Sopenharmony_ci	case AXIS_X:
24348c2ecf20Sopenharmony_ci		return xyval & HCI_ACCEL_DIRECTION_MASK ?
24358c2ecf20Sopenharmony_ci			-(xyval & HCI_ACCEL_MASK) : xyval & HCI_ACCEL_MASK;
24368c2ecf20Sopenharmony_ci	case AXIS_Y:
24378c2ecf20Sopenharmony_ci		return (xyval >> HCI_MISC_SHIFT) & HCI_ACCEL_DIRECTION_MASK ?
24388c2ecf20Sopenharmony_ci			-((xyval >> HCI_MISC_SHIFT) & HCI_ACCEL_MASK) :
24398c2ecf20Sopenharmony_ci			(xyval >> HCI_MISC_SHIFT) & HCI_ACCEL_MASK;
24408c2ecf20Sopenharmony_ci	case AXIS_Z:
24418c2ecf20Sopenharmony_ci		return zval & HCI_ACCEL_DIRECTION_MASK ?
24428c2ecf20Sopenharmony_ci			-(zval & HCI_ACCEL_MASK) : zval & HCI_ACCEL_MASK;
24438c2ecf20Sopenharmony_ci	}
24448c2ecf20Sopenharmony_ci
24458c2ecf20Sopenharmony_ci	return ret;
24468c2ecf20Sopenharmony_ci}
24478c2ecf20Sopenharmony_ci
24488c2ecf20Sopenharmony_cistatic int toshiba_iio_accel_read_raw(struct iio_dev *indio_dev,
24498c2ecf20Sopenharmony_ci				      struct iio_chan_spec const *chan,
24508c2ecf20Sopenharmony_ci				      int *val, int *val2, long mask)
24518c2ecf20Sopenharmony_ci{
24528c2ecf20Sopenharmony_ci	int ret;
24538c2ecf20Sopenharmony_ci
24548c2ecf20Sopenharmony_ci	switch (mask) {
24558c2ecf20Sopenharmony_ci	case IIO_CHAN_INFO_RAW:
24568c2ecf20Sopenharmony_ci		ret = toshiba_iio_accel_get_axis(chan->channel);
24578c2ecf20Sopenharmony_ci		if (ret == -EIO || ret == -ENODEV)
24588c2ecf20Sopenharmony_ci			return ret;
24598c2ecf20Sopenharmony_ci
24608c2ecf20Sopenharmony_ci		*val = ret;
24618c2ecf20Sopenharmony_ci
24628c2ecf20Sopenharmony_ci		return IIO_VAL_INT;
24638c2ecf20Sopenharmony_ci	}
24648c2ecf20Sopenharmony_ci
24658c2ecf20Sopenharmony_ci	return -EINVAL;
24668c2ecf20Sopenharmony_ci}
24678c2ecf20Sopenharmony_ci
24688c2ecf20Sopenharmony_ci#define TOSHIBA_IIO_ACCEL_CHANNEL(axis, chan) { \
24698c2ecf20Sopenharmony_ci	.type = IIO_ACCEL, \
24708c2ecf20Sopenharmony_ci	.modified = 1, \
24718c2ecf20Sopenharmony_ci	.channel = chan, \
24728c2ecf20Sopenharmony_ci	.channel2 = IIO_MOD_##axis, \
24738c2ecf20Sopenharmony_ci	.output = 1, \
24748c2ecf20Sopenharmony_ci	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
24758c2ecf20Sopenharmony_ci}
24768c2ecf20Sopenharmony_ci
24778c2ecf20Sopenharmony_cistatic const struct iio_chan_spec toshiba_iio_accel_channels[] = {
24788c2ecf20Sopenharmony_ci	TOSHIBA_IIO_ACCEL_CHANNEL(X, AXIS_X),
24798c2ecf20Sopenharmony_ci	TOSHIBA_IIO_ACCEL_CHANNEL(Y, AXIS_Y),
24808c2ecf20Sopenharmony_ci	TOSHIBA_IIO_ACCEL_CHANNEL(Z, AXIS_Z),
24818c2ecf20Sopenharmony_ci};
24828c2ecf20Sopenharmony_ci
24838c2ecf20Sopenharmony_cistatic const struct iio_info toshiba_iio_accel_info = {
24848c2ecf20Sopenharmony_ci	.read_raw = &toshiba_iio_accel_read_raw,
24858c2ecf20Sopenharmony_ci};
24868c2ecf20Sopenharmony_ci
24878c2ecf20Sopenharmony_ci/*
24888c2ecf20Sopenharmony_ci * Misc device
24898c2ecf20Sopenharmony_ci */
24908c2ecf20Sopenharmony_cistatic int toshiba_acpi_smm_bridge(SMMRegisters *regs)
24918c2ecf20Sopenharmony_ci{
24928c2ecf20Sopenharmony_ci	u32 in[TCI_WORDS] = { regs->eax, regs->ebx, regs->ecx,
24938c2ecf20Sopenharmony_ci			      regs->edx, regs->esi, regs->edi };
24948c2ecf20Sopenharmony_ci	u32 out[TCI_WORDS];
24958c2ecf20Sopenharmony_ci	acpi_status status;
24968c2ecf20Sopenharmony_ci
24978c2ecf20Sopenharmony_ci	status = tci_raw(toshiba_acpi, in, out);
24988c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
24998c2ecf20Sopenharmony_ci		pr_err("ACPI call to query SMM registers failed\n");
25008c2ecf20Sopenharmony_ci		return -EIO;
25018c2ecf20Sopenharmony_ci	}
25028c2ecf20Sopenharmony_ci
25038c2ecf20Sopenharmony_ci	/* Fillout the SMM struct with the TCI call results */
25048c2ecf20Sopenharmony_ci	regs->eax = out[0];
25058c2ecf20Sopenharmony_ci	regs->ebx = out[1];
25068c2ecf20Sopenharmony_ci	regs->ecx = out[2];
25078c2ecf20Sopenharmony_ci	regs->edx = out[3];
25088c2ecf20Sopenharmony_ci	regs->esi = out[4];
25098c2ecf20Sopenharmony_ci	regs->edi = out[5];
25108c2ecf20Sopenharmony_ci
25118c2ecf20Sopenharmony_ci	return 0;
25128c2ecf20Sopenharmony_ci}
25138c2ecf20Sopenharmony_ci
25148c2ecf20Sopenharmony_cistatic long toshiba_acpi_ioctl(struct file *fp, unsigned int cmd,
25158c2ecf20Sopenharmony_ci			       unsigned long arg)
25168c2ecf20Sopenharmony_ci{
25178c2ecf20Sopenharmony_ci	SMMRegisters __user *argp = (SMMRegisters __user *)arg;
25188c2ecf20Sopenharmony_ci	SMMRegisters regs;
25198c2ecf20Sopenharmony_ci	int ret;
25208c2ecf20Sopenharmony_ci
25218c2ecf20Sopenharmony_ci	if (!argp)
25228c2ecf20Sopenharmony_ci		return -EINVAL;
25238c2ecf20Sopenharmony_ci
25248c2ecf20Sopenharmony_ci	switch (cmd) {
25258c2ecf20Sopenharmony_ci	case TOSH_SMM:
25268c2ecf20Sopenharmony_ci		if (copy_from_user(&regs, argp, sizeof(SMMRegisters)))
25278c2ecf20Sopenharmony_ci			return -EFAULT;
25288c2ecf20Sopenharmony_ci		ret = toshiba_acpi_smm_bridge(&regs);
25298c2ecf20Sopenharmony_ci		if (ret)
25308c2ecf20Sopenharmony_ci			return ret;
25318c2ecf20Sopenharmony_ci		if (copy_to_user(argp, &regs, sizeof(SMMRegisters)))
25328c2ecf20Sopenharmony_ci			return -EFAULT;
25338c2ecf20Sopenharmony_ci		break;
25348c2ecf20Sopenharmony_ci	case TOSHIBA_ACPI_SCI:
25358c2ecf20Sopenharmony_ci		if (copy_from_user(&regs, argp, sizeof(SMMRegisters)))
25368c2ecf20Sopenharmony_ci			return -EFAULT;
25378c2ecf20Sopenharmony_ci		/* Ensure we are being called with a SCI_{GET, SET} register */
25388c2ecf20Sopenharmony_ci		if (regs.eax != SCI_GET && regs.eax != SCI_SET)
25398c2ecf20Sopenharmony_ci			return -EINVAL;
25408c2ecf20Sopenharmony_ci		if (!sci_open(toshiba_acpi))
25418c2ecf20Sopenharmony_ci			return -EIO;
25428c2ecf20Sopenharmony_ci		ret = toshiba_acpi_smm_bridge(&regs);
25438c2ecf20Sopenharmony_ci		sci_close(toshiba_acpi);
25448c2ecf20Sopenharmony_ci		if (ret)
25458c2ecf20Sopenharmony_ci			return ret;
25468c2ecf20Sopenharmony_ci		if (copy_to_user(argp, &regs, sizeof(SMMRegisters)))
25478c2ecf20Sopenharmony_ci			return -EFAULT;
25488c2ecf20Sopenharmony_ci		break;
25498c2ecf20Sopenharmony_ci	default:
25508c2ecf20Sopenharmony_ci		return -EINVAL;
25518c2ecf20Sopenharmony_ci	}
25528c2ecf20Sopenharmony_ci
25538c2ecf20Sopenharmony_ci	return 0;
25548c2ecf20Sopenharmony_ci}
25558c2ecf20Sopenharmony_ci
25568c2ecf20Sopenharmony_cistatic const struct file_operations toshiba_acpi_fops = {
25578c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
25588c2ecf20Sopenharmony_ci	.unlocked_ioctl = toshiba_acpi_ioctl,
25598c2ecf20Sopenharmony_ci	.llseek		= noop_llseek,
25608c2ecf20Sopenharmony_ci};
25618c2ecf20Sopenharmony_ci
25628c2ecf20Sopenharmony_ci/*
25638c2ecf20Sopenharmony_ci * WWAN RFKill handlers
25648c2ecf20Sopenharmony_ci */
25658c2ecf20Sopenharmony_cistatic int toshiba_acpi_wwan_set_block(void *data, bool blocked)
25668c2ecf20Sopenharmony_ci{
25678c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = data;
25688c2ecf20Sopenharmony_ci	int ret;
25698c2ecf20Sopenharmony_ci
25708c2ecf20Sopenharmony_ci	ret = toshiba_wireless_status(dev);
25718c2ecf20Sopenharmony_ci	if (ret)
25728c2ecf20Sopenharmony_ci		return ret;
25738c2ecf20Sopenharmony_ci
25748c2ecf20Sopenharmony_ci	if (!dev->killswitch)
25758c2ecf20Sopenharmony_ci		return 0;
25768c2ecf20Sopenharmony_ci
25778c2ecf20Sopenharmony_ci	return toshiba_wwan_set(dev, !blocked);
25788c2ecf20Sopenharmony_ci}
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_cistatic void toshiba_acpi_wwan_poll(struct rfkill *rfkill, void *data)
25818c2ecf20Sopenharmony_ci{
25828c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = data;
25838c2ecf20Sopenharmony_ci
25848c2ecf20Sopenharmony_ci	if (toshiba_wireless_status(dev))
25858c2ecf20Sopenharmony_ci		return;
25868c2ecf20Sopenharmony_ci
25878c2ecf20Sopenharmony_ci	rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch);
25888c2ecf20Sopenharmony_ci}
25898c2ecf20Sopenharmony_ci
25908c2ecf20Sopenharmony_cistatic const struct rfkill_ops wwan_rfk_ops = {
25918c2ecf20Sopenharmony_ci	.set_block = toshiba_acpi_wwan_set_block,
25928c2ecf20Sopenharmony_ci	.poll = toshiba_acpi_wwan_poll,
25938c2ecf20Sopenharmony_ci};
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_cistatic int toshiba_acpi_setup_wwan_rfkill(struct toshiba_acpi_dev *dev)
25968c2ecf20Sopenharmony_ci{
25978c2ecf20Sopenharmony_ci	int ret = toshiba_wireless_status(dev);
25988c2ecf20Sopenharmony_ci
25998c2ecf20Sopenharmony_ci	if (ret)
26008c2ecf20Sopenharmony_ci		return ret;
26018c2ecf20Sopenharmony_ci
26028c2ecf20Sopenharmony_ci	dev->wwan_rfk = rfkill_alloc("Toshiba WWAN",
26038c2ecf20Sopenharmony_ci				     &dev->acpi_dev->dev,
26048c2ecf20Sopenharmony_ci				     RFKILL_TYPE_WWAN,
26058c2ecf20Sopenharmony_ci				     &wwan_rfk_ops,
26068c2ecf20Sopenharmony_ci				     dev);
26078c2ecf20Sopenharmony_ci	if (!dev->wwan_rfk) {
26088c2ecf20Sopenharmony_ci		pr_err("Unable to allocate WWAN rfkill device\n");
26098c2ecf20Sopenharmony_ci		return -ENOMEM;
26108c2ecf20Sopenharmony_ci	}
26118c2ecf20Sopenharmony_ci
26128c2ecf20Sopenharmony_ci	rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch);
26138c2ecf20Sopenharmony_ci
26148c2ecf20Sopenharmony_ci	ret = rfkill_register(dev->wwan_rfk);
26158c2ecf20Sopenharmony_ci	if (ret) {
26168c2ecf20Sopenharmony_ci		pr_err("Unable to register WWAN rfkill device\n");
26178c2ecf20Sopenharmony_ci		rfkill_destroy(dev->wwan_rfk);
26188c2ecf20Sopenharmony_ci	}
26198c2ecf20Sopenharmony_ci
26208c2ecf20Sopenharmony_ci	return ret;
26218c2ecf20Sopenharmony_ci}
26228c2ecf20Sopenharmony_ci
26238c2ecf20Sopenharmony_ci/*
26248c2ecf20Sopenharmony_ci * Hotkeys
26258c2ecf20Sopenharmony_ci */
26268c2ecf20Sopenharmony_cistatic int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev)
26278c2ecf20Sopenharmony_ci{
26288c2ecf20Sopenharmony_ci	acpi_status status;
26298c2ecf20Sopenharmony_ci	u32 result;
26308c2ecf20Sopenharmony_ci
26318c2ecf20Sopenharmony_ci	status = acpi_evaluate_object(dev->acpi_dev->handle,
26328c2ecf20Sopenharmony_ci				      "ENAB", NULL, NULL);
26338c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status))
26348c2ecf20Sopenharmony_ci		return -ENODEV;
26358c2ecf20Sopenharmony_ci
26368c2ecf20Sopenharmony_ci	/*
26378c2ecf20Sopenharmony_ci	 * Enable the "Special Functions" mode only if they are
26388c2ecf20Sopenharmony_ci	 * supported and if they are activated.
26398c2ecf20Sopenharmony_ci	 */
26408c2ecf20Sopenharmony_ci	if (dev->kbd_function_keys_supported && dev->special_functions)
26418c2ecf20Sopenharmony_ci		result = hci_write(dev, HCI_HOTKEY_EVENT,
26428c2ecf20Sopenharmony_ci				   HCI_HOTKEY_SPECIAL_FUNCTIONS);
26438c2ecf20Sopenharmony_ci	else
26448c2ecf20Sopenharmony_ci		result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE);
26458c2ecf20Sopenharmony_ci
26468c2ecf20Sopenharmony_ci	if (result == TOS_FAILURE)
26478c2ecf20Sopenharmony_ci		return -EIO;
26488c2ecf20Sopenharmony_ci	else if (result == TOS_NOT_SUPPORTED)
26498c2ecf20Sopenharmony_ci		return -ENODEV;
26508c2ecf20Sopenharmony_ci
26518c2ecf20Sopenharmony_ci	return 0;
26528c2ecf20Sopenharmony_ci}
26538c2ecf20Sopenharmony_ci
26548c2ecf20Sopenharmony_cistatic bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
26558c2ecf20Sopenharmony_ci				      struct serio *port)
26568c2ecf20Sopenharmony_ci{
26578c2ecf20Sopenharmony_ci	if (str & I8042_STR_AUXDATA)
26588c2ecf20Sopenharmony_ci		return false;
26598c2ecf20Sopenharmony_ci
26608c2ecf20Sopenharmony_ci	if (unlikely(data == 0xe0))
26618c2ecf20Sopenharmony_ci		return false;
26628c2ecf20Sopenharmony_ci
26638c2ecf20Sopenharmony_ci	if ((data & 0x7f) == TOS1900_FN_SCAN) {
26648c2ecf20Sopenharmony_ci		schedule_work(&toshiba_acpi->hotkey_work);
26658c2ecf20Sopenharmony_ci		return true;
26668c2ecf20Sopenharmony_ci	}
26678c2ecf20Sopenharmony_ci
26688c2ecf20Sopenharmony_ci	return false;
26698c2ecf20Sopenharmony_ci}
26708c2ecf20Sopenharmony_ci
26718c2ecf20Sopenharmony_cistatic void toshiba_acpi_hotkey_work(struct work_struct *work)
26728c2ecf20Sopenharmony_ci{
26738c2ecf20Sopenharmony_ci	acpi_handle ec_handle = ec_get_handle();
26748c2ecf20Sopenharmony_ci	acpi_status status;
26758c2ecf20Sopenharmony_ci
26768c2ecf20Sopenharmony_ci	if (!ec_handle)
26778c2ecf20Sopenharmony_ci		return;
26788c2ecf20Sopenharmony_ci
26798c2ecf20Sopenharmony_ci	status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL);
26808c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status))
26818c2ecf20Sopenharmony_ci		pr_err("ACPI NTFY method execution failed\n");
26828c2ecf20Sopenharmony_ci}
26838c2ecf20Sopenharmony_ci
26848c2ecf20Sopenharmony_ci/*
26858c2ecf20Sopenharmony_ci * Returns hotkey scancode, or < 0 on failure.
26868c2ecf20Sopenharmony_ci */
26878c2ecf20Sopenharmony_cistatic int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev)
26888c2ecf20Sopenharmony_ci{
26898c2ecf20Sopenharmony_ci	unsigned long long value;
26908c2ecf20Sopenharmony_ci	acpi_status status;
26918c2ecf20Sopenharmony_ci
26928c2ecf20Sopenharmony_ci	status = acpi_evaluate_integer(dev->acpi_dev->handle, "INFO",
26938c2ecf20Sopenharmony_ci				      NULL, &value);
26948c2ecf20Sopenharmony_ci	if (ACPI_FAILURE(status)) {
26958c2ecf20Sopenharmony_ci		pr_err("ACPI INFO method execution failed\n");
26968c2ecf20Sopenharmony_ci		return -EIO;
26978c2ecf20Sopenharmony_ci	}
26988c2ecf20Sopenharmony_ci
26998c2ecf20Sopenharmony_ci	return value;
27008c2ecf20Sopenharmony_ci}
27018c2ecf20Sopenharmony_ci
27028c2ecf20Sopenharmony_cistatic void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev,
27038c2ecf20Sopenharmony_ci				       int scancode)
27048c2ecf20Sopenharmony_ci{
27058c2ecf20Sopenharmony_ci	if (scancode == 0x100)
27068c2ecf20Sopenharmony_ci		return;
27078c2ecf20Sopenharmony_ci
27088c2ecf20Sopenharmony_ci	/* Act on key press; ignore key release */
27098c2ecf20Sopenharmony_ci	if (scancode & 0x80)
27108c2ecf20Sopenharmony_ci		return;
27118c2ecf20Sopenharmony_ci
27128c2ecf20Sopenharmony_ci	if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true))
27138c2ecf20Sopenharmony_ci		pr_info("Unknown key %x\n", scancode);
27148c2ecf20Sopenharmony_ci}
27158c2ecf20Sopenharmony_ci
27168c2ecf20Sopenharmony_cistatic void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev)
27178c2ecf20Sopenharmony_ci{
27188c2ecf20Sopenharmony_ci	if (dev->info_supported) {
27198c2ecf20Sopenharmony_ci		int scancode = toshiba_acpi_query_hotkey(dev);
27208c2ecf20Sopenharmony_ci
27218c2ecf20Sopenharmony_ci		if (scancode < 0) {
27228c2ecf20Sopenharmony_ci			pr_err("Failed to query hotkey event\n");
27238c2ecf20Sopenharmony_ci		} else if (scancode != 0) {
27248c2ecf20Sopenharmony_ci			toshiba_acpi_report_hotkey(dev, scancode);
27258c2ecf20Sopenharmony_ci			dev->key_event_valid = 1;
27268c2ecf20Sopenharmony_ci			dev->last_key_event = scancode;
27278c2ecf20Sopenharmony_ci		}
27288c2ecf20Sopenharmony_ci	} else if (dev->system_event_supported) {
27298c2ecf20Sopenharmony_ci		u32 result;
27308c2ecf20Sopenharmony_ci		u32 value;
27318c2ecf20Sopenharmony_ci		int retries = 3;
27328c2ecf20Sopenharmony_ci
27338c2ecf20Sopenharmony_ci		do {
27348c2ecf20Sopenharmony_ci			result = hci_read(dev, HCI_SYSTEM_EVENT, &value);
27358c2ecf20Sopenharmony_ci			switch (result) {
27368c2ecf20Sopenharmony_ci			case TOS_SUCCESS:
27378c2ecf20Sopenharmony_ci				toshiba_acpi_report_hotkey(dev, (int)value);
27388c2ecf20Sopenharmony_ci				dev->key_event_valid = 1;
27398c2ecf20Sopenharmony_ci				dev->last_key_event = value;
27408c2ecf20Sopenharmony_ci				break;
27418c2ecf20Sopenharmony_ci			case TOS_NOT_SUPPORTED:
27428c2ecf20Sopenharmony_ci				/*
27438c2ecf20Sopenharmony_ci				 * This is a workaround for an unresolved
27448c2ecf20Sopenharmony_ci				 * issue on some machines where system events
27458c2ecf20Sopenharmony_ci				 * sporadically become disabled.
27468c2ecf20Sopenharmony_ci				 */
27478c2ecf20Sopenharmony_ci				result = hci_write(dev, HCI_SYSTEM_EVENT, 1);
27488c2ecf20Sopenharmony_ci				if (result == TOS_SUCCESS)
27498c2ecf20Sopenharmony_ci					pr_notice("Re-enabled hotkeys\n");
27508c2ecf20Sopenharmony_ci				fallthrough;
27518c2ecf20Sopenharmony_ci			default:
27528c2ecf20Sopenharmony_ci				retries--;
27538c2ecf20Sopenharmony_ci				break;
27548c2ecf20Sopenharmony_ci			}
27558c2ecf20Sopenharmony_ci		} while (retries && result != TOS_FIFO_EMPTY);
27568c2ecf20Sopenharmony_ci	}
27578c2ecf20Sopenharmony_ci}
27588c2ecf20Sopenharmony_ci
27598c2ecf20Sopenharmony_cistatic int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
27608c2ecf20Sopenharmony_ci{
27618c2ecf20Sopenharmony_ci	const struct key_entry *keymap = toshiba_acpi_keymap;
27628c2ecf20Sopenharmony_ci	acpi_handle ec_handle;
27638c2ecf20Sopenharmony_ci	int error;
27648c2ecf20Sopenharmony_ci
27658c2ecf20Sopenharmony_ci	if (disable_hotkeys) {
27668c2ecf20Sopenharmony_ci		pr_info("Hotkeys disabled by module parameter\n");
27678c2ecf20Sopenharmony_ci		return 0;
27688c2ecf20Sopenharmony_ci	}
27698c2ecf20Sopenharmony_ci
27708c2ecf20Sopenharmony_ci	if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) {
27718c2ecf20Sopenharmony_ci		pr_info("WMI event detected, hotkeys will not be monitored\n");
27728c2ecf20Sopenharmony_ci		return 0;
27738c2ecf20Sopenharmony_ci	}
27748c2ecf20Sopenharmony_ci
27758c2ecf20Sopenharmony_ci	error = toshiba_acpi_enable_hotkeys(dev);
27768c2ecf20Sopenharmony_ci	if (error)
27778c2ecf20Sopenharmony_ci		return error;
27788c2ecf20Sopenharmony_ci
27798c2ecf20Sopenharmony_ci	if (toshiba_hotkey_event_type_get(dev, &dev->hotkey_event_type))
27808c2ecf20Sopenharmony_ci		pr_notice("Unable to query Hotkey Event Type\n");
27818c2ecf20Sopenharmony_ci
27828c2ecf20Sopenharmony_ci	dev->hotkey_dev = input_allocate_device();
27838c2ecf20Sopenharmony_ci	if (!dev->hotkey_dev)
27848c2ecf20Sopenharmony_ci		return -ENOMEM;
27858c2ecf20Sopenharmony_ci
27868c2ecf20Sopenharmony_ci	dev->hotkey_dev->name = "Toshiba input device";
27878c2ecf20Sopenharmony_ci	dev->hotkey_dev->phys = "toshiba_acpi/input0";
27888c2ecf20Sopenharmony_ci	dev->hotkey_dev->id.bustype = BUS_HOST;
27898c2ecf20Sopenharmony_ci
27908c2ecf20Sopenharmony_ci	if (dev->hotkey_event_type == HCI_SYSTEM_TYPE1 ||
27918c2ecf20Sopenharmony_ci	    !dev->kbd_function_keys_supported)
27928c2ecf20Sopenharmony_ci		keymap = toshiba_acpi_keymap;
27938c2ecf20Sopenharmony_ci	else if (dev->hotkey_event_type == HCI_SYSTEM_TYPE2 ||
27948c2ecf20Sopenharmony_ci		 dev->kbd_function_keys_supported)
27958c2ecf20Sopenharmony_ci		keymap = toshiba_acpi_alt_keymap;
27968c2ecf20Sopenharmony_ci	else
27978c2ecf20Sopenharmony_ci		pr_info("Unknown event type received %x\n",
27988c2ecf20Sopenharmony_ci			dev->hotkey_event_type);
27998c2ecf20Sopenharmony_ci	error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL);
28008c2ecf20Sopenharmony_ci	if (error)
28018c2ecf20Sopenharmony_ci		goto err_free_dev;
28028c2ecf20Sopenharmony_ci
28038c2ecf20Sopenharmony_ci	/*
28048c2ecf20Sopenharmony_ci	 * For some machines the SCI responsible for providing hotkey
28058c2ecf20Sopenharmony_ci	 * notification doesn't fire. We can trigger the notification
28068c2ecf20Sopenharmony_ci	 * whenever the Fn key is pressed using the NTFY method, if
28078c2ecf20Sopenharmony_ci	 * supported, so if it's present set up an i8042 key filter
28088c2ecf20Sopenharmony_ci	 * for this purpose.
28098c2ecf20Sopenharmony_ci	 */
28108c2ecf20Sopenharmony_ci	ec_handle = ec_get_handle();
28118c2ecf20Sopenharmony_ci	if (ec_handle && acpi_has_method(ec_handle, "NTFY")) {
28128c2ecf20Sopenharmony_ci		INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work);
28138c2ecf20Sopenharmony_ci
28148c2ecf20Sopenharmony_ci		error = i8042_install_filter(toshiba_acpi_i8042_filter);
28158c2ecf20Sopenharmony_ci		if (error) {
28168c2ecf20Sopenharmony_ci			pr_err("Error installing key filter\n");
28178c2ecf20Sopenharmony_ci			goto err_free_dev;
28188c2ecf20Sopenharmony_ci		}
28198c2ecf20Sopenharmony_ci
28208c2ecf20Sopenharmony_ci		dev->ntfy_supported = 1;
28218c2ecf20Sopenharmony_ci	}
28228c2ecf20Sopenharmony_ci
28238c2ecf20Sopenharmony_ci	/*
28248c2ecf20Sopenharmony_ci	 * Determine hotkey query interface. Prefer using the INFO
28258c2ecf20Sopenharmony_ci	 * method when it is available.
28268c2ecf20Sopenharmony_ci	 */
28278c2ecf20Sopenharmony_ci	if (acpi_has_method(dev->acpi_dev->handle, "INFO"))
28288c2ecf20Sopenharmony_ci		dev->info_supported = 1;
28298c2ecf20Sopenharmony_ci	else if (hci_write(dev, HCI_SYSTEM_EVENT, 1) == TOS_SUCCESS)
28308c2ecf20Sopenharmony_ci		dev->system_event_supported = 1;
28318c2ecf20Sopenharmony_ci
28328c2ecf20Sopenharmony_ci	if (!dev->info_supported && !dev->system_event_supported) {
28338c2ecf20Sopenharmony_ci		pr_warn("No hotkey query interface found\n");
28348c2ecf20Sopenharmony_ci		error = -EINVAL;
28358c2ecf20Sopenharmony_ci		goto err_remove_filter;
28368c2ecf20Sopenharmony_ci	}
28378c2ecf20Sopenharmony_ci
28388c2ecf20Sopenharmony_ci	error = input_register_device(dev->hotkey_dev);
28398c2ecf20Sopenharmony_ci	if (error) {
28408c2ecf20Sopenharmony_ci		pr_info("Unable to register input device\n");
28418c2ecf20Sopenharmony_ci		goto err_remove_filter;
28428c2ecf20Sopenharmony_ci	}
28438c2ecf20Sopenharmony_ci
28448c2ecf20Sopenharmony_ci	return 0;
28458c2ecf20Sopenharmony_ci
28468c2ecf20Sopenharmony_ci err_remove_filter:
28478c2ecf20Sopenharmony_ci	if (dev->ntfy_supported)
28488c2ecf20Sopenharmony_ci		i8042_remove_filter(toshiba_acpi_i8042_filter);
28498c2ecf20Sopenharmony_ci err_free_dev:
28508c2ecf20Sopenharmony_ci	input_free_device(dev->hotkey_dev);
28518c2ecf20Sopenharmony_ci	dev->hotkey_dev = NULL;
28528c2ecf20Sopenharmony_ci	return error;
28538c2ecf20Sopenharmony_ci}
28548c2ecf20Sopenharmony_ci
28558c2ecf20Sopenharmony_cistatic int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
28568c2ecf20Sopenharmony_ci{
28578c2ecf20Sopenharmony_ci	struct backlight_properties props;
28588c2ecf20Sopenharmony_ci	int brightness;
28598c2ecf20Sopenharmony_ci	int ret;
28608c2ecf20Sopenharmony_ci
28618c2ecf20Sopenharmony_ci	/*
28628c2ecf20Sopenharmony_ci	 * Some machines don't support the backlight methods at all, and
28638c2ecf20Sopenharmony_ci	 * others support it read-only. Either of these is pretty useless,
28648c2ecf20Sopenharmony_ci	 * so only register the backlight device if the backlight method
28658c2ecf20Sopenharmony_ci	 * supports both reads and writes.
28668c2ecf20Sopenharmony_ci	 */
28678c2ecf20Sopenharmony_ci	brightness = __get_lcd_brightness(dev);
28688c2ecf20Sopenharmony_ci	if (brightness < 0)
28698c2ecf20Sopenharmony_ci		return 0;
28708c2ecf20Sopenharmony_ci	/*
28718c2ecf20Sopenharmony_ci	 * If transflective backlight is supported and the brightness is zero
28728c2ecf20Sopenharmony_ci	 * (lowest brightness level), the set_lcd_brightness function will
28738c2ecf20Sopenharmony_ci	 * activate the transflective backlight, making the LCD appear to be
28748c2ecf20Sopenharmony_ci	 * turned off, simply increment the brightness level to avoid that.
28758c2ecf20Sopenharmony_ci	 */
28768c2ecf20Sopenharmony_ci	if (dev->tr_backlight_supported && brightness == 0)
28778c2ecf20Sopenharmony_ci		brightness++;
28788c2ecf20Sopenharmony_ci	ret = set_lcd_brightness(dev, brightness);
28798c2ecf20Sopenharmony_ci	if (ret) {
28808c2ecf20Sopenharmony_ci		pr_debug("Backlight method is read-only, disabling backlight support\n");
28818c2ecf20Sopenharmony_ci		return 0;
28828c2ecf20Sopenharmony_ci	}
28838c2ecf20Sopenharmony_ci
28848c2ecf20Sopenharmony_ci	/*
28858c2ecf20Sopenharmony_ci	 * Tell acpi-video-detect code to prefer vendor backlight on all
28868c2ecf20Sopenharmony_ci	 * systems with transflective backlight and on dmi matched systems.
28878c2ecf20Sopenharmony_ci	 */
28888c2ecf20Sopenharmony_ci	if (dev->tr_backlight_supported ||
28898c2ecf20Sopenharmony_ci	    dmi_check_system(toshiba_vendor_backlight_dmi))
28908c2ecf20Sopenharmony_ci		acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
28918c2ecf20Sopenharmony_ci
28928c2ecf20Sopenharmony_ci	if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
28938c2ecf20Sopenharmony_ci		return 0;
28948c2ecf20Sopenharmony_ci
28958c2ecf20Sopenharmony_ci	memset(&props, 0, sizeof(props));
28968c2ecf20Sopenharmony_ci	props.type = BACKLIGHT_PLATFORM;
28978c2ecf20Sopenharmony_ci	props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
28988c2ecf20Sopenharmony_ci
28998c2ecf20Sopenharmony_ci	/* Adding an extra level and having 0 change to transflective mode */
29008c2ecf20Sopenharmony_ci	if (dev->tr_backlight_supported)
29018c2ecf20Sopenharmony_ci		props.max_brightness++;
29028c2ecf20Sopenharmony_ci
29038c2ecf20Sopenharmony_ci	dev->backlight_dev = backlight_device_register("toshiba",
29048c2ecf20Sopenharmony_ci						       &dev->acpi_dev->dev,
29058c2ecf20Sopenharmony_ci						       dev,
29068c2ecf20Sopenharmony_ci						       &toshiba_backlight_data,
29078c2ecf20Sopenharmony_ci						       &props);
29088c2ecf20Sopenharmony_ci	if (IS_ERR(dev->backlight_dev)) {
29098c2ecf20Sopenharmony_ci		ret = PTR_ERR(dev->backlight_dev);
29108c2ecf20Sopenharmony_ci		pr_err("Could not register toshiba backlight device\n");
29118c2ecf20Sopenharmony_ci		dev->backlight_dev = NULL;
29128c2ecf20Sopenharmony_ci		return ret;
29138c2ecf20Sopenharmony_ci	}
29148c2ecf20Sopenharmony_ci
29158c2ecf20Sopenharmony_ci	dev->backlight_dev->props.brightness = brightness;
29168c2ecf20Sopenharmony_ci	return 0;
29178c2ecf20Sopenharmony_ci}
29188c2ecf20Sopenharmony_ci
29198c2ecf20Sopenharmony_cistatic void print_supported_features(struct toshiba_acpi_dev *dev)
29208c2ecf20Sopenharmony_ci{
29218c2ecf20Sopenharmony_ci	pr_info("Supported laptop features:");
29228c2ecf20Sopenharmony_ci
29238c2ecf20Sopenharmony_ci	if (dev->hotkey_dev)
29248c2ecf20Sopenharmony_ci		pr_cont(" hotkeys");
29258c2ecf20Sopenharmony_ci	if (dev->backlight_dev)
29268c2ecf20Sopenharmony_ci		pr_cont(" backlight");
29278c2ecf20Sopenharmony_ci	if (dev->video_supported)
29288c2ecf20Sopenharmony_ci		pr_cont(" video-out");
29298c2ecf20Sopenharmony_ci	if (dev->fan_supported)
29308c2ecf20Sopenharmony_ci		pr_cont(" fan");
29318c2ecf20Sopenharmony_ci	if (dev->tr_backlight_supported)
29328c2ecf20Sopenharmony_ci		pr_cont(" transflective-backlight");
29338c2ecf20Sopenharmony_ci	if (dev->illumination_supported)
29348c2ecf20Sopenharmony_ci		pr_cont(" illumination");
29358c2ecf20Sopenharmony_ci	if (dev->kbd_illum_supported)
29368c2ecf20Sopenharmony_ci		pr_cont(" keyboard-backlight");
29378c2ecf20Sopenharmony_ci	if (dev->touchpad_supported)
29388c2ecf20Sopenharmony_ci		pr_cont(" touchpad");
29398c2ecf20Sopenharmony_ci	if (dev->eco_supported)
29408c2ecf20Sopenharmony_ci		pr_cont(" eco-led");
29418c2ecf20Sopenharmony_ci	if (dev->accelerometer_supported)
29428c2ecf20Sopenharmony_ci		pr_cont(" accelerometer-axes");
29438c2ecf20Sopenharmony_ci	if (dev->usb_sleep_charge_supported)
29448c2ecf20Sopenharmony_ci		pr_cont(" usb-sleep-charge");
29458c2ecf20Sopenharmony_ci	if (dev->usb_rapid_charge_supported)
29468c2ecf20Sopenharmony_ci		pr_cont(" usb-rapid-charge");
29478c2ecf20Sopenharmony_ci	if (dev->usb_sleep_music_supported)
29488c2ecf20Sopenharmony_ci		pr_cont(" usb-sleep-music");
29498c2ecf20Sopenharmony_ci	if (dev->kbd_function_keys_supported)
29508c2ecf20Sopenharmony_ci		pr_cont(" special-function-keys");
29518c2ecf20Sopenharmony_ci	if (dev->panel_power_on_supported)
29528c2ecf20Sopenharmony_ci		pr_cont(" panel-power-on");
29538c2ecf20Sopenharmony_ci	if (dev->usb_three_supported)
29548c2ecf20Sopenharmony_ci		pr_cont(" usb3");
29558c2ecf20Sopenharmony_ci	if (dev->wwan_supported)
29568c2ecf20Sopenharmony_ci		pr_cont(" wwan");
29578c2ecf20Sopenharmony_ci	if (dev->cooling_method_supported)
29588c2ecf20Sopenharmony_ci		pr_cont(" cooling-method");
29598c2ecf20Sopenharmony_ci
29608c2ecf20Sopenharmony_ci	pr_cont("\n");
29618c2ecf20Sopenharmony_ci}
29628c2ecf20Sopenharmony_ci
29638c2ecf20Sopenharmony_cistatic int toshiba_acpi_remove(struct acpi_device *acpi_dev)
29648c2ecf20Sopenharmony_ci{
29658c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
29668c2ecf20Sopenharmony_ci
29678c2ecf20Sopenharmony_ci	misc_deregister(&dev->miscdev);
29688c2ecf20Sopenharmony_ci
29698c2ecf20Sopenharmony_ci	remove_toshiba_proc_entries(dev);
29708c2ecf20Sopenharmony_ci
29718c2ecf20Sopenharmony_ci	if (dev->accelerometer_supported && dev->indio_dev) {
29728c2ecf20Sopenharmony_ci		iio_device_unregister(dev->indio_dev);
29738c2ecf20Sopenharmony_ci		iio_device_free(dev->indio_dev);
29748c2ecf20Sopenharmony_ci	}
29758c2ecf20Sopenharmony_ci
29768c2ecf20Sopenharmony_ci	if (dev->sysfs_created)
29778c2ecf20Sopenharmony_ci		sysfs_remove_group(&dev->acpi_dev->dev.kobj,
29788c2ecf20Sopenharmony_ci				   &toshiba_attr_group);
29798c2ecf20Sopenharmony_ci
29808c2ecf20Sopenharmony_ci	if (dev->ntfy_supported) {
29818c2ecf20Sopenharmony_ci		i8042_remove_filter(toshiba_acpi_i8042_filter);
29828c2ecf20Sopenharmony_ci		cancel_work_sync(&dev->hotkey_work);
29838c2ecf20Sopenharmony_ci	}
29848c2ecf20Sopenharmony_ci
29858c2ecf20Sopenharmony_ci	if (dev->hotkey_dev)
29868c2ecf20Sopenharmony_ci		input_unregister_device(dev->hotkey_dev);
29878c2ecf20Sopenharmony_ci
29888c2ecf20Sopenharmony_ci	backlight_device_unregister(dev->backlight_dev);
29898c2ecf20Sopenharmony_ci
29908c2ecf20Sopenharmony_ci	led_classdev_unregister(&dev->led_dev);
29918c2ecf20Sopenharmony_ci	led_classdev_unregister(&dev->kbd_led);
29928c2ecf20Sopenharmony_ci	led_classdev_unregister(&dev->eco_led);
29938c2ecf20Sopenharmony_ci
29948c2ecf20Sopenharmony_ci	if (dev->wwan_rfk) {
29958c2ecf20Sopenharmony_ci		rfkill_unregister(dev->wwan_rfk);
29968c2ecf20Sopenharmony_ci		rfkill_destroy(dev->wwan_rfk);
29978c2ecf20Sopenharmony_ci	}
29988c2ecf20Sopenharmony_ci
29998c2ecf20Sopenharmony_ci	if (toshiba_acpi)
30008c2ecf20Sopenharmony_ci		toshiba_acpi = NULL;
30018c2ecf20Sopenharmony_ci
30028c2ecf20Sopenharmony_ci	kfree(dev);
30038c2ecf20Sopenharmony_ci
30048c2ecf20Sopenharmony_ci	return 0;
30058c2ecf20Sopenharmony_ci}
30068c2ecf20Sopenharmony_ci
30078c2ecf20Sopenharmony_cistatic const char *find_hci_method(acpi_handle handle)
30088c2ecf20Sopenharmony_ci{
30098c2ecf20Sopenharmony_ci	if (acpi_has_method(handle, "GHCI"))
30108c2ecf20Sopenharmony_ci		return "GHCI";
30118c2ecf20Sopenharmony_ci
30128c2ecf20Sopenharmony_ci	if (acpi_has_method(handle, "SPFC"))
30138c2ecf20Sopenharmony_ci		return "SPFC";
30148c2ecf20Sopenharmony_ci
30158c2ecf20Sopenharmony_ci	return NULL;
30168c2ecf20Sopenharmony_ci}
30178c2ecf20Sopenharmony_ci
30188c2ecf20Sopenharmony_cistatic int toshiba_acpi_add(struct acpi_device *acpi_dev)
30198c2ecf20Sopenharmony_ci{
30208c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev;
30218c2ecf20Sopenharmony_ci	const char *hci_method;
30228c2ecf20Sopenharmony_ci	u32 dummy;
30238c2ecf20Sopenharmony_ci	int ret = 0;
30248c2ecf20Sopenharmony_ci
30258c2ecf20Sopenharmony_ci	if (toshiba_acpi)
30268c2ecf20Sopenharmony_ci		return -EBUSY;
30278c2ecf20Sopenharmony_ci
30288c2ecf20Sopenharmony_ci	pr_info("Toshiba Laptop ACPI Extras version %s\n",
30298c2ecf20Sopenharmony_ci	       TOSHIBA_ACPI_VERSION);
30308c2ecf20Sopenharmony_ci
30318c2ecf20Sopenharmony_ci	hci_method = find_hci_method(acpi_dev->handle);
30328c2ecf20Sopenharmony_ci	if (!hci_method) {
30338c2ecf20Sopenharmony_ci		pr_err("HCI interface not found\n");
30348c2ecf20Sopenharmony_ci		return -ENODEV;
30358c2ecf20Sopenharmony_ci	}
30368c2ecf20Sopenharmony_ci
30378c2ecf20Sopenharmony_ci	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
30388c2ecf20Sopenharmony_ci	if (!dev)
30398c2ecf20Sopenharmony_ci		return -ENOMEM;
30408c2ecf20Sopenharmony_ci	dev->acpi_dev = acpi_dev;
30418c2ecf20Sopenharmony_ci	dev->method_hci = hci_method;
30428c2ecf20Sopenharmony_ci	dev->miscdev.minor = MISC_DYNAMIC_MINOR;
30438c2ecf20Sopenharmony_ci	dev->miscdev.name = "toshiba_acpi";
30448c2ecf20Sopenharmony_ci	dev->miscdev.fops = &toshiba_acpi_fops;
30458c2ecf20Sopenharmony_ci
30468c2ecf20Sopenharmony_ci	ret = misc_register(&dev->miscdev);
30478c2ecf20Sopenharmony_ci	if (ret) {
30488c2ecf20Sopenharmony_ci		pr_err("Failed to register miscdevice\n");
30498c2ecf20Sopenharmony_ci		kfree(dev);
30508c2ecf20Sopenharmony_ci		return ret;
30518c2ecf20Sopenharmony_ci	}
30528c2ecf20Sopenharmony_ci
30538c2ecf20Sopenharmony_ci	acpi_dev->driver_data = dev;
30548c2ecf20Sopenharmony_ci	dev_set_drvdata(&acpi_dev->dev, dev);
30558c2ecf20Sopenharmony_ci
30568c2ecf20Sopenharmony_ci	/* Query the BIOS for supported features */
30578c2ecf20Sopenharmony_ci
30588c2ecf20Sopenharmony_ci	/*
30598c2ecf20Sopenharmony_ci	 * The "Special Functions" are always supported by the laptops
30608c2ecf20Sopenharmony_ci	 * with the new keyboard layout, query for its presence to help
30618c2ecf20Sopenharmony_ci	 * determine the keymap layout to use.
30628c2ecf20Sopenharmony_ci	 */
30638c2ecf20Sopenharmony_ci	ret = toshiba_function_keys_get(dev, &dev->special_functions);
30648c2ecf20Sopenharmony_ci	dev->kbd_function_keys_supported = !ret;
30658c2ecf20Sopenharmony_ci
30668c2ecf20Sopenharmony_ci	dev->hotkey_event_type = 0;
30678c2ecf20Sopenharmony_ci	if (toshiba_acpi_setup_keyboard(dev))
30688c2ecf20Sopenharmony_ci		pr_info("Unable to activate hotkeys\n");
30698c2ecf20Sopenharmony_ci
30708c2ecf20Sopenharmony_ci	/* Determine whether or not BIOS supports transflective backlight */
30718c2ecf20Sopenharmony_ci	ret = get_tr_backlight_status(dev, &dummy);
30728c2ecf20Sopenharmony_ci	dev->tr_backlight_supported = !ret;
30738c2ecf20Sopenharmony_ci
30748c2ecf20Sopenharmony_ci	ret = toshiba_acpi_setup_backlight(dev);
30758c2ecf20Sopenharmony_ci	if (ret)
30768c2ecf20Sopenharmony_ci		goto error;
30778c2ecf20Sopenharmony_ci
30788c2ecf20Sopenharmony_ci	toshiba_illumination_available(dev);
30798c2ecf20Sopenharmony_ci	if (dev->illumination_supported) {
30808c2ecf20Sopenharmony_ci		dev->led_dev.name = "toshiba::illumination";
30818c2ecf20Sopenharmony_ci		dev->led_dev.max_brightness = 1;
30828c2ecf20Sopenharmony_ci		dev->led_dev.brightness_set = toshiba_illumination_set;
30838c2ecf20Sopenharmony_ci		dev->led_dev.brightness_get = toshiba_illumination_get;
30848c2ecf20Sopenharmony_ci		led_classdev_register(&acpi_dev->dev, &dev->led_dev);
30858c2ecf20Sopenharmony_ci	}
30868c2ecf20Sopenharmony_ci
30878c2ecf20Sopenharmony_ci	toshiba_eco_mode_available(dev);
30888c2ecf20Sopenharmony_ci	if (dev->eco_supported) {
30898c2ecf20Sopenharmony_ci		dev->eco_led.name = "toshiba::eco_mode";
30908c2ecf20Sopenharmony_ci		dev->eco_led.max_brightness = 1;
30918c2ecf20Sopenharmony_ci		dev->eco_led.brightness_set = toshiba_eco_mode_set_status;
30928c2ecf20Sopenharmony_ci		dev->eco_led.brightness_get = toshiba_eco_mode_get_status;
30938c2ecf20Sopenharmony_ci		led_classdev_register(&dev->acpi_dev->dev, &dev->eco_led);
30948c2ecf20Sopenharmony_ci	}
30958c2ecf20Sopenharmony_ci
30968c2ecf20Sopenharmony_ci	toshiba_kbd_illum_available(dev);
30978c2ecf20Sopenharmony_ci	/*
30988c2ecf20Sopenharmony_ci	 * Only register the LED if KBD illumination is supported
30998c2ecf20Sopenharmony_ci	 * and the keyboard backlight operation mode is set to FN-Z
31008c2ecf20Sopenharmony_ci	 * or we detect a second gen keyboard backlight
31018c2ecf20Sopenharmony_ci	 */
31028c2ecf20Sopenharmony_ci	if (dev->kbd_illum_supported &&
31038c2ecf20Sopenharmony_ci	    (dev->kbd_mode == SCI_KBD_MODE_FNZ || dev->kbd_type == 2)) {
31048c2ecf20Sopenharmony_ci		dev->kbd_led.name = "toshiba::kbd_backlight";
31058c2ecf20Sopenharmony_ci		dev->kbd_led.flags = LED_BRIGHT_HW_CHANGED;
31068c2ecf20Sopenharmony_ci		dev->kbd_led.max_brightness = 1;
31078c2ecf20Sopenharmony_ci		dev->kbd_led.brightness_set = toshiba_kbd_backlight_set;
31088c2ecf20Sopenharmony_ci		dev->kbd_led.brightness_get = toshiba_kbd_backlight_get;
31098c2ecf20Sopenharmony_ci		led_classdev_register(&dev->acpi_dev->dev, &dev->kbd_led);
31108c2ecf20Sopenharmony_ci	}
31118c2ecf20Sopenharmony_ci
31128c2ecf20Sopenharmony_ci	ret = toshiba_touchpad_get(dev, &dummy);
31138c2ecf20Sopenharmony_ci	dev->touchpad_supported = !ret;
31148c2ecf20Sopenharmony_ci
31158c2ecf20Sopenharmony_ci	toshiba_accelerometer_available(dev);
31168c2ecf20Sopenharmony_ci	if (dev->accelerometer_supported) {
31178c2ecf20Sopenharmony_ci		dev->indio_dev = iio_device_alloc(&acpi_dev->dev, sizeof(*dev));
31188c2ecf20Sopenharmony_ci		if (!dev->indio_dev) {
31198c2ecf20Sopenharmony_ci			pr_err("Unable to allocate iio device\n");
31208c2ecf20Sopenharmony_ci			goto iio_error;
31218c2ecf20Sopenharmony_ci		}
31228c2ecf20Sopenharmony_ci
31238c2ecf20Sopenharmony_ci		pr_info("Registering Toshiba accelerometer iio device\n");
31248c2ecf20Sopenharmony_ci
31258c2ecf20Sopenharmony_ci		dev->indio_dev->info = &toshiba_iio_accel_info;
31268c2ecf20Sopenharmony_ci		dev->indio_dev->name = "Toshiba accelerometer";
31278c2ecf20Sopenharmony_ci		dev->indio_dev->modes = INDIO_DIRECT_MODE;
31288c2ecf20Sopenharmony_ci		dev->indio_dev->channels = toshiba_iio_accel_channels;
31298c2ecf20Sopenharmony_ci		dev->indio_dev->num_channels =
31308c2ecf20Sopenharmony_ci					ARRAY_SIZE(toshiba_iio_accel_channels);
31318c2ecf20Sopenharmony_ci
31328c2ecf20Sopenharmony_ci		ret = iio_device_register(dev->indio_dev);
31338c2ecf20Sopenharmony_ci		if (ret < 0) {
31348c2ecf20Sopenharmony_ci			pr_err("Unable to register iio device\n");
31358c2ecf20Sopenharmony_ci			iio_device_free(dev->indio_dev);
31368c2ecf20Sopenharmony_ci		}
31378c2ecf20Sopenharmony_ci	}
31388c2ecf20Sopenharmony_ciiio_error:
31398c2ecf20Sopenharmony_ci
31408c2ecf20Sopenharmony_ci	toshiba_usb_sleep_charge_available(dev);
31418c2ecf20Sopenharmony_ci
31428c2ecf20Sopenharmony_ci	ret = toshiba_usb_rapid_charge_get(dev, &dummy);
31438c2ecf20Sopenharmony_ci	dev->usb_rapid_charge_supported = !ret;
31448c2ecf20Sopenharmony_ci
31458c2ecf20Sopenharmony_ci	ret = toshiba_usb_sleep_music_get(dev, &dummy);
31468c2ecf20Sopenharmony_ci	dev->usb_sleep_music_supported = !ret;
31478c2ecf20Sopenharmony_ci
31488c2ecf20Sopenharmony_ci	ret = toshiba_panel_power_on_get(dev, &dummy);
31498c2ecf20Sopenharmony_ci	dev->panel_power_on_supported = !ret;
31508c2ecf20Sopenharmony_ci
31518c2ecf20Sopenharmony_ci	ret = toshiba_usb_three_get(dev, &dummy);
31528c2ecf20Sopenharmony_ci	dev->usb_three_supported = !ret;
31538c2ecf20Sopenharmony_ci
31548c2ecf20Sopenharmony_ci	ret = get_video_status(dev, &dummy);
31558c2ecf20Sopenharmony_ci	dev->video_supported = !ret;
31568c2ecf20Sopenharmony_ci
31578c2ecf20Sopenharmony_ci	ret = get_fan_status(dev, &dummy);
31588c2ecf20Sopenharmony_ci	dev->fan_supported = !ret;
31598c2ecf20Sopenharmony_ci
31608c2ecf20Sopenharmony_ci	toshiba_wwan_available(dev);
31618c2ecf20Sopenharmony_ci	if (dev->wwan_supported)
31628c2ecf20Sopenharmony_ci		toshiba_acpi_setup_wwan_rfkill(dev);
31638c2ecf20Sopenharmony_ci
31648c2ecf20Sopenharmony_ci	toshiba_cooling_method_available(dev);
31658c2ecf20Sopenharmony_ci
31668c2ecf20Sopenharmony_ci	print_supported_features(dev);
31678c2ecf20Sopenharmony_ci
31688c2ecf20Sopenharmony_ci	ret = sysfs_create_group(&dev->acpi_dev->dev.kobj,
31698c2ecf20Sopenharmony_ci				 &toshiba_attr_group);
31708c2ecf20Sopenharmony_ci	if (ret) {
31718c2ecf20Sopenharmony_ci		dev->sysfs_created = 0;
31728c2ecf20Sopenharmony_ci		goto error;
31738c2ecf20Sopenharmony_ci	}
31748c2ecf20Sopenharmony_ci	dev->sysfs_created = !ret;
31758c2ecf20Sopenharmony_ci
31768c2ecf20Sopenharmony_ci	create_toshiba_proc_entries(dev);
31778c2ecf20Sopenharmony_ci
31788c2ecf20Sopenharmony_ci	toshiba_acpi = dev;
31798c2ecf20Sopenharmony_ci
31808c2ecf20Sopenharmony_ci	return 0;
31818c2ecf20Sopenharmony_ci
31828c2ecf20Sopenharmony_cierror:
31838c2ecf20Sopenharmony_ci	toshiba_acpi_remove(acpi_dev);
31848c2ecf20Sopenharmony_ci	return ret;
31858c2ecf20Sopenharmony_ci}
31868c2ecf20Sopenharmony_ci
31878c2ecf20Sopenharmony_cistatic void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
31888c2ecf20Sopenharmony_ci{
31898c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
31908c2ecf20Sopenharmony_ci
31918c2ecf20Sopenharmony_ci	switch (event) {
31928c2ecf20Sopenharmony_ci	case 0x80: /* Hotkeys and some system events */
31938c2ecf20Sopenharmony_ci		/*
31948c2ecf20Sopenharmony_ci		 * Machines with this WMI GUID aren't supported due to bugs in
31958c2ecf20Sopenharmony_ci		 * their AML.
31968c2ecf20Sopenharmony_ci		 *
31978c2ecf20Sopenharmony_ci		 * Return silently to avoid triggering a netlink event.
31988c2ecf20Sopenharmony_ci		 */
31998c2ecf20Sopenharmony_ci		if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
32008c2ecf20Sopenharmony_ci			return;
32018c2ecf20Sopenharmony_ci		toshiba_acpi_process_hotkeys(dev);
32028c2ecf20Sopenharmony_ci		break;
32038c2ecf20Sopenharmony_ci	case 0x81: /* Dock events */
32048c2ecf20Sopenharmony_ci	case 0x82:
32058c2ecf20Sopenharmony_ci	case 0x83:
32068c2ecf20Sopenharmony_ci		pr_info("Dock event received %x\n", event);
32078c2ecf20Sopenharmony_ci		break;
32088c2ecf20Sopenharmony_ci	case 0x88: /* Thermal events */
32098c2ecf20Sopenharmony_ci		pr_info("Thermal event received\n");
32108c2ecf20Sopenharmony_ci		break;
32118c2ecf20Sopenharmony_ci	case 0x8f: /* LID closed */
32128c2ecf20Sopenharmony_ci	case 0x90: /* LID is closed and Dock has been ejected */
32138c2ecf20Sopenharmony_ci		break;
32148c2ecf20Sopenharmony_ci	case 0x8c: /* SATA power events */
32158c2ecf20Sopenharmony_ci	case 0x8b:
32168c2ecf20Sopenharmony_ci		pr_info("SATA power event received %x\n", event);
32178c2ecf20Sopenharmony_ci		break;
32188c2ecf20Sopenharmony_ci	case 0x92: /* Keyboard backlight mode changed */
32198c2ecf20Sopenharmony_ci		dev->kbd_event_generated = true;
32208c2ecf20Sopenharmony_ci		/* Update sysfs entries */
32218c2ecf20Sopenharmony_ci		if (sysfs_update_group(&acpi_dev->dev.kobj,
32228c2ecf20Sopenharmony_ci				       &toshiba_attr_group))
32238c2ecf20Sopenharmony_ci			pr_err("Unable to update sysfs entries\n");
32248c2ecf20Sopenharmony_ci		/* Notify LED subsystem about keyboard backlight change */
32258c2ecf20Sopenharmony_ci		if (dev->kbd_type == 2 && dev->kbd_mode != SCI_KBD_MODE_AUTO)
32268c2ecf20Sopenharmony_ci			led_classdev_notify_brightness_hw_changed(&dev->kbd_led,
32278c2ecf20Sopenharmony_ci					(dev->kbd_mode == SCI_KBD_MODE_ON) ?
32288c2ecf20Sopenharmony_ci					LED_FULL : LED_OFF);
32298c2ecf20Sopenharmony_ci		break;
32308c2ecf20Sopenharmony_ci	case 0x85: /* Unknown */
32318c2ecf20Sopenharmony_ci	case 0x8d: /* Unknown */
32328c2ecf20Sopenharmony_ci	case 0x8e: /* Unknown */
32338c2ecf20Sopenharmony_ci	case 0x94: /* Unknown */
32348c2ecf20Sopenharmony_ci	case 0x95: /* Unknown */
32358c2ecf20Sopenharmony_ci	default:
32368c2ecf20Sopenharmony_ci		pr_info("Unknown event received %x\n", event);
32378c2ecf20Sopenharmony_ci		break;
32388c2ecf20Sopenharmony_ci	}
32398c2ecf20Sopenharmony_ci
32408c2ecf20Sopenharmony_ci	acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class,
32418c2ecf20Sopenharmony_ci					dev_name(&acpi_dev->dev),
32428c2ecf20Sopenharmony_ci					event, (event == 0x80) ?
32438c2ecf20Sopenharmony_ci					dev->last_key_event : 0);
32448c2ecf20Sopenharmony_ci}
32458c2ecf20Sopenharmony_ci
32468c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
32478c2ecf20Sopenharmony_cistatic int toshiba_acpi_suspend(struct device *device)
32488c2ecf20Sopenharmony_ci{
32498c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
32508c2ecf20Sopenharmony_ci
32518c2ecf20Sopenharmony_ci	if (dev->hotkey_dev) {
32528c2ecf20Sopenharmony_ci		u32 result;
32538c2ecf20Sopenharmony_ci
32548c2ecf20Sopenharmony_ci		result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE);
32558c2ecf20Sopenharmony_ci		if (result != TOS_SUCCESS)
32568c2ecf20Sopenharmony_ci			pr_info("Unable to disable hotkeys\n");
32578c2ecf20Sopenharmony_ci	}
32588c2ecf20Sopenharmony_ci
32598c2ecf20Sopenharmony_ci	return 0;
32608c2ecf20Sopenharmony_ci}
32618c2ecf20Sopenharmony_ci
32628c2ecf20Sopenharmony_cistatic int toshiba_acpi_resume(struct device *device)
32638c2ecf20Sopenharmony_ci{
32648c2ecf20Sopenharmony_ci	struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
32658c2ecf20Sopenharmony_ci
32668c2ecf20Sopenharmony_ci	if (dev->hotkey_dev) {
32678c2ecf20Sopenharmony_ci		if (toshiba_acpi_enable_hotkeys(dev))
32688c2ecf20Sopenharmony_ci			pr_info("Unable to re-enable hotkeys\n");
32698c2ecf20Sopenharmony_ci	}
32708c2ecf20Sopenharmony_ci
32718c2ecf20Sopenharmony_ci	if (dev->wwan_rfk) {
32728c2ecf20Sopenharmony_ci		if (!toshiba_wireless_status(dev))
32738c2ecf20Sopenharmony_ci			rfkill_set_hw_state(dev->wwan_rfk, !dev->killswitch);
32748c2ecf20Sopenharmony_ci	}
32758c2ecf20Sopenharmony_ci
32768c2ecf20Sopenharmony_ci	return 0;
32778c2ecf20Sopenharmony_ci}
32788c2ecf20Sopenharmony_ci#endif
32798c2ecf20Sopenharmony_ci
32808c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(toshiba_acpi_pm,
32818c2ecf20Sopenharmony_ci			 toshiba_acpi_suspend, toshiba_acpi_resume);
32828c2ecf20Sopenharmony_ci
32838c2ecf20Sopenharmony_cistatic struct acpi_driver toshiba_acpi_driver = {
32848c2ecf20Sopenharmony_ci	.name	= "Toshiba ACPI driver",
32858c2ecf20Sopenharmony_ci	.owner	= THIS_MODULE,
32868c2ecf20Sopenharmony_ci	.ids	= toshiba_device_ids,
32878c2ecf20Sopenharmony_ci	.flags	= ACPI_DRIVER_ALL_NOTIFY_EVENTS,
32888c2ecf20Sopenharmony_ci	.ops	= {
32898c2ecf20Sopenharmony_ci		.add		= toshiba_acpi_add,
32908c2ecf20Sopenharmony_ci		.remove		= toshiba_acpi_remove,
32918c2ecf20Sopenharmony_ci		.notify		= toshiba_acpi_notify,
32928c2ecf20Sopenharmony_ci	},
32938c2ecf20Sopenharmony_ci	.drv.pm	= &toshiba_acpi_pm,
32948c2ecf20Sopenharmony_ci};
32958c2ecf20Sopenharmony_ci
32968c2ecf20Sopenharmony_cistatic int __init toshiba_acpi_init(void)
32978c2ecf20Sopenharmony_ci{
32988c2ecf20Sopenharmony_ci	int ret;
32998c2ecf20Sopenharmony_ci
33008c2ecf20Sopenharmony_ci	toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
33018c2ecf20Sopenharmony_ci	if (!toshiba_proc_dir) {
33028c2ecf20Sopenharmony_ci		pr_err("Unable to create proc dir " PROC_TOSHIBA "\n");
33038c2ecf20Sopenharmony_ci		return -ENODEV;
33048c2ecf20Sopenharmony_ci	}
33058c2ecf20Sopenharmony_ci
33068c2ecf20Sopenharmony_ci	ret = acpi_bus_register_driver(&toshiba_acpi_driver);
33078c2ecf20Sopenharmony_ci	if (ret) {
33088c2ecf20Sopenharmony_ci		pr_err("Failed to register ACPI driver: %d\n", ret);
33098c2ecf20Sopenharmony_ci		remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
33108c2ecf20Sopenharmony_ci	}
33118c2ecf20Sopenharmony_ci
33128c2ecf20Sopenharmony_ci	return ret;
33138c2ecf20Sopenharmony_ci}
33148c2ecf20Sopenharmony_ci
33158c2ecf20Sopenharmony_cistatic void __exit toshiba_acpi_exit(void)
33168c2ecf20Sopenharmony_ci{
33178c2ecf20Sopenharmony_ci	acpi_bus_unregister_driver(&toshiba_acpi_driver);
33188c2ecf20Sopenharmony_ci	if (toshiba_proc_dir)
33198c2ecf20Sopenharmony_ci		remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
33208c2ecf20Sopenharmony_ci}
33218c2ecf20Sopenharmony_ci
33228c2ecf20Sopenharmony_cimodule_init(toshiba_acpi_init);
33238c2ecf20Sopenharmony_cimodule_exit(toshiba_acpi_exit);
3324